feat(aosguard): the operations provisioning scripts were curling with a raw PAT #1082

Merged
coilysiren merged 1 commit from aos/claude/ym96-admin-verbs into main 2026-08-16 01:28:14 +00:00
Member

Kai on infrastructure#847: agents should never make direct SSM calls against the admin token either. If something needs it, it goes inside aosguard.

She is right, and #847 only got halfway. It removed the helper and the TTY gate, but left twelve call sites reading the SecureString into a shell variable and handing it to curl. The token still lands in a variable, in the script's memory, and in three cases in argv where ps can read it.

A guarded verb keeps the credential inside the binary. It reaches no variable, no log, and no ps. A script that fetches the token itself defeats the wrapper however carefully it behaves afterwards.

Sixteen verbs, derived from what the scripts actually call

I mapped every endpoint in the twelve call sites rather than guessing:

family verbs callers
Actions secrets, repo and org list, update, delete 5 provisioning scripts
Runner registration tokens get, org and repo provision-forgejo-runner-registration-token.sh
Packages list, get, delete the retention timer
Repository contents get, list also unblocks coilyco-bridge/deploy#545
User tokens list, create, delete bot PAT rotation

Twelve swagger paths vendored from upstream with transitive definitions and shared responses, because specgen lock prunes the vendored snapshot rather than fetching. 63 ops to 83.

Verified live

$ ward exec aosguard-run -- ops forgejo-admin repo-content get coilyco-gaming sirens-echo README.md
OK: README.md 4264 bytes, encoding base64

All 16 verbs materialize; 28 verbs on the wrapper total.

One thing I did not do, on purpose

adminCreateUser, adminDeleteUser, adminCreateOrg and orgCreateTeam are left out.

They back provision-coilyco-ops-bot.sh and grant-coilyco-ops-org-repo-create.sh, which create the bot user and grant it org rights. Those run approximately once. Wrapping them would give aosguard a permanent, standing capability to create and delete any user on the instance, in exchange for retiring a script that has already done its job.

That trade might still be right - a one-shot script that needs the raw token is exactly what this PR is against. But it is a genuine widening of the guarded surface rather than a config repair, so it is your call and I did not make it. Say which and I will follow up.

Follow-on

The infrastructure side - converting those twelve call sites to these verbs and deleting the raw curls - is a separate PR against infrastructure, and depends on this being released. infrastructure#848 carries the argv inventory that overlaps it.

🤖 Generated with Claude Code

Kai on infrastructure#847: agents should never make direct SSM calls against the admin token either. If something needs it, it goes inside aosguard. She is right, and #847 only got halfway. It removed the helper and the TTY gate, but left twelve call sites reading the SecureString into a shell variable and handing it to `curl`. The token still lands in a variable, in the script's memory, and in three cases in argv where `ps` can read it. **A guarded verb keeps the credential inside the binary.** It reaches no variable, no log, and no `ps`. A script that fetches the token itself defeats the wrapper however carefully it behaves afterwards. ## Sixteen verbs, derived from what the scripts actually call I mapped every endpoint in the twelve call sites rather than guessing: | family | verbs | callers | | --- | --- | --- | | Actions secrets, repo and org | list, update, delete | 5 provisioning scripts | | Runner registration tokens | get, org and repo | `provision-forgejo-runner-registration-token.sh` | | Packages | list, get, delete | the retention timer | | Repository contents | get, list | also unblocks `coilyco-bridge/deploy`#545 | | User tokens | list, create, delete | bot PAT rotation | Twelve swagger paths vendored from upstream with transitive definitions and shared responses, because `specgen lock` prunes the vendored snapshot rather than fetching. 63 ops to 83. ## Verified live ``` $ ward exec aosguard-run -- ops forgejo-admin repo-content get coilyco-gaming sirens-echo README.md OK: README.md 4264 bytes, encoding base64 ``` All 16 verbs materialize; 28 verbs on the wrapper total. ## One thing I did not do, on purpose `adminCreateUser`, `adminDeleteUser`, `adminCreateOrg` and `orgCreateTeam` are left out. They back `provision-coilyco-ops-bot.sh` and `grant-coilyco-ops-org-repo-create.sh`, which create the bot user and grant it org rights. **Those run approximately once.** Wrapping them would give aosguard a permanent, standing capability to create and delete any user on the instance, in exchange for retiring a script that has already done its job. That trade might still be right - a one-shot script that needs the raw token is exactly what this PR is against. But it is a genuine widening of the guarded surface rather than a config repair, so it is your call and I did not make it. Say which and I will follow up. ## Follow-on The infrastructure side - converting those twelve call sites to these verbs and deleting the raw curls - is a separate PR against `infrastructure`, and depends on this being released. `infrastructure`#848 carries the argv inventory that overlaps it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(aosguard): the operations provisioning scripts were curling with a raw PAT
All checks were successful
ci / aos-cli-tests (pull_request) Successful in 18s
ci / ward-doctor (pull_request) Successful in 19s
ci / gate (pull_request) Successful in 55s
763260e2ad
An agent should not hold the admin token at all. #1079 stopped it living in an
environment variable, and infrastructure#847 stopped a helper printing it, but
twelve call sites still read the SecureString into a shell variable and passed
it to curl. A guarded verb keeps the credential inside the binary, where it
reaches no variable, no log, and no ps.

Sixteen verbs, covering what those scripts actually call:

- actions secrets, repo and org, list/update/delete - five provisioning scripts
- runner registration tokens, org and repo
- packages list/get/delete, for the retention timer
- repository contents get/list, which also unblocks deploy#545
- user tokens list/create/delete, for bot PAT rotation

Twelve swagger paths vendored from upstream with their transitive definitions
and shared responses, since specgen prunes the vendored snapshot rather than
fetching. 63 ops to 83.

Not included, and deliberately: adminCreateUser, adminDeleteUser,
adminCreateOrg and orgCreateTeam. Those back a one-shot bootstrap, and wrapping
them would give aosguard a standing capability to create and delete any user
in exchange for a script that has run once. That is a call for Kai, not a
config repair.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilysiren deleted branch aos/claude/ym96-admin-verbs 2026-08-16 01:28:14 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os!1082
No description provided.