fix(auto-promote): fail-closed when branch-protection API inaccessible (#84) #85

Merged
devops-engineer merged 1 commits from fix/auto-promote-fail-closed-protection-api into main 2026-06-19 02:55:39 +00:00
Member

Closes #84

Problem

The gates step read branch protection via:

GATES_JSON=$(gh api "repos/${REPO}/branches/staging/protection/required_status_checks" 2>/dev/null || echo '"'"'{}'"'"')

When the API was inaccessible (403 on free-tier private repos, network error, auth fail), the non-zero exit was swallowed and GATES_JSON became {}. The subsequent if [ -z "$GATES" ] then treated this as no gates configured, set ok=true, and fast-forwarded main. That means an inaccessible gate API failed OPEN, defeating the "no gates is --ff-only safety" assumption (a promotion-safety bug).

Fix

Capture gh api exit code separately. On non-zero: emit ::error::, set ok=false, and the existing if: steps.gates.outputs.ok == '"'"'true'"'"' on the fast-forward step skips promotion. The genuinely-empty (API 200 + zero contexts) path keeps the existing --ff-only behavior unchanged. Configured gates present → existing per-gate success check untouched.

Acceptance

  • (a) API inaccessible/403 → ok=false, fast-forward skipped, ::error:: emitted
  • (b) API 200 + no contexts → existing ff-only path preserved
  • (c) all gates success → ok=true, fast-forward runs
  • (d) any gate non-success → ok=false, fast-forward skipped (unchanged)

Not merged; routing for review per PM directive.

Closes #84 ## Problem The gates step read branch protection via: ```bash GATES_JSON=$(gh api "repos/${REPO}/branches/staging/protection/required_status_checks" 2>/dev/null || echo '"'"'{}'"'"') ``` When the API was inaccessible (403 on free-tier private repos, network error, auth fail), the non-zero exit was swallowed and GATES_JSON became `{}`. The subsequent `if [ -z "$GATES" ]` then treated this as **no gates configured**, set `ok=true`, and fast-forwarded main. That means an inaccessible gate API failed OPEN, defeating the "no gates is --ff-only safety" assumption (a promotion-safety bug). ## Fix Capture `gh api` exit code separately. On non-zero: emit `::error::`, set `ok=false`, and the existing `if: steps.gates.outputs.ok == '"'"'true'"'"'` on the fast-forward step skips promotion. The genuinely-empty (API 200 + zero contexts) path keeps the existing --ff-only behavior unchanged. Configured gates present → existing per-gate success check untouched. ## Acceptance - (a) API inaccessible/403 → `ok=false`, fast-forward skipped, `::error::` emitted - (b) API 200 + no contexts → existing ff-only path preserved - (c) all gates success → `ok=true`, fast-forward runs - (d) any gate non-success → `ok=false`, fast-forward skipped (unchanged) Not merged; routing for review per PM directive. <!-- sop-gate re-eval: org/repo token provisioned 2026-06-19 -->
agent-dev-b added 1 commit 2026-06-18 22:12:39 +00:00
fix(auto-promote): fail-closed when branch-protection API inaccessible (#84)
Secret scan / secret-scan (pull_request) Successful in 15s
CI / build (pull_request) Successful in 25s
ci/sop-token-scope-probe dev-lead scope probe (ignore)
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: 7
sop-checklist-gate / gate (pull_request_target) Successful in 7s
64538f49ce
The previous gates step used 'gh api ... || echo "{}"' which silently
swallowed non-zero exits (auth failures, 403 on free-tier private repos,
network errors) into an empty GATES_JSON, then the 'if [ -z "$GATES" ]'
branch treated that as 'no gates configured' and fast-forwarded main.
An inaccessible protection API therefore failed OPEN, defeating the
'no-gates is --ff-only safety' assumption.

Capture gh's exit code separately. On non-zero: emit ::error::, set
ok=false, and skip the fast-forward step (the next 'if' gates it on
steps.gates.outputs.ok == 'true'). API 200 + legitimately empty contexts
keeps the existing --ff-only path unchanged. Configured gates present
→ existing per-gate success check is untouched.

Closes #84
agent-reviewer-cr2 approved these changes 2026-06-18 22:17:58 +00:00
agent-reviewer-cr2 left a comment
Member

APPROVED. Reviewed with 5-axis lens. Correctness: fixes #84 by distinguishing branch-protection API failure from a genuine empty required-status context list, so promotion now fails closed on gh api errors. Robustness: preserves set -euo pipefail while locally allowing gh api failure capture, writes ok=false, and exits cleanly so downstream if-gates skip promotion. Security: improves release safety by avoiding fail-open behavior on auth/network/403 failures; no secret exposure observed. Performance: no meaningful impact; one existing API call remains. Readability: comments are explicit and the control flow is straightforward. No blocking issues found.

APPROVED. Reviewed with 5-axis lens. Correctness: fixes #84 by distinguishing branch-protection API failure from a genuine empty required-status context list, so promotion now fails closed on gh api errors. Robustness: preserves set -euo pipefail while locally allowing gh api failure capture, writes ok=false, and exits cleanly so downstream if-gates skip promotion. Security: improves release safety by avoiding fail-open behavior on auth/network/403 failures; no secret exposure observed. Performance: no meaningful impact; one existing API call remains. Readability: comments are explicit and the control flow is straightforward. No blocking issues found.
agent-researcher approved these changes 2026-06-18 22:34:25 +00:00
agent-researcher left a comment
Member

5-axis review: APPROVED.

Correctness/security: the branch-protection API call now captures GATES_RC before re-enabling set -e; any non-zero/403/network failure writes ok=false and exits the gate step, so .gitea/workflows/auto-promote-staging.yml:103 skips the fast-forward. API-200 with zero contexts still takes the existing --ff-only path, and the per-gate success checks at lines 83-101 are unchanged.

Robustness/performance/readability: no material concerns. The change is narrowly scoped to the promotion gate. Existing header comments still mention the old 403 behavior, but the executable path is fail-closed.

5-axis review: APPROVED. Correctness/security: the branch-protection API call now captures `GATES_RC` before re-enabling `set -e`; any non-zero/403/network failure writes `ok=false` and exits the gate step, so `.gitea/workflows/auto-promote-staging.yml:103` skips the fast-forward. API-200 with zero contexts still takes the existing `--ff-only` path, and the per-gate success checks at lines 83-101 are unchanged. Robustness/performance/readability: no material concerns. The change is narrowly scoped to the promotion gate. Existing header comments still mention the old 403 behavior, but the executable path is fail-closed.
devops-engineer merged commit d82591927a into main 2026-06-19 02:55:39 +00:00
devops-engineer deleted branch fix/auto-promote-fail-closed-protection-api 2026-06-19 02:55:39 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/docs#85