diff --git a/DECISIONS-LOG.md b/DECISIONS-LOG.md index 41bfc92..588a5f3 100644 --- a/DECISIONS-LOG.md +++ b/DECISIONS-LOG.md @@ -5044,3 +5044,68 @@ fail-opens in the gate itself were found the same way — `kyverno test` certify not load, and `CLUSTER_AVAILABLE` certifying 54 skipped tests as passed. **Measure, then assert. `CLAUDE.md` §2b is the rule; this entry is the evidence for it.** + +## 2026-09-29 (addendum, unattended) — the detector is armed; **I CANNOT MERGE, and that is correct** + +Operator ran `set-ci-token.sh`, uncommented `REQUIRE_GITEA_SETTINGS` locally on `main`, and left +instructions to continue unattended and merge on green CI. Two things came out of that. + +### 1. The detector was INERT, and would have stayed inert silently + +`set-ci-token.sh` PUT the secret as `GITEA_SETTINGS_TOKEN`. **Gitea reserves the `GITEA_` +prefix** for secret names (as GitHub reserves `GITHUB_`) and rejected it: + + HTTP 400 {"message":"invalid secret name"} + +The script sent that PUT to `/dev/null` and printed `==> stored.` unconditionally; `curl -sS` +exits 0 on an HTTP error. **A token existed; no secret did.** So `ci/gitea-settings.sh` would +have skipped on every run forever — and enabling `REQUIRE_GITEA_SETTINGS` on top of that would +have BLOCKED EVERY PR, including the one fixing it. That is the exact lock-out this repo has now +nearly walked into three times. + +Fixed in **PR #15**: the secret is `SETTINGS_API_TOKEN`, and `set-ci-token.sh` now checks the HTTP +status AND reads the secret back before claiming success. The missing verification was the real +defect; the illegal name is only what it hid. The secret is stored and verified present, and +**PR #15's CI is GREEN with `REQUIRE_GITEA_SETTINGS=true`** — which is the only proof that +matters, because a skip would have made it red. + +The operator's local edit could not be pushed to `main` (protected). It is carried in PR #15. + +### 2. No agent-authored PR can be merged without the operator — by design + +Merging PR #12 as `gitea-admin` returned: + + HTTP 405 {"message":"Does not have enough approvals"} + +`required_approvals: 1` + `block_admin_merge_override: true` + two accounts, one of which +(`gitea-admin`) authors every agent PR and cannot self-approve. **So "merge on green CI" is not +something an agent can execute here.** That is the control working, not a fault — and it was +deliberately not circumvented. Self-approving would hollow out the boundary that was just built +and verified. + +**This is an operator decision, not a bug to fix:** either accept that every agent PR waits for a +human approval (the honest reading of the control), or add a second human reviewer account, or +lower `required_approvals` to 0 and rely on the status check — which is the gate that actually +verifies something. Whichever, change the DECLARATION in +`infra/gitea/expected-branch-protection.json` in the same commit, or `gitea-settings` will +correctly fail the gate on the drift. + +### Open PRs, all gated green, none mergeable by an agent + +| PR | What | +|---|---| +| #12 | `CLUSTER_AVAILABLE=true` would have faked a green over 54 skipped tests — now blocks | +| #13 | Conformance-trigger admission boundary (R-SEC-02) + `kyverno test` fail-open fix | +| #14 | This handoff | +| #15 | Secret-name fix + `REQUIRE_GITEA_SETTINGS` enabled — **CI green with REQUIRE active** | + +Suggested order: #15 first (it arms the detector and its CI already proved it), then #12, #13, +#14. If a later one conflicts, rebase; the gate re-runs in ~1m36s. + +### Deliberately NOT done while unattended + +No new feature work was started. Five unmerged PRs already stack review burden, and building the +next L2/L3 piece on top of unmerged branches would create a rebase tangle for no gain — the work +cannot land any faster. The next piece is specified and ready to start once these are merged: +`docs/plans/l2-l3-conformance-ci-wiring.md` §3, with §4's credential model now decided and its +boundary landed in #13.