Skip to content

feat(secrets): add ListServerSecrets + the compass server-secret CLI noun - #1059

Open
rigel-mintaka wants to merge 1 commit into
mainfrom
compass-server/rig-3597-server-secret-cli
Open

feat(secrets): add ListServerSecrets + the compass server-secret CLI noun#1059
rigel-mintaka wants to merge 1 commit into
mainfrom
compass-server/rig-3597-server-secret-cli

Conversation

@rigel-mintaka

Copy link
Copy Markdown
Contributor

SetServerSecret/DeleteServerSecret shipped as RPCs with no CLI verb, so
nothing could write a reserved-prefix server secret's provider VALUE. That is
load-bearing rather than cosmetic: validateForgeSecret resolves the PREFIXED
key at startup and hard-fails boot when it is absent, so configuring the forge
App ids on a deployment wedged the server with no CLI path to recover.

Adds compass server-secret set <NAME> (value on stdin, never argv) and
compass server-secret list, plus the ListServerSecrets RPC they need. The
list prints the BARE name at line start, stripping either reserved prefix: the
deployment's seed script gates its arming restart on a line-anchored
\n<NAME>: match, so the stored prefixed form would miss every glob and
re-arm on every converge.

is_set is a provider probe here, unlike ListSecrets which hardcodes true.
On the user path declare and set are one operation, but server-secret names are
self-declared at every boot while the operator populates values separately, so
declared-but-unset is routine and telling the two apart is the point of the
verb. The probe reads SecretSpec's value-free report through a new
Resolver.Statuses, not Resolve: buildManifest marks every declared name
required = true, so a Load-based probe would fail wholesale in exactly the
unset case it exists to describe, and would pull every deployment secret's
value into memory to answer a names-and-flags question. A genuine provider
fault stays CodeInternal rather than flattening to all-unset, so a broken
provider cannot read as an unprovisioned one.

server-secret set refuses a bare name that would shadow the gateway-family
row. list strips either reserved prefix, so the master key prints as bare
MASTER_KEY; wrapping that spelling back would send SERVER_MASTER_KEY, a
different secret that clears the server's exact-name master-key guard — minting
a shadow row while the real key stays unprovisioned and list printed the same
bare name twice. The full gateway name still goes through, so the server stays
the single authority on which names are writable.

Both set paths now read stdin through one shared readSecretValue, so the size
cap, newline trim, and empty-value rejection cannot drift between the verbs.

Refs RIG-3597

Co-authored-by: Matt Wilkinson matt@rigel.build

…noun

`SetServerSecret`/`DeleteServerSecret` shipped as RPCs with no CLI verb, so
nothing could write a reserved-prefix server secret's provider VALUE. That is
load-bearing rather than cosmetic: `validateForgeSecret` resolves the PREFIXED
key at startup and hard-fails boot when it is absent, so configuring the forge
App ids on a deployment wedged the server with no CLI path to recover.

Adds `compass server-secret set <NAME>` (value on stdin, never argv) and
`compass server-secret list`, plus the `ListServerSecrets` RPC they need. The
list prints the BARE name at line start, stripping either reserved prefix: the
deployment's seed script gates its arming restart on a line-anchored
`\n<NAME>: ` match, so the stored prefixed form would miss every glob and
re-arm on every converge.

`is_set` is a provider probe here, unlike `ListSecrets` which hardcodes true.
On the user path declare and set are one operation, but server-secret names are
self-declared at every boot while the operator populates values separately, so
declared-but-unset is routine and telling the two apart is the point of the
verb. The probe reads SecretSpec's value-free report through a new
`Resolver.Statuses`, not `Resolve`: `buildManifest` marks every declared name
`required = true`, so a `Load`-based probe would fail wholesale in exactly the
unset case it exists to describe, and would pull every deployment secret's
value into memory to answer a names-and-flags question. A genuine provider
fault stays `CodeInternal` rather than flattening to all-unset, so a broken
provider cannot read as an unprovisioned one.

`server-secret set` refuses a bare name that would shadow the gateway-family
row. `list` strips either reserved prefix, so the master key prints as bare
`MASTER_KEY`; wrapping that spelling back would send `SERVER_MASTER_KEY`, a
different secret that clears the server's exact-name master-key guard — minting
a shadow row while the real key stays unprovisioned and `list` printed the same
bare name twice. The full gateway name still goes through, so the server stays
the single authority on which names are writable.

Both set paths now read stdin through one shared `readSecretValue`, so the size
cap, newline trim, and empty-value rejection cannot drift between the verbs.

Refs RIG-3597

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@linear-code

linear-code Bot commented Sep 10, 2026

Copy link
Copy Markdown

RIG-3597

@trunk-io

trunk-io Bot commented Sep 10, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-server-rig-3597-serv.compass-eng-docs.pages.dev

Deployed from compass-server/rig-3597-server-secret-cli at f66e574.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant