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]