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 82b4f38  Move the workflow project check to the interaction module
82b4f38 is described below

commit 82b4f382c55347bbe8b0a95de615b50c8f108b35
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Sep 4 15:04:16 2025 +0100

    Move the workflow project check to the interaction module
---
 atr/blueprints/api/api.py | 36 +-----------------------------------
 atr/db/interaction.py     | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 35 deletions(-)

diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 48dde03..2ba6e5a 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -41,7 +41,6 @@ import atr.ldap as ldap
 import atr.log as log
 import atr.models as models
 import atr.models.sql as sql
-import atr.registry as registry
 import atr.revision as revision
 import atr.routes as routes
 import atr.routes.announce as announce
@@ -367,40 +366,7 @@ async def jwt_github(data: models.api.JwtGithubArgs) -> 
DictResponse:
     payload = await jwtoken.verify_github_oidc(data.jwt)
     asf_uid = await ldap.github_to_apache(payload["actor_id"])
 
-    # Debugging
-    log.info(f"GitHub OIDC JWT payload: {payload}")
-
-    repository = payload["repository"]
-    if not repository.startswith("apache/"):
-        raise exceptions.BadRequest("Repository must start with 'apache/'")
-    repository_name = repository.removeprefix("apache/")
-    workflow_ref = payload["workflow_ref"]
-    if not workflow_ref.startswith(repository + "/"):
-        raise exceptions.BadRequest(f"Workflow ref must start with repository, 
got {workflow_ref}")
-    workflow_path_at = workflow_ref.removeprefix(repository + "/")
-    if "@" not in workflow_path_at:
-        raise exceptions.BadRequest(f"Workflow path must contain '@', got 
{workflow_path_at}")
-    workflow_path = workflow_path_at.rsplit("@", 1)[0]
-    if not workflow_path.startswith(".github/workflows/"):
-        raise exceptions.BadRequest(f"Workflow path must start with 
'.github/workflows/', got {workflow_path}")
-    # TODO: If a policy is reused between projects, we can't get the project
-    async with db.session() as db_data:
-        policy = await db_data.release_policy(
-            github_repository_name=repository_name, 
github_workflow_path=workflow_path
-        ).demand(
-            exceptions.NotFound(
-                f"No release policy found for repository name 
{repository_name} and workflow path {workflow_path}"
-            )
-        )
-        project = await db_data.project(release_policy_id=policy.id).demand(
-            exceptions.NotFound(f"Project for release policy {policy.id} not 
found")
-        )
-    if project.committee is None:
-        raise exceptions.BadRequest(f"Project {project.name} has no committee")
-    if project.committee.name not in 
registry.GITHUB_AUTOMATED_RELEASE_COMMITTEES:
-        raise exceptions.BadRequest(f"Project {project.name} is not in a 
committee that can make releases")
-    log.info(f"Release policy: {policy}")
-    log.info(f"Project: {project}")
+    project = await interaction.trusted_project(payload["repository"], 
payload["workflow_ref"])
 
     # TODO: This needs to go in the storage interface
     # And it needs to create an audit event for logging
diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index a50e127..17bba07 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -29,6 +29,7 @@ import sqlmodel
 import atr.db as db
 import atr.log as log
 import atr.models.sql as sql
+import atr.registry as registry
 import atr.user as user
 import atr.util as util
 
@@ -219,6 +220,42 @@ async def tasks_ongoing_revision(
         return task_count, latest_revision
 
 
+async def trusted_project(repository: str, workflow_ref: str) -> sql.Project:
+    # Debugging
+    log.info(f"GitHub OIDC JWT payload: {repository} {workflow_ref}")
+
+    if not repository.startswith("apache/"):
+        raise InteractionError("Repository must start with 'apache/'")
+    repository_name = repository.removeprefix("apache/")
+    if not workflow_ref.startswith(repository + "/"):
+        raise InteractionError(f"Workflow ref must start with repository, got 
{workflow_ref}")
+    workflow_path_at = workflow_ref.removeprefix(repository + "/")
+    if "@" not in workflow_path_at:
+        raise InteractionError(f"Workflow path must contain '@', got 
{workflow_path_at}")
+    workflow_path = workflow_path_at.rsplit("@", 1)[0]
+    if not workflow_path.startswith(".github/workflows/"):
+        raise InteractionError(f"Workflow path must start with 
'.github/workflows/', got {workflow_path}")
+    # TODO: If a policy is reused between projects, we can't get the project
+    async with db.session() as db_data:
+        policy = await db_data.release_policy(
+            github_repository_name=repository_name, 
github_workflow_path=workflow_path
+        ).demand(
+            InteractionError(
+                f"No release policy found for repository name 
{repository_name} and workflow path {workflow_path}"
+            )
+        )
+        project = await db_data.project(release_policy_id=policy.id).demand(
+            InteractionError(f"Project for release policy {policy.id} not 
found")
+        )
+    if project.committee is None:
+        raise InteractionError(f"Project {project.name} has no committee")
+    if project.committee.name not in 
registry.GITHUB_AUTOMATED_RELEASE_COMMITTEES:
+        raise InteractionError(f"Project {project.name} is not in a committee 
that can make releases")
+    log.info(f"Release policy: {policy}")
+    log.info(f"Project: {project}")
+    return project
+
+
 async def unfinished_releases(asfuid: str) -> dict[str, list[sql.Release]]:
     releases: dict[str, list[sql.Release]] = {}
     async with db.session() as data:


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

Reply via email to