From fc9f09a8c2f00e004e6368ea456886916810d07c Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 27 Oct 2026 21:40:11 +0100 Subject: [PATCH] Record KeyCape owner acceptance of NK-WP-0049 isolated restore (issuer side) Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 4515@bnt-lap001 Assistant-Session: 0bf96127-6e04-41be-bfda-d11717c3f354 --- ...ted-restore-owner-acceptance-2026-10-27.md | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/nk49-isolated-restore-owner-acceptance-2026-10-27.md diff --git a/docs/nk49-isolated-restore-owner-acceptance-2026-10-27.md b/docs/nk49-isolated-restore-owner-acceptance-2026-10-27.md new file mode 100644 index 0000000..00efd15 --- /dev/null +++ b/docs/nk49-isolated-restore-owner-acceptance-2026-10-27.md @@ -0,0 +1,55 @@ +# 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.