Forgejo CI-token provisioning is a re-derivation trap every time; promote it to a skill #452

Closed
opened 2026-07-03 08:15:53 +00:00 by coilyco-ops · 3 comments
Member

What happened

Rotating CI_RELEASE_TOKEN with the new write:package scope (the operator followup from #448) took the better part of a session and hit the same walls we hit every previous time we touch a Forgejo CI credential. The code fix was one line. The operating the fix was the slog. This issue exists to capture that friction so the next run is a lookup, not a re-derivation.

The re-derivation trap

Every component below is knowable, and most were already written down somewhere, yet the flow got reconstructed from scratch anyway because nothing ties them together:

  1. MSYS leading-slash path mangling. On Windows Git Bash, a bare --name /forgejo/api-token gets rewritten to a Windows path before aws.exe sees it, so every aws ssm call 404s ParameterNotFound and put-parameter would silently write a mangled name. This was already documented in kai-windows-env skill, but disconnected from the token flow, so it cost most of the session to rediscover. Now hard-guarded in all six operator provision scripts (commits d1d7900, 7627c34).
  2. Minting needs basic auth. POST /users/{u}/tokens refuses token and admin auth (probed today: HTTP 401). Only a password works. Since login is GitHub OAuth, there is no password, so API-mint is out.
  3. coilyco-ops bot is the designated headless minter. It was built for exactly this. Agents keep re-litigating "real-user vs bot" because the decision was never recorded. It is recorded now: use the bot.
  4. Bot mints and writes SSM, but the org-secret PUT needs an org-admin token. The bot 403s on PUT /orgs/{org}/actions/secrets/.... The mint + SSM stash run as the bot, the org secret gets finished with the admin PAT. This split is non-obvious and bites every time.
  5. write:repository is not write:package. The whole of #448. The package registry needs write:package explicitly.
  6. No headless release re-run on Forgejo 15.0.2. The release workflow has no workflow_dispatch, and the API exposes no rerun endpoint (only GET runs/{id}). Re-running a failed job is a UI click or a fresh push. There is no way around this from a script today.
  7. Verify the payoff, not the write. Confirming SSM and the org secret are set proves nothing. The real check is the consuming pipeline succeeding (package registry filling, Flux syncing, CI green).

Ask

Promote this whole flow into a skill (proposed tooling-forgejo-token-provisioning in agentic-os-kai) that:

  • Tables each credential: script, SSM path, scope, mint auth, consumer, verify command. The family is provision-ci-release-token, provision-coilyco-ops-bot, provision-flux-deploy-token, provision-tap-bump-token, provision-github-app, grant-coilyco-ops-org-repo-create.
  • States the seven traps above up front.
  • Cross-links [[kai-windows-env]], [[kai-aws-auth]], [[kai-brew-release]].

Infra docs/ has no runbook for this either, so a repo-side companion is fair game.

  • #448 (the one-scope fix this operates)
  • kai-windows-env skill (already held trap 1)
## What happened Rotating `CI_RELEASE_TOKEN` with the new `write:package` scope (the operator followup from #448) took the better part of a session and hit the same walls we hit every previous time we touch a Forgejo CI credential. The code fix was one line. The *operating* the fix was the slog. This issue exists to capture that friction so the next run is a lookup, not a re-derivation. ## The re-derivation trap Every component below is knowable, and most were already written down somewhere, yet the flow got reconstructed from scratch anyway because nothing ties them together: 1. **MSYS leading-slash path mangling.** On Windows Git Bash, a bare `--name /forgejo/api-token` gets rewritten to a Windows path before `aws.exe` sees it, so every `aws ssm` call 404s `ParameterNotFound` and `put-parameter` would silently write a mangled name. This was *already documented* in `kai-windows-env` skill, but disconnected from the token flow, so it cost most of the session to rediscover. Now hard-guarded in all six operator provision scripts (commits d1d7900, 7627c34). 2. **Minting needs basic auth.** `POST /users/{u}/tokens` refuses token and admin auth (probed today: HTTP 401). Only a password works. Since login is GitHub OAuth, there is no password, so API-mint is out. 3. **`coilyco-ops` bot is the designated headless minter.** It was built for exactly this. Agents keep re-litigating "real-user vs bot" because the decision was never recorded. It is recorded now: use the bot. 4. **Bot mints and writes SSM, but the org-secret PUT needs an org-admin token.** The bot 403s on `PUT /orgs/{org}/actions/secrets/...`. The mint + SSM stash run as the bot, the org secret gets finished with the admin PAT. This split is non-obvious and bites every time. 5. **`write:repository` is not `write:package`.** The whole of #448. The package registry needs `write:package` explicitly. 6. **No headless release re-run on Forgejo 15.0.2.** The release workflow has no `workflow_dispatch`, and the API exposes no rerun endpoint (only `GET runs/{id}`). Re-running a failed job is a UI click or a fresh push. There is no way around this from a script today. 7. **Verify the payoff, not the write.** Confirming SSM and the org secret are set proves nothing. The real check is the consuming pipeline succeeding (package registry filling, Flux syncing, CI green). ## Ask Promote this whole flow into a skill (proposed `tooling-forgejo-token-provisioning` in agentic-os-kai) that: - Tables each credential: script, SSM path, scope, mint auth, consumer, verify command. The family is `provision-ci-release-token`, `provision-coilyco-ops-bot`, `provision-flux-deploy-token`, `provision-tap-bump-token`, `provision-github-app`, `grant-coilyco-ops-org-repo-create`. - States the seven traps above up front. - Cross-links `[[kai-windows-env]]`, `[[kai-aws-auth]]`, `[[kai-brew-release]]`. Infra `docs/` has no runbook for this either, so a repo-side companion is fair game. ## Related - #448 (the one-scope fix this operates) - `kai-windows-env` skill (already held trap 1)
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-infrastructure-452 on host KAI-SERVER is carrying this issue (reserved 2026-07-03T17:10:41Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-infrastructure-452` on host `KAI-SERVER` is carrying this issue (reserved 2026-07-03T17:10:41Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-infrastructure-452 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-05T03:22:03Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-infrastructure-452` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-05T03:22:03Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Owner

WARD-OUTCOME: done - token-minting skill now tables the whole Forgejo credential family, states the seven traps up front, and cross-links the three kai-* skills.

Honest retrospective: most of the substance was already sitting in the token-minting operator skill (it even name-dropped "infra#452 trap #4" before I got here), so this was less a promotion than finishing three specific gaps the skill hadn't closed: the six-column table, the seven traps stated up front, and the [[kai-windows-env]] / [[kai-aws-auth]] / [[kai-brew-release]] cross-links.

The one real judgment call: the issue proposed the skill in agentic-os-kai, but the seven provision scripts all live in infra and infra already grew its own operator skill layer (infra#451). Authoring-layer convention says the skill lives where the scripts live, and a second copy in agentic-os-kai would just be drift, so I landed it here and put the full table in a new references/forgejo-token-family.md.

What fought back: the 80-line / 4000-char doc-size cap. The seven traps plus the table pointer plus the cross-links pushed SKILL.md to 4010 chars on the first pass, so it took a trim to land at 3970. Nothing else resisted. The pre-commit pylint failure was a sandbox red herring (uv could not write its interpreter into a read-only /opt), not my markdown.

Confidence: high on the docs themselves, all skill hooks green. One caveat worth naming: the verify-column commands are transcribed faithfully from each script, not each re-run live against real tokens, since I did not actually rotate anything. Rough edge / possible follow-up: the [[...]] cross-links point at agentic-os-kai skills that no infra-side hook can validate, so a rename over there drifts silently. A thin pointer skill in agentic-os-kai back to this one might be worth a small issue if that surface wants discoverability from its side too.

WARD-OUTCOME: done - token-minting skill now tables the whole Forgejo credential family, states the seven traps up front, and cross-links the three kai-* skills. Honest retrospective: most of the substance was already sitting in the `token-minting` operator skill (it even name-dropped "infra#452 trap #4" before I got here), so this was less a promotion than finishing three specific gaps the skill hadn't closed: the six-column table, the seven traps stated up front, and the `[[kai-windows-env]]` / `[[kai-aws-auth]]` / `[[kai-brew-release]]` cross-links. The one real judgment call: the issue proposed the skill in agentic-os-kai, but the seven provision scripts all live in infra and infra already grew its own operator skill layer (infra#451). Authoring-layer convention says the skill lives where the scripts live, and a second copy in agentic-os-kai would just be drift, so I landed it here and put the full table in a new `references/forgejo-token-family.md`. What fought back: the 80-line / 4000-char doc-size cap. The seven traps plus the table pointer plus the cross-links pushed SKILL.md to 4010 chars on the first pass, so it took a trim to land at 3970. Nothing else resisted. The pre-commit pylint failure was a sandbox red herring (uv could not write its interpreter into a read-only /opt), not my markdown. Confidence: high on the docs themselves, all skill hooks green. One caveat worth naming: the verify-column commands are transcribed faithfully from each script, not each re-run live against real tokens, since I did not actually rotate anything. Rough edge / possible follow-up: the `[[...]]` cross-links point at agentic-os-kai skills that no infra-side hook can validate, so a rename over there drifts silently. A thin pointer skill in agentic-os-kai back to this one might be worth a small issue if that surface wants discoverability from its side too.
Sign in to join this conversation.
No description provided.