diff --git a/.gitea/scripts/audit-force-merge.sh b/.gitea/scripts/audit-force-merge.sh index 10ee9e6bf..0c115720c 100755 --- a/.gitea/scripts/audit-force-merge.sh +++ b/.gitea/scripts/audit-force-merge.sh @@ -18,15 +18,24 @@ # per §SOP-6 security model). No-op when merged=false. # # Required env (set by the workflow): -# GITEA_TOKEN, GITEA_HOST, REPO, PR_NUMBER, REQUIRED_CHECKS +# GITEA_TOKEN, GITEA_HOST, REPO, PR_NUMBER +# plus one of REQUIRED_CHECKS_JSON (preferred) or REQUIRED_CHECKS (legacy) # -# REQUIRED_CHECKS is a newline-separated list of status-check context -# names that branch protection requires. Declared in the workflow YAML -# rather than fetched from /branch_protections (which needs admin -# scope — sop-tier-bot has read-only). Trade dynamism for simplicity: -# when the required-check set changes, update both branch protection -# AND this env. Keeping them in sync is less complexity than granting -# the audit bot admin perms on every repo. +# REQUIRED_CHECKS_JSON is a JSON object keyed by branch name. Each value +# is an array of status-check context names that branch protection +# requires for that branch. The script looks up the PR's base branch and +# evaluates only the checks declared for that branch. +# +# {"main": ["CI / all-required (pull_request)", ...], +# "staging": ["CI / all-required (pull_request)", ...]} +# +# REQUIRED_CHECKS (legacy) is a newline-separated list used when the +# JSON variable is not set. Declared in the workflow YAML rather than +# fetched from /branch_protections (which needs admin scope — sop-tier-bot +# has read-only). Trade dynamism for simplicity: when the required-check +# set changes, update both branch protection AND this env. Keeping them +# in sync is less complexity than granting the audit bot admin perms on +# every repo. set -euo pipefail @@ -34,7 +43,10 @@ set -euo pipefail : "${GITEA_HOST:?required}" : "${REPO:?required}" : "${PR_NUMBER:?required}" -: "${REQUIRED_CHECKS:?required (newline-separated context names)}" +if [ -z "${REQUIRED_CHECKS_JSON:-}" ] && [ -z "${REQUIRED_CHECKS:-}" ]; then + echo "::error::Either REQUIRED_CHECKS_JSON or REQUIRED_CHECKS must be set" + exit 1 +fi OWNER="${REPO%%/*}" NAME="${REPO##*/}" @@ -65,10 +77,14 @@ if [ -z "$MERGE_SHA" ]; then exit 0 fi -# 2. Required status checks declared in the workflow env. -REQUIRED="$REQUIRED_CHECKS" +# 2. Required status checks — branch-aware JSON dict takes precedence. +if [ -n "${REQUIRED_CHECKS_JSON:-}" ]; then + REQUIRED=$(echo "$REQUIRED_CHECKS_JSON" | jq -r --arg branch "$BASE_BRANCH" '.[$branch] // [] | .[]') +else + REQUIRED="$REQUIRED_CHECKS" +fi if [ -z "${REQUIRED//[[:space:]]/}" ]; then - echo "::notice::REQUIRED_CHECKS empty — force-merge not applicable." + echo "::notice::REQUIRED_CHECKS empty for branch '$BASE_BRANCH' — force-merge not applicable." exit 0 fi diff --git a/.gitea/workflows/audit-force-merge.yml b/.gitea/workflows/audit-force-merge.yml index 899198275..00c47312f 100644 --- a/.gitea/workflows/audit-force-merge.yml +++ b/.gitea/workflows/audit-force-merge.yml @@ -47,13 +47,25 @@ jobs: REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} # Required-status-check contexts to evaluate at merge time. - # Newline-separated. Mirror this against branch protection - # (settings → branches → protected branch → required checks). + # Branch-aware JSON dict: keys are protected branch names, + # values are arrays of context names that branch protection + # requires for that branch. Mirror this against branch + # protection (settings → branches → protected branch → + # required checks) for each branch listed here. + # # Declared here rather than fetched from /branch_protections # because that endpoint requires admin write — sop-tier-bot is # read-only by design (least-privilege). - REQUIRED_CHECKS: | - CI / all-required (pull_request) - E2E API Smoke Test / E2E API Smoke Test (pull_request) - Handlers Postgres Integration / Handlers Postgres Integration (pull_request) + REQUIRED_CHECKS_JSON: | + { + "main": [ + "CI / all-required (pull_request)", + "E2E API Smoke Test / E2E API Smoke Test (pull_request)", + "Handlers Postgres Integration / Handlers Postgres Integration (pull_request)" + ], + "staging": [ + "CI / all-required (pull_request)", + "sop-checklist / all-items-acked (pull_request)" + ] + } run: bash .gitea/scripts/audit-force-merge.sh