Add an aosguard ops netlify wrap so agents can manage site domain aliases without holding the token #1353

Closed
opened 2026-08-28 19:07:23 +00:00 by coilyco-ops · 0 comments
Owner

What is needed

There is no aosguard ops netlify surface. Measured rather than assumed:

  • aosguard ops --help on aos-v0.257.0 lists ten areas - actions, aws, forgejo-admin, forgejo-storage, forgejo, kubectl, redis, signoz, tailscale, telegram - and no netlify
  • .specgen/guardfiles/aosguard/ contains no netlify guardfile
  • grep -ril netlify across the repo returns nothing, so this is not a wrap that exists and failed to mount
  • No Netlify MCP tool is available either

So it has to be authored. Kai chose this route explicitly over the two faster alternatives.

Why a wrap rather than a token grant

The immediate need is adding domain aliases to the website site. The netlify CLI is installed on the host and a token exists at /coilysiren/netlify/token.

An agent can technically read that token. aosguard ops aws ssm get-parameter permits it, since the guardfile's only restriction is deny-when name matches "*/prod/*" *secret* and that path matches neither. But reading it puts a live production credential into an agent session for what is a small, well-bounded operation.

A wrap gives the same capability with the token never leaving the guard, which is the pattern the Forgejo surfaces already use. Kai's call, and it is the right shape if vanity subdomains keep growing.

Immediate consumer

coilysiren/website#138. Delphi needs umbra.coilyco.ai serving so she can run a single decisive probe: whether a Netlify rewrite with force = true beats the primary-domain redirect. If it does not, #138 needs a different mechanism or dropping, and she does not want to build the Eleventy build-variant work on an unproven assumption.

DNS is already live and verified authoritative for all three vanity names, so the alias is the only remaining step:

  • umbra.coilyco.ai - needed for the probe
  • agent-compose.coilyco.ai - pre-staged
  • mcp-beaver.coilyco.ai - pre-staged

All three CNAME to coilysiren-dot-me.netlify.app.

Two hazards worth designing against

Adding an alias re-issues the certificate covering every domain on the site, coilysiren.me and www.coilysiren.me included. This is the one operation here that can affect the primary domain rather than only the new name. Two consequences: add all three aliases in one operation rather than three, so there is one issuance rather than three, and treat this as a verb worth doing while someone is watching rather than fire-and-forget.

domain_aliases on the Netlify site API is very likely a replace rather than a merge. A wrap that accepts one alias and sets it would then silently delete every existing alias. I have not verified this, because verifying it needs the token I do not hold, so treat it as a hazard to confirm rather than a measured fact. If it holds, the wrap needs a read-modify-write that appends, or a verb that takes the complete list and makes that explicit in its describe.

That second one is the same shape as the ConfigMap trap in #1344, where a record showing what changed was not sufficient for someone who had to declare what exists. Twice in one day is enough to call it a pattern worth watching for on any list-valued field.

Suggested surface

Read verbs first, so an agent can inspect before mutating:

  • listSites or equivalent, to resolve the site id
  • getSite, to read current domain_aliases before changing them

Then the write:

  • a verb that sets or appends domain aliases, with the site constrained to an allowlist so an agent cannot reconfigure an arbitrary Netlify site

Acceptance

  • An agent can add a domain alias to the website site through an approved aosguard verb
  • The token is never in argv, in the audit log, or in the calling session, matching the ssm put-parameter precedent where the log carries only a file URI
  • The target site is constrained rather than caller-supplied
  • Existing domain_aliases survive the operation, with a test that proves it rather than an assumption that it merges
  • --context equivalent: whatever the wrap-level mandatory-selector pattern from #1349 implies here, so the same silent-wrong-target class does not reappear on a new surface

Owner

Platform seat. aosguard is shared tooling other seats build on, outside the sysadmin scope for foundational software. Filed from the sysadmin side with the live-state facts attached.

## What is needed There is no `aosguard ops netlify` surface. Measured rather than assumed: * `aosguard ops --help` on `aos-v0.257.0` lists ten areas - actions, aws, forgejo-admin, forgejo-storage, forgejo, kubectl, redis, signoz, tailscale, telegram - and no netlify * `.specgen/guardfiles/aosguard/` contains no netlify guardfile * `grep -ril netlify` across the repo returns nothing, so this is not a wrap that exists and failed to mount * No Netlify MCP tool is available either So it has to be authored. Kai chose this route explicitly over the two faster alternatives. ## Why a wrap rather than a token grant The immediate need is adding domain aliases to the website site. The `netlify` CLI is installed on the host and a token exists at `/coilysiren/netlify/token`. An agent can technically read that token. `aosguard ops aws ssm get-parameter` permits it, since the guardfile's only restriction is `deny-when name matches "*/prod/*" *secret*` and that path matches neither. But reading it puts a live production credential into an agent session for what is a small, well-bounded operation. A wrap gives the same capability with the token never leaving the guard, which is the pattern the Forgejo surfaces already use. Kai's call, and it is the right shape if vanity subdomains keep growing. ## Immediate consumer coilysiren/website#138. Delphi needs `umbra.coilyco.ai` serving so she can run a single decisive probe: whether a Netlify rewrite with `force = true` beats the primary-domain redirect. If it does not, #138 needs a different mechanism or dropping, and she does not want to build the Eleventy build-variant work on an unproven assumption. DNS is already live and verified authoritative for all three vanity names, so the alias is the only remaining step: * `umbra.coilyco.ai` - needed for the probe * `agent-compose.coilyco.ai` - pre-staged * `mcp-beaver.coilyco.ai` - pre-staged All three CNAME to `coilysiren-dot-me.netlify.app`. ## Two hazards worth designing against **Adding an alias re-issues the certificate covering every domain on the site**, `coilysiren.me` and `www.coilysiren.me` included. This is the one operation here that can affect the primary domain rather than only the new name. Two consequences: add all three aliases in one operation rather than three, so there is one issuance rather than three, and treat this as a verb worth doing while someone is watching rather than fire-and-forget. **`domain_aliases` on the Netlify site API is very likely a replace rather than a merge.** A wrap that accepts one alias and sets it would then silently delete every existing alias. **I have not verified this**, because verifying it needs the token I do not hold, so treat it as a hazard to confirm rather than a measured fact. If it holds, the wrap needs a read-modify-write that appends, or a verb that takes the complete list and makes that explicit in its `describe`. That second one is the same shape as the ConfigMap trap in #1344, where a record showing what changed was not sufficient for someone who had to declare what exists. Twice in one day is enough to call it a pattern worth watching for on any list-valued field. ## Suggested surface Read verbs first, so an agent can inspect before mutating: * `listSites` or equivalent, to resolve the site id * `getSite`, to read current `domain_aliases` before changing them Then the write: * a verb that sets or appends domain aliases, with the site constrained to an allowlist so an agent cannot reconfigure an arbitrary Netlify site ## Acceptance * An agent can add a domain alias to the website site through an approved aosguard verb * The token is never in argv, in the audit log, or in the calling session, matching the `ssm put-parameter` precedent where the log carries only a file URI * The target site is constrained rather than caller-supplied * Existing `domain_aliases` survive the operation, with a test that proves it rather than an assumption that it merges * `--context` equivalent: whatever the wrap-level mandatory-selector pattern from #1349 implies here, so the same silent-wrong-target class does not reappear on a new surface ## Owner Platform seat. aosguard is shared tooling other seats build on, outside the sysadmin scope for foundational software. Filed from the sysadmin side with the live-state facts attached.
Sign in to join this conversation.
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#1353
No description provided.