key-cape/docs/nk49-isolated-restore-owner-acceptance-2026-10-27.md
tegwick fc9f09a8c2 Record KeyCape owner acceptance of NK-WP-0049 isolated restore (issuer side)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4515@bnt-lap001
Assistant-Session: 0bf96127-6e04-41be-bfda-d11717c3f354
2026-10-27 21:40:11 +01:00

4 KiB

KeyCape owner acceptance: NK-WP-0049 isolated restore (issuer side)

Date: 2026-10-27 · Owner: key-cape · Scope: NK-WP-0049-T15 (KeyCape lane) and the issuer-side part of T18 Estate mode: builder (not production). Acceptance is proportional to that.

Verdict

Accept with named residuals for KeyCape's issuer-side restore. This is not an acceptance of consumer continuity (T18 remainder) or MFA (T19).

Evidence assessed

  • NetKingdom verifier output docs/evidence/2026-10-23-nk49-t18-keycape-attempt/verifier-output.json: receipt sha256 16d72f7c…1651, verdict verified, no findings, claims_not_made lists consumer continuity, MFA and owner acceptance.
  • Native check source net-kingdom/tools/bootstrap-recovery/isolated-keycape.py (reviewed T38 pin 86f37add…), read against KeyCape source (src/cmd/keycape/main.go, src/internal/server/oidc/jwks.go, src/internal/server/policy/policy.go, src/internal/server/oidc/session.go).
  • No secret value, private receipt or live system was read for this review.

What KeyCape considers a correct restore, and coverage

KeyCape state Where it lives Covered by the run
Signing key key.pem → single JWKS key kid=key-1 (main.go:97) Yes. key.pem byte-equal to archive; live JWKS has exactly one RS256 key whose modulus/exponent equal the archived private key; a native exchange then verified against it.
Key rotation state none: KeyCape constructs one key, no previous/retired keys Nothing to restore. Single-key check is complete for this release.
Client registry clients: list inside config.yaml All entries byte-equal (whole file). One confidential client_credentials client exercised natively.
Client secrets KEYCAPE_* env from referenced Secrets Full KEYCAPE_* environment equal to archive; the tested client's secret accepted, unrelated secret and predecessor secret refused.
Policy / enrollment-mode store /var/lib/keycape-policy/ (policy.json, mutable via policy API) Entire durable tree byte-equal, no extra files; service started, so policy.Open validated it against the restored clients.
Factor read token /etc/keycape-factor/admin-token Byte-equal when present in archive; its use is T19 (passed 2026-10-24).
Issuer / TLS trust issuer in config, /recovery-tls Original HTTPS issuer and pinned trust preserved; TLS reissued in isolated namespace, production cert unchanged.
Binary admitted image digest Image equals pinned digest; /keycape verifier hash checked.
Sessions, auth codes, token status in memory (session.go) Not durable by design; loss on restore is expected (users sign in again; issued tokens stay verifiable because the key is preserved).

Named residuals (do not block issuer-side acceptance)

  1. Only one client exercised natively. Other registry entries (browser/PKCE relying parties such as portal and Vergabe, other service clients) are proven byte-preserved, not natively exercised. Authorization-code + PKCE through the restored chain is the T18 consumer run (RPF-WP-0064 phase B / SECRETS-WP-0015-T04).
  2. Recovery point. The restore equals the selected archive. Any client or policy change made after that archive (registry additions, enrollment-mode changes via the policy API) would be lost; the operator must reconcile against the current repo-held client definitions after a real restore.
  3. Release coupling. The single-key check (len(keys)==1, kid=key-1) is correct only for the current release. If KeyCape adds key rotation or a second key, the native check and this acceptance must be revisited.
  4. Receipt custody. The receipt is held outside Git on the founder workstation (founder decision 2026-10-23); this acceptance relies on the verifier output's binding to its sha256.

Not accepted here

Consumer continuity (T18 remainder), caller admission (T21), credential dispositions (T22) and final acceptance (T03) stay with their owners.