feat(admin): smirk-admin break-glass CLI [operator §1.6]

A binary that talks to Postgres directly, bypassing the HTTP admin plane and all
network rate limits — the recovery path when the network plane is unreachable or
a solo admin key is compromised. Authority = shell + DB creds +
ADMIN_KEY_INTEGRITY_SECRET. Every mutation writes a hash-chained audit row
(actor_kind=cli).

Commands:
- list-keys
- add-key --pubkey <64hex> [--label]
- revoke-key --id <uuid>            — MAY revoke the last key (keep_min_live=false;
  the network DELETE refuses that, the CLI is the authority)
- replace-key --old <uuid> --pubkey <64hex> [--revoke-all] — atomic rotate; with
  --revoke-all, the global break-glass that revokes every other live key
- create-admin-wallet --out <path> — generate a schnorr keypair from OS entropy,
  write the secret hex to a NEW 0600 file (create_new, never clobber/stdout/log),
  register only the pubkey; seed + secret buffers zeroized (zeroize crate)
- doctor — DB reachability, live-key count, audit-chain verification

Preflight refuses to run if a present .env is group/other-readable. No new dep
beyond zeroize; bin auto-discovered as `smirk-admin`. Smoke-tested end to end
(wallet file is 0600; bad pubkey rejected; doctor detects a wrong-secret chain).

Deferred (documented): remac-keys (integrity-secret rotation must also re-chain
the audit log) and setup/reset-setup (first-run bootstrap = Subsystem 3).
This commit is contained in:
jwinterm
2026-06-26 11:04:05 -04:00
parent 5df12d3df8
commit 12e4a54c63
3 changed files with 384 additions and 0 deletions
Generated
+1
View File
@@ -2731,6 +2731,7 @@ dependencies = [
"uuid",
"validator",
"webpki-roots 0.26.11",
"zeroize",
"zeromq",
]