fix(ci): the settings token could never have been stored #15

Merged
jakman85 merged 1 commits from fix/secret-name-and-require-gitea-settings into main 2026-09-29 18:14:30 +00:00
Owner

The drift detector merged in #11 was inert, and would have stayed inert silently.

infra/gitea/set-ci-token.sh minted a token and PUT it to the secret GITEA_SETTINGS_TOKEN.
Gitea reserves the GITEA_ prefix for secret names — as GitHub reserves GITHUB_ — and
rejects that with:

HTTP 400  {"message":"invalid secret name"}

The script sent the PUT to /dev/null and printed ==> stored. unconditionally, and curl -sS
exits 0 on an HTTP error. So it reported success for a store that never happened. Measured
afterwards: the token was in the user's token list, and the repo's secret list was empty.

ci/gitea-settings.sh would have skipped on every CI run forever — and with
REQUIRE_GITEA_SETTINGS=true it would instead have blocked every PR, including the one fixing
it.

Changes

  • Secret is now SETTINGS_API_TOKEN; the check reads it, keeping GITEA_SETTINGS_TOKEN as a
    local-run fallback.
  • set-ci-token.sh checks the PUT's HTTP status and reads the secret back, refusing to claim
    success otherwise. That missing verification is the real defect — the illegal name is only what
    it concealed.
  • gate.yml maps the secret and enables REQUIRE_GITEA_SETTINGS (the change Keith made
    locally; it could not be pushed to main directly, which is protection working correctly).

Why enabling it in this PR is safe

This PR's own CI run is the proof. If the stage were still skipping, REQUIRE turns that into
a failure and this PR goes red rather than merging. Green means the token resolved in CI and
live Gitea matched infra/gitea/expected-branch-protection.json.

Verified locally before pushing:

Condition Result
REQUIRE=true, token present gitea-settings: green → MERGE GATE: PASS
REQUIRE=true, no token gitea-settings: SKIPPED → BLOCKED (not a silent skip)

The secret is stored and read back as present, so CI has what it needs.

Co-Authored-By: Claude Opus 5 (1M context) [email protected]

🤖 Generated with Claude Code

**The drift detector merged in #11 was inert, and would have stayed inert silently.** `infra/gitea/set-ci-token.sh` minted a token and PUT it to the secret `GITEA_SETTINGS_TOKEN`. Gitea **reserves the `GITEA_` prefix** for secret names — as GitHub reserves `GITHUB_` — and rejects that with: ``` HTTP 400 {"message":"invalid secret name"} ``` The script sent the PUT to `/dev/null` and printed `==> stored.` unconditionally, and `curl -sS` exits 0 on an HTTP error. So it reported success for a store that never happened. Measured afterwards: the token was in the user's token list, and **the repo's secret list was empty.** `ci/gitea-settings.sh` would have skipped on every CI run forever — and with `REQUIRE_GITEA_SETTINGS=true` it would instead have **blocked every PR, including the one fixing it.** ### Changes - Secret is now **`SETTINGS_API_TOKEN`**; the check reads it, keeping `GITEA_SETTINGS_TOKEN` as a local-run fallback. - `set-ci-token.sh` checks the PUT's HTTP status **and reads the secret back**, refusing to claim success otherwise. That missing verification is the real defect — the illegal name is only what it concealed. - `gate.yml` maps the secret and **enables `REQUIRE_GITEA_SETTINGS`** (the change Keith made locally; it could not be pushed to `main` directly, which is protection working correctly). ### Why enabling it in this PR is safe **This PR's own CI run is the proof.** If the stage were still skipping, `REQUIRE` turns that into a failure and this PR goes **red** rather than merging. Green means the token resolved in CI and live Gitea matched `infra/gitea/expected-branch-protection.json`. Verified locally before pushing: | Condition | Result | |---|---| | `REQUIRE=true`, token present | `gitea-settings: green` → **MERGE GATE: PASS** | | `REQUIRE=true`, no token | `gitea-settings: SKIPPED` → **BLOCKED** (not a silent skip) | The secret is stored and read back as present, so CI has what it needs. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> 🤖 Generated with [Claude Code](https://claude.com/claude-code)
gitea-admin added 1 commit 2026-09-29 17:09:44 +00:00
fix(ci): the settings token could NEVER have been stored -- Gitea reserves the GITEA_ prefix
gate / gate (pull_request) Successful in 1m36s
gate / conformance (pull_request) Has been skipped
50a48e6f07
The drift detector merged in #11 was inert and would have stayed inert silently.

WHAT HAPPENED. infra/gitea/set-ci-token.sh minted a token and PUT it to the repo Actions
secret GITEA_SETTINGS_TOKEN. Gitea RESERVES the `GITEA_` prefix for secret names -- exactly
as GitHub reserves `GITHUB_` -- and rejects that PUT with:

    HTTP 400  {"message":"invalid secret name"}

The script sent the PUT to /dev/null and printed "==> stored." unconditionally, and
`curl -sS` exits 0 on an HTTP error, so it reported success for a store that never happened.
Measured afterwards: the token existed in the user's token list, and the repo's secret list
was EMPTY. ci/gitea-settings.sh would have skipped on every CI run forever, and with
REQUIRE_GITEA_SETTINGS=true it would instead have BLOCKED EVERY PR -- including the one
fixing it.

Three changes:
  * the secret is SETTINGS_API_TOKEN; ci/gitea-settings.sh reads it, keeping
    GITEA_SETTINGS_TOKEN as a local-run fallback;
  * set-ci-token.sh checks the PUT's HTTP status AND reads the secret back, refusing to claim
    success otherwise. That missing verification is the actual defect -- the wrong name was
    just what it hid;
  * gate.yml maps the secret and ENABLES REQUIRE_GITEA_SETTINGS.

WHY ENABLING IT HERE IS SAFE: this PR's own CI run is the proof. If the stage were still
skipping, REQUIRE turns that into a failure and this PR goes RED rather than merging. Green
means the token resolved and live Gitea matched infra/gitea/expected-branch-protection.json.

Verified locally before pushing:
  REQUIRE=true, token present -> MERGE GATE: PASS
  REQUIRE=true, no token      -> gitea-settings SKIPPED -> BLOCKED (not a silent skip)

The secret is already stored and read back as present, so CI has what it needs.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
jakman85 approved these changes 2026-09-29 18:14:26 +00:00
jakman85 merged commit 1d2d9d6549 into main 2026-09-29 18:14:30 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Home-Network/home-network-k3s-impl#15