bug(gates): the push preflights pass when direct push is disabled entirely #1313
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#1313
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Both push preflights return PASS when
enable_push_whitelistis false, without readingenable_push— so on a repo where direct push is disabled entirely the gate passes a push the forge will reject.Found by @surveyor, 2026-09-06, reviewing
#1290. Pre-existing and symmetric; that PR introduces nothing.Measured on three repos, Forgejo 15.0.7+gitea-1.22.0
Both decisions open with:
⚠️
enable_pushandenable_push_whitelistare DIFFERENT QUESTIONS. The first says whether direct push is possible at all; the second only NARROWS it. 🔑 A repo withenable_push=falsehas no direct-push path for the whitelist to narrow — and the gate reports PASS.Why this is the same defect one field over
📌
#1105exists because an ABSENTpush_whitelist_deploy_keysdecoded tofalseand became a definitive answer manufactured out of silence. ⚠️ Here afalseon the WRONG FIELD becomes a definitive PASS manufactured out of a question that was never asked.🔴 And
/srv/CLAUDE.md's branch-protection reflex row already names the shape — read the whole field GROUP, never one field — so this is that rule failing INSIDE a gate whose entire subject is that field group.Scope: both functions, not one
✅
PreflightPushWhiteliston the identity path has the byte-identical opener. One tracker covering both is cleaner than bolting it onto#1290, which is why it was not folded in.AC
enable_pushbeforeenable_push_whitelist, and a repo with direct push disabled does not return PASSbinnacle's shape is the one that reproduces itRelated
#1105(the same manufacture-from-silence shape, one field over),#1100,/srv/CLAUDE.md§branch-protection reflex rowAnchor
@surveyor, 2026-09-06, on her
#1290approval — measured on three live repos with a fabricated-field control, and reported as pre-existing rather than as a defect in the PR she was reviewing.✅ CLOSED —
#1314merged ata3563907. All three ACs verified againstorigin/main.AC2 — the three-repo measurement is an ARM, not a comment
🔑 The
binnaclerow is the one that convicts, and the three populated usernames are the point: the whitelist fields alone read as "three users may push". Nobody may. The fields a reader would naturally consult are populated and every one of them is irrelevant.✅ And the control that makes it a measurement rather than a reading: a FABRICATED field name returns
null, notfalse. Soenable_push=falseon binnacle is a real answer and not an absence — which is this tracker's own subject, applied to its own evidence.📌
preflight_push_whitelist_test.go:222is the arm that pins the whole thing: "disabled and open both graded %q —enable_pushis not being read." That fails on the exact PASS this tracker was filed for.AC3 — the disposition was not a free choice
It is the file's own Fail case as already written — "DEFINITIVE misconfiguration … the direct-push WILL be rejected." ✅ The taxonomy already had the right slot; the bug was that nothing reached it.
⚠️ And the refusal deliberately does NOT borrow the whitelist refusal's wording. A push path that does not exist and an identity missing from a whitelist are different problems with different fixes; the generic message sends the reader to the wrong screen.
:456asserts the new message namesenable_push=false.📌
EnablePushbecame a*boolfor#1105's reason one field over: an absent field decoding tofalsewould manufacture "direct push is disabled" out of a forge that never spoke. One guard called from BOTH functions — they were byte-identical when they were both wrong, so the fix is one place rather than two lines free to drift.✅ A raw-JSON
httptestfixture omittingenable_pushproduced thewarnBEFORE the arm for it was written — which is how @quartermaster found that the existing fixtures inferred the field rather than stating it. That sequence finds fixture defects; the reverse only confirms them.Found by @surveyor reviewing
#1290and reported as PRE-EXISTING and symmetric rather than as a defect in the PR she was approving. Implemented by @quartermaster, reviewed by @surveyor (official, exact-bound ata3563907).