This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new bcd1b77  Add an endpoint to announce a release using a GitHub OIDC JWT
bcd1b77 is described below

commit bcd1b7782c37949d8520bafeee364035e61c4c52
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Sep 4 16:11:05 2025 +0100

    Add an endpoint to announce a release using a GitHub OIDC JWT
---
 atr/blueprints/api/api.py | 76 +++++++++++++++++++++++++++++++++--------------
 atr/models/api.py         | 20 +++++++++++++
 2 files changed, 73 insertions(+), 23 deletions(-)

diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 7537965..e117d13 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -259,12 +259,65 @@ async def committees_list() -> DictResponse:
     ).model_dump(), 200
 
 
[email protected]("/github/release/announce", methods=["POST"])
+@quart_schema.validate_request(models.api.GithubReleaseAnnounceArgs)
+async def github_release_announce(data: models.api.GithubReleaseAnnounceArgs) 
-> DictResponse:
+    """
+    Announce a release with a corroborating GitHub OIDC JWT.
+    """
+    _payload, asf_uid, project = await interaction.github_trusted_jwt(data.jwt)
+    try:
+        # TODO: Add defaults
+        await announce.announce(
+            project.name,
+            data.version,
+            data.revision,
+            data.email_to,
+            data.subject,
+            data.body,
+            data.path_suffix,
+            asf_uid,
+            asf_uid,
+        )
+    except announce.AnnounceError as e:
+        raise exceptions.BadRequest(str(e))
+
+    return models.api.GithubReleaseAnnounceResults(
+        endpoint="/github/release/announce",
+        success=True,
+    ).model_dump(), 200
+
+
[email protected]("/github/ssh/register", methods=["POST"])
+@quart_schema.validate_request(models.api.GithubSshRegisterArgs)
+async def github_ssh_register(data: models.api.GithubSshRegisterArgs) -> 
DictResponse:
+    """
+    Register an SSH key sent with a corroborating GitHub OIDC JWT.
+    """
+    payload, asf_uid, project = await interaction.github_trusted_jwt(data.jwt)
+    async with 
storage.write_as_committee_member(util.unwrap(project.committee).name, asf_uid) 
as wacm:
+        fingerprint, expires = await wacm.ssh.add_workflow_key(
+            payload["actor"],
+            payload["actor_id"],
+            project.name,
+            data.ssh_key,
+        )
+
+    return models.api.GithubSshRegisterResults(
+        endpoint="/github/ssh/register",
+        fingerprint=fingerprint,
+        project=project.name,
+        expires=expires,
+    ).model_dump(), 200
+
+
 @api.BLUEPRINT.route("/github/vote/resolve", methods=["POST"])
 @quart_schema.validate_request(models.api.GithubVoteResolveArgs)
 async def github_vote_resolve(data: models.api.GithubVoteResolveArgs) -> 
DictResponse:
     """
     Resolve a vote with a corroborating GitHub OIDC JWT.
     """
+    # TODO: Need to be able to resolve and make the release immutable
     _payload, asf_uid, project = await interaction.github_trusted_jwt(data.jwt)
     if project.committee is None:
         raise exceptions.NotFound("Project has no committee")
@@ -297,29 +350,6 @@ async def github_vote_resolve(data: 
models.api.GithubVoteResolveArgs) -> DictRes
     ).model_dump(), 200
 
 
[email protected]("/github/ssh/register", methods=["POST"])
-@quart_schema.validate_request(models.api.GithubSshRegisterArgs)
-async def github_ssh_register(data: models.api.GithubSshRegisterArgs) -> 
DictResponse:
-    """
-    Register an SSH key sent with a corroborating GitHub OIDC JWT.
-    """
-    payload, asf_uid, project = await interaction.github_trusted_jwt(data.jwt)
-    async with 
storage.write_as_committee_member(util.unwrap(project.committee).name, asf_uid) 
as wacm:
-        fingerprint, expires = await wacm.ssh.add_workflow_key(
-            payload["actor"],
-            payload["actor_id"],
-            project.name,
-            data.ssh_key,
-        )
-
-    return models.api.GithubSshRegisterResults(
-        endpoint="/github/ssh/register",
-        fingerprint=fingerprint,
-        project=project.name,
-        expires=expires,
-    ).model_dump(), 200
-
-
 @api.BLUEPRINT.route("/ignore/add", methods=["POST"])
 @jwtoken.require
 @quart_schema.security_scheme([{"BearerAuth": []}])
diff --git a/atr/models/api.py b/atr/models/api.py
index 8c240a2..14e4cdb 100644
--- a/atr/models/api.py
+++ b/atr/models/api.py
@@ -71,6 +71,24 @@ class CommitteesListResults(schema.Strict):
     committees: Sequence[sql.Committee]
 
 
+class GithubReleaseAnnounceArgs(schema.Strict):
+    jwt: str = schema.Field(..., 
**example("eyJhbGciOiJIUzI1[...]mMjLiuyu5CSpyHI="))
+    version: str = schema.Field(..., **example("0.0.1"))
+    revision: str = schema.Field(..., **example("00005"))
+    email_to: str = schema.Field(..., **example("[email protected]"))
+    subject: str = schema.Field(..., **example("[ANNOUNCE] Apache Example 
1.0.0 release"))
+    body: str = schema.Field(
+        ...,
+        **example("The Apache Example team is pleased to announce the release 
of Example 1.0.0..."),
+    )
+    path_suffix: str = schema.Field(..., **example("example/1.0.0"))
+
+
+class GithubReleaseAnnounceResults(schema.Strict):
+    endpoint: Literal["/github/release/announce"] = 
schema.Field(alias="endpoint")
+    success: Literal[True] = schema.Field(..., **example(True))
+
+
 class GithubSshRegisterArgs(schema.Strict):
     jwt: str = schema.Field(..., 
**example("eyJhbGciOiJIUzI1[...]mMjLiuyu5CSpyHI="))
     ssh_key: str = schema.Field(
@@ -445,6 +463,7 @@ Results = Annotated[
     | CommitteeKeysResults
     | CommitteeProjectsResults
     | CommitteesListResults
+    | GithubReleaseAnnounceResults
     | GithubSshRegisterResults
     | GithubVoteResolveResults
     | IgnoreAddResults
@@ -499,6 +518,7 @@ validate_committee_get = validator(CommitteeGetResults)
 validate_committee_keys = validator(CommitteeKeysResults)
 validate_committee_projects = validator(CommitteeProjectsResults)
 validate_committees_list = validator(CommitteesListResults)
+validate_github_release_announce = validator(GithubReleaseAnnounceResults)
 validate_github_ssh_register = validator(GithubSshRegisterResults)
 validate_github_vote_resolve = validator(GithubVoteResolveResults)
 validate_ignore_add = validator(IgnoreAddResults)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to