Document 'agents rotate Forgejo CI/tap/flux/scoop tokens themselves' in the token-minting skill (+ add missing provision-scoop-write-token.sh) #454

Closed
opened 2026-07-03 18:13:31 +00:00 by coilysiren · 2 comments
Owner

Why

Kai keeps having to re-assert, session after session, that rotating Forgejo CI tokens is an agent action, not a human handoff. The token-minting skill today only states the exceptions ("the site-admin scripts are operator-run - agents are blocked from the site-admin PAT by design") and never states the affirmative rule, so agents default to treating every token wall as something to file back to Kai. This session did exactly that - it mislabeled SCOOP_WRITE_TOKEN and CI_RELEASE_TOKEN as "human-only" until corrected. Write the rule down so it stops recurring.

Part 1 - add the affirmative prose to skills/token-minting/SKILL.md

Add a prominent callout near the top of the body (before the per-script list, so it frames them), roughly:

These are yours to rotate

The Forgejo CI / tap / flux / scoop token scripts (provision-ci-release-token, provision-tap-bump-token, provision-flux-deploy-token, provision-scoop-write-token) are agent-run, not a human handoff. When a token is missing, stale, or - the usual tell - a release job fails its PUT (the package registry doesn't fill, the bucket push 403s), re-run its provision script yourself from any box with AWS/SSM (--aws on a warded engineer, or a creds-having host). Each script is idempotent and self-rotating: delete the old token + SSM param, re-run, done. Do not park the run waiting on a "grant" or file it back to Kai - the grant is a script you run.

The only operator-run scripts are the two needing the site-admin PAT - provision-coilyco-ops-bot and grant-coilyco-ops-org-repo-create - agents are blocked from that PAT by design. Everything else here is yours.

Caveat: a read-only director surface holds the bot token but not AWS/SSM or a minting password, so it cannot run these in-session - it dispatches a warded engineer ... --aws that can.

Match the skill's house voice (the AGENTS.md rules - no em-dashes, no semicolons in prose, bold for anchors).

Part 2 - add the missing scripts/provision-scoop-write-token.sh

Mirror scripts/provision-tap-bump-token.sh: mint a write:repository Forgejo token scoop-write, stash at SSM /forgejo/scoop-write-token (SecureString, no --overwrite), keep the MSYS_NO_PATHCONV=1 guard (infra#448). Then set it as the Forgejo secret SCOOP_WRITE_TOKEN that ward#571's bump-scoop-manifest job consumes.

Confirm the secret's scope: if SCOOP_WRITE_TOKEN is an org secret it needs the admin PAT (infra#452 trap #4, so that step stays operator-adjacent); if a ward repo secret the bot may set it directly. Document which in the script, matching how provision-ci-release-token.sh handles the CI_RELEASE_TOKEN org-secret step.

Add the new script to the skill's per-script list.

  • infra#452 - the re-derivation-trap issue that canonized this flow (and asked for the skill).
  • infra#448 - the MSYS path-conversion trap + the write:package scope.
  • ward#571 - the bump-scoop-manifest job that needs SCOOP_WRITE_TOKEN.
  • ward#576 - the two ungranted secrets currently blocking a green release (this makes them self-serve to rotate).
## Why Kai keeps having to re-assert, session after session, that **rotating Forgejo CI tokens is an agent action, not a human handoff**. The `token-minting` skill today only states the *exceptions* ("the site-admin scripts are operator-run - agents are blocked from the site-admin PAT by design") and never states the affirmative rule, so agents default to treating every token wall as something to file back to Kai. This session did exactly that - it mislabeled `SCOOP_WRITE_TOKEN` and `CI_RELEASE_TOKEN` as "human-only" until corrected. Write the rule down so it stops recurring. ## Part 1 - add the affirmative prose to `skills/token-minting/SKILL.md` Add a prominent callout near the top of the body (before the per-script list, so it frames them), roughly: > ## These are yours to rotate > > The Forgejo CI / tap / flux / scoop token scripts (`provision-ci-release-token`, `provision-tap-bump-token`, `provision-flux-deploy-token`, `provision-scoop-write-token`) are **agent-run, not a human handoff**. When a token is missing, stale, or - the usual tell - a release job fails its PUT (the package registry doesn't fill, the bucket push 403s), **re-run its provision script yourself** from any box with AWS/SSM (`--aws` on a warded engineer, or a creds-having host). Each script is idempotent and self-rotating: delete the old token + SSM param, re-run, done. Do **not** park the run waiting on a "grant" or file it back to Kai - the grant *is* a script you run. > > The **only** operator-run scripts are the two needing the site-admin PAT - `provision-coilyco-ops-bot` and `grant-coilyco-ops-org-repo-create` - agents are blocked from that PAT by design. Everything else here is yours. > > Caveat: a **read-only director surface** holds the bot token but not AWS/SSM or a minting password, so it cannot run these in-session - it dispatches a `warded engineer ... --aws` that can. Match the skill's house voice (the AGENTS.md rules - no em-dashes, no semicolons in prose, bold for anchors). ## Part 2 - add the missing `scripts/provision-scoop-write-token.sh` Mirror `scripts/provision-tap-bump-token.sh`: mint a `write:repository` Forgejo token `scoop-write`, stash at SSM `/forgejo/scoop-write-token` (SecureString, no `--overwrite`), keep the `MSYS_NO_PATHCONV=1` guard (infra#448). Then set it as the Forgejo secret `SCOOP_WRITE_TOKEN` that ward#571's `bump-scoop-manifest` job consumes. Confirm the secret's scope: if `SCOOP_WRITE_TOKEN` is an **org** secret it needs the admin PAT (infra#452 trap #4, so that step stays operator-adjacent); if a **ward repo** secret the bot may set it directly. Document which in the script, matching how `provision-ci-release-token.sh` handles the `CI_RELEASE_TOKEN` org-secret step. Add the new script to the skill's per-script list. ## Related - infra#452 - the re-derivation-trap issue that canonized this flow (and asked for the skill). - infra#448 - the MSYS path-conversion trap + the `write:package` scope. - ward#571 - the `bump-scoop-manifest` job that needs `SCOOP_WRITE_TOKEN`. - ward#576 - the two ungranted secrets currently blocking a green release (this makes them self-serve to rotate).
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-infrastructure-454 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T18:13:48Z). 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-454` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T18:13:48Z). 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
Owner

WARD-OUTCOME: done - added the "these are yours to rotate" callout to the token-minting skill + the missing provision-scoop-write-token.sh, landed on main (82cc631, CI green).

Retro: the substance was quick - the affirmative rule was already drafted in the issue, and the scoop script is a near-clone of provision-tap-bump-token with the ci-release secret-PUT step grafted on. The one real judgment call, org secret vs repo secret, resolved cleanly: ward's release.md lists SCOOP_WRITE_TOKEN right next to the TAP_WRITE_TOKEN repo secret and the job pushes as coilysiren:$SCOOP_WRITE_TOKEN, so it is a repo secret the minting user sets with its own basic auth - no admin PAT, fully agent-runnable, which is exactly the point the callout is making.

What fought back was the doc-size hooks, not the content. The SKILL grew ~1.3k chars past the 4000-char cap, so most of the session was trimming prose sentence by sentence down to 3997 without dropping the affirmative rule or any script mapping. Also hit a container-local quirk: the pylint pre-commit hook's uv could not write /opt/uv/python, fixed by pointing UV_PYTHON_INSTALL_DIR at a writable dir - worth a look if other runs on this host trip the same wall.

Confident in the prose and the script's shape. The one thing unexercised is the live mint+PUT (no Forgejo minting creds in this box), so the repo-secrets API path is verified by reading the API contract, not by a real 201/204. A follow-up worth filing: actually run it once to rotate SCOOP_WRITE_TOKEN and unblock ward#576's release.

WARD-OUTCOME: done - added the "these are yours to rotate" callout to the token-minting skill + the missing provision-scoop-write-token.sh, landed on main (82cc631, CI green). Retro: the substance was quick - the affirmative rule was already drafted in the issue, and the scoop script is a near-clone of provision-tap-bump-token with the ci-release secret-PUT step grafted on. The one real judgment call, org secret vs repo secret, resolved cleanly: ward's release.md lists SCOOP_WRITE_TOKEN right next to the TAP_WRITE_TOKEN *repo* secret and the job pushes as `coilysiren:$SCOOP_WRITE_TOKEN`, so it is a repo secret the minting user sets with its own basic auth - no admin PAT, fully agent-runnable, which is exactly the point the callout is making. What fought back was the doc-size hooks, not the content. The SKILL grew ~1.3k chars past the 4000-char cap, so most of the session was trimming prose sentence by sentence down to 3997 without dropping the affirmative rule or any script mapping. Also hit a container-local quirk: the pylint pre-commit hook's `uv` could not write /opt/uv/python, fixed by pointing UV_PYTHON_INSTALL_DIR at a writable dir - worth a look if other runs on this host trip the same wall. Confident in the prose and the script's shape. The one thing unexercised is the live mint+PUT (no Forgejo minting creds in this box), so the repo-secrets API path is verified by reading the API contract, not by a real 201/204. A follow-up worth filing: actually run it once to rotate SCOOP_WRITE_TOKEN and unblock ward#576's release.
Sign in to join this conversation.
No description provided.