fix(auto-promote): fail-closed when branch-protection API inaccessible (#84) #85
Reference in New Issue
Block a user
Delete Branch "fix/auto-promote-fail-closed-protection-api"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #84
Problem
The gates step read branch protection via:
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 subsequentif [ -z "$GATES" ]then treated this as no gates configured, setok=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 apiexit code separately. On non-zero: emit::error::, setok=false, and the existingif: 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
ok=false, fast-forward skipped,::error::emittedok=true, fast-forward runsok=false, fast-forward skipped (unchanged)Not merged; routing for review per PM directive.
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 #84APPROVED. 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.
5-axis review: APPROVED.
Correctness/security: the branch-protection API call now captures
GATES_RCbefore re-enablingset -e; any non-zero/403/network failure writesok=falseand exits the gate step, so.gitea/workflows/auto-promote-staging.yml:103skips the fast-forward. API-200 with zero contexts still takes the existing--ff-onlypath, 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.