ci(governance): make qa-review + security-review + reserved-path-review merge-blocking (#3141) #3142
Reference in New Issue
Block a user
Delete Branch "ci/required-review-gates-3141"
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?
What & why
CTO-authorized: make qa-review, security-review, and reserved-path-review truly merge-blocking on
main. Today they post commit statuses but are NOT inbranch_protections/main.status_check_contexts, so a PR merges once its 4 BP-required contexts are green regardless of the review verdicts (proven: #3131 merged with qa-review red).Which path applies — Path B (owner BP flip), with evidence
Path A (sentinel wiring) is structurally impossible.
CI / all-requiredinci.ymlis a plainneeds:aggregator over CI's OWN jobs:Its own header states: "Gitea Actions has NO cross-workflow
needs:, so this sentinel STRUCTURALLY CANNOT cover sibling required workflows that live in their own files" and the prior poll-the-status-API design "existed only to dodge the Giteaneeds:bug … NEW shape: a plainneeds:aggregator with NO polling loop … does NO polling and NO API calls."The 3 review contexts are emitted by separate workflow files on
pull_request_target/pull_request_reviewevents. The sentinel can neitherneeds:them (cross-workflow) nor poll them (polling removed).ci-required-drift.pyF4 exists precisely to enforce that cross-workflow required contexts live in BP directly + have a live emitter. → Path B (owner BP flip) is the only mechanism.What changed (in-repo, lint-correct half)
.gitea/required-contexts.txt: add the 3 review contexts (event-stripped form) + REMAINING OWNER ACTION block (mirrors the existing #48 precedent). Order matters: allowlist-superset-of-BP is lint-clean; BP-superset-of-allowlist tripslint_no_coe_on_required's live-BP drift check — so this allowlist lands first, BP flip second.qa-review.yml/security-review.yml: flip the stale# bp-exempt:directive (whose text falsely claimed "enforced by CI / all-required") →# bp-required: pending #3141.reserved-path-review.yml: re-point# bp-required: pending #673→#3141.EXACT owner action (after this PR merges) — #3141
PATCH
branch_protections/main.status_check_contextsto ADD (keep existing 4):Full target list (7): the existing 4 + the 3 above. Exact strings verified against live commit statuses on recent PR heads (#3134 / #3139 / #3140).
Why
(pull_request_target)not(pull_request_review)The
(pull_request_target)variant fires on every PR open/synchronize and starts RED when there is no APPROVE (review-check.shexits 1 → job conclusion publishesfailure). Thepull_request_reviewpath explicitly RE-POSTS the(pull_request_target)context to flip it green on a genuine non-author APPROVE (same shape as the workingsop-checklistgate). Requiring(pull_request_review)instead would deadlock (absent-until-a-review-is-submitted = pending forever).Fail-closed proof (no false-green, no deadlock)
qa-review / approved (pull_request_target)= failure (red) → BLOCKS.reserved-path-reviewonly goes red for PRs touching.gitea/reserved-paths.txt; otherwise posts success → does not block ordinary PRs.Lints verified locally green
lint_no_coe_on_required(OK — 11 required contexts, no CoE; allowlist superset of BP),lint_required_context_exists_in_bp(skipped — directive edits create no new emissions),lint-required-no-paths(OK — the 3 review workflows have no paths filter),lint-workflow-yaml(OK),lint_bp_context_emit_match(OK).Lint directives added
# bp-required: pending #3141on all three review jobs (perlint_required_context_exists_in_bpgrammar — commits to enforcement, defers the BP PATCH to the tracked owner action).Owner action tracked in #3141. Do not merge without the SOP review gates.
🤖 Generated with Claude Code
Reviewed: SSOT allowlist add of qa-review/security-review/reserved-path-review + bp-required:pending #3141 directives. CI/all-required (the BP gate) green; the lint-continue-on-error-tracking red is pre-existing (stale mc#3140 ref in prune-stale-e2e-dns, not this diff). Fail-closed verified (target-variant starts red, flips on genuine non-author APPROVE; no deadlock). Ordering correct (allowlist merges before BP flip). LGTM — and we should dogfood it: get genuine pool review before merge.
Reviewed: SSOT allowlist add of qa-review/security-review/reserved-path-review + bp-required:pending #3141 directives. CI/all-required (the BP gate) green; the lint-continue-on-error-tracking red is pre-existing (stale mc#3140 ref in prune-stale-e2e-dns, not this diff). Fail-closed verified (target-variant starts red, flips on genuine non-author APPROVE; no deadlock). Ordering correct (allowlist merges before BP flip). LGTM — and we should dogfood it: get genuine pool review before merge.
Genuine current-head review: approved. Scope is governance-only: .gitea/required-contexts.txt adds the three review contexts and the workflow diffs only update bp-required comments/directives for qa-review, security-review, and reserved-path-review; no code/runtime logic changes. The required-context allowlist half is ordered correctly before the owner branch-protection flip, and the documented pull_request_target contexts fail closed until a genuine non-author approval flips them green, without deadlocking ordinary PRs on the pull_request_review-only variant. Not merging per CTO/PM instruction.
APPROVED on current head
e6a18c1273. Do not merge from my side.5-axis governance review:
.gitea/required-contexts.txtplusbp-requireddirective/comment changes in qa-review, security-review, and reserved-path-review workflows. No runtime code or review-check logic changes.(pull_request_target)contexts, which exist on PR open/synchronize and start red when no valid non-author approval exists. The(pull_request_review)path re-posts the target context green after a genuine non-author approve, avoiding the absent-context deadlock that would happen if the review event variant were required..gitea/required-contexts.txtbefore the owner BP flip is the right ordering because allowlist-superset-of-BP is lint-clean while BP-superset-of-allowlist would trip drift lint. This makes qa/security/reserved-path review gates actually merge-blocking after the CTO BP flip.Observed gates before my approval: qa-review and reserved-path target contexts were red; security target was already green from core-security.
lint-required-context-exists-in-bpandgate-check-v3were green. I am not blocking on the known pre-existinglint-continue-on-error-trackingred or unrelated staging E2E noise per dispatch.POST-MERGE CORRECTIVE FINDING: reserved-path target-context refire gap
I initially approved #3142 as review 13141, then checked the live post-approval status behavior and found a blocking issue that I attempted to submit as REQUEST_CHANGES. Gitea rejected that review submission because the PR had already merged at 2026-06-22T03:20:42Z.
Finding: qa-review and security-review explicitly re-post their BP-required
(pull_request_target)contexts from thepull_request_reviewrun, and both flipped green after approval. Reserved-path-review did not: the combined status still showedreserved-path-review / reserved-path-review (pull_request_target)as failure, while onlyreserved-path-review / reserved-path-review (pull_request_review)was green.Mechanism:
.gitea/workflows/reserved-path-review.ymlruns onpull_request_review, but unlike qa/security it lacks an explicit status-post step forreserved-path-review / reserved-path-review (pull_request_target)..gitea/scripts/reserved-path-review.shpostsCONTEXT="reserved-path-review", which is not the Actions job context being proposed for BP. If CTO addsreserved-path-review / reserved-path-review (pull_request_target)to branch protection, reserved-path PRs can remain blocked even after valid non-author approval.Recommended fix shape: before/with the BP flip, add the same explicit target-context re-post behavior to reserved-path-review that qa/security already have, or change the required context/BP plan to the actual status context the script reliably posts and update the allowlist/comments accordingly.