fix(merge-queue): live pre-merge status re-fetch — close within-window snapshot-staleness fail-open (#3210 tail) #3226
Reference in New Issue
Block a user
Delete Branch "fix/merge-gate-live-recheck-3210d"
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?
#3210 tail — close the within-window snapshot-staleness fail-open (the LAST one)
After #3224 the conductor snapshot is only used when fresh (ts <=600s), but a required/enforced/critical context that flips RED within that window (after capture) was still read GREEN by the merge decision;
process_oncere-checked only that MAIN hadn't moved beforemerge_pull, never the candidate head's own live statuses → a snapshot-green-but-now-red PR could be merged.Fix: immediately before
merge_pull, re-fetch the candidate head's LIVE status (get_combined_status(prefer_live=True)bypasses the snapshot) and re-run the SAME gates the decision used (critical + required + enforced) vialive_premerge_status_regressions; on any regression SKIP the candidate (no merge), keep scanning. Snapshot still drives the cheap scan; only the ONE candidate about to merge pays one extra live GET.Strictly tightening, no existing check weakened. Tests: +6 (red-on-live required/critical/enforced → not merged; green-live → merges; prefer_live bypasses snapshot; spy confirms the re-fetch). 163 passed locally; proven to fail against pre-fix. Closes the last merge-gate fail-open of the #3210 audit family (#3222/#3224/#3225 already merged).
APPROVED on
3be4391b.5-axis/security review: Correctness: get_combined_status now supports prefer_live=True, and the final pre-merge path calls live_premerge_status_regressions immediately before merge_pull. That helper bypasses the conductor snapshot and re-runs all snapshot-stale status gates: critical contexts, branch-required contexts, and enforced-file contexts when present. A within-window red/missing flip now returns a regression reason and skips the candidate instead of merging snapshot-green state; green-live heads still merge. Robustness: get status failures remain fail-closed via the existing API path, head_sha is surfaced from _evaluate_candidate, and tests cover required, critical, enforced, green happy path, and snapshot bypass. Security: strictly tightens the merge gate; no secret/auth surface and no weakened approval/RC/mergeability checks. Performance: one extra live status GET only for the candidate about to merge. Readability: helper isolates the final status recheck and comments/tests document why it exists.
Reviewed files: .gitea/scripts/gitea-merge-queue.py and .gitea/scripts/tests/test_gitea_merge_queue.py. CI/all-required is green; approval-gated contexts were red pending fresh pool/security approval at review time.
Independent 5-axis review: APPROVE.
Correctness: the fix adds a final live status re-fetch immediately before
merge_pull, withget_combined_status(head_sha, prefer_live=True)explicitly bypassing conductor snapshots. The pre-merge helper re-runs the same status gates that can be snapshot-stale: critical contexts, BP/governance required contexts, and non-empty.gitea/required-contexts.txtenforced contexts. On any regression it skips the candidate and continues scanning, so a snapshot-green but now-red head is not merged.Robustness: the helper is narrow and fail-closed through existing status-fetch error behavior. Tests cover required, critical, enforced-file regressions, live-green merge, and the snapshot-bypass behavior. The existing main-moved check remains in place before the live re-check.
Security: I do not see a remaining within-window stale-snapshot bypass for required, critical, or enforced contexts.
prefer_live=Trueavoids the cached snapshot path. Off-path gates such as approvals and REQUEST_CHANGES remain handled by the decision flow; this change does not relax them. The only residual TOCTOU is the unavoidable small gap between live status GET and the merge POST, which is strictly tighter than the prior 600s snapshot trust window.Performance: one additional live status fetch is paid only for the single candidate about to merge; that is an acceptable cost for a merge-gate security check.
Readability: the helper is explicit, documented, and the tests make the stale-snapshot threat model clear. CI required contexts are green; Ops Scripts is red in unrelated SOP tests, not in the changed merge-queue coverage. This approval also covers the security/reserved-path review for this gate-protection change.