From a6eee04d420eb993660c914594f3ceab83b3f567 Mon Sep 17 00:00:00 2001 From: codex Date: Sat, 17 Oct 2026 07:51:36 +0200 Subject: [PATCH] Record native security preparation and owner checkpoints (2/7) --- ...-bootstrap-secret-free-recovery-handoff.md | 1253 ++++++++++++++++ .../refinement-r2/NK-WP-0049.postimage.md | 1308 +++++++++++++++++ .../refinement-r2/NK-WP-0049.preimage.md | 1271 ++++++++++++++++ .../refinement-r2/manifest.json | 27 + .../refinement-r2/task-refinement.patch | 96 ++ .../refinement-r2/updated-owner-source.patch | 189 +++ .../native-identity-r1/routing-discovery.json | 77 + .../selector-preflight.json | 28 + .../selector-uniqueness.patch | 80 + .../native-identity-r1/source-references.json | 173 +++ .../native-identity-r1/verification.json | 70 + .../native-registration-r1/assemble_review.py | 240 +++ .../descriptor-composition.json | 402 +++++ .../native-registration-r1/manifest.json | 44 + .../original-attempt-review.json | 101 ++ .../register-client.proposed-descriptor.json | 1 + .../source-manifest.json | 323 ++++ .../source-verification.json | 87 ++ 18 files changed, 5770 insertions(+) create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.postimage.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.preimage.md create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/task-refinement.patch create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/updated-owner-source.patch create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/routing-discovery.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-preflight.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-uniqueness.patch create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/source-references.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-identity-r1/verification.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/assemble_review.py create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/descriptor-composition.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/original-attempt-review.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/register-client.proposed-descriptor.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-manifest.json create mode 100644 docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-verification.json diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md new file mode 100644 index 00000000..1a3eaf36 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -0,0 +1,1253 @@ +--- +id: NK-WP-0049 +type: workplan +title: "Remove bootstrap secret output and verify separated recovery custody" +domain: infotech +repo: net-kingdom +status: active +owner: codex +topic_slug: netkingdom +created: "2026-10-12" +updated: "2026-10-17" +flavor: implementation +depends_on: [] +state_hub_workstream_id: "17d315f0-829e-57c7-85cc-3a7914152804" +--- + +Native owner work for CUST-WP-0080 G08. This workplan remains active until the +remaining caller, service-recovery and custody acceptance gates are satisfied. +NK-WP-0045 covers the non-secret root-grant record. Founder-deferred exposure +rotation remains in CUST-WP-0073-T05; this plan does not silently reopen it. + +**Replanned 2026-10-16 at the operator's request:** substantial completed work is +now represented by completed tasks, and remaining work has separate deliverables, +dependencies and acceptance criteria. T01–T03 retain their historical IDs and Hub +UUIDs. Completed parts of the old T02/T03 umbrellas are extracted into T04–T14; +T02 now covers the current-caller ledger and T03 retains final owner acceptance. +These are retrospective task records of evidenced work, not additional delivery +or newly granted authority. The earlier dated narrative remains in Git at +`cc2dd01`; its evidence references are carried into the tasks below. + +**Current position, source refinement 2026-10-17:** 25 tasks done; 4 in +progress; 1 ready to start (`todo`); 7 waiting on explicit prerequisites. These are task counts, not an effort-based +completion percentage. Assignees are also written in task descriptions because +the current Forge projector does not populate the dedicated Hub assignee field. The outage-retrieval tool and restore-packet draft are now prepared; +independent outage retrieval and Storage Share publication are accepted; +service admission remains an explicit gate. + +**Next actions:** finish the read-only caller ledger (T02); admit the drafted +isolated restore packet (T15) and record residual-scope handoffs (T24). +Independent outage retrieval (T23) and guide publication (T26) are done. After owner admission, execute the individual native service and +caller checks. A task's owner is accountable for the result; another repository's +approval or credential grant still requires its own owner path. + +**Closure:** T03 assembles owner acceptance after its named dependencies pass. +Passing archive recovery does not prove existing-user authentication, retained +MFA-token decryption, historical audit signatures or current caller admission. +The verified backup job stays active while those separate tasks are completed. + +## Remove secret-bearing output and ambient root discovery + +```task +id: NK-WP-0049-T01 +status: done +priority: high +assignee: codex +state_hub_task_id: "d7ca8d5f-c5ff-5cba-bd25-038cb53ffe4e" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +2026-10-12: regression reproduced emergency/reprint root export, generation +prefix disclosure, permissive file modes, dry-run side effects and unattended +entry. Replaced emergency export with a non-secret guide (legacy secret-input +arguments refused), suppressed generation prefixes/tracing and set private +permissions. Bootstrap requires the registered public recipient and an attended +terminal; never generates/discovers a permanent private key. Encrypted resume +requires an explicit matching temporary custody key before cluster activity. +Dry-run is a non-mutating plan. The live cluster/apply path was not executed. + +A fresh uniquely named encrypted ops bundle follows apply; old delivery flags +cannot skip current acknowledgment. New acknowledgment state binds its SHA256 +and timestamp. Declining stops before cleanup/completion. This is an operator +statement, not an independent restore receipt. Historical fields remain unchanged. +Make/help/status/console and current credential guidance reflect that distinction. +Evidence and exact source manifest: Custodian +`docs/evidence/2026-10-12-netkingdom-security/bootstrap-handoff.json`. + +## Harden custody, SOPS and rotation source entry points + +```task +id: NK-WP-0049-T04 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T01] +state_hub_task_id: "04c4e8be-5bd8-5d5c-99b1-79d8ae758462" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-12–13. Public-recipient-only encryption, explicit temporary +custody, private no-overwrite output, sanitized diagnostics, stdin-only secret +transport and failed-operation cleanup replace ambient-key and output paths. +SOPS read/edit/data-key rotation preserve recipient/MAC/source-version guards; +component rotations preserve unrelated fields and retain recovery candidates. +This records source and disposable-native proof, not live rotation or revocation. + +Evidence: Custodian `docs/evidence/2026-10-12-netkingdom-security/` receipts +`custody-entrypoints.json`, `sops-make-entrypoints.json`, `rotation-output.json`, +and `admin-bootstrap.json`; October13 `sops-write-callers.json`. + +## Repair component, diagnostic, LDAP and resolver callers + +```task +id: NK-WP-0049-T05 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04] +state_hub_task_id: "e8e38f42-609e-5c07-a8e6-e73c8eb4ae95" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-13–14. Repaired KeyCape configuration and component Secret +publication, original privacyIDEA key export/restore transport, scoped MFA +counts, LDAP group maintenance and configuration-preserving resolver cutover. +Retired unsafe personal-token mint/refresh and direct LDAP lifecycle shortcuts. +Disposable native PI/LLDAP tests and source regressions passed; estate provider +admission, historical credential validity and service authentication remain T21/T22. + +Evidence: Custodian October13 `keycape-caller-reconciliation.json`, +`service-secret-callers.json`, `privacyidea-key-custody.json`, +`mfa-state-diagnostic.json`, `realm-bootstrap-repair.json`; October14 +`legacy-lldap-retirement.json`, `platform-group-boundary.json`, +`lldap-group-maintenance.json`, `resolver-cutover.json` under the corresponding +`docs/evidence/YYYY-MM-DD-netkingdom-security/` directories. + +## Inventory source callers and retire remaining unsafe delivery paths + +```task +id: NK-WP-0049-T06 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04, NK-WP-0049-T05] +state_hub_task_id: "a5f50891-c5b2-513b-8670-e1915ee52015" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15. Enumerated all 87 current non-test shell/Python callers +in the declared bootstrap/k8s scope plus Make/console/delivery adapters. Repaired +streamed encrypted bundle publication and fail-closed bootstrap/lab paths; +retired unsafe delivery copiers, root prompts, registry patchers and stale +rollback recipes. The attended inventory records source dispositions and their +native-proof limits. T02 separately maps these to current live users/owners. + +Evidence: [caller inventory](../docs/evidence/2026-10-15-bootstrap-recovery/caller-source-inventory.json), +[attended procedures](../docs/attended-procedure-inventory.md) and the October15 +recovery evidence directory. No live production bootstrap or lab-init acceptance +is claimed. + +## Discover off-host coverage and recover the existing PI database + +```task +id: NK-WP-0049-T07 +status: done +priority: high +assignee: codex +state_hub_task_id: "2d7302a2-319a-5633-bf58-d51ccd25ebf6" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15–16. Bounded Storage Share/Scaleway inventories identified +existing database coverage and the missing full identity bundle. The operator +independently matched the backup recipient, then recovered the exact existing +PI dump: correct-key decryption, wrong-key refusal, isolated native PostgreSQL +restore/readback and cleanup passed (5 tokens, 2 resolvers, 2 realms). + +Evidence: October15 recovery `offsite-discovery-summary.json`, +`privacyidea-transfer-r1.json`, `privacyidea-database-drill-r1.json`, +`database-drill-review.json`. This database-only proof led to T08–T14. + +## Implement the full identity capture and archive recovery toolchain + +```task +id: NK-WP-0049-T08 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06, NK-WP-0049-T07] +state_hub_task_id: "317ca173-c784-5329-9810-5e3d300604b8" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Defined exact LLDAP/Authelia/KeyCape/privacyIDEA assets, +Deployment/PVC/reference bindings, original keys and snapshot consistency limits. +Implemented native SQLite/PG capture, streamed age sealing, strict data-bearing +manifest checks, provider readback, independent retrieval, bounded retention, +root runtime and attended archive verifier. All 56 focused checks passed, +including actual synthetic encrypted/native PostgreSQL recovery. + +Evidence: [profile](../tools/bootstrap-recovery/identity-backup-profile.json), +[implementation review](../docs/evidence/2026-10-16-identity-backup-implementation/review.json), +and the live evidence's tested ESO-default/host-binding corrections. Production +archive recovery is separately evidenced in T13. + +## Admit and verify the two scoped backup credential deliveries + +```task +id: NK-WP-0049-T09 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "4a47eb2a-7e42-5ae7-9df1-f5ede746eca1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Platform CCR-2026-0048/0049 are verified. The operator +approved folder-only provider-normalized publisher21/retention25 rights, including +re-sharing, in addition to the original rollout. Coding-agent denials precede KV +publication. Exact 900-second single-policy readers, wrong-SA/namespace/audience +rejection, metadata/sibling/old-escrow/token-create denials, ESO equality and +reader/session revocation passed. Operator passwords and age private keys are +not job credentials. + +Evidence: live `publisher-setup-verified.json`, `retention-setup-verified.json`, +`publisher-native-delivery-verified.json`, `retention-native-delivery-verified.json`; +approval decisions `40bfae40-6108-4e51-8613-073339f5345f` and +`5edd5203-fae7-461b-8775-5d22b7873971`; Platform CCR files. + +## Apply capture isolation and install the guarded node runtime + +```task +id: NK-WP-0049-T10 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T09] +state_hub_task_id: "0519444c-d559-5455-aa27-8c5dc8b832b0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Applied exact UID/resource-version/spec-guarded DNS +selector exclusions, preserving ordinary service matches. Capture refuses any +remaining helper allow policy. Installed immutable runtime sources bound to the +actual hostname, machine identity and cluster UID. Disabled-unit replacement +checked previous contents and retained rollback bytes. Health unit validation +passed. Activation remained gated until T13. + +Evidence: live `isolation-applied.json`, `capture-ready-plan.json`, +`installed-runtime-packet-r2.json`, `upgrade-disabled-runtime.py`. Actual complete +hardened-job execution is recorded in T14. + +## Connect recovery to Railiance bootstrap and reuse discovery + +```task +id: NK-WP-0049-T11 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "d69af493-4026-56a8-a526-c267d90dce18" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Added the Railiance bootstrap `identity-recovery` +dispatcher and independent-custody → isolated verification → layer/service-owner +handoff. Updated `capability.security.bootstrap-recovery`, linked bootstrap +sequencing and composed reuse-surface federation. Keyword discovery for identity +backup, restore, privacyIDEA and disaster recovery was verified. The operator +actually used this handoff in T13. No unattended production importer is claimed. + +Evidence: [ceremony](../docs/bootstrap-recovery-ceremony.md), owning capability +entry, `railiance-bootstrap/docs/identity-recovery.md`, bootstrap commit `d1dcfde` +and reuse-surface federation commit `662782e`. + +## Create and verify the first full off-host identity bundle + +```task +id: NK-WP-0049-T12 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T09, NK-WP-0049-T10] +state_hub_task_id: "decb415a-8012-521c-9dbe-d73c6ff0bbfb" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Captured original service keys/current data plus the +linked native PI database dump, sealed and published a unique Storage Share +artifact, then downloaded it and verified size/digest before publishing its index. +Helper and plaintext cleanup passed. Artifact: +`net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age` (109738344 bytes). + +Evidence: live `actual-capture.json`, `actual-offsite.json`; ciphertext SHA256 +`7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`. +No age private key was needed by the capture job. + +## Independently retrieve and recover the complete actual archive + +```task +id: NK-WP-0049-T13 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T11, NK-WP-0049-T12] +state_hub_task_id: "602d4921-cfac-5e5b-9993-4fbf67195c7d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Independently downloaded the exact first generation +through attended Backup-account custody, rehashed it locally and revoked the +session. The operator used the independently held age key through the bootstrap +handoff. Correct/wrong-key cases, all 36 manifest files/hashes, original RSA pairs, +SQLite integrity and isolated native PG16.14 restore/readback passed; plaintext +and containers were removed. No key or restored secret values reached the agent. + +Evidence: live `independent-owner-transfer.json`, `actual-full-archive-recovery.json`, +`actual-full-recovery-review.json`. Existing-user/MFA authentication and old audit +signatures are deliberately separate T16–T20 outcomes. + +## Activate and prove the complete recurring backup and retention job + +```task +id: NK-WP-0049-T14 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T10, NK-WP-0049-T13] +state_hub_task_id: "eaf0708f-b3b7-5531-8172-95edf30c3a19" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 after T13. Both daily backup/retention and hourly health +timers are enabled/active. The actual hardened systemd service passed retention +before/after a second capture/upload/download (Result=success, ExecMainStatus=0). +Both verified generations are retained, the independently recovered point is +pinned, and nothing was deleted. Helpers/plaintext were cleaned; failure markers +and reporting outbox are empty. Health check succeeded. + +Evidence: live `activation-result.json`, `activation-review.json`, +`recurring-job-review.json`. Cadence: daily 03:45 UTC plus up to 5 minutes jitter, +hourly health, 25-hour freshness bound. Second-provider/host-loss gaps go to T24; +this completed task is not a full-estate recovery claim. + +## Map current callers, owners and native acceptance gaps + +```task +id: NK-WP-0049-T02 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06] +state_hub_task_id: "479d6970-6516-50f5-9436-bb5b56d58aad" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +The source inventory and known legacy objects exist; a complete current-use +ledger is not yet accepted. Next action is read-only reconciliation of the 93 +entries in the latest October15 source inventory (the earlier snapshot had 87) against active Make/bootstrap/operator routes and owner evidence. + +**Done when:** each entry is identified as current, retired or owner-deferred, +with its owner, credential route, current consumer(s), native evidence or exact +missing proof, and next responsible task. Explicitly cover the historical +`sso/keycape-pi-token` and `mfa/privacyidea-trigger-admin` objects, lab init, +factor diagnostic delivery, LDAP group/provider boundary, resolver cutover and +root-output/isolation boundaries. Secret presence is not credential validity. +Send current native checks to T21 and historical revocation/rotation decisions to +T22. Do not reopen completed source repairs without a new finding. + +## Prepare the isolated full-service restore and acceptance packet + +```task +id: NK-WP-0049-T15 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28, NK-WP-0049-T29, NK-WP-0049-T30] +state_hub_task_id: "1d1eb903-a4b0-5bc4-a421-0b842d7f68ae" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Prepared draft scope moved to T27.** See +`docs/identity-service-restore-packet.md`: restore order, containment, safe evidence +and per-service positive/negative checks are drafted. Read-only current runtime +image digests were observed for all four services; correspondence to the selected +archive and independent image availability are not yet proved. + +**Next action:** admit a named disposable target/private route, verify and stage +matching images independently, obtain private existing-user/MFA test inputs and +review version-specific native commands with service owners. Incorporate T02's +ledger before submitting current-caller acceptance. + +2026-10-16 checkpoint: T28 completed the exact local image save/load/inspect +and T29 prepared and natively tested the bounded LLDAP stage. Its actual owner +run is T16 and can proceed independently of the remaining multi-service packet. +The other service adapters, matching archive/runtime lineage and private +existing-user/MFA inputs are still required; no blanket T15 completion is claimed. + +**Done when:** service owners accept the exact targets/procedure, existing-user +and MFA test identities/input custody are available without posting secrets, +outbound notification/provider writes are disabled, and every required new +credential or production effect has its own owner decision. The verifier deletes +its plaintext; it is not a production importer. This task prepares authority and +inputs for T16–T20, not an automatic production restore. + +## Prove restored LLDAP directory and existing-user authentication + +```task +id: NK-WP-0049-T16 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T29] +state_hub_task_id: "b64d4d6a-e851-58d1-9929-f03343147de0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom directory/User Engine owners. Restore the captured +original directory/configuration in the admitted isolated environment. + +**Done when:** user, group and membership identities are preserved; an independently +supplied existing-user credential authenticates; a wrong credential is refused; +provider writes/outbound effects stay confined; cleanup is verified. Native +fixtures from T05 and SQLite integrity from T13 do not satisfy this current-data +acceptance. Record only safe counts, identities and outcomes. + + +Completed 2026-10-16 at 18:37 UTC. The operator privately supplied the +independent age key and an existing backup-era account credential to the exact +local executor. All 36 archive hashes and the known ciphertext/source/target +bindings matched. Native existing-user LDAP bind passed; explicit invalid +credentials were rejected. The original seven users, 17 groups, 13 memberships +and the available attribute/schema rows were preserved across service startup, +authentication and graceful shutdown. The container had only loopback/no +external routes; pre-import isolation and container/tmpfs cleanup passed. +No production endpoint was contacted or secret exported to the agent. + +Evidence: `actual-isolated-lldap-recovery.json` and +`actual-isolated-lldap-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. This closes the actual +LLDAP stage independently of the remaining T15 packet. It does not prove +Authelia/KeyCape authentication, retained-token MFA or audit continuity. T17, +T18 and T19 retain their remaining adapter/input prerequisites. + +## Prove restored Authelia storage and OIDC continuity + +```task +id: NK-WP-0049-T17 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16] +blocking_reason: "LLDAP recovery T16 passed; await the exact isolated Authelia adapter/procedure and private authentication-flow inputs from T15." +state_hub_task_id: "b47f9975-d6d7-5bb8-93ce-886deb1dfa70" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: SSO/Authelia and directory owners. Restore the original storage, +encryption/session/signing material and configuration in isolation. + +**Done when:** native storage decryption succeeds, issuer/signing identity and +client configuration are preserved, and an isolated authentication flow has +positive/negative results using the restored directory. Disable outbound +notifications and verify cleanup. Archive integrity/RSA parsing alone are not +native Authelia acceptance. + +## Prove retained privacyIDEA token decryption and existing-token MFA + +```task +id: NK-WP-0049-T19 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T31] +blocking_reason: "LLDAP T16, token-material T31 and audit T20 passed; await the exact isolated MFA adapter and owner-selected retained-token/factor inputs." +state_hub_task_id: "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA and directory owners. Use the exact linked dump +and original enckey from the independently recovered generation. + +**Done when:** retained token material decrypts inside the isolated process, +a selected existing token completes a native MFA check, a wrong key/code is +refused, and cleanup is verified. Obtain any token/user input through attended +private custody; never emit token plaintext, seeds or credentials. Native database +row counts and disposable synthetic-token fixtures do not prove this outcome. + + +2026-10-16 refinement: native token-material readback is separately tracked in +T31 using the prepared T30 executor. T19 retains actual existing-token MFA and +wrong-code/wrong-key authentication refusal. Internal decryption or padding +success does not authenticate a user. No MFA code is needed for T20/T31; the +selected user's private factor input and exact isolated MFA adapter remain T19. + +## Prove historical and new privacyIDEA audit-signature continuity + +```task +id: NK-WP-0049-T20 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "375fa8f9-b8a5-5048-97a7-ec141aa7c45d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA audit owner. Use the original recovered audit +pair and linked database in the admitted isolated target. + +**Done when:** existing pre-backup audit signatures are verified natively, a new +isolated audit entry is signed and verified with the preserved identity, a wrong +key fails, and cleanup is recorded. Report any historical verification failure +for explicit owner disposition; do not regenerate keys to hide it. Matching RSA +pairs from T13 are a prerequisite, not audit-history verification. + + +Completed 2026-10-16 at 19:10 UTC using the actual independently retrieved +bundle and original audit identity on the fixed isolated local engine. All +279,209 stored rows were signed and verified; zero unsigned, invalid or legacy +signatures. A new isolated entry verified, and tampering/unrelated-public-key +checks were refused. Container/plaintext cleanup passed. Receipt and reviewed +source/ciphertext/target bindings: `actual-isolated-privacyidea-recovery.json` +and `actual-isolated-privacyidea-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. +Stored-row continuity is accepted; event completeness and existing-token MFA +are separate and are not claimed. + +## Prove restored KeyCape issuer, policy and consumer continuity + +```task +id: NK-WP-0049-T18 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T19, NK-WP-0049-T32, NK-WP-0049-T33] +blocking_reason: "Source and synthetic KeyCape lifecycle proof are delivered in T32; await exact owner-held recovery attempt preparation T33, selected consumer acceptance and retained-token MFA for the selected flow." +state_hub_task_id: "141dd773-c1fa-56c1-a852-bbe2372e5125" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: KeyCape and the selected current consumer owners. Restore the +original signing/configuration, registry, authentication policies and receipts. + +**Done when:** issuer/JWKS signing identity, registry/client configuration and +policy/receipt continuity are preserved; selected current consumers pass native +positive/negative authentication using the restored dependencies; and isolation +and cleanup hold. Confirm the actual dependency graph in T15. Do not route a +production consumer to the isolated issuer or mint new client grants implicitly. + +## Verify current caller and provider admission at their actual boundaries + +```task +id: NK-WP-0049-T21 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02] +blocking_reason: "Await the current-caller ledger and exact per-caller owner admission/test inputs; the backup credential grants do not admit unrelated callers." +state_hub_task_id: "77aa42be-7a39-5d93-8042-03d78b4094b4" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: each current caller's service/provider and credential owner. +Use T02's ledger to select the exact current procedures and required owner lanes. + +**Done when:** each current caller has scoped delivery and native positive/negative +acceptance or an explicit accepted retirement/disposition. Include dedicated +factor-diagnostic admission (do not borrow KeyCape's reader), deployed reserved +LDAP group denial, resolver/cutover input provenance and functional proof, and +bootstrap/root-output/isolation callers. Fixtures, an existing tty and historical +bootstrap receipts are not current authority. Propose exact write/cutover actions +before execution; record deferred actions separately rather than faking a pass. + +## Resolve historical credential and configuration-preserving rotation dispositions + +```task +id: NK-WP-0049-T22 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T21] +blocking_reason: "Await the caller/consumer ledger, current replacement-lane acceptance and explicit credential-owner dispositions; existing exposure-rotation deferral is unchanged." +state_hub_task_id: "3ea6bf00-a87f-58ea-bdce-328c13a03a55" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: Platform/custody and affected consumer owners. Review historical +personal-admin/trigger credential copies and unsafe predecessor paths against +known current consumers and rollback custody. + +**Done when:** every affected credential has an owner-accepted disposition: +verified revocation/replacement, continued bounded use with acceptance, or an +explicit linked deferral. Signing/client-secret changes require preservation and +native multi-consumer proof if actually approved. CUST-WP-0073-T05's founder +rotation deferral and decision `1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa` remain in force; +record their exact applicability rather than automatically rotating or treating +source retirement as provider revocation. + +## Provide retrieval that works when OpenBao and SSO are unavailable + +```task +id: NK-WP-0049-T23 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T25] +state_hub_task_id: "1ec537ee-dfee-5576-be36-a81bdba417d1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 at 18:02 UTC. The operator used independently held Backup +account access in the private prompt. The actual protected 109,738,344-byte +ciphertext was downloaded with unchanged ETag/size/SHA256, with no OpenBao/SSO +contact or provider writes by the retrieval path. The human-held age key matched +the registered recipient; wrong-key refusal, all 36 manifest hashes, SQLite +integrity, original key pairs and native isolated PostgreSQL 16.14 restore passed. +The database retained five token, two resolver and two realm rows. Disposable +container and temporary plaintext cleanup passed. The agent received no secret. + +Evidence: `actual-offline-transfer.json`, `actual-offline-recovery.json` and +`actual-offline-review.json` under +`docs/evidence/2026-10-16-identity-outage-recovery/`. The review rechecked the +local ciphertext digest and verifier source. This proves the independent path +without requiring a deliberate production outage. Service authentication, +retained-token decryption and historical audit verification remain T16–T20. +T26 separately records accepted guide publication. + +## Record owner disposition for second-provider and external monitoring gaps + +```task +id: NK-WP-0049-T24 +status: todo +priority: medium +assignee: codex +depends_on: [NK-WP-0049-T14] +state_hub_task_id: "474f5a78-a643-59c6-bcf9-fc4a908dfcb0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Next action:** record the current single-provider and host-local-health limits, +then obtain explicit owner scope decisions for a second encrypted provider copy, +external host-loss/freshness detection and recurring recovery-drill cadence. + +**Done when:** each gap has either an accepted bounded residual risk or a linked +live intake/workplan with owner and trigger. Existing daily RPO/25-hour health +settings remain the approved baseline. Scaleway full-identity publication and +an external watchdog are not implemented; do not add their grants/jobs implicitly. +This task triages the new insights instead of silently expanding NK49's required +implementation to an entire disaster-recovery programme. + +## Deliver and verify the offline retrieval adapter and recovery tools kit + +```task +id: NK-WP-0049-T25 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13] +state_hub_task_id: "1c5ea7a1-edf7-5072-b36b-8be7f827957a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. `retrieve-identity-offline.py` uses privately entered +independent Backup-account access or an exact read-capable identity-folder share. +It performs only fixed-provider HEAD/GET, binds the reviewed generation by strong +ETag/length/SHA256, refuses redirects/proxies/unreviewed scope and removes failed +downloads. No OpenBao/SSO, age key or standing agent credential is required. +`recovery-kit.py` builds a reproducible allowlisted ZIP containing the tools, +public profile, known-good ciphertext receipt and recovery guides, with file +checksums. Its publication path creates only three versioned guide/ZIP/checksum +objects and verifies readback without overwriting existing conflicting objects. +`run-offline-recovery.sh` provides the owner's two-hidden-prompt handoff. + +Evidence: `tests/test_identity_offline_recovery.py` and the bounded test/build +receipt in `docs/evidence/2026-10-16-identity-outage-recovery/`. The focused run +passed 65 tests including real disposable age/PostgreSQL fixtures. ZIP-contained +entry points import without sibling repositories. This is source/fixture proof, +not actual independent-provider retrieval (T23) or publication (T26). + +2026-10-16 correction: the first owner handoff stopped before its credential +prompt because Python text `r+` requires a seekable stream. Reproduced against a +real controlling PTY; replaced both prompts with the shared hidden-input helper, +refusing redirected input and echo fallback. Added real-terminal and both-CLI +regressions plus closed stage/HTTP-code diagnostics (no raw responses). The +focused rerun passed 36 tests. Evidence: `terminal-prompt-fix.json` in the outage +evidence directory. This source correction does not complete T23/T26. + +## Publish and verify the disaster recovery guide on Storage Share + +```task +id: NK-WP-0049-T26 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T25, NK-WP-0049-T27] +state_hub_task_id: "94d054fe-e5d8-5ddf-8e48-80714123d184" +``` + +**Accountable worker:** codex; operator holds provider access privately. + +Requested by the operator on 2026-10-16; decision +`fc3ef8db-0a33-41d5-a0ba-d13169c5f884` records the bounded scope. Guide source: +`docs/disaster-recovery-storage-share.md`. Document scope, independently held +provider/key requirements, exact known-good fallback, copy/download verification, +archive-check commands, service restore order, recurring schedule and remaining +coverage limits. Include the offline tools so failed Forgejo does not prevent +access to the recovery scripts; retain an independent copy and trusted digest. + +Completed 2026-10-16 at 18:01 UTC through the private independent-provider +owner handoff. All three objects were conditionally created and read back with +matching strong ETag, length and content; the recorded digests match a fresh +reproducible local build. No existing object or provider permission was changed. +The failed first attempt and terminal correction remain documented in T25. + +**Published location:** Storage Share account Backup, +`railiance-backups/net-kingdom-identity/`: + +- `net-kingdom-recovery-57d1940947aa25ff-START-HERE.md` +- `net-kingdom-recovery-57d1940947aa25ff.zip` +- `net-kingdom-recovery-57d1940947aa25ff.zip.sha256` + +**Trusted ZIP SHA256:** +`57d1940947aa25ff83d0f25ddf30090eb40595cccaab64225de882a2fd59ea2f`. +Evidence: `actual-offline-publication.json` and `actual-offline-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. The published guide is the +exact pre-drill revision; this acceptance record records the later successful +drill without implying an unperformed republication. Keep an independent copy +and trusted digest outside the failed service/provider dependency. + +## Draft the isolated service restore packet and observe candidate images + +```task +id: NK-WP-0049-T27 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13] +state_hub_task_id: "e273e803-bee7-5d90-bc51-ecc08c0c8eff" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. Draft in `docs/identity-service-restore-packet.md` names the +known recovered input, restore order, original key/data ownership, default-deny +containment, blocked production/provider/notification effects, cleanup and five +native acceptance lanes with positive/negative checks. Read-only metadata from +the pinned primary cluster resolved all four current service image digests, +including the separately observed privacyIDEA main container and LLDAP's mutable +source tag. Evidence: `docs/evidence/2026-10-16-identity-outage-recovery/image-observation.json`. + +This task extracts completed preparation from T15. Named target admission, +archive/runtime image-lineage matching and independent image availability, +private existing-user/MFA inputs and owner-reviewed native commands remain T15; +no service restore, production change or owner acceptance is claimed. + +## Stage and verify the five exact service images for local offline recovery + +```task +id: NK-WP-0049-T28 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T27] +state_hub_task_id: "4829b091-76d2-5b10-bdfc-032800190c0a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. All five pinned references (PostgreSQL, LLDAP, Authelia, +KeyCape, privacyIDEA) were inspected on the fixed local Linux Docker engine +`bnt-lap001`, ID `74f93783-6cef-43a8-a3c4-f62586cd3bc1`. Missing LLDAP and +privacyIDEA images were pulled only by their observed immutable digests. Saved a +private 347,521,536-byte image archive, loaded it and re-inspected every exact +reference. Evidence and archive SHA256/location: +`docs/evidence/2026-10-16-identity-outage-recovery/offline-service-images.json`. + +The local drill no longer requires the production registry. This is not off-host +image escrow or proof of historical mutable-tag/backup lineage; those limits +remain in T15. No service custody or age key was supplied to image caching. + +## Prepare and verify the bounded native LLDAP recovery executor + +```task +id: NK-WP-0049-T29 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28] +state_hub_task_id: "2f8c73b0-1cdd-5b22-99b6-017ccde4454b" +``` + +**Accountable worker:** codex; operator retains actual private recovery inputs. + +Completed 2026-10-16. `isolated-lldap.py` and `run-isolated-lldap.sh` provide the +exact owner-run stage in `docs/identity-service-restore-packet.md`: fixed local +engine/images, no remote Docker endpoint, original key/seed/JWT/directory data, +Linux-tmpfs decryption, memory/stdin-only private inputs, network-none/read-only +containers, isolation inspection before import, actual existing-user bind, +explicit invalid-credential denial, stable directory rows and cleanup checks. +Missing original server keys are refused; reset/replacement/notification paths +are disabled. No live Kubernetes/OpenBao/SSO path or provider grant is used. + +Evidence: `tests/test_isolated_lldap_recovery.py` exercises the actual pinned +image, disposable retained-account directory and a full synthetic encrypted +bundle through the same native executor. The private real-bundle run and its +acceptance remain T16; fixture success is not actual user/MFA/audit recovery. +See `isolated-lldap-preparation.json` in the October16 outage evidence directory +for exact test/source/target provenance and limitations. + +## Prepare the bounded native privacyIDEA token-material and audit executor + +```task +id: NK-WP-0049-T30 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T28] +state_hub_task_id: "6e4a43db-9be2-5662-bdbf-1595fce03052" +``` + +**Accountable worker:** codex; operator retains private recovery inputs. + +Completed 2026-10-16. `isolated-privacyidea.py` and its owner launcher use the +fixed local Docker target and exact cached PostgreSQL/privacyIDEA3.12.2 images. +The linked dump, original enckey/audit pair and required secret fields are +restored only into a loopback-only, nonroot, read-only, capability-free, +no-host-mount/port, tmpfs-backed environment with inspected pre-import isolation. +Decrypted host staging is tmpfs; normal cleanup removes all private data and +owned containers, with a bounded holding lifetime if the parent is interrupted. + +The native provider decrypts token-key material internally, checks every stored +audit row, adds one isolated signed entry and checks wrong-public-key/tampering +negatives. Original policy for legacy signature verification is retained only +from literal archived configuration; archived Python is never executed. Invalid +or unsigned history remains reported, not repaired or sampled away. Native +material readback is not existing-token MFA or proof of event completeness. + +Evidence: `tests/test_isolated_privacyidea_recovery.py` and +`isolated-privacyidea-preparation.json` in the October16 outage evidence folder. +Synthetic pinned-image tests exercise valid/tampered/unsigned history, malformed +keys, encrypted archive to native restore, isolation and cleanup. Real original +material/audit acceptance remains T31/T20; actual MFA remains T19. + +## Verify retained privacyIDEA token material inside the isolated provider + +```task +id: NK-WP-0049-T31 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "26383841-8076-5c53-bbd1-9db64e32544a" +``` + +**Accountable worker:** codex; operator supplies only the independently held age +key in the hidden helper. This task extracts actual material-readback scope from +T19, preserving T19's existing-token MFA acceptance gate and historical identity. + +Completed 2026-10-16 at 19:10 UTC in the same actual run as T20. All five +retained token materials were decrypted internally with the original enckey; +an unrelated key could not reproduce any of the five. All 36 manifest hashes, +exact executor/ciphertext/target bindings, isolation and cleanup passed. Safe +receipts are the `actual-isolated-privacyidea-{recovery,review}.json` files +referenced under T20. No retained-factor authentication is claimed. +**Done when:** exact ciphertext/source/target/manifest bindings pass; the native +provider reads every nonempty encrypted token-key field using the original +enckey without exporting material; an unrelated key cannot reproduce that +material; aggregate counts and container/plaintext cleanup are recorded. + +Only bounded internal readback is accepted here. Padding/readback success does +not prove the recovered secret authenticates a retained factor; actual positive +MFA and wrong-key/wrong-code authentication refusal remain T19. No token seed, +plaintext, serial or user record belongs in the receipt, Git, State Hub or chat. + +## Deliver isolated KeyCape restore source and synthetic lifecycle proof + +```task +id: NK-WP-0049-T32 +status: done +priority: high +assignee: codex +state_hub_task_id: "cd78dbb7-a8f2-5754-8788-6eb1b7d97741" +``` + +Completed 2026-10-16. This extracts bounded source/fixture delivery from T18; +T18 retains actual original archive, issuer and selected consumer acceptance. +The adapter reuses the existing transfer/archive/custody contracts, binds the +fixed local daemon and cached images, restores private state only to temporary +memory, verifies original issuer/TLS/signing/configuration/policy bytes and runs +the original native service-client checker with wrong-secret/excess-scope denial. +Durable pre-import obligations and exact parent pidfd/session quiescence precede +loss/deadline cleanup. Daemon response uncertainty remains uncertainty after +resource absence; it never authorizes recovery success or replay. + +Frozen R6 fixes a demonstrated image-declared anonymous-volume incompatibility +using bounded helper-only tmpfs, preserving anonymous disk-volume refusal. Safe +phase markers carry no private diagnostics. Independently passed 72 focused +checks, then actual pinned-image synthetic positive, hard-parent-loss, deadline +and nonzero-after-accept cases. Independent fixed-daemon inventories and host +mount-namespace checks prove all exact resources and plaintext absent. Reaper +outcomes are retained; initial sandbox receipt lookup failure is preserved and +superseded by device-bound host verification. R1–R5 failures remain retained. + +Evidence: Custodian docs/changes/netkingdom-target-2026-10-16/ +identity-restore-adapter-next/revisions/r6/, actual-fixture-r6-all.json and +coordinator-r6-all-review.json. Exact source/dependency hashes and candidate +manifest bind the proof. This uses generated test keys only; it proves neither +actual owner-held recovery, human MFA, downstream reconnect nor native authority. + +Publication preparation R7 preserves every R6 recovery adapter byte and digest. +The normal scanner flagged eight public source-file SHA-256 values in the R6 +manifest. Explicit sha256-qualified checksums resolve those false positives; +the fixture reader strictly validates their type/shape before checking the same +bytes. R7 passes 73 focused checks including malformed/untyped digest refusal. +The frozen R6 actual four-case proof remains the runtime evidence; no repeated +native outcome is claimed for publication encoding. Original scanner refusal is +retained, and scanner policy/exemptions are unchanged. + +## Prepare the exact owner-held KeyCape recovery attempt + +```task +id: NK-WP-0049-T33 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32, NK-WP-0049-T34, NK-WP-0049-T35, NK-WP-0049-T36] +blocking_reason: "Source custody/preflight preparation is evidenced in T34; await original TLS/trust recovery disposition T35 and selected original registration/private-admission metadata T36 before final reviewed command and existing owner process." +state_hub_task_id: "56c8d469-7a10-5d50-a30e-95cbf3cd4756" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and selected consumer owners. +This umbrella retains final attempt readiness. Completed custody/preflight source +preparation is extracted into T34; T35 resolves original TLS/trust recovery and +T36 prepares the selected original registration and private admission. This split +records distinct outcomes without counting source preparation as recovery. + +After those deliverables, assemble the exact existing six-argument attended +command and admission digest, bind the integrated source/dependency revision and +fixed local target, and record execution deadline, safe receipt location, abort, +rollback and independent receipt verification through the existing owner process. +Keep private manifest derivation inside custody and original TLS/client/key inputs +in the owner's own terminal; the current null fields must refuse execution. +Existing session authorization is retained within scope; this record does not +supply missing owner assent or approve any actual recovery attempt. + +**Done when:** reviewed executable command and complete metadata-only/private +admission packet are ready for the existing attended custody path; prerequisites +and independent receipt verification are explicit. T18 still owns actual +execution, original consumer continuity and acceptance. T19 retains retained-factor +MFA. This task neither authorizes a production consumer redirect nor creates a +new client grant. + +## Deliver attended custody, metadata preflight and private manifest preparation source + +```task +id: NK-WP-0049-T34 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32] +state_hub_task_id: "821b3a56-6f36-5812-abc9-5a00e37cb2e7" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian source review. +Completed 2026-10-17 as source preparation. Existing attended custody entry points +now have a reviewed candidate sealed anonymous descriptor mode: hidden prompt, +actual public-recipient verification, strict owned/private/full-seal descriptor +admission, non-inheritable returned duplicate and explicit descriptor passing. +The existing file mode stays compatible, with its original hard-loss limitation; +no improved file-mode cleanup is claimed. Exact parent-loss tests prove descriptor +lifetime without signalling inherited user shell groups. An admitted child retains +its descriptor until it exits; parent loss is not child revocation. + +The candidate checks bounded, duplicate-free public JSON, exact admission digest, +transfer/archive and selected service bindings, typed hashes for all 17 invoked +local source/config dependencies and required Python imports before requesting a +key. TLS and ciphertext preparation uses file metadata only. Legacy explicit +manifest digests remain supported; versioned ciphertext-derived binding computes +the canonical digest privately only after exact reviewed ciphertext, authenticated +age decryption and full existing archive validation. The derived private digest +never enters safe receipts/checkpoints and grants no new consumer authority. + +The coordinator independently passed 111 focused checks. The existing custody +regression suite passed 94 checks; 61 real-SOPS tests skipped because that trusted +runtime is unavailable, so that compatibility coverage remains unverified. Tests +use generated keys/archive material only, including actual age cryptography, +synthetic hidden-prompt and exact parent-loss processes. Manifest-builder tests +mock Docker/issuer behavior and confer no new native proof. Frozen R6/R7 proof, +intermediate test failures and scanner history remain retained. + +Bounded public image readback separately establishes the cached original image's +13670142-byte `/keycape` executable as +`sha256:cd89121393e1465aa76009763602a5b8c75f9dddb5679aea6242623f135b51b4`. +This is executable identity metadata, not recovery or custody acceptance. + +Evidence: Custodian `docs/changes/netkingdom-target-2026-10-16/recovery-attempt-r1/` +(`candidate.patch`, `review.json`, source closure, attempt/admission metadata and +`public-verifier-image-readback.json`). Canonical integration/publication and +projection receipts must be recorded separately when performed; this completed +source-preparation record does not invent them. T33 remains open for complete +attempt readiness; actual recovery/consumer acceptance remains T18 and MFA T19. + +## Establish original KeyCape TLS and trust recovery ownership for outage use + +```task +id: NK-WP-0049-T35 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "1bfd1703-589f-5511-bad5-812d860e4a71" +``` + +**Accountable worker:** NetKingdom codex, coordinating with the source owner of +Ingress/cert-manager/Traefik and the original TLS custody/provider boundary. +**Next action:** identify and record that actual owner's existing recovery path, +then obtain its metadata/disposition through the ordinary owner process. A missing +exact credential-routing catalog match is not evidence that no owner exists. + +Current source declares `kc.coulomb.social`, `sso/kc-tls`, cert-manager +`ClusterIssuer/letsencrypt-prod` and Traefik TLS termination before KeyCape 8080. +The identity backup profile excludes `kc-tls`; the verified archive therefore +establishes no independent recovery of that TLS identity/trust. Determine whether +the exact original certificate/key/trust is independently recoverable during an +issuer/cluster outage, or whether a documented reissue path is acceptable for the +selected continuity claim. Do not read or place the TLS key in work records, use +a fresh self-signed trust substitute, mutate production or claim owner assent. + +**Done when:** named owner/provider, independent outage prerequisites, original +public identity/certificate/trust hashes or accepted reissue disposition, private +custody entry point and verification/abort limits are explicit and reviewed. +Record any unavailable recovery capability as a live owner work record and bind +its dependency/unblock condition; a prose-only gap or untested archive is not +completion. This delivers preparation/disposition, not actual TLS recovery. + +2026-10-17 owner handoff progress: the four reviewed Railiance Cluster source +additions are present, including `RCLUSTER-WP-0018` and public-only TLS metadata +preparation. They are not published. The normal publication path stopped at the +existing historical identifier guard (`ensure_missing_work_record_identifiers`, +execute=False): 15 bare task-label findings and five collisions. A separately +retained read-only allocator preview records those findings; the original failed +publication stderr was not retained and is not reconstructed. No Cluster Hub +workplan/task existence or projection, actual certificate/key custody, reissue +assent or native TLS acceptance is claimed. The source record and next owner +publication action remain live; do not bypass the historical identity guard. +Evidence: Custodian October17 `cluster-integration.json`, `coordinator-checkpoint.json` +and October16 `cluster-historical-publication-r1/actual-source-allocator-preview.json`. + +## Prepare selected original service registration and private admission bindings + +```task +id: NK-WP-0049-T36 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "8b72334b-fc27-5707-a189-bad345eaf3bc" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and the selected existing +service consumer's owner. **Next action:** identify that owner and the exact +original registration's non-secret selector metadata using existing source/owner +evidence; preserve independent private custody and never retrieve a client secret. + +Bind reviewed ciphertext `7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`, +its independently verified transfer, source/image/executable closure and an +explicit versioned manifest-binding mode. For the original service registration, +record client identifier, secret environment name, audience, granted scope, +subject, tenant, required roles and denied scope without values or new grants. +Describe the native service-client dependency graph and distinguish unexercised +LLDAP/Authelia/privacyIDEA/downstream flows. Keep private manifest material inside +the existing custody process, never in Git, safe receipts, State Hub or chat. + +**Done when:** the selected existing service owner and exact non-secret registration +bindings are independently established, the private admission builder validates +positive/negative source/archive/selector cases, and its metadata is ready to +combine with T35's original TLS/trust disposition under T33. This task may prepare +registration metadata while T35 proceeds independently; it does not finalize the +whole admission, perform actual recovery, redirect a consumer or confer assent. + +2026-10-17 owner handoff progress: Secrets Engine source workplan +`SECRETS-WP-0015` and bounded public selector/preflight source were published as +`c59bbf568c0be8a72ac593508f48c9b1f61ec4c1`; the central primary/railiance01 +reconciliation receipt reports the same expected/derived commit, four owner task +bindings and two T04 dependency edges, with no unresolved edges. T01/T02 source +preparation is done, T03 exact outage-compatible consumer proof/custody planning +is todo, and T04 actual admitted consumer result waits on T03 and NK-WP-0049-T33. +This publishes an owner handoff, not exact archived registration validation, +current native assent, an OpenBao read, a new grant or consumer continuity. +T36 therefore remains progress; T18/T19 and final native gates remain open. +Evidence: Custodian October17 `secrets-engine-projection.json` and October16 +`recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote +readback is recorded separately when performed. + +## Verify actual SOPS compatibility and sealed-descriptor read/write custody + +```task +id: NK-WP-0049-T37 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "3403e266-d63b-5ce1-b891-3bfeac93d28c" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian fixture review. +Completed 2026-10-17 as generated-fixture compatibility proof. The coordinator +ran the actual reviewed SOPS 3.13.3 binary in a network/host-custody-isolated +namespace: all 65 tests passed in 14.85 seconds, including the 61 real-SOPS cases +previously skipped in T34 and four new actual sealed-FD cases. The latter cover +correct-key descriptor-only decryption, wrong-recipient refusal and descriptor-only +edit/rotation through the real Make entry points. Generated custody key files +were removed before these FD-only invocations; explicit descriptor passing, +private output modes, declared encryption-policy preservation, suppressed synthetic plaintext +and operation cleanup were checked. + +This is a dated successor to T34's historical 94-pass/61-skip record, which stays +unchanged. The prior skip is not rewritten as an earlier pass. Binary digest +`sha256:e5bec3346a873ae91d871550f3e698c1aad962aff462a080e40f25fde17fef6b` +matched the official release asset/checksum; Sigstore signature verification was +not performed. SOPS was not installed systemwide or admitted for production +runtime. Host custody was not mounted, network routes were absent, diagnostics +were suppressed and namespace teardown completed. All material was generated; +no original owner key/archive, private manifest, production credential, native +service continuity or owner assent was exercised. + +Evidence: Custodian +`docs/changes/netkingdom-target-2026-10-17/sops-real-regressions.json`, +`sops-source-tool.json` and `sops-fd-r2/` (exact test patch/manifest). The focused +custody/source checks and frozen R6/R7 native fixture evidence remain separate. +T33 attempt readiness, T18 actual recovery/consumer acceptance, T19 retained MFA, +T35 TLS/trust disposition and T36 original registration/private admission remain +open under their existing owner boundaries. + +## Accept remaining recovery and caller evidence and close the G08 handoff + +```task +id: NK-WP-0049-T03 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T16, NK-WP-0049-T17, NK-WP-0049-T18, NK-WP-0049-T19, NK-WP-0049-T20, NK-WP-0049-T21, NK-WP-0049-T22, NK-WP-0049-T23, NK-WP-0049-T24, NK-WP-0049-T26] +blocking_reason: "Await the separately tracked native service proofs, current/legacy caller dispositions and residual-scope decisions; archive recovery, backup activation, independent outage retrieval and guide publication are complete." +state_hub_task_id: "d68cd4d3-1ba3-530e-88f9-26ebb8dd6eac" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom, Platform and affected service owners, with Custodian +G08 receiving the final evidence. The completed archive/job milestones remain +accepted independently of this final gate. + +**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted +handoff outcomes; service authentication/token/audit proof and current/legacy +caller dispositions are accepted; the source workplan and projected tasks agree; +and G08 has an exact evidence/handoff record. Record actionable residuals as live +work records before workplan closure. Preserve historical IDs and receipts; do +not call a deferred rotation or an untested full-estate restore complete. + +## Evidence locations and refinement history + +“Live” above means `docs/evidence/2026-10-16-identity-backup-live/` in NetKingdom. +Implementation preparation is in the October16 implementation directory; earlier +backup discovery/database recovery is in `docs/evidence/2026-10-15-bootstrap-recovery/`. +The source-repair receipts explicitly labelled Custodian belong to that owning +repository. Use the [recovery ceremony](../docs/bootstrap-recovery-ceremony.md) +for exact procedure and approval history. No secret values belong in task evidence. + +Refinement rule: substantial work and newly understood remaining scope must be +visible in task blocks at a checkpoint, not only in progress prose. This replan +preserves T01–T03 identity and original evidence while making the completed +milestones and each remaining acceptance gate separately manageable. + +Managed identifier assignment also consumed a preexisting staged generated brief; +the follow-up commit restores its prior published baseline while preserving the +operator's working brief and original staged version. This is a projection-tool +side effect, not new recovery evidence. + + +R7 source publication and task bindings verified: +`5fcd5952add1c0167116094298a1d5feaa60cf30` is the observed published source. +All eight canonical additions match the reviewed bytes; all 33 task statuses +match the actual hub projection, including T32 done and T33 todo. Original +staged/working brief content is preserved. Normal synchronization has zero +failures/automation errors; existing warnings and scanner false-positive history +remain retained. Custodian identity-restore-adapter-next/canonical-r7-integration.json +binds source/projection/native-fixture evidence separately. T18 remains waiting +for the actual owner-held attempt and selected consumer acceptance. + + +2026-10-17 source/attempt refinement: T34 records completed attended custody, +preflight/private-manifest source preparation and its bounded tests; T35 and T36 +make original TLS recovery ownership and selected original admission metadata live +work. T33 retains final attempt readiness and its original Hub UUID. This adds no +actual recovery, MFA, native authority or owner assent. Source task counts above +refer to this file; projection has not been claimed for this proposed refinement. + +2026-10-17 verified source follow-through: source commit `4f65e41` passed normal +local scanning and 111 canonical focused checks. The initial T34 source-only +preparation now has an exact integrated source revision; existing real-SOPS +compatibility remains partly skipped and actual owner-held execution remains T18. + +T35/T36 source preparation is underway, with 17 pinned public-source references. +railiance-cluster owns the ingress/cert-manager/cluster-backup substrate; the +inspected same-host encrypted backup source establishes no independent original +kc-tls/trust recovery or accepted reissue. Draft owner questions remain unsent; +no private TLS input was requested. The historically deployed +secrets-engine-openbao registration is a defensible proposed consumer: its +7 October issuer and 10 October consumer proofs predate the reviewed archive. +The exact selector proposal is retained without current assent or private archive +validation. No token exchange, OpenBao login, client secret retrieval, new grant +or production redirect occurred. Keep incomplete admission refused before custody. +Custodian evidence: recovery-attempt-r1/t35-t36-source-next; final source/projection +review: resume-integration-r1/publication-verification.json. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.postimage.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.postimage.md new file mode 100644 index 00000000..15dacf69 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.postimage.md @@ -0,0 +1,1308 @@ +--- +id: NK-WP-0049 +type: workplan +title: "Remove bootstrap secret output and verify separated recovery custody" +domain: infotech +repo: net-kingdom +status: active +owner: codex +topic_slug: netkingdom +created: "2026-10-12" +updated: "2026-10-17" +flavor: implementation +depends_on: [] +state_hub_workstream_id: "17d315f0-829e-57c7-85cc-3a7914152804" +--- + +Native owner work for CUST-WP-0080 G08. This workplan remains active until the +remaining caller, service-recovery and custody acceptance gates are satisfied. +NK-WP-0045 covers the non-secret root-grant record. Founder-deferred exposure +rotation remains in CUST-WP-0073-T05; this plan does not silently reopen it. + +**Replanned 2026-10-16 at the operator's request:** substantial completed work is +now represented by completed tasks, and remaining work has separate deliverables, +dependencies and acceptance criteria. T01–T03 retain their historical IDs and Hub +UUIDs. Completed parts of the old T02/T03 umbrellas are extracted into T04–T14; +T02 now covers the current-caller ledger and T03 retains final owner acceptance. +These are retrospective task records of evidenced work, not additional delivery +or newly granted authority. The earlier dated narrative remains in Git at +`cc2dd01`; its evidence references are carried into the tasks below. + +**Current position, source refinement 2026-10-17:** 25 tasks done; 4 in +progress; 1 ready to start (`todo`); 7 waiting on explicit prerequisites. These are task counts, not an effort-based +completion percentage. Assignees are also written in task descriptions because +the current Forge projector does not populate the dedicated Hub assignee field. The outage-retrieval tool and restore-packet draft are now prepared; +independent outage retrieval and Storage Share publication are accepted; +service admission remains an explicit gate. + +**Next actions:** finish the read-only caller ledger (T02); admit the drafted +isolated restore packet (T15) and record residual-scope handoffs (T24). +Independent outage retrieval (T23) and guide publication (T26) are done. After owner admission, execute the individual native service and +caller checks. A task's owner is accountable for the result; another repository's +approval or credential grant still requires its own owner path. + +**Closure:** T03 assembles owner acceptance after its named dependencies pass. +Passing archive recovery does not prove existing-user authentication, retained +MFA-token decryption, historical audit signatures or current caller admission. +The verified backup job stays active while those separate tasks are completed. + +## Remove secret-bearing output and ambient root discovery + +```task +id: NK-WP-0049-T01 +status: done +priority: high +assignee: codex +state_hub_task_id: "d7ca8d5f-c5ff-5cba-bd25-038cb53ffe4e" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +2026-10-12: regression reproduced emergency/reprint root export, generation +prefix disclosure, permissive file modes, dry-run side effects and unattended +entry. Replaced emergency export with a non-secret guide (legacy secret-input +arguments refused), suppressed generation prefixes/tracing and set private +permissions. Bootstrap requires the registered public recipient and an attended +terminal; never generates/discovers a permanent private key. Encrypted resume +requires an explicit matching temporary custody key before cluster activity. +Dry-run is a non-mutating plan. The live cluster/apply path was not executed. + +A fresh uniquely named encrypted ops bundle follows apply; old delivery flags +cannot skip current acknowledgment. New acknowledgment state binds its SHA256 +and timestamp. Declining stops before cleanup/completion. This is an operator +statement, not an independent restore receipt. Historical fields remain unchanged. +Make/help/status/console and current credential guidance reflect that distinction. +Evidence and exact source manifest: Custodian +`docs/evidence/2026-10-12-netkingdom-security/bootstrap-handoff.json`. + +## Harden custody, SOPS and rotation source entry points + +```task +id: NK-WP-0049-T04 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T01] +state_hub_task_id: "04c4e8be-5bd8-5d5c-99b1-79d8ae758462" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-12–13. Public-recipient-only encryption, explicit temporary +custody, private no-overwrite output, sanitized diagnostics, stdin-only secret +transport and failed-operation cleanup replace ambient-key and output paths. +SOPS read/edit/data-key rotation preserve recipient/MAC/source-version guards; +component rotations preserve unrelated fields and retain recovery candidates. +This records source and disposable-native proof, not live rotation or revocation. + +Evidence: Custodian `docs/evidence/2026-10-12-netkingdom-security/` receipts +`custody-entrypoints.json`, `sops-make-entrypoints.json`, `rotation-output.json`, +and `admin-bootstrap.json`; October13 `sops-write-callers.json`. + +## Repair component, diagnostic, LDAP and resolver callers + +```task +id: NK-WP-0049-T05 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04] +state_hub_task_id: "e8e38f42-609e-5c07-a8e6-e73c8eb4ae95" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-13–14. Repaired KeyCape configuration and component Secret +publication, original privacyIDEA key export/restore transport, scoped MFA +counts, LDAP group maintenance and configuration-preserving resolver cutover. +Retired unsafe personal-token mint/refresh and direct LDAP lifecycle shortcuts. +Disposable native PI/LLDAP tests and source regressions passed; estate provider +admission, historical credential validity and service authentication remain T21/T22. + +Evidence: Custodian October13 `keycape-caller-reconciliation.json`, +`service-secret-callers.json`, `privacyidea-key-custody.json`, +`mfa-state-diagnostic.json`, `realm-bootstrap-repair.json`; October14 +`legacy-lldap-retirement.json`, `platform-group-boundary.json`, +`lldap-group-maintenance.json`, `resolver-cutover.json` under the corresponding +`docs/evidence/YYYY-MM-DD-netkingdom-security/` directories. + +## Inventory source callers and retire remaining unsafe delivery paths + +```task +id: NK-WP-0049-T06 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04, NK-WP-0049-T05] +state_hub_task_id: "a5f50891-c5b2-513b-8670-e1915ee52015" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15. Enumerated all 87 current non-test shell/Python callers +in the declared bootstrap/k8s scope plus Make/console/delivery adapters. Repaired +streamed encrypted bundle publication and fail-closed bootstrap/lab paths; +retired unsafe delivery copiers, root prompts, registry patchers and stale +rollback recipes. The attended inventory records source dispositions and their +native-proof limits. T02 separately maps these to current live users/owners. + +Evidence: [caller inventory](../docs/evidence/2026-10-15-bootstrap-recovery/caller-source-inventory.json), +[attended procedures](../docs/attended-procedure-inventory.md) and the October15 +recovery evidence directory. No live production bootstrap or lab-init acceptance +is claimed. + +## Discover off-host coverage and recover the existing PI database + +```task +id: NK-WP-0049-T07 +status: done +priority: high +assignee: codex +state_hub_task_id: "2d7302a2-319a-5633-bf58-d51ccd25ebf6" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15–16. Bounded Storage Share/Scaleway inventories identified +existing database coverage and the missing full identity bundle. The operator +independently matched the backup recipient, then recovered the exact existing +PI dump: correct-key decryption, wrong-key refusal, isolated native PostgreSQL +restore/readback and cleanup passed (5 tokens, 2 resolvers, 2 realms). + +Evidence: October15 recovery `offsite-discovery-summary.json`, +`privacyidea-transfer-r1.json`, `privacyidea-database-drill-r1.json`, +`database-drill-review.json`. This database-only proof led to T08–T14. + +## Implement the full identity capture and archive recovery toolchain + +```task +id: NK-WP-0049-T08 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06, NK-WP-0049-T07] +state_hub_task_id: "317ca173-c784-5329-9810-5e3d300604b8" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Defined exact LLDAP/Authelia/KeyCape/privacyIDEA assets, +Deployment/PVC/reference bindings, original keys and snapshot consistency limits. +Implemented native SQLite/PG capture, streamed age sealing, strict data-bearing +manifest checks, provider readback, independent retrieval, bounded retention, +root runtime and attended archive verifier. All 56 focused checks passed, +including actual synthetic encrypted/native PostgreSQL recovery. + +Evidence: [profile](../tools/bootstrap-recovery/identity-backup-profile.json), +[implementation review](../docs/evidence/2026-10-16-identity-backup-implementation/review.json), +and the live evidence's tested ESO-default/host-binding corrections. Production +archive recovery is separately evidenced in T13. + +## Admit and verify the two scoped backup credential deliveries + +```task +id: NK-WP-0049-T09 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "4a47eb2a-7e42-5ae7-9df1-f5ede746eca1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Platform CCR-2026-0048/0049 are verified. The operator +approved folder-only provider-normalized publisher21/retention25 rights, including +re-sharing, in addition to the original rollout. Coding-agent denials precede KV +publication. Exact 900-second single-policy readers, wrong-SA/namespace/audience +rejection, metadata/sibling/old-escrow/token-create denials, ESO equality and +reader/session revocation passed. Operator passwords and age private keys are +not job credentials. + +Evidence: live `publisher-setup-verified.json`, `retention-setup-verified.json`, +`publisher-native-delivery-verified.json`, `retention-native-delivery-verified.json`; +approval decisions `40bfae40-6108-4e51-8613-073339f5345f` and +`5edd5203-fae7-461b-8775-5d22b7873971`; Platform CCR files. + +## Apply capture isolation and install the guarded node runtime + +```task +id: NK-WP-0049-T10 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T09] +state_hub_task_id: "0519444c-d559-5455-aa27-8c5dc8b832b0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Applied exact UID/resource-version/spec-guarded DNS +selector exclusions, preserving ordinary service matches. Capture refuses any +remaining helper allow policy. Installed immutable runtime sources bound to the +actual hostname, machine identity and cluster UID. Disabled-unit replacement +checked previous contents and retained rollback bytes. Health unit validation +passed. Activation remained gated until T13. + +Evidence: live `isolation-applied.json`, `capture-ready-plan.json`, +`installed-runtime-packet-r2.json`, `upgrade-disabled-runtime.py`. Actual complete +hardened-job execution is recorded in T14. + +## Connect recovery to Railiance bootstrap and reuse discovery + +```task +id: NK-WP-0049-T11 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "d69af493-4026-56a8-a526-c267d90dce18" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Added the Railiance bootstrap `identity-recovery` +dispatcher and independent-custody → isolated verification → layer/service-owner +handoff. Updated `capability.security.bootstrap-recovery`, linked bootstrap +sequencing and composed reuse-surface federation. Keyword discovery for identity +backup, restore, privacyIDEA and disaster recovery was verified. The operator +actually used this handoff in T13. No unattended production importer is claimed. + +Evidence: [ceremony](../docs/bootstrap-recovery-ceremony.md), owning capability +entry, `railiance-bootstrap/docs/identity-recovery.md`, bootstrap commit `d1dcfde` +and reuse-surface federation commit `662782e`. + +## Create and verify the first full off-host identity bundle + +```task +id: NK-WP-0049-T12 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T09, NK-WP-0049-T10] +state_hub_task_id: "decb415a-8012-521c-9dbe-d73c6ff0bbfb" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Captured original service keys/current data plus the +linked native PI database dump, sealed and published a unique Storage Share +artifact, then downloaded it and verified size/digest before publishing its index. +Helper and plaintext cleanup passed. Artifact: +`net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age` (109738344 bytes). + +Evidence: live `actual-capture.json`, `actual-offsite.json`; ciphertext SHA256 +`7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`. +No age private key was needed by the capture job. + +## Independently retrieve and recover the complete actual archive + +```task +id: NK-WP-0049-T13 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T11, NK-WP-0049-T12] +state_hub_task_id: "602d4921-cfac-5e5b-9993-4fbf67195c7d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Independently downloaded the exact first generation +through attended Backup-account custody, rehashed it locally and revoked the +session. The operator used the independently held age key through the bootstrap +handoff. Correct/wrong-key cases, all 36 manifest files/hashes, original RSA pairs, +SQLite integrity and isolated native PG16.14 restore/readback passed; plaintext +and containers were removed. No key or restored secret values reached the agent. + +Evidence: live `independent-owner-transfer.json`, `actual-full-archive-recovery.json`, +`actual-full-recovery-review.json`. Existing-user/MFA authentication and old audit +signatures are deliberately separate T16–T20 outcomes. + +## Activate and prove the complete recurring backup and retention job + +```task +id: NK-WP-0049-T14 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T10, NK-WP-0049-T13] +state_hub_task_id: "eaf0708f-b3b7-5531-8172-95edf30c3a19" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 after T13. Both daily backup/retention and hourly health +timers are enabled/active. The actual hardened systemd service passed retention +before/after a second capture/upload/download (Result=success, ExecMainStatus=0). +Both verified generations are retained, the independently recovered point is +pinned, and nothing was deleted. Helpers/plaintext were cleaned; failure markers +and reporting outbox are empty. Health check succeeded. + +Evidence: live `activation-result.json`, `activation-review.json`, +`recurring-job-review.json`. Cadence: daily 03:45 UTC plus up to 5 minutes jitter, +hourly health, 25-hour freshness bound. Second-provider/host-loss gaps go to T24; +this completed task is not a full-estate recovery claim. + +## Map current callers, owners and native acceptance gaps + +```task +id: NK-WP-0049-T02 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06] +state_hub_task_id: "479d6970-6516-50f5-9436-bb5b56d58aad" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +The source inventory and known legacy objects exist; a complete current-use +ledger is not yet accepted. Next action is read-only reconciliation of the 93 +entries in the latest October15 source inventory (the earlier snapshot had 87) against active Make/bootstrap/operator routes and owner evidence. + +**Done when:** each entry is identified as current, retired or owner-deferred, +with its owner, credential route, current consumer(s), native evidence or exact +missing proof, and next responsible task. Explicitly cover the historical +`sso/keycape-pi-token` and `mfa/privacyidea-trigger-admin` objects, lab init, +factor diagnostic delivery, LDAP group/provider boundary, resolver cutover and +root-output/isolation boundaries. Secret presence is not credential validity. +Send current native checks to T21 and historical revocation/rotation decisions to +T22. Do not reopen completed source repairs without a new finding. + +## Prepare the isolated full-service restore and acceptance packet + +```task +id: NK-WP-0049-T15 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28, NK-WP-0049-T29, NK-WP-0049-T30] +state_hub_task_id: "1d1eb903-a4b0-5bc4-a421-0b842d7f68ae" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Prepared draft scope moved to T27.** See +`docs/identity-service-restore-packet.md`: restore order, containment, safe evidence +and per-service positive/negative checks are drafted. Read-only current runtime +image digests were observed for all four services; correspondence to the selected +archive and independent image availability are not yet proved. + +**Next action:** admit a named disposable target/private route, verify and stage +matching images independently, obtain private existing-user/MFA test inputs and +review version-specific native commands with service owners. Incorporate T02's +ledger before submitting current-caller acceptance. + +2026-10-16 checkpoint: T28 completed the exact local image save/load/inspect +and T29 prepared and natively tested the bounded LLDAP stage. Its actual owner +run is T16 and can proceed independently of the remaining multi-service packet. +The other service adapters, matching archive/runtime lineage and private +existing-user/MFA inputs are still required; no blanket T15 completion is claimed. + +**Done when:** service owners accept the exact targets/procedure, existing-user +and MFA test identities/input custody are available without posting secrets, +outbound notification/provider writes are disabled, and every required new +credential or production effect has its own owner decision. The verifier deletes +its plaintext; it is not a production importer. This task prepares authority and +inputs for T16–T20, not an automatic production restore. + +## Prove restored LLDAP directory and existing-user authentication + +```task +id: NK-WP-0049-T16 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T29] +state_hub_task_id: "b64d4d6a-e851-58d1-9929-f03343147de0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom directory/User Engine owners. Restore the captured +original directory/configuration in the admitted isolated environment. + +**Done when:** user, group and membership identities are preserved; an independently +supplied existing-user credential authenticates; a wrong credential is refused; +provider writes/outbound effects stay confined; cleanup is verified. Native +fixtures from T05 and SQLite integrity from T13 do not satisfy this current-data +acceptance. Record only safe counts, identities and outcomes. + + +Completed 2026-10-16 at 18:37 UTC. The operator privately supplied the +independent age key and an existing backup-era account credential to the exact +local executor. All 36 archive hashes and the known ciphertext/source/target +bindings matched. Native existing-user LDAP bind passed; explicit invalid +credentials were rejected. The original seven users, 17 groups, 13 memberships +and the available attribute/schema rows were preserved across service startup, +authentication and graceful shutdown. The container had only loopback/no +external routes; pre-import isolation and container/tmpfs cleanup passed. +No production endpoint was contacted or secret exported to the agent. + +Evidence: `actual-isolated-lldap-recovery.json` and +`actual-isolated-lldap-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. This closes the actual +LLDAP stage independently of the remaining T15 packet. It does not prove +Authelia/KeyCape authentication, retained-token MFA or audit continuity. T17, +T18 and T19 retain their remaining adapter/input prerequisites. + +## Prove restored Authelia storage and OIDC continuity + +```task +id: NK-WP-0049-T17 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16] +blocking_reason: "LLDAP recovery T16 passed; await the exact isolated Authelia adapter/procedure and private authentication-flow inputs from T15." +state_hub_task_id: "b47f9975-d6d7-5bb8-93ce-886deb1dfa70" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: SSO/Authelia and directory owners. Restore the original storage, +encryption/session/signing material and configuration in isolation. + +**Done when:** native storage decryption succeeds, issuer/signing identity and +client configuration are preserved, and an isolated authentication flow has +positive/negative results using the restored directory. Disable outbound +notifications and verify cleanup. Archive integrity/RSA parsing alone are not +native Authelia acceptance. + +## Prove retained privacyIDEA token decryption and existing-token MFA + +```task +id: NK-WP-0049-T19 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T31] +blocking_reason: "LLDAP T16, token-material T31 and audit T20 passed; await the exact isolated MFA adapter and owner-selected retained-token/factor inputs." +state_hub_task_id: "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA and directory owners. Use the exact linked dump +and original enckey from the independently recovered generation. + +**Done when:** retained token material decrypts inside the isolated process, +a selected existing token completes a native MFA check, a wrong key/code is +refused, and cleanup is verified. Obtain any token/user input through attended +private custody; never emit token plaintext, seeds or credentials. Native database +row counts and disposable synthetic-token fixtures do not prove this outcome. + + +2026-10-16 refinement: native token-material readback is separately tracked in +T31 using the prepared T30 executor. T19 retains actual existing-token MFA and +wrong-code/wrong-key authentication refusal. Internal decryption or padding +success does not authenticate a user. No MFA code is needed for T20/T31; the +selected user's private factor input and exact isolated MFA adapter remain T19. + +## Prove historical and new privacyIDEA audit-signature continuity + +```task +id: NK-WP-0049-T20 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "375fa8f9-b8a5-5048-97a7-ec141aa7c45d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA audit owner. Use the original recovered audit +pair and linked database in the admitted isolated target. + +**Done when:** existing pre-backup audit signatures are verified natively, a new +isolated audit entry is signed and verified with the preserved identity, a wrong +key fails, and cleanup is recorded. Report any historical verification failure +for explicit owner disposition; do not regenerate keys to hide it. Matching RSA +pairs from T13 are a prerequisite, not audit-history verification. + + +Completed 2026-10-16 at 19:10 UTC using the actual independently retrieved +bundle and original audit identity on the fixed isolated local engine. All +279,209 stored rows were signed and verified; zero unsigned, invalid or legacy +signatures. A new isolated entry verified, and tampering/unrelated-public-key +checks were refused. Container/plaintext cleanup passed. Receipt and reviewed +source/ciphertext/target bindings: `actual-isolated-privacyidea-recovery.json` +and `actual-isolated-privacyidea-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. +Stored-row continuity is accepted; event completeness and existing-token MFA +are separate and are not claimed. + +## Prove restored KeyCape issuer, policy and consumer continuity + +```task +id: NK-WP-0049-T18 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T19, NK-WP-0049-T32, NK-WP-0049-T33] +blocking_reason: "Source and synthetic KeyCape lifecycle proof are delivered in T32; await exact owner-held recovery attempt preparation T33, selected consumer acceptance and retained-token MFA for the selected flow." +state_hub_task_id: "141dd773-c1fa-56c1-a852-bbe2372e5125" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: KeyCape and the selected current consumer owners. Restore the +original signing/configuration, registry, authentication policies and receipts. + +**Done when:** issuer/JWKS signing identity, registry/client configuration and +policy/receipt continuity are preserved; selected current consumers pass native +positive/negative authentication using the restored dependencies; and isolation +and cleanup hold. Confirm the actual dependency graph in T15. Do not route a +production consumer to the isolated issuer or mint new client grants implicitly. + +## Verify current caller and provider admission at their actual boundaries + +```task +id: NK-WP-0049-T21 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02] +blocking_reason: "Await the current-caller ledger and exact per-caller owner admission/test inputs; the backup credential grants do not admit unrelated callers." +state_hub_task_id: "77aa42be-7a39-5d93-8042-03d78b4094b4" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: each current caller's service/provider and credential owner. +Use T02's ledger to select the exact current procedures and required owner lanes. + +**Done when:** each current caller has scoped delivery and native positive/negative +acceptance or an explicit accepted retirement/disposition. Include dedicated +factor-diagnostic admission (do not borrow KeyCape's reader), deployed reserved +LDAP group denial, resolver/cutover input provenance and functional proof, and +bootstrap/root-output/isolation callers. Fixtures, an existing tty and historical +bootstrap receipts are not current authority. Propose exact write/cutover actions +before execution; record deferred actions separately rather than faking a pass. + +## Resolve historical credential and configuration-preserving rotation dispositions + +```task +id: NK-WP-0049-T22 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T21] +blocking_reason: "Await the caller/consumer ledger, current replacement-lane acceptance and explicit credential-owner dispositions; existing exposure-rotation deferral is unchanged." +state_hub_task_id: "3ea6bf00-a87f-58ea-bdce-328c13a03a55" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: Platform/custody and affected consumer owners. Review historical +personal-admin/trigger credential copies and unsafe predecessor paths against +known current consumers and rollback custody. + +**Done when:** every affected credential has an owner-accepted disposition: +verified revocation/replacement, continued bounded use with acceptance, or an +explicit linked deferral. Signing/client-secret changes require preservation and +native multi-consumer proof if actually approved. CUST-WP-0073-T05's founder +rotation deferral and decision `1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa` remain in force; +record their exact applicability rather than automatically rotating or treating +source retirement as provider revocation. + +## Provide retrieval that works when OpenBao and SSO are unavailable + +```task +id: NK-WP-0049-T23 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T25] +state_hub_task_id: "1ec537ee-dfee-5576-be36-a81bdba417d1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 at 18:02 UTC. The operator used independently held Backup +account access in the private prompt. The actual protected 109,738,344-byte +ciphertext was downloaded with unchanged ETag/size/SHA256, with no OpenBao/SSO +contact or provider writes by the retrieval path. The human-held age key matched +the registered recipient; wrong-key refusal, all 36 manifest hashes, SQLite +integrity, original key pairs and native isolated PostgreSQL 16.14 restore passed. +The database retained five token, two resolver and two realm rows. Disposable +container and temporary plaintext cleanup passed. The agent received no secret. + +Evidence: `actual-offline-transfer.json`, `actual-offline-recovery.json` and +`actual-offline-review.json` under +`docs/evidence/2026-10-16-identity-outage-recovery/`. The review rechecked the +local ciphertext digest and verifier source. This proves the independent path +without requiring a deliberate production outage. Service authentication, +retained-token decryption and historical audit verification remain T16–T20. +T26 separately records accepted guide publication. + +## Record owner disposition for second-provider and external monitoring gaps + +```task +id: NK-WP-0049-T24 +status: todo +priority: medium +assignee: codex +depends_on: [NK-WP-0049-T14] +state_hub_task_id: "474f5a78-a643-59c6-bcf9-fc4a908dfcb0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Next action:** record the current single-provider and host-local-health limits, +then obtain explicit owner scope decisions for a second encrypted provider copy, +external host-loss/freshness detection and recurring recovery-drill cadence. + +**Done when:** each gap has either an accepted bounded residual risk or a linked +live intake/workplan with owner and trigger. Existing daily RPO/25-hour health +settings remain the approved baseline. Scaleway full-identity publication and +an external watchdog are not implemented; do not add their grants/jobs implicitly. +This task triages the new insights instead of silently expanding NK49's required +implementation to an entire disaster-recovery programme. + +## Deliver and verify the offline retrieval adapter and recovery tools kit + +```task +id: NK-WP-0049-T25 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13] +state_hub_task_id: "1c5ea7a1-edf7-5072-b36b-8be7f827957a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. `retrieve-identity-offline.py` uses privately entered +independent Backup-account access or an exact read-capable identity-folder share. +It performs only fixed-provider HEAD/GET, binds the reviewed generation by strong +ETag/length/SHA256, refuses redirects/proxies/unreviewed scope and removes failed +downloads. No OpenBao/SSO, age key or standing agent credential is required. +`recovery-kit.py` builds a reproducible allowlisted ZIP containing the tools, +public profile, known-good ciphertext receipt and recovery guides, with file +checksums. Its publication path creates only three versioned guide/ZIP/checksum +objects and verifies readback without overwriting existing conflicting objects. +`run-offline-recovery.sh` provides the owner's two-hidden-prompt handoff. + +Evidence: `tests/test_identity_offline_recovery.py` and the bounded test/build +receipt in `docs/evidence/2026-10-16-identity-outage-recovery/`. The focused run +passed 65 tests including real disposable age/PostgreSQL fixtures. ZIP-contained +entry points import without sibling repositories. This is source/fixture proof, +not actual independent-provider retrieval (T23) or publication (T26). + +2026-10-16 correction: the first owner handoff stopped before its credential +prompt because Python text `r+` requires a seekable stream. Reproduced against a +real controlling PTY; replaced both prompts with the shared hidden-input helper, +refusing redirected input and echo fallback. Added real-terminal and both-CLI +regressions plus closed stage/HTTP-code diagnostics (no raw responses). The +focused rerun passed 36 tests. Evidence: `terminal-prompt-fix.json` in the outage +evidence directory. This source correction does not complete T23/T26. + +## Publish and verify the disaster recovery guide on Storage Share + +```task +id: NK-WP-0049-T26 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T25, NK-WP-0049-T27] +state_hub_task_id: "94d054fe-e5d8-5ddf-8e48-80714123d184" +``` + +**Accountable worker:** codex; operator holds provider access privately. + +Requested by the operator on 2026-10-16; decision +`fc3ef8db-0a33-41d5-a0ba-d13169c5f884` records the bounded scope. Guide source: +`docs/disaster-recovery-storage-share.md`. Document scope, independently held +provider/key requirements, exact known-good fallback, copy/download verification, +archive-check commands, service restore order, recurring schedule and remaining +coverage limits. Include the offline tools so failed Forgejo does not prevent +access to the recovery scripts; retain an independent copy and trusted digest. + +Completed 2026-10-16 at 18:01 UTC through the private independent-provider +owner handoff. All three objects were conditionally created and read back with +matching strong ETag, length and content; the recorded digests match a fresh +reproducible local build. No existing object or provider permission was changed. +The failed first attempt and terminal correction remain documented in T25. + +**Published location:** Storage Share account Backup, +`railiance-backups/net-kingdom-identity/`: + +- `net-kingdom-recovery-57d1940947aa25ff-START-HERE.md` +- `net-kingdom-recovery-57d1940947aa25ff.zip` +- `net-kingdom-recovery-57d1940947aa25ff.zip.sha256` + +**Trusted ZIP SHA256:** +`57d1940947aa25ff83d0f25ddf30090eb40595cccaab64225de882a2fd59ea2f`. +Evidence: `actual-offline-publication.json` and `actual-offline-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. The published guide is the +exact pre-drill revision; this acceptance record records the later successful +drill without implying an unperformed republication. Keep an independent copy +and trusted digest outside the failed service/provider dependency. + +## Draft the isolated service restore packet and observe candidate images + +```task +id: NK-WP-0049-T27 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13] +state_hub_task_id: "e273e803-bee7-5d90-bc51-ecc08c0c8eff" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. Draft in `docs/identity-service-restore-packet.md` names the +known recovered input, restore order, original key/data ownership, default-deny +containment, blocked production/provider/notification effects, cleanup and five +native acceptance lanes with positive/negative checks. Read-only metadata from +the pinned primary cluster resolved all four current service image digests, +including the separately observed privacyIDEA main container and LLDAP's mutable +source tag. Evidence: `docs/evidence/2026-10-16-identity-outage-recovery/image-observation.json`. + +This task extracts completed preparation from T15. Named target admission, +archive/runtime image-lineage matching and independent image availability, +private existing-user/MFA inputs and owner-reviewed native commands remain T15; +no service restore, production change or owner acceptance is claimed. + +## Stage and verify the five exact service images for local offline recovery + +```task +id: NK-WP-0049-T28 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T27] +state_hub_task_id: "4829b091-76d2-5b10-bdfc-032800190c0a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. All five pinned references (PostgreSQL, LLDAP, Authelia, +KeyCape, privacyIDEA) were inspected on the fixed local Linux Docker engine +`bnt-lap001`, ID `74f93783-6cef-43a8-a3c4-f62586cd3bc1`. Missing LLDAP and +privacyIDEA images were pulled only by their observed immutable digests. Saved a +private 347,521,536-byte image archive, loaded it and re-inspected every exact +reference. Evidence and archive SHA256/location: +`docs/evidence/2026-10-16-identity-outage-recovery/offline-service-images.json`. + +The local drill no longer requires the production registry. This is not off-host +image escrow or proof of historical mutable-tag/backup lineage; those limits +remain in T15. No service custody or age key was supplied to image caching. + +## Prepare and verify the bounded native LLDAP recovery executor + +```task +id: NK-WP-0049-T29 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28] +state_hub_task_id: "2f8c73b0-1cdd-5b22-99b6-017ccde4454b" +``` + +**Accountable worker:** codex; operator retains actual private recovery inputs. + +Completed 2026-10-16. `isolated-lldap.py` and `run-isolated-lldap.sh` provide the +exact owner-run stage in `docs/identity-service-restore-packet.md`: fixed local +engine/images, no remote Docker endpoint, original key/seed/JWT/directory data, +Linux-tmpfs decryption, memory/stdin-only private inputs, network-none/read-only +containers, isolation inspection before import, actual existing-user bind, +explicit invalid-credential denial, stable directory rows and cleanup checks. +Missing original server keys are refused; reset/replacement/notification paths +are disabled. No live Kubernetes/OpenBao/SSO path or provider grant is used. + +Evidence: `tests/test_isolated_lldap_recovery.py` exercises the actual pinned +image, disposable retained-account directory and a full synthetic encrypted +bundle through the same native executor. The private real-bundle run and its +acceptance remain T16; fixture success is not actual user/MFA/audit recovery. +See `isolated-lldap-preparation.json` in the October16 outage evidence directory +for exact test/source/target provenance and limitations. + +## Prepare the bounded native privacyIDEA token-material and audit executor + +```task +id: NK-WP-0049-T30 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T28] +state_hub_task_id: "6e4a43db-9be2-5662-bdbf-1595fce03052" +``` + +**Accountable worker:** codex; operator retains private recovery inputs. + +Completed 2026-10-16. `isolated-privacyidea.py` and its owner launcher use the +fixed local Docker target and exact cached PostgreSQL/privacyIDEA3.12.2 images. +The linked dump, original enckey/audit pair and required secret fields are +restored only into a loopback-only, nonroot, read-only, capability-free, +no-host-mount/port, tmpfs-backed environment with inspected pre-import isolation. +Decrypted host staging is tmpfs; normal cleanup removes all private data and +owned containers, with a bounded holding lifetime if the parent is interrupted. + +The native provider decrypts token-key material internally, checks every stored +audit row, adds one isolated signed entry and checks wrong-public-key/tampering +negatives. Original policy for legacy signature verification is retained only +from literal archived configuration; archived Python is never executed. Invalid +or unsigned history remains reported, not repaired or sampled away. Native +material readback is not existing-token MFA or proof of event completeness. + +Evidence: `tests/test_isolated_privacyidea_recovery.py` and +`isolated-privacyidea-preparation.json` in the October16 outage evidence folder. +Synthetic pinned-image tests exercise valid/tampered/unsigned history, malformed +keys, encrypted archive to native restore, isolation and cleanup. Real original +material/audit acceptance remains T31/T20; actual MFA remains T19. + +## Verify retained privacyIDEA token material inside the isolated provider + +```task +id: NK-WP-0049-T31 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "26383841-8076-5c53-bbd1-9db64e32544a" +``` + +**Accountable worker:** codex; operator supplies only the independently held age +key in the hidden helper. This task extracts actual material-readback scope from +T19, preserving T19's existing-token MFA acceptance gate and historical identity. + +Completed 2026-10-16 at 19:10 UTC in the same actual run as T20. All five +retained token materials were decrypted internally with the original enckey; +an unrelated key could not reproduce any of the five. All 36 manifest hashes, +exact executor/ciphertext/target bindings, isolation and cleanup passed. Safe +receipts are the `actual-isolated-privacyidea-{recovery,review}.json` files +referenced under T20. No retained-factor authentication is claimed. +**Done when:** exact ciphertext/source/target/manifest bindings pass; the native +provider reads every nonempty encrypted token-key field using the original +enckey without exporting material; an unrelated key cannot reproduce that +material; aggregate counts and container/plaintext cleanup are recorded. + +Only bounded internal readback is accepted here. Padding/readback success does +not prove the recovered secret authenticates a retained factor; actual positive +MFA and wrong-key/wrong-code authentication refusal remain T19. No token seed, +plaintext, serial or user record belongs in the receipt, Git, State Hub or chat. + +## Deliver isolated KeyCape restore source and synthetic lifecycle proof + +```task +id: NK-WP-0049-T32 +status: done +priority: high +assignee: codex +state_hub_task_id: "cd78dbb7-a8f2-5754-8788-6eb1b7d97741" +``` + +Completed 2026-10-16. This extracts bounded source/fixture delivery from T18; +T18 retains actual original archive, issuer and selected consumer acceptance. +The adapter reuses the existing transfer/archive/custody contracts, binds the +fixed local daemon and cached images, restores private state only to temporary +memory, verifies original issuer/TLS/signing/configuration/policy bytes and runs +the original native service-client checker with wrong-secret/excess-scope denial. +Durable pre-import obligations and exact parent pidfd/session quiescence precede +loss/deadline cleanup. Daemon response uncertainty remains uncertainty after +resource absence; it never authorizes recovery success or replay. + +Frozen R6 fixes a demonstrated image-declared anonymous-volume incompatibility +using bounded helper-only tmpfs, preserving anonymous disk-volume refusal. Safe +phase markers carry no private diagnostics. Independently passed 72 focused +checks, then actual pinned-image synthetic positive, hard-parent-loss, deadline +and nonzero-after-accept cases. Independent fixed-daemon inventories and host +mount-namespace checks prove all exact resources and plaintext absent. Reaper +outcomes are retained; initial sandbox receipt lookup failure is preserved and +superseded by device-bound host verification. R1–R5 failures remain retained. + +Evidence: Custodian docs/changes/netkingdom-target-2026-10-16/ +identity-restore-adapter-next/revisions/r6/, actual-fixture-r6-all.json and +coordinator-r6-all-review.json. Exact source/dependency hashes and candidate +manifest bind the proof. This uses generated test keys only; it proves neither +actual owner-held recovery, human MFA, downstream reconnect nor native authority. + +Publication preparation R7 preserves every R6 recovery adapter byte and digest. +The normal scanner flagged eight public source-file SHA-256 values in the R6 +manifest. Explicit sha256-qualified checksums resolve those false positives; +the fixture reader strictly validates their type/shape before checking the same +bytes. R7 passes 73 focused checks including malformed/untyped digest refusal. +The frozen R6 actual four-case proof remains the runtime evidence; no repeated +native outcome is claimed for publication encoding. Original scanner refusal is +retained, and scanner policy/exemptions are unchanged. + +## Prepare the exact owner-held KeyCape recovery attempt + +```task +id: NK-WP-0049-T33 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32, NK-WP-0049-T34, NK-WP-0049-T35, NK-WP-0049-T36] +blocking_reason: "Source custody/preflight preparation is evidenced in T34; await original TLS/trust recovery disposition T35 and selected original registration/private-admission metadata T36 before final reviewed command and existing owner process." +state_hub_task_id: "56c8d469-7a10-5d50-a30e-95cbf3cd4756" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and selected consumer owners. +This umbrella retains final attempt readiness. Completed custody/preflight source +preparation is extracted into T34; T35 resolves original TLS/trust recovery and +T36 prepares the selected original registration and private admission. This split +records distinct outcomes without counting source preparation as recovery. + +After those deliverables, assemble the exact existing six-argument attended +command and admission digest, bind the integrated source/dependency revision and +fixed local target, and record execution deadline, safe receipt location, abort, +rollback and independent receipt verification through the existing owner process. +Keep private manifest derivation inside custody and original TLS/client/key inputs +in the owner's own terminal; the current null fields must refuse execution. +Existing session authorization is retained within scope; this record does not +supply missing owner assent or approve any actual recovery attempt. + +**Done when:** reviewed executable command and complete metadata-only/private +admission packet are ready for the existing attended custody path; prerequisites +and independent receipt verification are explicit. T18 still owns actual +execution, original consumer continuity and acceptance. T19 retains retained-factor +MFA. This task neither authorizes a production consumer redirect nor creates a +new client grant. + +## Deliver attended custody, metadata preflight and private manifest preparation source + +```task +id: NK-WP-0049-T34 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32] +state_hub_task_id: "821b3a56-6f36-5812-abc9-5a00e37cb2e7" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian source review. +Completed 2026-10-17 as source preparation. Existing attended custody entry points +now have a reviewed candidate sealed anonymous descriptor mode: hidden prompt, +actual public-recipient verification, strict owned/private/full-seal descriptor +admission, non-inheritable returned duplicate and explicit descriptor passing. +The existing file mode stays compatible, with its original hard-loss limitation; +no improved file-mode cleanup is claimed. Exact parent-loss tests prove descriptor +lifetime without signalling inherited user shell groups. An admitted child retains +its descriptor until it exits; parent loss is not child revocation. + +The candidate checks bounded, duplicate-free public JSON, exact admission digest, +transfer/archive and selected service bindings, typed hashes for all 17 invoked +local source/config dependencies and required Python imports before requesting a +key. TLS and ciphertext preparation uses file metadata only. Legacy explicit +manifest digests remain supported; versioned ciphertext-derived binding computes +the canonical digest privately only after exact reviewed ciphertext, authenticated +age decryption and full existing archive validation. The derived private digest +never enters safe receipts/checkpoints and grants no new consumer authority. + +The coordinator independently passed 111 focused checks. The existing custody +regression suite passed 94 checks; 61 real-SOPS tests skipped because that trusted +runtime is unavailable, so that compatibility coverage remains unverified. Tests +use generated keys/archive material only, including actual age cryptography, +synthetic hidden-prompt and exact parent-loss processes. Manifest-builder tests +mock Docker/issuer behavior and confer no new native proof. Frozen R6/R7 proof, +intermediate test failures and scanner history remain retained. + +Bounded public image readback separately establishes the cached original image's +13670142-byte `/keycape` executable as +`sha256:cd89121393e1465aa76009763602a5b8c75f9dddb5679aea6242623f135b51b4`. +This is executable identity metadata, not recovery or custody acceptance. + +Evidence: Custodian `docs/changes/netkingdom-target-2026-10-16/recovery-attempt-r1/` +(`candidate.patch`, `review.json`, source closure, attempt/admission metadata and +`public-verifier-image-readback.json`). Canonical integration/publication and +projection receipts must be recorded separately when performed; this completed +source-preparation record does not invent them. T33 remains open for complete +attempt readiness; actual recovery/consumer acceptance remains T18 and MFA T19. + +## Establish original KeyCape TLS and trust recovery ownership for outage use + +```task +id: NK-WP-0049-T35 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "1bfd1703-589f-5511-bad5-812d860e4a71" +``` + +**Accountable worker:** NetKingdom codex, coordinating with the source owner of +Ingress/cert-manager/Traefik and the original TLS custody/provider boundary. +**Next action:** identify and record that actual owner's existing recovery path, +then obtain its metadata/disposition through the ordinary owner process. A missing +exact credential-routing catalog match is not evidence that no owner exists. + +Current source declares `kc.coulomb.social`, `sso/kc-tls`, cert-manager +`ClusterIssuer/letsencrypt-prod` and Traefik TLS termination before KeyCape 8080. +The identity backup profile excludes `kc-tls`; the verified archive therefore +establishes no independent recovery of that TLS identity/trust. Determine whether +the exact original certificate/key/trust is independently recoverable during an +issuer/cluster outage, or whether a documented reissue path is acceptable for the +selected continuity claim. Do not read or place the TLS key in work records, use +a fresh self-signed trust substitute, mutate production or claim owner assent. + +**Done when:** named owner/provider, independent outage prerequisites, original +public identity/certificate/trust hashes or accepted reissue disposition, private +custody entry point and verification/abort limits are explicit and reviewed. +Record any unavailable recovery capability as a live owner work record and bind +its dependency/unblock condition; a prose-only gap or untested archive is not +completion. This delivers preparation/disposition, not actual TLS recovery. + +2026-10-17 owner handoff progress: the four reviewed Railiance Cluster source +additions are present, including `RCLUSTER-WP-0018` and public-only TLS metadata +preparation. They are not published. The normal publication path stopped at the +existing historical identifier guard (`ensure_missing_work_record_identifiers`, +execute=False): 15 bare task-label findings and five collisions. A separately +retained read-only allocator preview records those findings; the original failed +publication stderr was not retained and is not reconstructed. No Cluster Hub +workplan/task existence or projection, actual certificate/key custody, reissue +assent or native TLS acceptance is claimed. The source record and next owner +publication action remain live; do not bypass the historical identity guard. +Evidence: Custodian October17 `cluster-integration.json`, `coordinator-checkpoint.json` +and October16 `cluster-historical-publication-r1/actual-source-allocator-preview.json`. + +## Prepare selected original service registration and private admission bindings + +```task +id: NK-WP-0049-T36 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "8b72334b-fc27-5707-a189-bad345eaf3bc" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and the selected existing +service consumer's owner. **Next action:** identify that owner and the exact +original registration's non-secret selector metadata using existing source/owner +evidence; preserve independent private custody and never retrieve a client secret. + +Bind reviewed ciphertext `7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`, +its independently verified transfer, source/image/executable closure and an +explicit versioned manifest-binding mode. For the original service registration, +record client identifier, secret environment name, audience, granted scope, +subject, tenant, required roles and denied scope without values or new grants. +Describe the native service-client dependency graph and distinguish unexercised +LLDAP/Authelia/privacyIDEA/downstream flows. Keep private manifest material inside +the existing custody process, never in Git, safe receipts, State Hub or chat. + +**Done when:** the selected existing service owner and exact non-secret registration +bindings are independently established, the private admission builder validates +positive/negative source/archive/selector cases, and its metadata is ready to +combine with T35's original TLS/trust disposition under T33. This task may prepare +registration metadata while T35 proceeds independently; it does not finalize the +whole admission, perform actual recovery, redirect a consumer or confer assent. + +2026-10-17 owner handoff progress: Secrets Engine source workplan +`SECRETS-WP-0015` and bounded public selector/preflight source were published as +`c59bbf568c0be8a72ac593508f48c9b1f61ec4c1`; the central primary/railiance01 +reconciliation receipt reports the same expected/derived commit, four owner task +bindings and two T04 dependency edges, with no unresolved edges. T01/T02 source +preparation is done, T03 exact outage-compatible consumer proof/custody planning +is todo, and T04 actual admitted consumer result waits on T03 and NK-WP-0049-T33. +This publishes an owner handoff, not exact archived registration validation, +current native assent, an OpenBao read, a new grant or consumer continuity. +T36 therefore remains progress; T18/T19 and final native gates remain open. +Evidence: Custodian October17 `secrets-engine-projection.json` and October16 +`recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote +readback is recorded separately when performed. + +2026-10-17 source checkpoint refinement: the completed exact-one original +selector guard and its bounded refusal/unique-selector proof are extracted into +T38. T36 retains exact archive-to-selector binding, current actual service-owner +recovery assent and outage-compatible private admission/consumer preparation. +The current eight-field source-selector correspondence is evidenced separately; +it does not complete those remaining obligations or any T18/T19 native gate. +T33 continues to require the complete reviewed TLS/custody/admission packet. +This extraction records one source outcome rather than counting it again as +original registration validation or consumer continuity. + +## Verify actual SOPS compatibility and sealed-descriptor read/write custody + +```task +id: NK-WP-0049-T37 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "3403e266-d63b-5ce1-b891-3bfeac93d28c" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian fixture review. +Completed 2026-10-17 as generated-fixture compatibility proof. The coordinator +ran the actual reviewed SOPS 3.13.3 binary in a network/host-custody-isolated +namespace: all 65 tests passed in 14.85 seconds, including the 61 real-SOPS cases +previously skipped in T34 and four new actual sealed-FD cases. The latter cover +correct-key descriptor-only decryption, wrong-recipient refusal and descriptor-only +edit/rotation through the real Make entry points. Generated custody key files +were removed before these FD-only invocations; explicit descriptor passing, +private output modes, declared encryption-policy preservation, suppressed synthetic plaintext +and operation cleanup were checked. + +This is a dated successor to T34's historical 94-pass/61-skip record, which stays +unchanged. The prior skip is not rewritten as an earlier pass. Binary digest +`sha256:e5bec3346a873ae91d871550f3e698c1aad962aff462a080e40f25fde17fef6b` +matched the official release asset/checksum; Sigstore signature verification was +not performed. SOPS was not installed systemwide or admitted for production +runtime. Host custody was not mounted, network routes were absent, diagnostics +were suppressed and namespace teardown completed. All material was generated; +no original owner key/archive, private manifest, production credential, native +service continuity or owner assent was exercised. + +Evidence: Custodian +`docs/changes/netkingdom-target-2026-10-17/sops-real-regressions.json`, +`sops-source-tool.json` and `sops-fd-r2/` (exact test patch/manifest). The focused +custody/source checks and frozen R6/R7 native fixture evidence remain separate. +T33 attempt readiness, T18 actual recovery/consumer acceptance, T19 retained MFA, +T35 TLS/trust disposition and T36 original registration/private admission remain +open under their existing owner boundaries. + +## Deliver exact-one original selector guard and bounded source refusal proof + +```task +id: NK-WP-0049-T38 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +``` + +Completed 2026-10-17 as source preparation, independently reviewed by the +coordinating Custodian agent. The adapter now requires exactly one selected +registration in the already-restored archive configuration before further runtime +environment reads, signer-key parsing or native checker invocation. Absent, +empty, identical-duplicate and conflicting-duplicate selectors refuse before +those later inputs; the existing unique-selector mocked native path still passes. +Current KeyCape Go configuration also rejects duplicate IDs; this makes the +adapter's own boundary explicit and establishes no native duplicate exploit. +The guard cannot run before archive decryption or the original key prompt. + +The 39 adapter checks passed, including four added early-refusal regressions. +Running those four cases against the retained original adapter failed the new +refusal contract as expected. The broader 77-check source run retained 76 passes +and one stale fixture-proposal source-hash refusal. Only the two affected hashes +and scope of that unexecuted/unapproved successor proposal were then refreshed; +all four affected fixture-plan checks passed. The original manifest preimage and +failure receipt remain retained, and frozen actual R6 runtime receipts were not +changed or claimed as proof of this successor. No broader native rerun occurred. + +Evidence: Custodian +`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`: +`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages, +`original-behavior-regression.txt` and `focused-regressions.stderr.txt`. +The later task extraction and exact workplan successor bytes are in +`refinement-r2/`; the original source-proof packet remains immutable. +Canonical owner publication, allocator-assigned Hub UUID and projection must be +recorded separately through the normal owner process; none is claimed here. + +This completes only the source guard/refusal deliverable extracted from T36. +T35 original TLS public provenance/private custody or accepted reissue, T36 exact +archive binding/current owner assent/consumer custody preparation, T33 complete +attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor +MFA remain open. No actual archive, private key, Secret object, token exchange, +OpenBao login, rotation, production action or owner assent was exercised. + +## Accept remaining recovery and caller evidence and close the G08 handoff + +```task +id: NK-WP-0049-T03 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T16, NK-WP-0049-T17, NK-WP-0049-T18, NK-WP-0049-T19, NK-WP-0049-T20, NK-WP-0049-T21, NK-WP-0049-T22, NK-WP-0049-T23, NK-WP-0049-T24, NK-WP-0049-T26] +blocking_reason: "Await the separately tracked native service proofs, current/legacy caller dispositions and residual-scope decisions; archive recovery, backup activation, independent outage retrieval and guide publication are complete." +state_hub_task_id: "d68cd4d3-1ba3-530e-88f9-26ebb8dd6eac" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom, Platform and affected service owners, with Custodian +G08 receiving the final evidence. The completed archive/job milestones remain +accepted independently of this final gate. + +**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted +handoff outcomes; service authentication/token/audit proof and current/legacy +caller dispositions are accepted; the source workplan and projected tasks agree; +and G08 has an exact evidence/handoff record. Record actionable residuals as live +work records before workplan closure. Preserve historical IDs and receipts; do +not call a deferred rotation or an untested full-estate restore complete. + +## Evidence locations and refinement history + +“Live” above means `docs/evidence/2026-10-16-identity-backup-live/` in NetKingdom. +Implementation preparation is in the October16 implementation directory; earlier +backup discovery/database recovery is in `docs/evidence/2026-10-15-bootstrap-recovery/`. +The source-repair receipts explicitly labelled Custodian belong to that owning +repository. Use the [recovery ceremony](../docs/bootstrap-recovery-ceremony.md) +for exact procedure and approval history. No secret values belong in task evidence. + +Refinement rule: substantial work and newly understood remaining scope must be +visible in task blocks at a checkpoint, not only in progress prose. This replan +preserves T01–T03 identity and original evidence while making the completed +milestones and each remaining acceptance gate separately manageable. + +Managed identifier assignment also consumed a preexisting staged generated brief; +the follow-up commit restores its prior published baseline while preserving the +operator's working brief and original staged version. This is a projection-tool +side effect, not new recovery evidence. + + +R7 source publication and task bindings verified: +`5fcd5952add1c0167116094298a1d5feaa60cf30` is the observed published source. +All eight canonical additions match the reviewed bytes; all 33 task statuses +match the actual hub projection, including T32 done and T33 todo. Original +staged/working brief content is preserved. Normal synchronization has zero +failures/automation errors; existing warnings and scanner false-positive history +remain retained. Custodian identity-restore-adapter-next/canonical-r7-integration.json +binds source/projection/native-fixture evidence separately. T18 remains waiting +for the actual owner-held attempt and selected consumer acceptance. + + +2026-10-17 source/attempt refinement: T34 records completed attended custody, +preflight/private-manifest source preparation and its bounded tests; T35 and T36 +make original TLS recovery ownership and selected original admission metadata live +work. T33 retains final attempt readiness and its original Hub UUID. This adds no +actual recovery, MFA, native authority or owner assent. Source task counts above +refer to this file; projection has not been claimed for this proposed refinement. + +2026-10-17 verified source follow-through: source commit `4f65e41` passed normal +local scanning and 111 canonical focused checks. The initial T34 source-only +preparation now has an exact integrated source revision; existing real-SOPS +compatibility remains partly skipped and actual owner-held execution remains T18. + +T35/T36 source preparation is underway, with 17 pinned public-source references. +railiance-cluster owns the ingress/cert-manager/cluster-backup substrate; the +inspected same-host encrypted backup source establishes no independent original +kc-tls/trust recovery or accepted reissue. Draft owner questions remain unsent; +no private TLS input was requested. The historically deployed +secrets-engine-openbao registration is a defensible proposed consumer: its +7 October issuer and 10 October consumer proofs predate the reviewed archive. +The exact selector proposal is retained without current assent or private archive +validation. No token exchange, OpenBao login, client secret retrieval, new grant +or production redirect occurred. Keep incomplete admission refused before custody. +Custodian evidence: recovery-attempt-r1/t35-t36-source-next; final source/projection +review: resume-integration-r1/publication-verification.json. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.preimage.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.preimage.md new file mode 100644 index 00000000..e14d24bd --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/NK-WP-0049.preimage.md @@ -0,0 +1,1271 @@ +--- +id: NK-WP-0049 +type: workplan +title: "Remove bootstrap secret output and verify separated recovery custody" +domain: infotech +repo: net-kingdom +status: active +owner: codex +topic_slug: netkingdom +created: "2026-10-12" +updated: "2026-10-17" +flavor: implementation +depends_on: [] +state_hub_workstream_id: "17d315f0-829e-57c7-85cc-3a7914152804" +--- + +Native owner work for CUST-WP-0080 G08. This workplan remains active until the +remaining caller, service-recovery and custody acceptance gates are satisfied. +NK-WP-0045 covers the non-secret root-grant record. Founder-deferred exposure +rotation remains in CUST-WP-0073-T05; this plan does not silently reopen it. + +**Replanned 2026-10-16 at the operator's request:** substantial completed work is +now represented by completed tasks, and remaining work has separate deliverables, +dependencies and acceptance criteria. T01–T03 retain their historical IDs and Hub +UUIDs. Completed parts of the old T02/T03 umbrellas are extracted into T04–T14; +T02 now covers the current-caller ledger and T03 retains final owner acceptance. +These are retrospective task records of evidenced work, not additional delivery +or newly granted authority. The earlier dated narrative remains in Git at +`cc2dd01`; its evidence references are carried into the tasks below. + +**Current position, source refinement 2026-10-17:** 25 tasks done; 4 in +progress; 1 ready to start (`todo`); 7 waiting on explicit prerequisites. These are task counts, not an effort-based +completion percentage. Assignees are also written in task descriptions because +the current Forge projector does not populate the dedicated Hub assignee field. The outage-retrieval tool and restore-packet draft are now prepared; +independent outage retrieval and Storage Share publication are accepted; +service admission remains an explicit gate. + +**Next actions:** finish the read-only caller ledger (T02); admit the drafted +isolated restore packet (T15) and record residual-scope handoffs (T24). +Independent outage retrieval (T23) and guide publication (T26) are done. After owner admission, execute the individual native service and +caller checks. A task's owner is accountable for the result; another repository's +approval or credential grant still requires its own owner path. + +**Closure:** T03 assembles owner acceptance after its named dependencies pass. +Passing archive recovery does not prove existing-user authentication, retained +MFA-token decryption, historical audit signatures or current caller admission. +The verified backup job stays active while those separate tasks are completed. + +## Remove secret-bearing output and ambient root discovery + +```task +id: NK-WP-0049-T01 +status: done +priority: high +assignee: codex +state_hub_task_id: "d7ca8d5f-c5ff-5cba-bd25-038cb53ffe4e" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +2026-10-12: regression reproduced emergency/reprint root export, generation +prefix disclosure, permissive file modes, dry-run side effects and unattended +entry. Replaced emergency export with a non-secret guide (legacy secret-input +arguments refused), suppressed generation prefixes/tracing and set private +permissions. Bootstrap requires the registered public recipient and an attended +terminal; never generates/discovers a permanent private key. Encrypted resume +requires an explicit matching temporary custody key before cluster activity. +Dry-run is a non-mutating plan. The live cluster/apply path was not executed. + +A fresh uniquely named encrypted ops bundle follows apply; old delivery flags +cannot skip current acknowledgment. New acknowledgment state binds its SHA256 +and timestamp. Declining stops before cleanup/completion. This is an operator +statement, not an independent restore receipt. Historical fields remain unchanged. +Make/help/status/console and current credential guidance reflect that distinction. +Evidence and exact source manifest: Custodian +`docs/evidence/2026-10-12-netkingdom-security/bootstrap-handoff.json`. + +## Harden custody, SOPS and rotation source entry points + +```task +id: NK-WP-0049-T04 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T01] +state_hub_task_id: "04c4e8be-5bd8-5d5c-99b1-79d8ae758462" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-12–13. Public-recipient-only encryption, explicit temporary +custody, private no-overwrite output, sanitized diagnostics, stdin-only secret +transport and failed-operation cleanup replace ambient-key and output paths. +SOPS read/edit/data-key rotation preserve recipient/MAC/source-version guards; +component rotations preserve unrelated fields and retain recovery candidates. +This records source and disposable-native proof, not live rotation or revocation. + +Evidence: Custodian `docs/evidence/2026-10-12-netkingdom-security/` receipts +`custody-entrypoints.json`, `sops-make-entrypoints.json`, `rotation-output.json`, +and `admin-bootstrap.json`; October13 `sops-write-callers.json`. + +## Repair component, diagnostic, LDAP and resolver callers + +```task +id: NK-WP-0049-T05 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04] +state_hub_task_id: "e8e38f42-609e-5c07-a8e6-e73c8eb4ae95" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-13–14. Repaired KeyCape configuration and component Secret +publication, original privacyIDEA key export/restore transport, scoped MFA +counts, LDAP group maintenance and configuration-preserving resolver cutover. +Retired unsafe personal-token mint/refresh and direct LDAP lifecycle shortcuts. +Disposable native PI/LLDAP tests and source regressions passed; estate provider +admission, historical credential validity and service authentication remain T21/T22. + +Evidence: Custodian October13 `keycape-caller-reconciliation.json`, +`service-secret-callers.json`, `privacyidea-key-custody.json`, +`mfa-state-diagnostic.json`, `realm-bootstrap-repair.json`; October14 +`legacy-lldap-retirement.json`, `platform-group-boundary.json`, +`lldap-group-maintenance.json`, `resolver-cutover.json` under the corresponding +`docs/evidence/YYYY-MM-DD-netkingdom-security/` directories. + +## Inventory source callers and retire remaining unsafe delivery paths + +```task +id: NK-WP-0049-T06 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T04, NK-WP-0049-T05] +state_hub_task_id: "a5f50891-c5b2-513b-8670-e1915ee52015" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15. Enumerated all 87 current non-test shell/Python callers +in the declared bootstrap/k8s scope plus Make/console/delivery adapters. Repaired +streamed encrypted bundle publication and fail-closed bootstrap/lab paths; +retired unsafe delivery copiers, root prompts, registry patchers and stale +rollback recipes. The attended inventory records source dispositions and their +native-proof limits. T02 separately maps these to current live users/owners. + +Evidence: [caller inventory](../docs/evidence/2026-10-15-bootstrap-recovery/caller-source-inventory.json), +[attended procedures](../docs/attended-procedure-inventory.md) and the October15 +recovery evidence directory. No live production bootstrap or lab-init acceptance +is claimed. + +## Discover off-host coverage and recover the existing PI database + +```task +id: NK-WP-0049-T07 +status: done +priority: high +assignee: codex +state_hub_task_id: "2d7302a2-319a-5633-bf58-d51ccd25ebf6" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-15–16. Bounded Storage Share/Scaleway inventories identified +existing database coverage and the missing full identity bundle. The operator +independently matched the backup recipient, then recovered the exact existing +PI dump: correct-key decryption, wrong-key refusal, isolated native PostgreSQL +restore/readback and cleanup passed (5 tokens, 2 resolvers, 2 realms). + +Evidence: October15 recovery `offsite-discovery-summary.json`, +`privacyidea-transfer-r1.json`, `privacyidea-database-drill-r1.json`, +`database-drill-review.json`. This database-only proof led to T08–T14. + +## Implement the full identity capture and archive recovery toolchain + +```task +id: NK-WP-0049-T08 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06, NK-WP-0049-T07] +state_hub_task_id: "317ca173-c784-5329-9810-5e3d300604b8" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Defined exact LLDAP/Authelia/KeyCape/privacyIDEA assets, +Deployment/PVC/reference bindings, original keys and snapshot consistency limits. +Implemented native SQLite/PG capture, streamed age sealing, strict data-bearing +manifest checks, provider readback, independent retrieval, bounded retention, +root runtime and attended archive verifier. All 56 focused checks passed, +including actual synthetic encrypted/native PostgreSQL recovery. + +Evidence: [profile](../tools/bootstrap-recovery/identity-backup-profile.json), +[implementation review](../docs/evidence/2026-10-16-identity-backup-implementation/review.json), +and the live evidence's tested ESO-default/host-binding corrections. Production +archive recovery is separately evidenced in T13. + +## Admit and verify the two scoped backup credential deliveries + +```task +id: NK-WP-0049-T09 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "4a47eb2a-7e42-5ae7-9df1-f5ede746eca1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Platform CCR-2026-0048/0049 are verified. The operator +approved folder-only provider-normalized publisher21/retention25 rights, including +re-sharing, in addition to the original rollout. Coding-agent denials precede KV +publication. Exact 900-second single-policy readers, wrong-SA/namespace/audience +rejection, metadata/sibling/old-escrow/token-create denials, ESO equality and +reader/session revocation passed. Operator passwords and age private keys are +not job credentials. + +Evidence: live `publisher-setup-verified.json`, `retention-setup-verified.json`, +`publisher-native-delivery-verified.json`, `retention-native-delivery-verified.json`; +approval decisions `40bfae40-6108-4e51-8613-073339f5345f` and +`5edd5203-fae7-461b-8775-5d22b7873971`; Platform CCR files. + +## Apply capture isolation and install the guarded node runtime + +```task +id: NK-WP-0049-T10 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T09] +state_hub_task_id: "0519444c-d559-5455-aa27-8c5dc8b832b0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Applied exact UID/resource-version/spec-guarded DNS +selector exclusions, preserving ordinary service matches. Capture refuses any +remaining helper allow policy. Installed immutable runtime sources bound to the +actual hostname, machine identity and cluster UID. Disabled-unit replacement +checked previous contents and retained rollback bytes. Health unit validation +passed. Activation remained gated until T13. + +Evidence: live `isolation-applied.json`, `capture-ready-plan.json`, +`installed-runtime-packet-r2.json`, `upgrade-disabled-runtime.py`. Actual complete +hardened-job execution is recorded in T14. + +## Connect recovery to Railiance bootstrap and reuse discovery + +```task +id: NK-WP-0049-T11 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08] +state_hub_task_id: "d69af493-4026-56a8-a526-c267d90dce18" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Added the Railiance bootstrap `identity-recovery` +dispatcher and independent-custody → isolated verification → layer/service-owner +handoff. Updated `capability.security.bootstrap-recovery`, linked bootstrap +sequencing and composed reuse-surface federation. Keyword discovery for identity +backup, restore, privacyIDEA and disaster recovery was verified. The operator +actually used this handoff in T13. No unattended production importer is claimed. + +Evidence: [ceremony](../docs/bootstrap-recovery-ceremony.md), owning capability +entry, `railiance-bootstrap/docs/identity-recovery.md`, bootstrap commit `d1dcfde` +and reuse-surface federation commit `662782e`. + +## Create and verify the first full off-host identity bundle + +```task +id: NK-WP-0049-T12 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T09, NK-WP-0049-T10] +state_hub_task_id: "decb415a-8012-521c-9dbe-d73c6ff0bbfb" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Captured original service keys/current data plus the +linked native PI database dump, sealed and published a unique Storage Share +artifact, then downloaded it and verified size/digest before publishing its index. +Helper and plaintext cleanup passed. Artifact: +`net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age` (109738344 bytes). + +Evidence: live `actual-capture.json`, `actual-offsite.json`; ciphertext SHA256 +`7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`. +No age private key was needed by the capture job. + +## Independently retrieve and recover the complete actual archive + +```task +id: NK-WP-0049-T13 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T11, NK-WP-0049-T12] +state_hub_task_id: "602d4921-cfac-5e5b-9993-4fbf67195c7d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16. Independently downloaded the exact first generation +through attended Backup-account custody, rehashed it locally and revoked the +session. The operator used the independently held age key through the bootstrap +handoff. Correct/wrong-key cases, all 36 manifest files/hashes, original RSA pairs, +SQLite integrity and isolated native PG16.14 restore/readback passed; plaintext +and containers were removed. No key or restored secret values reached the agent. + +Evidence: live `independent-owner-transfer.json`, `actual-full-archive-recovery.json`, +`actual-full-recovery-review.json`. Existing-user/MFA authentication and old audit +signatures are deliberately separate T16–T20 outcomes. + +## Activate and prove the complete recurring backup and retention job + +```task +id: NK-WP-0049-T14 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T10, NK-WP-0049-T13] +state_hub_task_id: "eaf0708f-b3b7-5531-8172-95edf30c3a19" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 after T13. Both daily backup/retention and hourly health +timers are enabled/active. The actual hardened systemd service passed retention +before/after a second capture/upload/download (Result=success, ExecMainStatus=0). +Both verified generations are retained, the independently recovered point is +pinned, and nothing was deleted. Helpers/plaintext were cleaned; failure markers +and reporting outbox are empty. Health check succeeded. + +Evidence: live `activation-result.json`, `activation-review.json`, +`recurring-job-review.json`. Cadence: daily 03:45 UTC plus up to 5 minutes jitter, +hourly health, 25-hour freshness bound. Second-provider/host-loss gaps go to T24; +this completed task is not a full-estate recovery claim. + +## Map current callers, owners and native acceptance gaps + +```task +id: NK-WP-0049-T02 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T06] +state_hub_task_id: "479d6970-6516-50f5-9436-bb5b56d58aad" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +The source inventory and known legacy objects exist; a complete current-use +ledger is not yet accepted. Next action is read-only reconciliation of the 93 +entries in the latest October15 source inventory (the earlier snapshot had 87) against active Make/bootstrap/operator routes and owner evidence. + +**Done when:** each entry is identified as current, retired or owner-deferred, +with its owner, credential route, current consumer(s), native evidence or exact +missing proof, and next responsible task. Explicitly cover the historical +`sso/keycape-pi-token` and `mfa/privacyidea-trigger-admin` objects, lab init, +factor diagnostic delivery, LDAP group/provider boundary, resolver cutover and +root-output/isolation boundaries. Secret presence is not credential validity. +Send current native checks to T21 and historical revocation/rotation decisions to +T22. Do not reopen completed source repairs without a new finding. + +## Prepare the isolated full-service restore and acceptance packet + +```task +id: NK-WP-0049-T15 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28, NK-WP-0049-T29, NK-WP-0049-T30] +state_hub_task_id: "1d1eb903-a4b0-5bc4-a421-0b842d7f68ae" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Prepared draft scope moved to T27.** See +`docs/identity-service-restore-packet.md`: restore order, containment, safe evidence +and per-service positive/negative checks are drafted. Read-only current runtime +image digests were observed for all four services; correspondence to the selected +archive and independent image availability are not yet proved. + +**Next action:** admit a named disposable target/private route, verify and stage +matching images independently, obtain private existing-user/MFA test inputs and +review version-specific native commands with service owners. Incorporate T02's +ledger before submitting current-caller acceptance. + +2026-10-16 checkpoint: T28 completed the exact local image save/load/inspect +and T29 prepared and natively tested the bounded LLDAP stage. Its actual owner +run is T16 and can proceed independently of the remaining multi-service packet. +The other service adapters, matching archive/runtime lineage and private +existing-user/MFA inputs are still required; no blanket T15 completion is claimed. + +**Done when:** service owners accept the exact targets/procedure, existing-user +and MFA test identities/input custody are available without posting secrets, +outbound notification/provider writes are disabled, and every required new +credential or production effect has its own owner decision. The verifier deletes +its plaintext; it is not a production importer. This task prepares authority and +inputs for T16–T20, not an automatic production restore. + +## Prove restored LLDAP directory and existing-user authentication + +```task +id: NK-WP-0049-T16 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T29] +state_hub_task_id: "b64d4d6a-e851-58d1-9929-f03343147de0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom directory/User Engine owners. Restore the captured +original directory/configuration in the admitted isolated environment. + +**Done when:** user, group and membership identities are preserved; an independently +supplied existing-user credential authenticates; a wrong credential is refused; +provider writes/outbound effects stay confined; cleanup is verified. Native +fixtures from T05 and SQLite integrity from T13 do not satisfy this current-data +acceptance. Record only safe counts, identities and outcomes. + + +Completed 2026-10-16 at 18:37 UTC. The operator privately supplied the +independent age key and an existing backup-era account credential to the exact +local executor. All 36 archive hashes and the known ciphertext/source/target +bindings matched. Native existing-user LDAP bind passed; explicit invalid +credentials were rejected. The original seven users, 17 groups, 13 memberships +and the available attribute/schema rows were preserved across service startup, +authentication and graceful shutdown. The container had only loopback/no +external routes; pre-import isolation and container/tmpfs cleanup passed. +No production endpoint was contacted or secret exported to the agent. + +Evidence: `actual-isolated-lldap-recovery.json` and +`actual-isolated-lldap-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. This closes the actual +LLDAP stage independently of the remaining T15 packet. It does not prove +Authelia/KeyCape authentication, retained-token MFA or audit continuity. T17, +T18 and T19 retain their remaining adapter/input prerequisites. + +## Prove restored Authelia storage and OIDC continuity + +```task +id: NK-WP-0049-T17 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16] +blocking_reason: "LLDAP recovery T16 passed; await the exact isolated Authelia adapter/procedure and private authentication-flow inputs from T15." +state_hub_task_id: "b47f9975-d6d7-5bb8-93ce-886deb1dfa70" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: SSO/Authelia and directory owners. Restore the original storage, +encryption/session/signing material and configuration in isolation. + +**Done when:** native storage decryption succeeds, issuer/signing identity and +client configuration are preserved, and an isolated authentication flow has +positive/negative results using the restored directory. Disable outbound +notifications and verify cleanup. Archive integrity/RSA parsing alone are not +native Authelia acceptance. + +## Prove retained privacyIDEA token decryption and existing-token MFA + +```task +id: NK-WP-0049-T19 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T31] +blocking_reason: "LLDAP T16, token-material T31 and audit T20 passed; await the exact isolated MFA adapter and owner-selected retained-token/factor inputs." +state_hub_task_id: "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA and directory owners. Use the exact linked dump +and original enckey from the independently recovered generation. + +**Done when:** retained token material decrypts inside the isolated process, +a selected existing token completes a native MFA check, a wrong key/code is +refused, and cleanup is verified. Obtain any token/user input through attended +private custody; never emit token plaintext, seeds or credentials. Native database +row counts and disposable synthetic-token fixtures do not prove this outcome. + + +2026-10-16 refinement: native token-material readback is separately tracked in +T31 using the prepared T30 executor. T19 retains actual existing-token MFA and +wrong-code/wrong-key authentication refusal. Internal decryption or padding +success does not authenticate a user. No MFA code is needed for T20/T31; the +selected user's private factor input and exact isolated MFA adapter remain T19. + +## Prove historical and new privacyIDEA audit-signature continuity + +```task +id: NK-WP-0049-T20 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "375fa8f9-b8a5-5048-97a7-ec141aa7c45d" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: MFA/privacyIDEA audit owner. Use the original recovered audit +pair and linked database in the admitted isolated target. + +**Done when:** existing pre-backup audit signatures are verified natively, a new +isolated audit entry is signed and verified with the preserved identity, a wrong +key fails, and cleanup is recorded. Report any historical verification failure +for explicit owner disposition; do not regenerate keys to hide it. Matching RSA +pairs from T13 are a prerequisite, not audit-history verification. + + +Completed 2026-10-16 at 19:10 UTC using the actual independently retrieved +bundle and original audit identity on the fixed isolated local engine. All +279,209 stored rows were signed and verified; zero unsigned, invalid or legacy +signatures. A new isolated entry verified, and tampering/unrelated-public-key +checks were refused. Container/plaintext cleanup passed. Receipt and reviewed +source/ciphertext/target bindings: `actual-isolated-privacyidea-recovery.json` +and `actual-isolated-privacyidea-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. +Stored-row continuity is accepted; event completeness and existing-token MFA +are separate and are not claimed. + +## Prove restored KeyCape issuer, policy and consumer continuity + +```task +id: NK-WP-0049-T18 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T15, NK-WP-0049-T16, NK-WP-0049-T19, NK-WP-0049-T32, NK-WP-0049-T33] +blocking_reason: "Source and synthetic KeyCape lifecycle proof are delivered in T32; await exact owner-held recovery attempt preparation T33, selected consumer acceptance and retained-token MFA for the selected flow." +state_hub_task_id: "141dd773-c1fa-56c1-a852-bbe2372e5125" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: KeyCape and the selected current consumer owners. Restore the +original signing/configuration, registry, authentication policies and receipts. + +**Done when:** issuer/JWKS signing identity, registry/client configuration and +policy/receipt continuity are preserved; selected current consumers pass native +positive/negative authentication using the restored dependencies; and isolation +and cleanup hold. Confirm the actual dependency graph in T15. Do not route a +production consumer to the isolated issuer or mint new client grants implicitly. + +## Verify current caller and provider admission at their actual boundaries + +```task +id: NK-WP-0049-T21 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02] +blocking_reason: "Await the current-caller ledger and exact per-caller owner admission/test inputs; the backup credential grants do not admit unrelated callers." +state_hub_task_id: "77aa42be-7a39-5d93-8042-03d78b4094b4" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: each current caller's service/provider and credential owner. +Use T02's ledger to select the exact current procedures and required owner lanes. + +**Done when:** each current caller has scoped delivery and native positive/negative +acceptance or an explicit accepted retirement/disposition. Include dedicated +factor-diagnostic admission (do not borrow KeyCape's reader), deployed reserved +LDAP group denial, resolver/cutover input provenance and functional proof, and +bootstrap/root-output/isolation callers. Fixtures, an existing tty and historical +bootstrap receipts are not current authority. Propose exact write/cutover actions +before execution; record deferred actions separately rather than faking a pass. + +## Resolve historical credential and configuration-preserving rotation dispositions + +```task +id: NK-WP-0049-T22 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T21] +blocking_reason: "Await the caller/consumer ledger, current replacement-lane acceptance and explicit credential-owner dispositions; existing exposure-rotation deferral is unchanged." +state_hub_task_id: "3ea6bf00-a87f-58ea-bdce-328c13a03a55" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: Platform/custody and affected consumer owners. Review historical +personal-admin/trigger credential copies and unsafe predecessor paths against +known current consumers and rollback custody. + +**Done when:** every affected credential has an owner-accepted disposition: +verified revocation/replacement, continued bounded use with acceptance, or an +explicit linked deferral. Signing/client-secret changes require preservation and +native multi-consumer proof if actually approved. CUST-WP-0073-T05's founder +rotation deferral and decision `1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa` remain in force; +record their exact applicability rather than automatically rotating or treating +source retirement as provider revocation. + +## Provide retrieval that works when OpenBao and SSO are unavailable + +```task +id: NK-WP-0049-T23 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T25] +state_hub_task_id: "1ec537ee-dfee-5576-be36-a81bdba417d1" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Completed 2026-10-16 at 18:02 UTC. The operator used independently held Backup +account access in the private prompt. The actual protected 109,738,344-byte +ciphertext was downloaded with unchanged ETag/size/SHA256, with no OpenBao/SSO +contact or provider writes by the retrieval path. The human-held age key matched +the registered recipient; wrong-key refusal, all 36 manifest hashes, SQLite +integrity, original key pairs and native isolated PostgreSQL 16.14 restore passed. +The database retained five token, two resolver and two realm rows. Disposable +container and temporary plaintext cleanup passed. The agent received no secret. + +Evidence: `actual-offline-transfer.json`, `actual-offline-recovery.json` and +`actual-offline-review.json` under +`docs/evidence/2026-10-16-identity-outage-recovery/`. The review rechecked the +local ciphertext digest and verifier source. This proves the independent path +without requiring a deliberate production outage. Service authentication, +retained-token decryption and historical audit verification remain T16–T20. +T26 separately records accepted guide publication. + +## Record owner disposition for second-provider and external monitoring gaps + +```task +id: NK-WP-0049-T24 +status: todo +priority: medium +assignee: codex +depends_on: [NK-WP-0049-T14] +state_hub_task_id: "474f5a78-a643-59c6-bcf9-fc4a908dfcb0" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +**Next action:** record the current single-provider and host-local-health limits, +then obtain explicit owner scope decisions for a second encrypted provider copy, +external host-loss/freshness detection and recurring recovery-drill cadence. + +**Done when:** each gap has either an accepted bounded residual risk or a linked +live intake/workplan with owner and trigger. Existing daily RPO/25-hour health +settings remain the approved baseline. Scaleway full-identity publication and +an external watchdog are not implemented; do not add their grants/jobs implicitly. +This task triages the new insights instead of silently expanding NK49's required +implementation to an entire disaster-recovery programme. + +## Deliver and verify the offline retrieval adapter and recovery tools kit + +```task +id: NK-WP-0049-T25 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13] +state_hub_task_id: "1c5ea7a1-edf7-5072-b36b-8be7f827957a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. `retrieve-identity-offline.py` uses privately entered +independent Backup-account access or an exact read-capable identity-folder share. +It performs only fixed-provider HEAD/GET, binds the reviewed generation by strong +ETag/length/SHA256, refuses redirects/proxies/unreviewed scope and removes failed +downloads. No OpenBao/SSO, age key or standing agent credential is required. +`recovery-kit.py` builds a reproducible allowlisted ZIP containing the tools, +public profile, known-good ciphertext receipt and recovery guides, with file +checksums. Its publication path creates only three versioned guide/ZIP/checksum +objects and verifies readback without overwriting existing conflicting objects. +`run-offline-recovery.sh` provides the owner's two-hidden-prompt handoff. + +Evidence: `tests/test_identity_offline_recovery.py` and the bounded test/build +receipt in `docs/evidence/2026-10-16-identity-outage-recovery/`. The focused run +passed 65 tests including real disposable age/PostgreSQL fixtures. ZIP-contained +entry points import without sibling repositories. This is source/fixture proof, +not actual independent-provider retrieval (T23) or publication (T26). + +2026-10-16 correction: the first owner handoff stopped before its credential +prompt because Python text `r+` requires a seekable stream. Reproduced against a +real controlling PTY; replaced both prompts with the shared hidden-input helper, +refusing redirected input and echo fallback. Added real-terminal and both-CLI +regressions plus closed stage/HTTP-code diagnostics (no raw responses). The +focused rerun passed 36 tests. Evidence: `terminal-prompt-fix.json` in the outage +evidence directory. This source correction does not complete T23/T26. + +## Publish and verify the disaster recovery guide on Storage Share + +```task +id: NK-WP-0049-T26 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T25, NK-WP-0049-T27] +state_hub_task_id: "94d054fe-e5d8-5ddf-8e48-80714123d184" +``` + +**Accountable worker:** codex; operator holds provider access privately. + +Requested by the operator on 2026-10-16; decision +`fc3ef8db-0a33-41d5-a0ba-d13169c5f884` records the bounded scope. Guide source: +`docs/disaster-recovery-storage-share.md`. Document scope, independently held +provider/key requirements, exact known-good fallback, copy/download verification, +archive-check commands, service restore order, recurring schedule and remaining +coverage limits. Include the offline tools so failed Forgejo does not prevent +access to the recovery scripts; retain an independent copy and trusted digest. + +Completed 2026-10-16 at 18:01 UTC through the private independent-provider +owner handoff. All three objects were conditionally created and read back with +matching strong ETag, length and content; the recorded digests match a fresh +reproducible local build. No existing object or provider permission was changed. +The failed first attempt and terminal correction remain documented in T25. + +**Published location:** Storage Share account Backup, +`railiance-backups/net-kingdom-identity/`: + +- `net-kingdom-recovery-57d1940947aa25ff-START-HERE.md` +- `net-kingdom-recovery-57d1940947aa25ff.zip` +- `net-kingdom-recovery-57d1940947aa25ff.zip.sha256` + +**Trusted ZIP SHA256:** +`57d1940947aa25ff83d0f25ddf30090eb40595cccaab64225de882a2fd59ea2f`. +Evidence: `actual-offline-publication.json` and `actual-offline-review.json` in +`docs/evidence/2026-10-16-identity-outage-recovery/`. The published guide is the +exact pre-drill revision; this acceptance record records the later successful +drill without implying an unperformed republication. Keep an independent copy +and trusted digest outside the failed service/provider dependency. + +## Draft the isolated service restore packet and observe candidate images + +```task +id: NK-WP-0049-T27 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T08, NK-WP-0049-T13] +state_hub_task_id: "e273e803-bee7-5d90-bc51-ecc08c0c8eff" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. Draft in `docs/identity-service-restore-packet.md` names the +known recovered input, restore order, original key/data ownership, default-deny +containment, blocked production/provider/notification effects, cleanup and five +native acceptance lanes with positive/negative checks. Read-only metadata from +the pinned primary cluster resolved all four current service image digests, +including the separately observed privacyIDEA main container and LLDAP's mutable +source tag. Evidence: `docs/evidence/2026-10-16-identity-outage-recovery/image-observation.json`. + +This task extracts completed preparation from T15. Named target admission, +archive/runtime image-lineage matching and independent image availability, +private existing-user/MFA inputs and owner-reviewed native commands remain T15; +no service restore, production change or owner acceptance is claimed. + +## Stage and verify the five exact service images for local offline recovery + +```task +id: NK-WP-0049-T28 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T27] +state_hub_task_id: "4829b091-76d2-5b10-bdfc-032800190c0a" +``` + +**Accountable worker:** codex. + +Completed 2026-10-16. All five pinned references (PostgreSQL, LLDAP, Authelia, +KeyCape, privacyIDEA) were inspected on the fixed local Linux Docker engine +`bnt-lap001`, ID `74f93783-6cef-43a8-a3c4-f62586cd3bc1`. Missing LLDAP and +privacyIDEA images were pulled only by their observed immutable digests. Saved a +private 347,521,536-byte image archive, loaded it and re-inspected every exact +reference. Evidence and archive SHA256/location: +`docs/evidence/2026-10-16-identity-outage-recovery/offline-service-images.json`. + +The local drill no longer requires the production registry. This is not off-host +image escrow or proof of historical mutable-tag/backup lineage; those limits +remain in T15. No service custody or age key was supplied to image caching. + +## Prepare and verify the bounded native LLDAP recovery executor + +```task +id: NK-WP-0049-T29 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T27, NK-WP-0049-T28] +state_hub_task_id: "2f8c73b0-1cdd-5b22-99b6-017ccde4454b" +``` + +**Accountable worker:** codex; operator retains actual private recovery inputs. + +Completed 2026-10-16. `isolated-lldap.py` and `run-isolated-lldap.sh` provide the +exact owner-run stage in `docs/identity-service-restore-packet.md`: fixed local +engine/images, no remote Docker endpoint, original key/seed/JWT/directory data, +Linux-tmpfs decryption, memory/stdin-only private inputs, network-none/read-only +containers, isolation inspection before import, actual existing-user bind, +explicit invalid-credential denial, stable directory rows and cleanup checks. +Missing original server keys are refused; reset/replacement/notification paths +are disabled. No live Kubernetes/OpenBao/SSO path or provider grant is used. + +Evidence: `tests/test_isolated_lldap_recovery.py` exercises the actual pinned +image, disposable retained-account directory and a full synthetic encrypted +bundle through the same native executor. The private real-bundle run and its +acceptance remain T16; fixture success is not actual user/MFA/audit recovery. +See `isolated-lldap-preparation.json` in the October16 outage evidence directory +for exact test/source/target provenance and limitations. + +## Prepare the bounded native privacyIDEA token-material and audit executor + +```task +id: NK-WP-0049-T30 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T28] +state_hub_task_id: "6e4a43db-9be2-5662-bdbf-1595fce03052" +``` + +**Accountable worker:** codex; operator retains private recovery inputs. + +Completed 2026-10-16. `isolated-privacyidea.py` and its owner launcher use the +fixed local Docker target and exact cached PostgreSQL/privacyIDEA3.12.2 images. +The linked dump, original enckey/audit pair and required secret fields are +restored only into a loopback-only, nonroot, read-only, capability-free, +no-host-mount/port, tmpfs-backed environment with inspected pre-import isolation. +Decrypted host staging is tmpfs; normal cleanup removes all private data and +owned containers, with a bounded holding lifetime if the parent is interrupted. + +The native provider decrypts token-key material internally, checks every stored +audit row, adds one isolated signed entry and checks wrong-public-key/tampering +negatives. Original policy for legacy signature verification is retained only +from literal archived configuration; archived Python is never executed. Invalid +or unsigned history remains reported, not repaired or sampled away. Native +material readback is not existing-token MFA or proof of event completeness. + +Evidence: `tests/test_isolated_privacyidea_recovery.py` and +`isolated-privacyidea-preparation.json` in the October16 outage evidence folder. +Synthetic pinned-image tests exercise valid/tampered/unsigned history, malformed +keys, encrypted archive to native restore, isolation and cleanup. Real original +material/audit acceptance remains T31/T20; actual MFA remains T19. + +## Verify retained privacyIDEA token material inside the isolated provider + +```task +id: NK-WP-0049-T31 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T13, NK-WP-0049-T30] +state_hub_task_id: "26383841-8076-5c53-bbd1-9db64e32544a" +``` + +**Accountable worker:** codex; operator supplies only the independently held age +key in the hidden helper. This task extracts actual material-readback scope from +T19, preserving T19's existing-token MFA acceptance gate and historical identity. + +Completed 2026-10-16 at 19:10 UTC in the same actual run as T20. All five +retained token materials were decrypted internally with the original enckey; +an unrelated key could not reproduce any of the five. All 36 manifest hashes, +exact executor/ciphertext/target bindings, isolation and cleanup passed. Safe +receipts are the `actual-isolated-privacyidea-{recovery,review}.json` files +referenced under T20. No retained-factor authentication is claimed. +**Done when:** exact ciphertext/source/target/manifest bindings pass; the native +provider reads every nonempty encrypted token-key field using the original +enckey without exporting material; an unrelated key cannot reproduce that +material; aggregate counts and container/plaintext cleanup are recorded. + +Only bounded internal readback is accepted here. Padding/readback success does +not prove the recovered secret authenticates a retained factor; actual positive +MFA and wrong-key/wrong-code authentication refusal remain T19. No token seed, +plaintext, serial or user record belongs in the receipt, Git, State Hub or chat. + +## Deliver isolated KeyCape restore source and synthetic lifecycle proof + +```task +id: NK-WP-0049-T32 +status: done +priority: high +assignee: codex +state_hub_task_id: "cd78dbb7-a8f2-5754-8788-6eb1b7d97741" +``` + +Completed 2026-10-16. This extracts bounded source/fixture delivery from T18; +T18 retains actual original archive, issuer and selected consumer acceptance. +The adapter reuses the existing transfer/archive/custody contracts, binds the +fixed local daemon and cached images, restores private state only to temporary +memory, verifies original issuer/TLS/signing/configuration/policy bytes and runs +the original native service-client checker with wrong-secret/excess-scope denial. +Durable pre-import obligations and exact parent pidfd/session quiescence precede +loss/deadline cleanup. Daemon response uncertainty remains uncertainty after +resource absence; it never authorizes recovery success or replay. + +Frozen R6 fixes a demonstrated image-declared anonymous-volume incompatibility +using bounded helper-only tmpfs, preserving anonymous disk-volume refusal. Safe +phase markers carry no private diagnostics. Independently passed 72 focused +checks, then actual pinned-image synthetic positive, hard-parent-loss, deadline +and nonzero-after-accept cases. Independent fixed-daemon inventories and host +mount-namespace checks prove all exact resources and plaintext absent. Reaper +outcomes are retained; initial sandbox receipt lookup failure is preserved and +superseded by device-bound host verification. R1–R5 failures remain retained. + +Evidence: Custodian docs/changes/netkingdom-target-2026-10-16/ +identity-restore-adapter-next/revisions/r6/, actual-fixture-r6-all.json and +coordinator-r6-all-review.json. Exact source/dependency hashes and candidate +manifest bind the proof. This uses generated test keys only; it proves neither +actual owner-held recovery, human MFA, downstream reconnect nor native authority. + +Publication preparation R7 preserves every R6 recovery adapter byte and digest. +The normal scanner flagged eight public source-file SHA-256 values in the R6 +manifest. Explicit sha256-qualified checksums resolve those false positives; +the fixture reader strictly validates their type/shape before checking the same +bytes. R7 passes 73 focused checks including malformed/untyped digest refusal. +The frozen R6 actual four-case proof remains the runtime evidence; no repeated +native outcome is claimed for publication encoding. Original scanner refusal is +retained, and scanner policy/exemptions are unchanged. + +## Prepare the exact owner-held KeyCape recovery attempt + +```task +id: NK-WP-0049-T33 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32, NK-WP-0049-T34, NK-WP-0049-T35, NK-WP-0049-T36] +blocking_reason: "Source custody/preflight preparation is evidenced in T34; await original TLS/trust recovery disposition T35 and selected original registration/private-admission metadata T36 before final reviewed command and existing owner process." +state_hub_task_id: "56c8d469-7a10-5d50-a30e-95cbf3cd4756" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and selected consumer owners. +This umbrella retains final attempt readiness. Completed custody/preflight source +preparation is extracted into T34; T35 resolves original TLS/trust recovery and +T36 prepares the selected original registration and private admission. This split +records distinct outcomes without counting source preparation as recovery. + +After those deliverables, assemble the exact existing six-argument attended +command and admission digest, bind the integrated source/dependency revision and +fixed local target, and record execution deadline, safe receipt location, abort, +rollback and independent receipt verification through the existing owner process. +Keep private manifest derivation inside custody and original TLS/client/key inputs +in the owner's own terminal; the current null fields must refuse execution. +Existing session authorization is retained within scope; this record does not +supply missing owner assent or approve any actual recovery attempt. + +**Done when:** reviewed executable command and complete metadata-only/private +admission packet are ready for the existing attended custody path; prerequisites +and independent receipt verification are explicit. T18 still owns actual +execution, original consumer continuity and acceptance. T19 retains retained-factor +MFA. This task neither authorizes a production consumer redirect nor creates a +new client grant. + +## Deliver attended custody, metadata preflight and private manifest preparation source + +```task +id: NK-WP-0049-T34 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T32] +state_hub_task_id: "821b3a56-6f36-5812-abc9-5a00e37cb2e7" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian source review. +Completed 2026-10-17 as source preparation. Existing attended custody entry points +now have a reviewed candidate sealed anonymous descriptor mode: hidden prompt, +actual public-recipient verification, strict owned/private/full-seal descriptor +admission, non-inheritable returned duplicate and explicit descriptor passing. +The existing file mode stays compatible, with its original hard-loss limitation; +no improved file-mode cleanup is claimed. Exact parent-loss tests prove descriptor +lifetime without signalling inherited user shell groups. An admitted child retains +its descriptor until it exits; parent loss is not child revocation. + +The candidate checks bounded, duplicate-free public JSON, exact admission digest, +transfer/archive and selected service bindings, typed hashes for all 17 invoked +local source/config dependencies and required Python imports before requesting a +key. TLS and ciphertext preparation uses file metadata only. Legacy explicit +manifest digests remain supported; versioned ciphertext-derived binding computes +the canonical digest privately only after exact reviewed ciphertext, authenticated +age decryption and full existing archive validation. The derived private digest +never enters safe receipts/checkpoints and grants no new consumer authority. + +The coordinator independently passed 111 focused checks. The existing custody +regression suite passed 94 checks; 61 real-SOPS tests skipped because that trusted +runtime is unavailable, so that compatibility coverage remains unverified. Tests +use generated keys/archive material only, including actual age cryptography, +synthetic hidden-prompt and exact parent-loss processes. Manifest-builder tests +mock Docker/issuer behavior and confer no new native proof. Frozen R6/R7 proof, +intermediate test failures and scanner history remain retained. + +Bounded public image readback separately establishes the cached original image's +13670142-byte `/keycape` executable as +`sha256:cd89121393e1465aa76009763602a5b8c75f9dddb5679aea6242623f135b51b4`. +This is executable identity metadata, not recovery or custody acceptance. + +Evidence: Custodian `docs/changes/netkingdom-target-2026-10-16/recovery-attempt-r1/` +(`candidate.patch`, `review.json`, source closure, attempt/admission metadata and +`public-verifier-image-readback.json`). Canonical integration/publication and +projection receipts must be recorded separately when performed; this completed +source-preparation record does not invent them. T33 remains open for complete +attempt readiness; actual recovery/consumer acceptance remains T18 and MFA T19. + +## Establish original KeyCape TLS and trust recovery ownership for outage use + +```task +id: NK-WP-0049-T35 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "1bfd1703-589f-5511-bad5-812d860e4a71" +``` + +**Accountable worker:** NetKingdom codex, coordinating with the source owner of +Ingress/cert-manager/Traefik and the original TLS custody/provider boundary. +**Next action:** identify and record that actual owner's existing recovery path, +then obtain its metadata/disposition through the ordinary owner process. A missing +exact credential-routing catalog match is not evidence that no owner exists. + +Current source declares `kc.coulomb.social`, `sso/kc-tls`, cert-manager +`ClusterIssuer/letsencrypt-prod` and Traefik TLS termination before KeyCape 8080. +The identity backup profile excludes `kc-tls`; the verified archive therefore +establishes no independent recovery of that TLS identity/trust. Determine whether +the exact original certificate/key/trust is independently recoverable during an +issuer/cluster outage, or whether a documented reissue path is acceptable for the +selected continuity claim. Do not read or place the TLS key in work records, use +a fresh self-signed trust substitute, mutate production or claim owner assent. + +**Done when:** named owner/provider, independent outage prerequisites, original +public identity/certificate/trust hashes or accepted reissue disposition, private +custody entry point and verification/abort limits are explicit and reviewed. +Record any unavailable recovery capability as a live owner work record and bind +its dependency/unblock condition; a prose-only gap or untested archive is not +completion. This delivers preparation/disposition, not actual TLS recovery. + +2026-10-17 owner handoff progress: the four reviewed Railiance Cluster source +additions are present, including `RCLUSTER-WP-0018` and public-only TLS metadata +preparation. They are not published. The normal publication path stopped at the +existing historical identifier guard (`ensure_missing_work_record_identifiers`, +execute=False): 15 bare task-label findings and five collisions. A separately +retained read-only allocator preview records those findings; the original failed +publication stderr was not retained and is not reconstructed. No Cluster Hub +workplan/task existence or projection, actual certificate/key custody, reissue +assent or native TLS acceptance is claimed. The source record and next owner +publication action remain live; do not bypass the historical identity guard. +Evidence: Custodian October17 `cluster-integration.json`, `coordinator-checkpoint.json` +and October16 `cluster-historical-publication-r1/actual-source-allocator-preview.json`. + +## Prepare selected original service registration and private admission bindings + +```task +id: NK-WP-0049-T36 +status: progress +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "8b72334b-fc27-5707-a189-bad345eaf3bc" +``` + +**Accountable worker:** NetKingdom codex with KeyCape and the selected existing +service consumer's owner. **Next action:** identify that owner and the exact +original registration's non-secret selector metadata using existing source/owner +evidence; preserve independent private custody and never retrieve a client secret. + +Bind reviewed ciphertext `7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30`, +its independently verified transfer, source/image/executable closure and an +explicit versioned manifest-binding mode. For the original service registration, +record client identifier, secret environment name, audience, granted scope, +subject, tenant, required roles and denied scope without values or new grants. +Describe the native service-client dependency graph and distinguish unexercised +LLDAP/Authelia/privacyIDEA/downstream flows. Keep private manifest material inside +the existing custody process, never in Git, safe receipts, State Hub or chat. + +**Done when:** the selected existing service owner and exact non-secret registration +bindings are independently established, the private admission builder validates +positive/negative source/archive/selector cases, and its metadata is ready to +combine with T35's original TLS/trust disposition under T33. This task may prepare +registration metadata while T35 proceeds independently; it does not finalize the +whole admission, perform actual recovery, redirect a consumer or confer assent. + +2026-10-17 owner handoff progress: Secrets Engine source workplan +`SECRETS-WP-0015` and bounded public selector/preflight source were published as +`c59bbf568c0be8a72ac593508f48c9b1f61ec4c1`; the central primary/railiance01 +reconciliation receipt reports the same expected/derived commit, four owner task +bindings and two T04 dependency edges, with no unresolved edges. T01/T02 source +preparation is done, T03 exact outage-compatible consumer proof/custody planning +is todo, and T04 actual admitted consumer result waits on T03 and NK-WP-0049-T33. +This publishes an owner handoff, not exact archived registration validation, +current native assent, an OpenBao read, a new grant or consumer continuity. +T36 therefore remains progress; T18/T19 and final native gates remain open. +Evidence: Custodian October17 `secrets-engine-projection.json` and October16 +`recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote +readback is recorded separately when performed. + +2026-10-17 exact-selector source preparation: the adapter now requires exactly +one selected client in the already-restored archived configuration before further +runtime environment reads, signer-key parsing or native checker invocation. +Absent, duplicate (identical or conflicting) and empty selectors refuse early; +existing unique registration behavior is retained. This check cannot run before +private archive decryption or its key prompt. Current KeyCape Go configuration +also rejects duplicate IDs; this is an explicit adapter guard, not a claim that +the pinned native issuer admitted duplicates. Tests use public/synthetic config +and mocked native calls only. Changed adapter bytes require a fresh reviewed +source/dependency and admission binding; old actual fixture receipts are retained. +The exact eight-field current consumer selector independently passes its offline +AST-only preflight. TLS public provenance/private custody, archive-time selector +binding, current owner recovery assent and outage-compatible actual consumer +proof remain open under T35/T36 and the existing owner tasks. No actual archive, +key, Secret object, token exchange, OpenBao login, rotation or native action was +performed. Source evidence and proposed owner declaration/consumer plan: +Custodian docs/changes/netkingdom-target-2026-10-17/native-identity-r1/. + +## Verify actual SOPS compatibility and sealed-descriptor read/write custody + +```task +id: NK-WP-0049-T37 +status: done +priority: high +assignee: codex +depends_on: [NK-WP-0049-T34] +state_hub_task_id: "3403e266-d63b-5ce1-b891-3bfeac93d28c" +``` + +**Accountable worker:** NetKingdom codex; independent Custodian fixture review. +Completed 2026-10-17 as generated-fixture compatibility proof. The coordinator +ran the actual reviewed SOPS 3.13.3 binary in a network/host-custody-isolated +namespace: all 65 tests passed in 14.85 seconds, including the 61 real-SOPS cases +previously skipped in T34 and four new actual sealed-FD cases. The latter cover +correct-key descriptor-only decryption, wrong-recipient refusal and descriptor-only +edit/rotation through the real Make entry points. Generated custody key files +were removed before these FD-only invocations; explicit descriptor passing, +private output modes, declared encryption-policy preservation, suppressed synthetic plaintext +and operation cleanup were checked. + +This is a dated successor to T34's historical 94-pass/61-skip record, which stays +unchanged. The prior skip is not rewritten as an earlier pass. Binary digest +`sha256:e5bec3346a873ae91d871550f3e698c1aad962aff462a080e40f25fde17fef6b` +matched the official release asset/checksum; Sigstore signature verification was +not performed. SOPS was not installed systemwide or admitted for production +runtime. Host custody was not mounted, network routes were absent, diagnostics +were suppressed and namespace teardown completed. All material was generated; +no original owner key/archive, private manifest, production credential, native +service continuity or owner assent was exercised. + +Evidence: Custodian +`docs/changes/netkingdom-target-2026-10-17/sops-real-regressions.json`, +`sops-source-tool.json` and `sops-fd-r2/` (exact test patch/manifest). The focused +custody/source checks and frozen R6/R7 native fixture evidence remain separate. +T33 attempt readiness, T18 actual recovery/consumer acceptance, T19 retained MFA, +T35 TLS/trust disposition and T36 original registration/private admission remain +open under their existing owner boundaries. + +## Accept remaining recovery and caller evidence and close the G08 handoff + +```task +id: NK-WP-0049-T03 +status: wait +priority: high +assignee: codex +depends_on: [NK-WP-0049-T02, NK-WP-0049-T16, NK-WP-0049-T17, NK-WP-0049-T18, NK-WP-0049-T19, NK-WP-0049-T20, NK-WP-0049-T21, NK-WP-0049-T22, NK-WP-0049-T23, NK-WP-0049-T24, NK-WP-0049-T26] +blocking_reason: "Await the separately tracked native service proofs, current/legacy caller dispositions and residual-scope decisions; archive recovery, backup activation, independent outage retrieval and guide publication are complete." +state_hub_task_id: "d68cd4d3-1ba3-530e-88f9-26ebb8dd6eac" +``` + +**Accountable worker:** codex. Service/credential-owner acceptance remains with +the named owner boundary. + +Owner boundary: NetKingdom, Platform and affected service owners, with Custodian +G08 receiving the final evidence. The completed archive/job milestones remain +accepted independently of this final gate. + +**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted +handoff outcomes; service authentication/token/audit proof and current/legacy +caller dispositions are accepted; the source workplan and projected tasks agree; +and G08 has an exact evidence/handoff record. Record actionable residuals as live +work records before workplan closure. Preserve historical IDs and receipts; do +not call a deferred rotation or an untested full-estate restore complete. + +## Evidence locations and refinement history + +“Live” above means `docs/evidence/2026-10-16-identity-backup-live/` in NetKingdom. +Implementation preparation is in the October16 implementation directory; earlier +backup discovery/database recovery is in `docs/evidence/2026-10-15-bootstrap-recovery/`. +The source-repair receipts explicitly labelled Custodian belong to that owning +repository. Use the [recovery ceremony](../docs/bootstrap-recovery-ceremony.md) +for exact procedure and approval history. No secret values belong in task evidence. + +Refinement rule: substantial work and newly understood remaining scope must be +visible in task blocks at a checkpoint, not only in progress prose. This replan +preserves T01–T03 identity and original evidence while making the completed +milestones and each remaining acceptance gate separately manageable. + +Managed identifier assignment also consumed a preexisting staged generated brief; +the follow-up commit restores its prior published baseline while preserving the +operator's working brief and original staged version. This is a projection-tool +side effect, not new recovery evidence. + + +R7 source publication and task bindings verified: +`5fcd5952add1c0167116094298a1d5feaa60cf30` is the observed published source. +All eight canonical additions match the reviewed bytes; all 33 task statuses +match the actual hub projection, including T32 done and T33 todo. Original +staged/working brief content is preserved. Normal synchronization has zero +failures/automation errors; existing warnings and scanner false-positive history +remain retained. Custodian identity-restore-adapter-next/canonical-r7-integration.json +binds source/projection/native-fixture evidence separately. T18 remains waiting +for the actual owner-held attempt and selected consumer acceptance. + + +2026-10-17 source/attempt refinement: T34 records completed attended custody, +preflight/private-manifest source preparation and its bounded tests; T35 and T36 +make original TLS recovery ownership and selected original admission metadata live +work. T33 retains final attempt readiness and its original Hub UUID. This adds no +actual recovery, MFA, native authority or owner assent. Source task counts above +refer to this file; projection has not been claimed for this proposed refinement. + +2026-10-17 verified source follow-through: source commit `4f65e41` passed normal +local scanning and 111 canonical focused checks. The initial T34 source-only +preparation now has an exact integrated source revision; existing real-SOPS +compatibility remains partly skipped and actual owner-held execution remains T18. + +T35/T36 source preparation is underway, with 17 pinned public-source references. +railiance-cluster owns the ingress/cert-manager/cluster-backup substrate; the +inspected same-host encrypted backup source establishes no independent original +kc-tls/trust recovery or accepted reissue. Draft owner questions remain unsent; +no private TLS input was requested. The historically deployed +secrets-engine-openbao registration is a defensible proposed consumer: its +7 October issuer and 10 October consumer proofs predate the reviewed archive. +The exact selector proposal is retained without current assent or private archive +validation. No token exchange, OpenBao login, client secret retrieval, new grant +or production redirect occurred. Keep incomplete admission refused before custody. +Custodian evidence: recovery-attempt-r1/t35-t36-source-next; final source/projection +review: resume-integration-r1/publication-verification.json. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/manifest.json new file mode 100644 index 00000000..d4623fde --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/manifest.json @@ -0,0 +1,27 @@ +{ + "schema": "custodian.native-identity-refinement.v1", + "revision": 2, + "status": "source_task_refinement_ready_not_published", + "task": "NK-WP-0049-T38", + "previous_task_count": 37, + "result_task_count": 38, + "old_task_blocks_preserved": true, + "uuid_assignment": "normal owner allocator; no UUID supplied", + "root_source_review": "accepted narrow guard and two-hash unexecuted successor scope in root instruction; no privileged/native approval inferred", + "knowledge_orientation": { + "package_version": "0.2.6", + "package_digest": "sha256:8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02", + "retrieval_status": "withheld", + "reason": "source changed", + "source_review": "current AGENTS, environment orientation, Security Companion and identity/start card source reviewed directly; knowledge is source-only orientation and grants no authority" + }, + "frozen_r1_manifest_sha256": "sha256:6821e650a4ca07087697b5091a3db26b722456170c1c4816ca8c49bdf527fce4", + "files": { + "NK-WP-0049.postimage.md": "sha256:e0cd01320b366ab8961a0a52a908edc1524f98b3cfab7382a14fa915da2f60a2", + "NK-WP-0049.preimage.md": "sha256:5830c429f58a0317b28c7b4bcf22a1b46e6d01b41378cdae95f947c6d9317e44", + "task-refinement.patch": "sha256:a2e17aa51eb0313f1370ff366afb1198ce93624bb7451445dd62be9b663e70f0", + "updated-owner-source.patch": "sha256:552484c86a7ac8b443faea6222aeb6d660eb0148f5d596c90f94ac9c60c2a6b0" + }, + "canonical_workplan_matches_postimage": true, + "diff_whitespace_check": "passed" +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/task-refinement.patch b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/task-refinement.patch new file mode 100644 index 00000000..4700339e --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/task-refinement.patch @@ -0,0 +1,96 @@ +--- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md ++++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +@@ -1130,23 +1130,15 @@ + `recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote + readback is recorded separately when performed. + +-2026-10-17 exact-selector source preparation: the adapter now requires exactly +-one selected client in the already-restored archived configuration before further +-runtime environment reads, signer-key parsing or native checker invocation. +-Absent, duplicate (identical or conflicting) and empty selectors refuse early; +-existing unique registration behavior is retained. This check cannot run before +-private archive decryption or its key prompt. Current KeyCape Go configuration +-also rejects duplicate IDs; this is an explicit adapter guard, not a claim that +-the pinned native issuer admitted duplicates. Tests use public/synthetic config +-and mocked native calls only. Changed adapter bytes require a fresh reviewed +-source/dependency and admission binding; old actual fixture receipts are retained. +-The exact eight-field current consumer selector independently passes its offline +-AST-only preflight. TLS public provenance/private custody, archive-time selector +-binding, current owner recovery assent and outage-compatible actual consumer +-proof remain open under T35/T36 and the existing owner tasks. No actual archive, +-key, Secret object, token exchange, OpenBao login, rotation or native action was +-performed. Source evidence and proposed owner declaration/consumer plan: +-Custodian docs/changes/netkingdom-target-2026-10-17/native-identity-r1/. ++2026-10-17 source checkpoint refinement: the completed exact-one original ++selector guard and its bounded refusal/unique-selector proof are extracted into ++T38. T36 retains exact archive-to-selector binding, current actual service-owner ++recovery assent and outage-compatible private admission/consumer preparation. ++The current eight-field source-selector correspondence is evidenced separately; ++it does not complete those remaining obligations or any T18/T19 native gate. ++T33 continues to require the complete reviewed TLS/custody/admission packet. ++This extraction records one source outcome rather than counting it again as ++original registration validation or consumer continuity. + + ## Verify actual SOPS compatibility and sealed-descriptor read/write custody + +@@ -1188,6 +1180,51 @@ + T35 TLS/trust disposition and T36 original registration/private admission remain + open under their existing owner boundaries. + ++## Deliver exact-one original selector guard and bounded source refusal proof ++ ++```task ++id: NK-WP-0049-T38 ++status: done ++priority: high ++assignee: codex ++depends_on: [NK-WP-0049-T34] ++``` ++ ++Completed 2026-10-17 as source preparation, independently reviewed by the ++coordinating Custodian agent. The adapter now requires exactly one selected ++registration in the already-restored archive configuration before further runtime ++environment reads, signer-key parsing or native checker invocation. Absent, ++empty, identical-duplicate and conflicting-duplicate selectors refuse before ++those later inputs; the existing unique-selector mocked native path still passes. ++Current KeyCape Go configuration also rejects duplicate IDs; this makes the ++adapter's own boundary explicit and establishes no native duplicate exploit. ++The guard cannot run before archive decryption or the original key prompt. ++ ++The 39 adapter checks passed, including four added early-refusal regressions. ++Running those four cases against the retained original adapter failed the new ++refusal contract as expected. The broader 77-check source run retained 76 passes ++and one stale fixture-proposal source-hash refusal. Only the two affected hashes ++and scope of that unexecuted/unapproved successor proposal were then refreshed; ++all four affected fixture-plan checks passed. The original manifest preimage and ++failure receipt remain retained, and frozen actual R6 runtime receipts were not ++changed or claimed as proof of this successor. No broader native rerun occurred. ++ ++Evidence: Custodian ++`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`: ++`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages, ++`original-behavior-regression.txt` and `focused-regressions.stderr.txt`. ++The later task extraction and exact workplan successor bytes are in ++`refinement-r2/`; the original source-proof packet remains immutable. ++Canonical owner publication, allocator-assigned Hub UUID and projection must be ++recorded separately through the normal owner process; none is claimed here. ++ ++This completes only the source guard/refusal deliverable extracted from T36. ++T35 original TLS public provenance/private custody or accepted reissue, T36 exact ++archive binding/current owner assent/consumer custody preparation, T33 complete ++attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor ++MFA remain open. No actual archive, private key, Secret object, token exchange, ++OpenBao login, rotation, production action or owner assent was exercised. ++ + ## Accept remaining recovery and caller evidence and close the G08 handoff + + ```task +@@ -1207,7 +1244,7 @@ + G08 receiving the final evidence. The completed archive/job milestones remain + accepted independently of this final gate. + +-**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted ++**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted + handoff outcomes; service authentication/token/audit proof and current/legacy + caller dispositions are accepted; the source workplan and projected tasks agree; + and G08 has an exact evidence/handoff record. Record actionable residuals as live diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/updated-owner-source.patch b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/updated-owner-source.patch new file mode 100644 index 00000000..20efd004 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/refinement-r2/updated-owner-source.patch @@ -0,0 +1,189 @@ +--- a/tools/bootstrap-recovery/isolated-keycape.py ++++ b/tools/bootstrap-recovery/isolated-keycape.py +@@ -322,6 +322,23 @@ + + + def run_verifier(session, admission, payload): ++ # Select from the already-restored config before further private/runtime reads. ++ # This is not public preflight before archive decryption or its key prompt. ++ import yaml ++ cfg = yaml.safe_load(base64.b64decode(payload['files']['/etc/keycape/config.yaml'],validate=True)) ++ if not isinstance(cfg,dict) or cfg.get('issuer') != admission['issuer']: ++ raise Refused() ++ consumer = admission['consumer'] ++ clients = cfg.get('clients') ++ if not isinstance(clients,list) or any(not isinstance(client,dict) for client in clients): ++ raise Refused() ++ matches = [client for client in clients if client.get('clientId') == consumer['client_id']] ++ if len(matches) != 1: ++ raise Refused() ++ client = matches[0] ++ if (client.get('secretRef') != 'env:'+consumer['secret_env'] or client.get('clientType') != 'confidential' ++ or 'client_credentials' not in client.get('grantTypes',[])): ++ raise Refused() + issuer = session['issuer'] + if {v['target'] for v in session.get('volumes',{}).values()}!={'/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls'}:raise Refused() + from urllib.parse import urlsplit +@@ -352,15 +369,7 @@ + if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}: + raise Refused() + equal() +- # Reading YAML is data parsing only; no archived executable is evaluated. +- import yaml +- cfg = yaml.safe_load(files['/etc/keycape/config.yaml']) +- if cfg['issuer'] != admission['issuer']: +- raise Refused() +- consumer = admission['consumer'] +- client = next(x for x in cfg['clients'] if x['clientId']==consumer['client_id']) +- if (client['secretRef']!='env:'+consumer['secret_env'] or client['clientType']!='confidential' +- or 'client_credentials' not in client['grantTypes'] or not env.get(consumer['secret_env'])): ++ if not env.get(consumer['secret_env']): + raise Refused() + from cryptography.hazmat.primitives import serialization + key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) +--- a/tests/test_isolated_keycape_recovery.py ++++ b/tests/test_isolated_keycape_recovery.py +@@ -53,6 +53,34 @@ + for row in self.manifest['files']: + if row['path'].endswith('/deployment/keycape.json'):row.update(bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest()) + with self.assertRaises(a.Refused):self.payload() ++ ++ ++class OriginalSelectorTests(unittest.TestCase): ++ """Already-restored public fixture config; no archive/key/native action.""" ++ def assert_refused_before_further_inputs(self,clients): ++ import yaml ++ cfg={'issuer':'https://issuer.example','clients':clients} ++ payload={'files':{'/etc/keycape/config.yaml':base64.b64encode(yaml.safe_dump(cfg).encode()).decode(), ++ '/etc/keycape/key.pem':'deliberately-not-base64'}} ++ admission={'issuer':'https://issuer.example','consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET'}} ++ # Empty session/no env and an undecodable key also expose early private access. ++ from contextlib import ExitStack ++ with ExitStack() as stack: ++ blocked=[stack.enter_context(patch.object(a,name,side_effect=AssertionError('later input or native call'))) ++ for name in ('container_file','runtime_file','runtime_files','command','check_jwks','process')] ++ with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) ++ for call in blocked:call.assert_not_called() ++ def client(self): ++ return {'clientId':'existing','clientType':'confidential','secretRef':'env:KEYCAPE_ORIGINAL_SECRET', ++ 'grantTypes':['client_credentials']} ++ def test_absent_original_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')]) ++ def test_identical_duplicate_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([self.client(),self.client()]) ++ def test_conflicting_duplicate_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')]) ++ def test_empty_registry_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([]) + + class NativeTests(unittest.TestCase): + def setUp(self): +--- a/tests/isolated-keycape-native-fixture-manifest.json ++++ b/tests/isolated-keycape-native-fixture-manifest.json +@@ -7,7 +7,7 @@ + "tests/run_isolated_keycape_native_fixture.py": "sha256:ecbadecc475622eaaf20a726110aebef5f4fe7af141110a98aca1640179b4a03", + "tests/test_identity_bundle.py": "sha256:be5ce74097594cc7f7e77dbccd6cb53aa72f263cd1bb442ce5464038aed1116c", + "tests/test_isolated_keycape_fixture_plan.py": "sha256:5945619f4c5957187763276cc900870a9f08f9475b63c240694688e0c2eca7dd", +- "tests/test_isolated_keycape_recovery.py": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55", ++ "tests/test_isolated_keycape_recovery.py": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea", + "tests/test_isolated_keycape_session.py": "sha256:cbdf51efde26eff337e9303a2c431f80b333b8846d763eb62853f81eb3f13e2c", + "tools/bootstrap-recovery/capture-identity.py": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705", + "tools/bootstrap-recovery/check-privacyidea-database.py": "sha256:90f454c87998d7f5d625e3c6656c3418f8f56275dc1879a9d19ed605431b94a4", +@@ -25,7 +25,7 @@ + "tools/bootstrap-recovery/inventory-scaleway.py": "sha256:a219df205708fa4ed44b763a418585d63c820c25434bc0fd14e805eb5c2f79d3", + "tools/bootstrap-recovery/inventory-storage-share.py": "sha256:673f9b17fb2f3fef6fcdb5c50a2bcca69e3df3157a9e5582a2d995c6b87640b5", + "tools/bootstrap-recovery/isolated-keycape-session.py": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22", +- "tools/bootstrap-recovery/isolated-keycape.py": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2", ++ "tools/bootstrap-recovery/isolated-keycape.py": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718", + "tools/bootstrap-recovery/isolated-lldap.py": "sha256:35bfa8411186ad936a199bd450c7e18c2ad51059301a6db9650e6bd055ab1b81", + "tools/bootstrap-recovery/isolated-privacyidea.py": "sha256:4df7196678aac1ad594f32abf45c68dc21a9d2760d9e8a536a215a4a3c5d277f", + "tools/bootstrap-recovery/prepare-identity-coverage.py": "sha256:cd5f3067d28b4c7cc93ed08b8cf3869218bdecf7c54b5dffed22d697de71dbb1", +@@ -81,7 +81,7 @@ + "synthetic_source_root": "private /dev/shm/nk49-keycape-fixture-", + "safe_result": "private /tmp/nk49-keycape-native-fixture-review-/result.json" + }, +- "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before", ++ "scope": "candidate itself on complete synthetic format/integrity archive fixture; no native PI/LLDAP/Authelia proof, real custody, real factor or real client credential; successor binds sealed-descriptor custody preparation sources; synthetic fixture itself overrides custody with generated fixture key as before; unexecuted exact-one-selector adapter successor: no new native outcome inferred from earlier fixtures", + "mutations": [ + "conditional creation of exact fresh local containers and local-driver tmpfs volumes", + "private synthetic file import to those volumes", +--- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md ++++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +@@ -1130,6 +1130,16 @@ + `recovery-owner-handoffs-r1` source review; independent ID/UUID/status/remote + readback is recorded separately when performed. + ++2026-10-17 source checkpoint refinement: the completed exact-one original ++selector guard and its bounded refusal/unique-selector proof are extracted into ++T38. T36 retains exact archive-to-selector binding, current actual service-owner ++recovery assent and outage-compatible private admission/consumer preparation. ++The current eight-field source-selector correspondence is evidenced separately; ++it does not complete those remaining obligations or any T18/T19 native gate. ++T33 continues to require the complete reviewed TLS/custody/admission packet. ++This extraction records one source outcome rather than counting it again as ++original registration validation or consumer continuity. ++ + ## Verify actual SOPS compatibility and sealed-descriptor read/write custody + + ```task +@@ -1170,6 +1180,51 @@ + T35 TLS/trust disposition and T36 original registration/private admission remain + open under their existing owner boundaries. + ++## Deliver exact-one original selector guard and bounded source refusal proof ++ ++```task ++id: NK-WP-0049-T38 ++status: done ++priority: high ++assignee: codex ++depends_on: [NK-WP-0049-T34] ++``` ++ ++Completed 2026-10-17 as source preparation, independently reviewed by the ++coordinating Custodian agent. The adapter now requires exactly one selected ++registration in the already-restored archive configuration before further runtime ++environment reads, signer-key parsing or native checker invocation. Absent, ++empty, identical-duplicate and conflicting-duplicate selectors refuse before ++those later inputs; the existing unique-selector mocked native path still passes. ++Current KeyCape Go configuration also rejects duplicate IDs; this makes the ++adapter's own boundary explicit and establishes no native duplicate exploit. ++The guard cannot run before archive decryption or the original key prompt. ++ ++The 39 adapter checks passed, including four added early-refusal regressions. ++Running those four cases against the retained original adapter failed the new ++refusal contract as expected. The broader 77-check source run retained 76 passes ++and one stale fixture-proposal source-hash refusal. Only the two affected hashes ++and scope of that unexecuted/unapproved successor proposal were then refreshed; ++all four affected fixture-plan checks passed. The original manifest preimage and ++failure receipt remain retained, and frozen actual R6 runtime receipts were not ++changed or claimed as proof of this successor. No broader native rerun occurred. ++ ++Evidence: Custodian ++`docs/changes/netkingdom-target-2026-10-17/native-identity-r1/`: ++`owner-source.patch`, `verification.json`, `manifest.json`, retained preimages, ++`original-behavior-regression.txt` and `focused-regressions.stderr.txt`. ++The later task extraction and exact workplan successor bytes are in ++`refinement-r2/`; the original source-proof packet remains immutable. ++Canonical owner publication, allocator-assigned Hub UUID and projection must be ++recorded separately through the normal owner process; none is claimed here. ++ ++This completes only the source guard/refusal deliverable extracted from T36. ++T35 original TLS public provenance/private custody or accepted reissue, T36 exact ++archive binding/current owner assent/consumer custody preparation, T33 complete ++attempt readiness, T18 actual recovery/consumer acceptance and T19 retained-factor ++MFA remain open. No actual archive, private key, Secret object, token exchange, ++OpenBao login, rotation, production action or owner assent was exercised. ++ + ## Accept remaining recovery and caller evidence and close the G08 handoff + + ```task +@@ -1189,7 +1244,7 @@ + G08 receiving the final evidence. The completed archive/job milestones remain + accepted independently of this final gate. + +-**Done when:** T02 and T15–T37 have their stated completed or explicitly accepted ++**Done when:** T02 and T15–T38 have their stated completed or explicitly accepted + handoff outcomes; service authentication/token/audit proof and current/legacy + caller dispositions are accepted; the source workplan and projected tasks agree; + and G08 has an exact evidence/handoff record. Record actionable residuals as live diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/routing-discovery.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/routing-discovery.json new file mode 100644 index 00000000..a3055a3a --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/routing-discovery.json @@ -0,0 +1,77 @@ +{ + "credential_request_performed": false, + "queries": [ + { + "query": "original KeyCape ingress TLS certificate recovery independent custody", + "candidates": [ + { + "id": "keycape-client-secret-generate", + "owner_repo": "railiance-platform", + "resolvable": false, + "warden_executes": false + }, + { + "id": "openrouter-llm-connect", + "owner_repo": "railiance-platform", + "resolvable": true, + "warden_executes": false + }, + { + "id": "openbao-structure-survey", + "owner_repo": "ops-mason", + "resolvable": false, + "warden_executes": false + }, + { + "id": "agent-harness-forgejo-deploy", + "owner_repo": "railiance-platform", + "resolvable": true, + "warden_executes": false + }, + { + "id": "key-cape-oidc-login", + "owner_repo": "key-cape", + "resolvable": false, + "warden_executes": false + } + ], + "interpretation": "Discovery only; no exact independent original TLS custody route or new credential authority inferred; unrelated generation/rotation lanes not selected." + }, + { + "query": "KeyCape secrets-engine-openbao client secret custody", + "candidates": [ + { + "id": "keycape-client-secret-generate", + "owner_repo": "railiance-platform", + "resolvable": false, + "warden_executes": false + }, + { + "id": "rapp-qonto-keycape-client", + "owner_repo": "key-cape", + "resolvable": true, + "warden_executes": false + }, + { + "id": "secrets-engine-approval-client-login", + "owner_repo": "railiance-platform", + "resolvable": true, + "warden_executes": false + }, + { + "id": "database-dynamic-credentials", + "owner_repo": "rapp-postgres", + "resolvable": false, + "warden_executes": false + }, + { + "id": "openbao-api-key", + "owner_repo": "railiance-platform", + "resolvable": false, + "warden_executes": false + } + ], + "interpretation": "Discovery only; no exact independent original TLS custody route or new credential authority inferred; unrelated generation/rotation lanes not selected." + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-preflight.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-preflight.json new file mode 100644 index 00000000..f552baf5 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-preflight.json @@ -0,0 +1,28 @@ +{ + "command": [ + "python3", + "tools/check-keycape-recovery-selector.py", + "--selector", + "docs/keycape-recovery-selector.json", + "--source-sha256", + "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0" + ], + "exit_code": 0, + "result": { + "schema": "secrets-engine.recovery-selector-preflight.v1", + "status": "source_selector_matches_not_native_assent", + "source_sha256": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0", + "consumer": { + "client_id": "secrets-engine-openbao", + "secret_env": "KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET", + "audience": "secrets-engine-openbao", + "scope": "openbao:login", + "subject": "service:secrets-engine", + "tenant": "tenant:platform", + "roles": "secrets-engine", + "deny_scope": "openbao:admin" + }, + "credential_source_exercised": false, + "network_contacted": false + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-uniqueness.patch b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-uniqueness.patch new file mode 100644 index 00000000..7d0f43b5 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/selector-uniqueness.patch @@ -0,0 +1,80 @@ +--- a/tools/bootstrap-recovery/isolated-keycape.py ++++ b/tools/bootstrap-recovery/isolated-keycape.py +@@ -322,6 +322,23 @@ + + + def run_verifier(session, admission, payload): ++ # Select from the already-restored config before further private/runtime reads. ++ # This is not public preflight before archive decryption or its key prompt. ++ import yaml ++ cfg = yaml.safe_load(base64.b64decode(payload['files']['/etc/keycape/config.yaml'],validate=True)) ++ if not isinstance(cfg,dict) or cfg.get('issuer') != admission['issuer']: ++ raise Refused() ++ consumer = admission['consumer'] ++ clients = cfg.get('clients') ++ if not isinstance(clients,list) or any(not isinstance(client,dict) for client in clients): ++ raise Refused() ++ matches = [client for client in clients if client.get('clientId') == consumer['client_id']] ++ if len(matches) != 1: ++ raise Refused() ++ client = matches[0] ++ if (client.get('secretRef') != 'env:'+consumer['secret_env'] or client.get('clientType') != 'confidential' ++ or 'client_credentials' not in client.get('grantTypes',[])): ++ raise Refused() + issuer = session['issuer'] + if {v['target'] for v in session.get('volumes',{}).values()}!={'/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls'}:raise Refused() + from urllib.parse import urlsplit +@@ -352,15 +369,7 @@ + if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}: + raise Refused() + equal() +- # Reading YAML is data parsing only; no archived executable is evaluated. +- import yaml +- cfg = yaml.safe_load(files['/etc/keycape/config.yaml']) +- if cfg['issuer'] != admission['issuer']: +- raise Refused() +- consumer = admission['consumer'] +- client = next(x for x in cfg['clients'] if x['clientId']==consumer['client_id']) +- if (client['secretRef']!='env:'+consumer['secret_env'] or client['clientType']!='confidential' +- or 'client_credentials' not in client['grantTypes'] or not env.get(consumer['secret_env'])): ++ if not env.get(consumer['secret_env']): + raise Refused() + from cryptography.hazmat.primitives import serialization + key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) +--- a/tests/test_isolated_keycape_recovery.py ++++ b/tests/test_isolated_keycape_recovery.py +@@ -53,6 +53,34 @@ + for row in self.manifest['files']: + if row['path'].endswith('/deployment/keycape.json'):row.update(bytes=len(raw),sha256=hashlib.sha256(raw).hexdigest()) + with self.assertRaises(a.Refused):self.payload() ++ ++ ++class OriginalSelectorTests(unittest.TestCase): ++ """Already-restored public fixture config; no archive/key/native action.""" ++ def assert_refused_before_further_inputs(self,clients): ++ import yaml ++ cfg={'issuer':'https://issuer.example','clients':clients} ++ payload={'files':{'/etc/keycape/config.yaml':base64.b64encode(yaml.safe_dump(cfg).encode()).decode(), ++ '/etc/keycape/key.pem':'deliberately-not-base64'}} ++ admission={'issuer':'https://issuer.example','consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET'}} ++ # Empty session/no env and an undecodable key also expose early private access. ++ from contextlib import ExitStack ++ with ExitStack() as stack: ++ blocked=[stack.enter_context(patch.object(a,name,side_effect=AssertionError('later input or native call'))) ++ for name in ('container_file','runtime_file','runtime_files','command','check_jwks','process')] ++ with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) ++ for call in blocked:call.assert_not_called() ++ def client(self): ++ return {'clientId':'existing','clientType':'confidential','secretRef':'env:KEYCAPE_ORIGINAL_SECRET', ++ 'grantTypes':['client_credentials']} ++ def test_absent_original_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')]) ++ def test_identical_duplicate_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([self.client(),self.client()]) ++ def test_conflicting_duplicate_selector_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')]) ++ def test_empty_registry_refused_before_further_inputs(self): ++ self.assert_refused_before_further_inputs([]) + + class NativeTests(unittest.TestCase): + def setUp(self): diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/source-references.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/source-references.json new file mode 100644 index 00000000..7094bdad --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/source-references.json @@ -0,0 +1,173 @@ +{ + "status": "pre_edit_reviewed_public_source_snapshot", + "references": [ + { + "repo": "net-kingdom", + "path": "AGENTS.md", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "SECURITY-COMPANION.md", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:06374445ca888549f1bf79527d1345d94918d7a7ec363160d8427d0e7a31d643", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "sso-mfa/k8s/keycape/ingress.yaml", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:bc5c7524a82de5e8b9755e7d7d408b4a66e034424cb2663c1d21352d292d5a72", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "tools/bootstrap-recovery/identity-backup-profile.json", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "tools/bootstrap-recovery/isolated-keycape.py", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "tools/bootstrap-recovery/isolated-keycape-session.py", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:8fa38efe28167b59a6307f342b2ac8fcda78ecda60e6228f22017424d2343c22", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "tools/bootstrap-recovery/prepare-isolated-keycape.py", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "tools/bootstrap-recovery/run-isolated-keycape.sh", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668", + "worktree_matches_head": true + }, + { + "repo": "net-kingdom", + "path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "head_observed": "70f408ca2389bf3722a91a03832fc6e8587355e5", + "worktree_sha256": "sha256:678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "AGENTS.md", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:1b98e24f9eb35c4c56b96ee7cbac21919bbe3b928144bfa7f29cca1c3249d5d0", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "src/secrets_engine/service_auth.py", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:c0ade429edf452ad17f05d690b7ebef091db7f1a42b5ac350f1e40955c8586c0", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "src/secrets_engine/engine_auth.py", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:e0479cf6d8c13233cf99dc39491143478c021597941ae8b6ba0e37957a42f330", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "docs/keycape-recovery-selector.json", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:02077af3c18b24f5e4a85992a3d4d0df51a8e458de1e48b48f7eb5f482257012", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "docs/keycape-isolated-recovery-selector.md", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:ed23b0df3d4b49e4b76df795455153c805971ccd37886836c960f550709e0739", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "tools/check-keycape-recovery-selector.py", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:e3e5e3ee743a212247701d6cb40fcf5b7f19349126fa9b32cbef9a3cc9459150", + "worktree_matches_head": true + }, + { + "repo": "secrets-engine", + "path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md", + "head_observed": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1", + "worktree_sha256": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b", + "worktree_matches_head": true + }, + { + "repo": "railiance-cluster", + "path": "AGENTS.md", + "head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6", + "worktree_sha256": "sha256:5cc7808a6d0e5cdebc7b3f13a0d7dce9cee5441ed6de4703b67cf3fe1800d45b", + "worktree_matches_head": true + }, + { + "repo": "railiance-cluster", + "path": "docs/keycape-tls-recovery-boundary.md", + "head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6", + "worktree_sha256": "sha256:f4bcb1d1832c566f9c87793ed2a461c8cd8a00859dc4ae66cd3c160d7ceefa70", + "worktree_matches_head": true + }, + { + "repo": "railiance-cluster", + "path": "tools/public-tls-metadata.py", + "head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6", + "worktree_sha256": "sha256:87c167e44f0fcf154c9f2afae2187bebd33e5f220c05f579c1233b58bfe4f30b", + "worktree_matches_head": true + }, + { + "repo": "railiance-cluster", + "path": "tools/cmd/railiance-backup-s2", + "head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6", + "worktree_sha256": "sha256:35c60b7ccccd7b4d5a1cf2134c1f2ca78c45040a7ffcc55f2c32c385a0a682a3", + "worktree_matches_head": true + }, + { + "repo": "railiance-cluster", + "path": "workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "head_observed": "6ae3f847c83da3402883453ee7110457bfb2d0d6", + "worktree_sha256": "sha256:96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b", + "worktree_matches_head": true + }, + { + "repo": "key-cape", + "path": "src/internal/config/validate.go", + "head_observed": "834b0d06a13bb2ece9cc98392cb39ba0e2167ecb", + "worktree_sha256": "sha256:8189ee82e7df74a2a4a1f53e213b1be0a5c737fd76d8f283f7ec9f8ed38c3a65", + "worktree_matches_head": true + }, + { + "repo": "emergent-security", + "path": "knowledge/cards/start.md", + "head_observed": "6eead2a922ae2eb81593213f54bf1f35e1c9970f", + "worktree_sha256": "sha256:698a18f4a8f97a43da75ed0767aa0425c970e17c04a9cbea75cfab719564cc5d", + "worktree_matches_head": true + }, + { + "repo": "emergent-security", + "path": "knowledge/cards/identity.md", + "head_observed": "6eead2a922ae2eb81593213f54bf1f35e1c9970f", + "worktree_sha256": "sha256:5137f088da301f2229d15f198e6b9a492f9e141eeb572cca37a44251f954fad0", + "worktree_matches_head": true + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/verification.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/verification.json new file mode 100644 index 00000000..2f286c8f --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/verification.json @@ -0,0 +1,70 @@ +{ + "status": "source_regressions_passed_not_native_assent", + "canonical_changed_paths": [ + "tools/bootstrap-recovery/isolated-keycape.py", + "tests/test_isolated_keycape_recovery.py", + "tests/isolated-keycape-native-fixture-manifest.json", + "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md" + ], + "changes": [ + { + "path": "tools/bootstrap-recovery/isolated-keycape.py", + "preimage_sha256": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2", + "postimage_sha256": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718" + }, + { + "path": "tests/test_isolated_keycape_recovery.py", + "preimage_sha256": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55", + "postimage_sha256": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea" + }, + { + "path": "tests/isolated-keycape-native-fixture-manifest.json", + "preimage_sha256": "sha256:1dcefbc7ca7b0c2be33135b1b7977b89ba657223ecbb1310cc691d151b3d916e", + "postimage_sha256": "sha256:936ee435be04b27f391391e7dda02def69e153bde3adcce92d569f33f308db2e" + }, + { + "path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "preimage_sha256": "sha256:678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "postimage_sha256": "sha256:5830c429f58a0317b28c7b4bcf22a1b46e6d01b41378cdae95f947c6d9317e44" + } + ], + "checks": [ + { + "command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape_recovery.py", + "tests": 39, + "exit_code": 0, + "evidence": "tool result; includes existing full unique-selector mocked flow and four new pre-further-input refusal tests" + }, + { + "command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape*.py", + "tests": 77, + "pass": 76, + "errors": 1, + "exit_code": 1, + "evidence": "focused-regressions.stderr.txt", + "finding": "unexecuted source manifest correctly refused changed adapter/test hashes; retained before two-hash/scope update" + }, + { + "command": "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p test_isolated_keycape_fixture_plan.py", + "tests": 4, + "exit_code": 0, + "evidence": "tool result; only affected fixture-plan checks repeated after two-hash/scope refresh" + }, + { + "command": "git diff --check -- four changed paths", + "exit_code": 0 + }, + { + "command": "new refusal regressions against retained original adapter bytes", + "tests": 4, + "errors": 4, + "expected_original_contract_failure": true, + "evidence": "original-behavior-regression.txt" + } + ], + "limit": "All fixtures synthetic/mocked. Exact-one check runs on already-restored config, not before decryption or initial key prompt; no runtime action or credential source performed. Current native Go validation also rejects duplicate IDs.", + "review_status": "pending root independent review; no owner publication/sync performed", + "hub_writes": false, + "frozen_runtime_receipts_changed": false, + "task_status_changes": false +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/assemble_review.py b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/assemble_review.py new file mode 100644 index 00000000..687ff9de --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/assemble_review.py @@ -0,0 +1,240 @@ +"""Rebuild source-only registration review; no native calls or source mutation.""" +from pathlib import Path +import ast +import dataclasses +import datetime +import hashlib +import importlib.util +import json +import subprocess +import sys + +sys.dont_write_bytecode = True +import yaml + +HERE = Path(__file__).resolve().parent +CUST = HERE.parents[3] +NK = Path('/home/worsch/net-kingdom') +WARDEN = Path('/home/worsch/ops-warden') +AUDIT = Path('/home/worsch/audit-core') +PLATFORM = Path('/home/worsch/railiance-platform') +CHECKER = Path('/tmp/nk-checker-environment-r2-rebuild/keycape') +CHECKER_DIGEST = 'sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5' +REGISTER = NK / 'sso-mfa/k8s/keycape/keycape-registration-adapter.py' +refs = {} + +def sha(data): + return 'sha256:' + hashlib.sha256(data).hexdigest() + +def source(path, symbols=()): + path = Path(path) + raw = path.read_bytes() + item = {'path': str(path), 'sha256': sha(raw), 'bytes': len(raw)} + if path.suffix == '.py': + tree = ast.parse(raw) + item['symbols'] = {n.name: {'line': n.lineno, 'end_line': n.end_lineno} + for n in ast.walk(tree) if isinstance(n, (ast.FunctionDef, ast.ClassDef)) + and n.name in symbols} + refs[str(path)] = item + return raw + + +def emit(name, value): + (HERE / name).write_text(json.dumps(value, indent=2, sort_keys=True) + '\n') + +before_paths = [NK / 'security-case-types/oidc-browser-relying-party/type.yaml', + NK / 'security-cases/forgejo-netkingdom-oidc.yaml', + NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml', + NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml', + NK / 'security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json', + NK / 'workplans/NK-WP-0048-security-case-types.md'] +before = {str(p): sha(source(p)) for p in before_paths} +for p in [NK / 'AGENTS.md', WARDEN / 'AGENTS.md', NK / 'SECURITY-COMPANION.md', + WARDEN / 'INTENT.md', NK / 'canon/standards/security-case-types_v0.1.md', + NK / 'docs/security-case-execution-owner-review.md', + NK / 'sso-mfa/k8s/keycape/registration-adapter.md', + WARDEN / 'docs/security-case-execution-kernel-v1.md', + WARDEN / 'workplans/WARDEN-WP-0044-security-case-follow-through.md', + AUDIT / 'docs/audit-backend-contract.md', + CUST / 'docs/changes/netkingdom-target-2026-10-16/browser-checker-environment-r2/build-receipt.json', + CUST / 'docs/changes/netkingdom-target-2026-10-16/browser-checker-artifact-next/coordinator-build-review.json']: + source(p) +source(REGISTER, ['build', 'source_digest', 'descriptor', 'execute', 'verify', 'checker_snapshot']) +source(WARDEN / 'src/warden/case_run.py', ['Journal', 'load', 'save', 'Executor', 'admit', 'run', 'rollback', 'reconcile', '_attempt', '_result']) +source(WARDEN / 'src/warden/case_receipt_state.py', ['recover', 'begin_rollback']) +source(WARDEN / 'src/warden/case_inputs.py', ['BrowserInputs', 'target']) +source(NK / 'tools/security-case-types/security_case_evidence.py', ['read_journal', 'check_steps', 'audit']) +source(NK / 'tools/security-case-types/security_case_validator.py', ['load_type', 'validate_execution_descriptors']) +source(NK / 'sso-mfa/k8s/keycape/test_keycape_registration_adapter.py', ['test_process_loss_does_not_reconstruct_created_authority', 'test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo']) +source(AUDIT / 'audit_core/ingestion.py', ['_read', 'normalize']) +source(AUDIT / 'audit_core/senders.py', ['SenderIdentity', 'evidence_declaration']) +source(AUDIT / 'audit_core/interface.py', ['AuditEvent', 'AcceptResult']) +source(PLATFORM / 'scripts/keycape_client_secret_generate.py', ['check_case', 'run', 'record_state_hub']) + +# Generate the one existing real owner descriptor from current maintained source. +# Importing this source installs no adapters and performs no tooling operation. +sys.path.insert(0, str(WARDEN / 'src')) +spec = importlib.util.spec_from_file_location('registration_review_adapter', REGISTER) +adapter = importlib.util.module_from_spec(spec) +spec.loader.exec_module(adapter) +from warden.case_run import Descriptor +for name in adapter.SOURCE_FILES: + source(REGISTER.parent / name) +checker_bytes = CHECKER.read_bytes() +if sha(checker_bytes) != CHECKER_DIGEST: + raise SystemExit('reviewed existing checker bytes no longer match; stop') +source(CHECKER) +desc = adapter.descriptor(CHECKER_DIGEST) +descriptor_bytes = json.dumps(dataclasses.asdict(desc), sort_keys=True, separators=(',', ':')).encode() +if Descriptor.decode(descriptor_bytes) != desc: + raise SystemExit('actual owner descriptor decode failed') +(HERE / 'register-client.proposed-descriptor.json').write_bytes(descriptor_bytes) + +# Preserve real source versions and list every actual follow-through boundary. +types = {} +for version, root in [('1.1', NK / 'security-case-types'), ('1.2', NK / 'security-case-type-revisions/1.2')]: + typ = yaml.safe_load((root / 'oidc-browser-relying-party/type.yaml').read_text()) + types[version] = typ + if typ['spec'].get('execution_descriptors'): + raise SystemExit('owner source gained descriptor admission; review must be refreshed') + +remaining = { + 'ensure-groups': {'owner': 'net-kingdom', 'existing_seam': 'identity-provisioner governed journal T14 with delivered PostgreSQL T21', + 'missing': ['native dedicated CNPG consumer, checkpoint holder and backup/lost-store continuity', 'authoritative tenant/case/source/principal callbacks', 'all LDAP writers fenced or provider CAS/ABA exclusion', 'exact owner adapter/source/descriptor and revocation evidence; existing legacy ensure/revoke is not created-only undo'], + 'rollback': 'Only independently authenticated created groups/memberships; preserve shared/preexisting membership and unresolved intents.'}, + 'mint-secret': {'owner': 'railiance-platform', 'existing_seam': 'scripts/keycape_client_secret_generate.py; RPF-WP-0054 and existing broker lane', + 'missing': ['fixed kernel Adapter/Descriptor for exact admitted case/type and broker source', 'authoritative case materialization receipt and original CAS0 uncertainty reconciliation', 'independent broker-grant AND parent-session revocation receipts for exact current attempt'], + 'rollback': 'Never regenerate after uncertain write; read-only metadata reconciliation does not establish creation or retry authority; owner custody delete only if exact created-only entitlement.'}, + 'deliver-secret': {'owner': 'railiance-platform', 'existing_seam': 'existing ESO delivery/role and structural materialization boundary', + 'missing': ['exact delivery object UID/ownerReference prestate and admitted owner adapter', 'current Ready status/readback without value access', 'independent cleanup/revocation receipt and owner custody identity'], + 'rollback': 'Delete only authenticated case-created delivery objects, preserve preexisting target and shared resources.'}, + 'bind-env': {'owner': 'net-kingdom', 'existing_seam': 'existing sso/keycape Deployment prerequisite checked by keycape-client.py; T12', + 'missing': ['reviewed fixed exact Deployment UID/resourceVersion/env binding update adapter', 'created-only prestate/readback and owner evidence/session capabilities', 'separately reviewed quiet-window restart/readiness procedure; registry helper only reports restart_required'], + 'rollback': 'Restore only exact case-created env binding under current revision; a whole Deployment rollback or deleting preexisting env is not admitted.'}, + 'register-client': {'owner': 'net-kingdom', 'existing_seam': 'keycape-registration-adapter.py build/publish/authenticate/revoke_session injection seam', + 'missing': ['actual admitted durable owner publisher/authenticator and exact parent-session revoker', 'native executable storage/provenance and exact descriptor/type source admission', 'T15 original-attempt recovery contract; fresh adapter intentionally cannot undo prior-process creation'], + 'rollback': 'Same-process authenticated successful creation only; exact original entry and unchanged postcreation UID/resourceVersion; post-restart stays refused.'}, + 'deliver-consumer-secret': {'owner': 'railiance-apps for Forgejo', 'existing_seam': 'acknowledged source1.2 dedicated SA/namespace SecretStore/ExternalSecret composition', + 'missing': ['actual installed ESO TokenRequest/RBAC compatibility and consumer owner admission', 'fixed owner adapter/descriptor for exact identities with created/preexisting readback', 'receiver evidence for Ready status and case-issued token revocation/expiry'], + 'rollback': 'Revert consumer reference first; delete only authenticated created UID/ownerReference resources; SA/Store deletion alone does not immediately revoke OpenBao tokens.'}, + 'hand-over': {'owner': 'railiance-apps for Forgejo', 'existing_seam': 'consumer owner OIDC configuration and groups enforcement path', + 'missing': ['owner exact deployment/source adapter/descriptor and accepted issuer/client/delivery binding', 'actual human login/group-denial and public authorization/MFA pin verifications', 'rollback and native receipt/custody acceptance'], + 'rollback': 'Remove only this case-created OIDC source; preserve shared/preexisting auth sources and consumer state.'}, +} +composition = [] +for step in types['1.2']['spec']['follow_through']: + name = step['id']; item = remaining[name] + composition.append({'step': name, 'source_order': len(composition) + 1, + 'declared_owner': step['owner'], 'resolved_first_consumer_owner': item['owner'], + 'exists_in_default_1_1': name in [s['id'] for s in types['1.1']['spec']['follow_through']], + 'source_step': step, 'existing_seam': item['existing_seam'], + 'candidate_descriptor': json.loads(descriptor_bytes) if name == 'register-client' else None, + 'candidate_descriptor_digest': sha(descriptor_bytes) if name == 'register-client' else None, + 'missing_exact_owner_facts': item['missing'], 'rollback_requirement': item['rollback'], + 'native_owner_assent': False, 'dispatch_permitted': False}) +if set(remaining) != {s['id'] for s in types['1.2']['spec']['follow_through']}: + raise SystemExit('composition is incomplete for actual1.2 step inventory') + +emit('descriptor-composition.json', { + 'schema': 'custodian.registration-descriptor-review.v1', + 'purpose': 'Review inventory only; this is not a Warden descriptor bundle or accepted SecurityCaseType.', + 'source_versions': {v: {'status': t['spec']['status'], 'step_count': len(t['spec']['follow_through']), 'machine_descriptor_map_present': False} for v, t in types.items()}, + 'proposed_version_selection': {'first_consumer': 'Forgejo', 'review_base': 'explicit source-only oidc-browser-relying-party@1.2', + 'why': 'Its dedicated consumer SA/ESO authentication boundary expresses the reviewed six-object structural design;1.1 does not.', + 'default_loader': 'Keep canonical1.1 unchanged; select1.2 only through existing explicit version-root option for source review.', + 'canonical_case': 'Keep1.1 accepted history unchanged and1.2 example proposed without acceptance fields.', + 'descriptor_revision': 'Do not edit acknowledged source1.1/1.2 in place or inherit old acknowledgment for new descriptor bytes. Allocate the exact successor revision/version through NetKingdom canon section6 after the complete owner-reviewed set exists.', + 'classification': 'Exact closed execution references and any changed trust/materialization/authentication must be classified by the existing owner; changed trust/authentication requires informed-decision acknowledgment, never self-classified as harmless validation.'}, + 'checker': {'path': str(CHECKER), 'sha256': CHECKER_DIGEST, 'bytes': len(checker_bytes), 'native_custody_admitted': False, + 'runtime_contract': 'Current owner adapter rehashes source/file, snapshots exact checker into sealed memfd, executes same snapshot for live/proposed checks with empty environment; this does not establish parent-directory/interpreter/kernel custody.'}, + 'register_descriptor': {'path': 'register-client.proposed-descriptor.json', 'sha256': sha(descriptor_bytes), 'owner_source_composition': desc.adapter_source, + 'decode': 'Actual Warden Descriptor.decode round-trip passed; no Executor admission or tooling invocation performed.'}, + 'composition': composition, + 'verification_inventory': types['1.2']['spec']['verification'], + 'rollback_inventory': types['1.2']['spec']['rollback'], + 'run_order_and_completion': [ + 'Accepted exact case source and independently verified six-object native structural materialization before follow-through; a file status or rendered bundle is insufficient.', + 'Preserve existing source follow-through order. Delivery Ready and exact Deployment env prerequisite before registry apply. Separate quiet-window restart/readiness after checked registration before real sign-in; registry changed receipt alone is not service activation.', + 'Warden rechecks actual caller principal/actor/lane before each admitted dispatch. A session revoked at a step cannot be reused for later steps; owner must define fresh-session or admitted run-envelope grouping without weakening parent-session revocation.', + 'Mint must carry separately authenticated broker-grant and parent-session revocation; every completed step requires independently authenticated owner and session evidence.', + 'Verification is the complete declared positive/negative inventory plus actual human login/group denial. Reverse only independently confirmed creations, retaining uncertain intents and preserving shared/preexisting objects.' + ], + 'complete_executable_descriptor_set': False, + 'missing_descriptor_steps': [s['step'] for s in composition if s['candidate_descriptor'] is None], + 'native_complete': False, 'execution_permitted': False, +}) + +emit('original-attempt-review.json', { + 'schema': 'custodian.registration-original-attempt-review.v1', + 'task': 'NK-WP-0048-T15', 'disposition': 'Existing seams inspected; no admitted original-attempt holder/readback matches. Source contract review only; recovery remains refused.', + 'actual_source_findings': [ + {'source': str(REGISTER), 'symbol': 'build/execute/verify', 'fact': 'records and creation live only in the build closure; original payload publication is injected. Rebuilding the Adapter loses original creation, even if caller retains OwnerResult. Adapter.reconcile is absent.'}, + {'source': str(WARDEN / 'src/warden/case_run.py'), 'symbol': 'Journal.save/load', 'fact': 'Durable rows keep attempt_id/operation and exact pins/created history but only digest(evidence identifier), digest(session reference) and digest(grant reference), not original owner payload or recoverable evidence identifier. Journal.load returns StepState and drops persisted attempt context.'}, + {'source': str(WARDEN / 'src/warden/case_run.py'), 'symbol': 'Executor.run/reconcile/_attempt', 'fact': 'Crash recovery appends recovered state without invocation/evidence; historical intent rows remain but latest may have no original attempt identity. reconcile creates a fresh attempt identity and calls Adapter.reconcile(new_invocation), supplying no original attempt reference.'}, + {'source': str(NK / 'tools/security-case-types/security_case_evidence.py'), 'symbol': 'read_journal/check_steps', 'fact': 'Read-only compatibility projection takes latest rows and explicitly returns native_authenticated false. It is not a holder authenticator or recovery authority.'}, + {'source': str(AUDIT / 'audit_core/ingestion.py'), 'symbol': '_read/normalize', 'fact': 'Existing authenticated POST/v1/events and privileged tenant-filtered GET/v1/events/{event_id} can supply custody/readback, but this source review found no registration publisher/class admission or owner authenticator wiring to that surface. Generic custody readiness is not creation attribution.'}, + {'source': str(AUDIT / 'audit_core/senders.py'), 'symbol': 'SenderIdentity', 'fact': 'Sender credential restricts allowed source/tenant; may_write does not imply may_read. Evidence defaults attributive; rollback-load-bearing source requires explicit owner declaration and emission atomicity/detection contract.'} + ], + 'reviewed_existing_holder_candidates': [ + {'holder': 'Warden private SQLite Journal', 'use': 'Original intent/sequence lookup from existing immutable history rows after source/owner integrity checks.', 'not_sufficient': 'Has only hashed evidence references and reducer state; it cannot authenticate original creation or supply missing owner bytes.'}, + {'holder': 'Actual registration owner publish/authenticate callbacks', 'use': 'The existing fixed injected owner capability is the intended successful-attempt custody seam.', 'not_sufficient': 'No native implementation, named holder or authenticated readback capability is present. The in-test dict authenticator is synthetic only.'}, + {'holder': 'Audit Core existing event custody/readback', 'use': 'A concrete existing provider to consider, with source/tenant-scoped sender and separate reader through existing owner admission process.', 'not_sufficient': 'Not selected or admitted for registration; no invented registration sender, token, event authority, runtime verifier or new backend is created.'}, + {'holder': 'State Hub progress/request, JSON receipt, current matching registry', 'use': 'Diagnostic/source references only.', 'not_sufficient': 'No creation custody/provenance guarantee. A current matching entry cannot distinguish an original successful write from preexisting or same-byte foreign creation.'} + ], + 'proposed_recovery_sequence_through_existing_seams': [ + 'Re-admit exact case/type/descriptor/catalog/acceptance and new current caller principal/actor/lane through normal Executor.admit. No old session is resurrected.', + 'Under existing Journal process lock, owner retrieves original intended run attempt from immutable history: exact step/target/pins and original attempt_id/operation. Fresh reconcile attempt_id is distinct and must never substitute for this original identity.', + 'The selected admitted owner lookup authenticates exact original netkingdom.keycape-registration.attempt.v1 bytes by original attempt_id and admitted source scope. A case-supplied path, JSON payload or evidence identifier is not a capability. Journal fingerprints only detect correspondence after independent authentication.', + 'Validate original payload against original full Invocation, current admission pins, reviewed adapter/helper/checker source, created-only SUCCESS (not NO_CHANGE), exact owner/target, before/after UID/resourceVersion and original session-revocation evidence. Tenant/realm provenance must come from the actual admitted owner/session context; Invocation has no independent tenant field, so do not add a caller label as a substitute.', + 'Independently attest original result/session evidence; inspect current native registry through the maintained contained owner helper and match original exact created entry plus unchanged postcreation UID/resourceVersion. Hash equality alone and same client_id are insufficient.', + 'Bind lookup result and original provenance to the NEW reconcile attempt and newly revoked parent-session evidence. Preserve original record and current uncertainty. Only after owner-reviewed provenance hydration and normal kernel verification could subsequent independently authorized rollback consider that exact creation.', + 'If original receipt was never durably published, is missing/ambiguous/stale, shows NO_CHANGE, mismatches tenant/case/source/principal, or native revision drifted, retain UNCERTAIN and refuse add replay and undo. Do not infer FAILED_BEFORE from missing evidence. Lost-write/readback cases require attended owner reconciliation; no automatic creation attribution is introduced.' + ], + 'minimal_exact_owner_facts_before_implementation': [ + {'owner': 'ops-warden; existing WARDEN-WP-0044-T03', 'fact': 'Approve exact original-intent lookup in existing Journal history and how original Invocation/evidence identifier is handed to a fixed reconciler alongside the fresh reconcile Invocation. Current method supplies only fresh attempt. Preserve historical rows and current no-replay behavior.'}, + {'owner': 'NetKingdom registration evidence owner with Warden admission', 'fact': 'Name the actual existing publish/authenticate holder and its bounded authenticated original-attempt readback; supply public interface/source/tenant/principal provenance references and loss/unavailable/ambiguous dispositions. No secret value or new backend is requested.'}, + {'owner': 'audit-core only if actual selected holder', 'fact': 'Admit the registration source/event class and load-bearing completeness/intent-to-result custody contract, concrete event-id/original-attempt mapping, normalized-data equality/redaction policy and separate tenant-scoped reader. Generic POST acceptance or counts do not authenticate native creation.'}, + {'owner': 'Warden caller-session/revocation owner', 'fact': 'Name actual original and current session evidence purposes and verifier/capability source; original revocation does not authorize a new session, and each new reconcile/rollback attempt must revoke its own parent.'} + ], + 'targeted_existing_fixture_coverage': {'not_rerun': True, 'source': str(NK / 'sso-mfa/k8s/keycape/test_keycape_registration_adapter.py'), + 'existing_cases': ['test_process_loss_does_not_reconstruct_created_authority', 'test_missing_or_tampered_evidence_never_verifies_or_authorizes_undo', 'test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo'], + 'limits': 'Current synthetic Kubernetes/dict trust tests prove refusal; none supply original native custody. No duplicate fixture framework or fake native tests added.'}, + 'implementation_disposition': 'No source guard/adapter change is justified until the listed existing owner contracts identify authority. Existing fail-closed behavior is retained.', + 'task_done': False, 'native_acceptance': False, 'retry_authorized': False, 'rollback_authorized': False, +}) + +# Read-only source selection demonstrates the actual default/version boundaries. +cli = NK / 'tools/security-case-types/security_case_validator.py' +commands = [ + [sys.executable, '-B', str(cli), 'render', str(before_paths[1]), '--types', str(NK / 'security-case-types'), '--repos-root', '/home/worsch', '--allow-unimplemented'], + [sys.executable, '-B', str(cli), 'render', str(before_paths[3]), '--types', str(NK / 'security-case-types'), '--version-root', '1.2=' + str(NK / 'security-case-type-revisions/1.2'), '--repos-root', '/home/worsch', '--allow-unimplemented'], + [sys.executable, '-B', str(cli), 'validate-case', str(before_paths[3]), '--types', str(NK / 'security-case-types'), '--version-root', '1.2=' + str(NK / 'security-case-type-revisions/1.2')] +] +results=[] +for command in commands: + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, env={'PATH': '/usr/bin:/bin', 'PYTHONDONTWRITEBYTECODE': '1'}) + row = {'argv': command, 'returncode': result.returncode, 'stdout_sha256': sha(result.stdout), 'stderr': result.stderr.decode()} + if result.returncode == 0 and command[3] == 'render': + data=json.loads(result.stdout); row.update(type=data['type'], render_digest=data['digest'], execution_permitted=data['execution']['permitted']) + results.append(row) +if [r['returncode'] for r in results] != [0,0,1] or any(r.get('execution_permitted') is not False for r in results[:2]): + raise SystemExit('actual source-selection/refusal behavior changed; inspect results') +after = {str(p): sha(p.read_bytes()) for p in before_paths} +if before != after: + raise SystemExit('reviewed canonical bytes changed during source inspection') +emit('source-verification.json', {'observed_at': datetime.datetime.now(datetime.timezone.utc).isoformat(), + 'checks': results, 'canonical_pre_post_hashes_equal': True, 'canonical_hashes': after, + 'descriptor_round_trip': True, 'checker_rehash_matches_delivered_artifact': True, + 'closed_descriptor_count': 1, 'complete_review_step_count': len(composition), + 'native_execution': False, 'tests_added_or_rerun': False, + 'knowledge': {'package_version': '0.2.6', 'package_digest': '8d1d6a9d4d07fec7b619618de7dfe2254c1790f85f4198c7fe19db9751c02', + 'cards': ['start','evidence'], 'status': 'withheld source changed; direct owner source reviewed, no offline guidance used as authority'}}) +audit_path = CUST / 'docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json' +if sha(audit_path.read_bytes()) != 'sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2': + raise SystemExit('immutable prior audit changed') +emit('source-manifest.json', {'sources': list(refs.values()), 'original_audit_immutable': { + 'path': str(CUST / 'docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json'), + 'expected_sha256': 'sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2'}}) +print(json.dumps({'descriptor_sha256': sha(descriptor_bytes), 'descriptor_owner_source': desc.adapter_source, + 'complete_step_inventory': len(composition), 'source_checks': [r['returncode'] for r in results], + 'native_authority': False})) diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/descriptor-composition.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/descriptor-composition.json new file mode 100644 index 00000000..8add7051 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/descriptor-composition.json @@ -0,0 +1,402 @@ +{ + "checker": { + "bytes": 13633409, + "native_custody_admitted": false, + "path": "/tmp/nk-checker-environment-r2-rebuild/keycape", + "runtime_contract": "Current owner adapter rehashes source/file, snapshots exact checker into sealed memfd, executes same snapshot for live/proposed checks with empty environment; this does not establish parent-directory/interpreter/kernel custody.", + "sha256": "sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5" + }, + "complete_executable_descriptor_set": false, + "composition": [ + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "net-kingdom", + "dispatch_permitted": false, + "existing_seam": "identity-provisioner governed journal T14 with delivered PostgreSQL T21", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "native dedicated CNPG consumer, checkpoint holder and backup/lost-store continuity", + "authoritative tenant/case/source/principal callbacks", + "all LDAP writers fenced or provider CAS/ABA exclusion", + "exact owner adapter/source/descriptor and revocation evidence; existing legacy ensure/revoke is not created-only undo" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "net-kingdom", + "rollback_requirement": "Only independently authenticated created groups/memberships; preserve shared/preexisting membership and unresolved intents.", + "source_order": 1, + "source_step": { + "attended": true, + "attended_justification": "The provisioner's only HTTP credential is user-engine's runtime token, and its NetworkPolicy admits only user-engine pods. A proxy lane would act as user-engine (ops-warden review R8; canon section 3; ops-warden ADR-0002). Running it in the session register-client already needs adds no attended session. It can become unattended once the provisioner has an operator credential of its own and an admitted path.", + "auth": "operator cluster access in the attended register-client session; the in-pod call uses the provisioner's own directory binding, and no provisioner or user-engine token is read or sent", + "entry_point": "identity-provisioner ensure_service_groups, run inside the provisioner pod through the session's contained cluster access (groups {access_groups}; members exactly {initial_members} as recorded in the accepted case, nothing else)", + "id": "ensure-groups", + "lane": "key-cape-oidc-login", + "owner": "net-kingdom", + "value_handling": "none", + "warden_executes": false + }, + "step": "ensure-groups" + }, + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "railiance-platform", + "dispatch_permitted": false, + "existing_seam": "scripts/keycape_client_secret_generate.py; RPF-WP-0054 and existing broker lane", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "fixed kernel Adapter/Descriptor for exact admitted case/type and broker source", + "authoritative case materialization receipt and original CAS0 uncertainty reconciliation", + "independent broker-grant AND parent-session revocation receipts for exact current attempt" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "railiance-platform", + "rollback_requirement": "Never regenerate after uncertain write; read-only metadata reconciliation does not establish creation or retry authority; owner custody delete only if exact created-only entitlement.", + "source_order": 2, + "source_step": { + "attended": false, + "auth": "the caller's broker grant for the case's KV path, through its lane; the value is generated in custody and never returned", + "entry_point": "railiance-platform credential broker: generate a client secret inside custody at bao:platform/workloads/keycape/{client_id}", + "id": "mint-secret", + "lane": "keycape-client-secret-generate", + "owner": "railiance-platform", + "value_handling": "generated_in_custody", + "warden_executes": true, + "when": "client_type == confidential" + }, + "step": "mint-secret" + }, + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "railiance-platform", + "dispatch_permitted": false, + "existing_seam": "existing ESO delivery/role and structural materialization boundary", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "exact delivery object UID/ownerReference prestate and admitted owner adapter", + "current Ready status/readback without value access", + "independent cleanup/revocation receipt and owner custody identity" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "railiance-platform", + "rollback_requirement": "Delete only authenticated case-created delivery objects, preserve preexisting target and shared resources.", + "source_order": 3, + "source_step": { + "attended": false, + "auth": "railiance-platform ESO delivery through role external-secrets-keycape-{client_id}; no value leaves custody", + "entry_point": "ExternalSecret sso/keycape-{client_id}-client (key client-secret) from bao:platform/workloads/keycape/{client_id}", + "id": "deliver-secret", + "owner": "railiance-platform", + "ready_check": "the delivery for sso/keycape-{client_id}-client reports Ready=True (status only, no value read)", + "value_handling": "none", + "warden_executes": false, + "when": "client_type == confidential" + }, + "step": "deliver-secret" + }, + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "net-kingdom", + "dispatch_permitted": false, + "existing_seam": "existing sso/keycape Deployment prerequisite checked by keycape-client.py; T12", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "reviewed fixed exact Deployment UID/resourceVersion/env binding update adapter", + "created-only prestate/readback and owner evidence/session capabilities", + "separately reviewed quiet-window restart/readiness procedure; registry helper only reports restart_required" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "net-kingdom", + "rollback_requirement": "Restore only exact case-created env binding under current revision; a whole Deployment rollback or deleting preexisting env is not admitted.", + "source_order": 4, + "source_step": { + "attended": true, + "attended_justification": "A change to the live identity provider's Deployment. It runs in the same attended operator session as register-client, before it, because KeyCape resolves a confidential client's secret at start and fails closed if the binding is missing.", + "auth": "operator kube credentials for namespace sso", + "entry_point": "patch Deployment sso/keycape: env KEYCAPE_{client_id:env}_CLIENT_SECRET from sso/keycape-{client_id}-client", + "id": "bind-env", + "lane": "key-cape-oidc-login", + "owner": "net-kingdom", + "value_handling": "none", + "warden_executes": false, + "when": "client_type == confidential" + }, + "step": "bind-env" + }, + { + "candidate_descriptor": { + "actor": "human", + "adapter": "net-kingdom/keycape-registration@v1", + "adapter_source": "sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1", + "allowed_created": [ + "keycape-client" + ], + "effect": "change", + "lane": "key-cape-oidc-login", + "owner": "net-kingdom", + "retry_safe": false, + "revocation_scopes": [ + "parent-session" + ], + "step": "register-client", + "target_parameter": "client_id", + "version": "warden.case.execution.v1" + }, + "candidate_descriptor_digest": "sha256:1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa", + "declared_owner": "net-kingdom", + "dispatch_permitted": false, + "existing_seam": "keycape-registration-adapter.py build/publish/authenticate/revoke_session injection seam", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "actual admitted durable owner publisher/authenticator and exact parent-session revoker", + "native executable storage/provenance and exact descriptor/type source admission", + "T15 original-attempt recovery contract; fresh adapter intentionally cannot undo prior-process creation" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "net-kingdom", + "rollback_requirement": "Same-process authenticated successful creation only; exact original entry and unchanged postcreation UID/resourceVersion; post-restart stays refused.", + "source_order": 5, + "source_step": { + "attended": true, + "attended_justification": "The live KeyCape client registry is a Kubernetes Secret, and agents do not read or write Secrets. Until KeyCape loads clients from a non-secret registry with secrets referenced from custody, one attended operator session applies the rendered registration. ops-warden groups all attended steps of a run into that one session. KeyCape loads clients at startup and keeps login, authorization and handoff state in memory, so the restart drops in-flight logins and sessions for every client; runs go in a quiet window (key-cape type review R4). The rendered registry must pass KeyCape's own startup checks (keycape check-config, key-cape c528daa, which keycape-client.py runs before it patches) before the restart: a refused entry stops the single replica and every client loses sign-in (R1).", + "auth": "operator write access to the live KeyCape client registry in namespace sso", + "entry_point": "sso-mfa/k8s/keycape/keycape-client.py apply --client-file --case-acceptance --check-config (net-kingdom.keycape-client-registration)", + "id": "register-client", + "lane": "key-cape-oidc-login", + "owner": "net-kingdom", + "value_handling": "none", + "warden_executes": false + }, + "step": "register-client" + }, + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "{consumer_owner_repo}", + "dispatch_permitted": false, + "existing_seam": "acknowledged source1.2 dedicated SA/namespace SecretStore/ExternalSecret composition", + "exists_in_default_1_1": false, + "missing_exact_owner_facts": [ + "actual installed ESO TokenRequest/RBAC compatibility and consumer owner admission", + "fixed owner adapter/descriptor for exact identities with created/preexisting readback", + "receiver evidence for Ready status and case-issued token revocation/expiry" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "railiance-apps for Forgejo", + "rollback_requirement": "Revert consumer reference first; delete only authenticated created UID/ownerReference resources; SA/Store deletion alone does not immediately revoke OpenBao tokens.", + "source_order": 6, + "source_step": { + "attended": false, + "auth": "Consumer owner contained Kubernetes deployment authority; ESO authenticates to OpenBao role external-secrets-keycape-{client_id}-{consuming_service} with a TokenRequest for the dedicated namespaced serviceAccountRef; controller remains trusted", + "entry_point": "Owner applies dedicated ServiceAccount {consumer_namespace}/{consuming_service}-keycape-{client_id}-eso (automount=false, no legacy tokens), namespace SecretStore openbao-keycape-{client_id}-consumer with serviceAccountRef and audiences [openbao], and ExternalSecret {consuming_service}-netkingdom-oidc-client with Owner target, Retain remote deletion and only CLIENT_SECRET from workloads/keycape/{client_id}. Admission validates actual installed ESO TokenRequest support and common controller RBAC before any owner-approved apply.", + "id": "deliver-consumer-secret", + "owner": "{consumer_owner_repo}", + "ready_check": "Namespace SecretStore and ExternalSecret both report Ready=True; dedicated SA has no legacy token refs; status and fixed metadata only, never Secret values.", + "value_handling": "none", + "warden_executes": false, + "when": "client_type == confidential" + }, + "step": "deliver-consumer-secret" + }, + { + "candidate_descriptor": null, + "candidate_descriptor_digest": null, + "declared_owner": "{consumer_owner_repo}", + "dispatch_permitted": false, + "existing_seam": "consumer owner OIDC configuration and groups enforcement path", + "exists_in_default_1_1": true, + "missing_exact_owner_facts": [ + "owner exact deployment/source adapter/descriptor and accepted issuer/client/delivery binding", + "actual human login/group-denial and public authorization/MFA pin verifications", + "rollback and native receipt/custody acceptance" + ], + "native_owner_assent": false, + "resolved_first_consumer_owner": "railiance-apps for Forgejo", + "rollback_requirement": "Remove only this case-created OIDC source; preserve shared/preexisting auth sources and consumer state.", + "source_order": 7, + "source_step": { + "attended": false, + "auth": "the consumer owner's own deployment path", + "entry_point": "configure {consuming_service} with issuer {issuer}, client {client_id} and custody bao:platform/workloads/keycape/{client_id}, and make it require one of {access_groups} in the groups claim before sign-in completes", + "id": "hand-over", + "owner": "{consumer_owner_repo}", + "value_handling": "none", + "warden_executes": false + }, + "step": "hand-over" + } + ], + "execution_permitted": false, + "missing_descriptor_steps": [ + "ensure-groups", + "mint-secret", + "deliver-secret", + "bind-env", + "deliver-consumer-secret", + "hand-over" + ], + "native_complete": false, + "proposed_version_selection": { + "canonical_case": "Keep1.1 accepted history unchanged and1.2 example proposed without acceptance fields.", + "classification": "Exact closed execution references and any changed trust/materialization/authentication must be classified by the existing owner; changed trust/authentication requires informed-decision acknowledgment, never self-classified as harmless validation.", + "default_loader": "Keep canonical1.1 unchanged; select1.2 only through existing explicit version-root option for source review.", + "descriptor_revision": "Do not edit acknowledged source1.1/1.2 in place or inherit old acknowledgment for new descriptor bytes. Allocate the exact successor revision/version through NetKingdom canon section6 after the complete owner-reviewed set exists.", + "first_consumer": "Forgejo", + "review_base": "explicit source-only oidc-browser-relying-party@1.2", + "why": "Its dedicated consumer SA/ESO authentication boundary expresses the reviewed six-object structural design;1.1 does not." + }, + "purpose": "Review inventory only; this is not a Warden descriptor bundle or accepted SecurityCaseType.", + "register_descriptor": { + "decode": "Actual Warden Descriptor.decode round-trip passed; no Executor admission or tooling invocation performed.", + "owner_source_composition": "sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1", + "path": "register-client.proposed-descriptor.json", + "sha256": "sha256:1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa" + }, + "rollback_inventory": [ + { + "action": "remove the OIDC source for {client_id} from {consuming_service} (owner {consumer_owner_repo})", + "reverses": "hand-over" + }, + { + "action": "After reverting consumer secret reference, delete only authenticated created ExternalSecret/owned target by UID and ownerReference, then SecretStore and dedicated SA; preserve preexisting-matched resources and never delete a shared target. Retain audit and ownership receipts; removing SecretStore/SA alone is not immediate OpenBao token revocation.", + "reverses": "deliver-consumer-secret", + "when": "client_type == confidential" + }, + { + "action": "keycape-client.py apply --operation remove for {client_id}", + "reverses": "register-client" + }, + { + "action": "remove env KEYCAPE_{client_id:env}_CLIENT_SECRET from Deployment sso/keycape, after register-client is reversed", + "reverses": "bind-env", + "when": "client_type == confidential" + }, + { + "action": "delete ExternalSecret sso/keycape-{client_id}-client and its target", + "reverses": "deliver-secret", + "when": "client_type == confidential" + }, + { + "action": "covered by client-secret-path: one metadata delete, after deliver-secret is reversed", + "reverses": "mint-secret", + "when": "client_type == confidential" + }, + { + "action": "identity-provisioner revoke_service_groups inside the provisioner pod (attended, as ensure-groups) with the case's memberships; delete_if_empty only if no other case uses {access_groups}", + "reverses": "ensure-groups" + }, + { + "action": "delete metadata and all versions at platform/workloads/keycape/{client_id}, after the ExternalSecret is gone (this also reverses mint-secret)", + "reverses": "client-secret-path", + "when": "client_type == confidential" + }, + { + "action": "delete Kubernetes-auth role external-secrets-keycape-{client_id}", + "reverses": "eso-role", + "when": "client_type == confidential" + }, + { + "action": "delete policy workload-kv-read-keycape-{client_id}-eso, after eso-role", + "reverses": "keycape-reader-policy", + "when": "client_type == confidential" + }, + { + "action": "Delete only this case-created role external-secrets-keycape-{client_id}-{consuming_service}, before deleting consumer-reader-policy; revoke case-issued OpenBao tokens or prove expiration before declaring deactivation.", + "reverses": "consumer-eso-role", + "when": "client_type == confidential" + }, + { + "action": "delete policy workload-kv-read-keycape-{client_id}-{consuming_service}", + "reverses": "consumer-reader-policy", + "when": "client_type == confidential" + }, + { + "action": "remove catalog entry {consuming_service}-keycape-client", + "reverses": "catalog-entry" + } + ], + "run_order_and_completion": [ + "Accepted exact case source and independently verified six-object native structural materialization before follow-through; a file status or rendered bundle is insufficient.", + "Preserve existing source follow-through order. Delivery Ready and exact Deployment env prerequisite before registry apply. Separate quiet-window restart/readiness after checked registration before real sign-in; registry changed receipt alone is not service activation.", + "Warden rechecks actual caller principal/actor/lane before each admitted dispatch. A session revoked at a step cannot be reused for later steps; owner must define fresh-session or admitted run-envelope grouping without weakening parent-session revocation.", + "Mint must carry separately authenticated broker-grant and parent-session revocation; every completed step requires independently authenticated owner and session evidence.", + "Verification is the complete declared positive/negative inventory plus actual human login/group denial. Reverse only independently confirmed creations, retaining uncertain intents and preserving shared/preexisting objects." + ], + "schema": "custodian.registration-descriptor-review.v1", + "source_versions": { + "1.1": { + "machine_descriptor_map_present": false, + "status": "acknowledged", + "step_count": 6 + }, + "1.2": { + "machine_descriptor_map_present": false, + "status": "acknowledged", + "step_count": 7 + } + }, + "verification_inventory": [ + { + "check": "GET {issuer}/authorize with client {client_id} and each of {redirect_uris} returns the login page", + "expect": "present", + "id": "authorize-accepts-redirects", + "reads_secret_value": false + }, + { + "check": "GET {issuer}/authorize with client {client_id} and an unregistered redirect returns an OAuth error", + "expect": "deny", + "id": "authorize-refuses-other-redirect", + "reads_secret_value": false + }, + { + "check": "a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/{client_id}", + "expect": "deny", + "id": "custody-denied-to-default", + "reads_secret_value": false, + "when": "client_type == confidential" + }, + { + "check": "policy workload-kv-read-keycape-{client_id}-{consuming_service} grants read on bao:platform/workloads/keycape/{client_id} (capabilities check only)", + "expect": "allow", + "id": "custody-allowed-to-consumer", + "reads_secret_value": false, + "when": "client_type == confidential" + }, + { + "check": "LLDAP groups {access_groups} exist, with exactly the memberships of the accepted case added", + "expect": "present", + "id": "groups-present", + "reads_secret_value": false + }, + { + "check": "{consuming_service}'s OIDC source for {client_id} (owner {consumer_owner_repo}) requires one of {access_groups} in the groups claim (configuration read, no secret value)", + "expect": "present", + "id": "consumer-enforces-groups", + "reads_secret_value": false + }, + { + "check": "the delivery for sso/keycape-{client_id}-client reports Ready=True (status only)", + "expect": "present", + "id": "secret-delivered", + "reads_secret_value": false, + "when": "client_type == confidential" + }, + { + "check": "keycape-client.py inspect for {client_id} shows the MFA pin on the registered client (non-secret client view)", + "expect": "present", + "id": "mfa-pinned", + "reads_secret_value": false, + "when": "mfa_required == true" + }, + { + "check": "{consumer_namespace} SecretStore openbao-keycape-{client_id}-consumer and ExternalSecret {consuming_service}-netkingdom-oidc-client Ready=True, exact dedicated SA/audience role binding, fixed CLIENT_SECRET mapping; no Secret value read", + "expect": "present", + "id": "consumer-secret-delivered", + "reads_secret_value": false, + "when": "client_type == confidential" + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/manifest.json new file mode 100644 index 00000000..b4f59f74 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/manifest.json @@ -0,0 +1,44 @@ +{ + "files": [ + { + "path": "assemble_review.py", + "sha256": "554cc213824098e3b3599d9e801330a28aea72f19336b7492adacebbf84d62f4", + "bytes": 25834 + }, + { + "path": "descriptor-composition.json", + "sha256": "e097abe5f7b149e5688850cfb0ef7793a1b3206388b52f069b51137f6ca92170", + "bytes": 22885 + }, + { + "path": "original-attempt-review.json", + "sha256": "d0df5c45f53f7d61ac54589e55b09f1c9cff098ade63e5853e434ced8f83fe3c", + "bytes": 8753 + }, + { + "path": "register-client.proposed-descriptor.json", + "sha256": "1b86e9032845ec35a58d88a9f1108dbb7d8cee0c9c9176d4a694b893d9d7a3fa", + "bytes": 413 + }, + { + "path": "source-manifest.json", + "sha256": "33c475045cfe958bab5b7545783dea497427373448c83c1859888550e965c104", + "bytes": 10433 + }, + { + "path": "source-verification.json", + "sha256": "2ed179ecdcda85a29b0e86e7e19274fdce408d154e4e79f61bbccc80304c8dfd", + "bytes": 4054 + }, + { + "path": "summary.json", + "sha256": "3ede75b2d55190fb41236a92c4d2ed157be04c819ab5226e5d9c404d87d51bdd", + "bytes": 1878 + }, + { + "path": "work-record-proposal.json", + "sha256": "0aec5c8a8473232d1800c6c3b70661dd1412271e57effe0d7f19242201897134", + "bytes": 3009 + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/original-attempt-review.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/original-attempt-review.json new file mode 100644 index 00000000..4c18f1a7 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/original-attempt-review.json @@ -0,0 +1,101 @@ +{ + "actual_source_findings": [ + { + "fact": "records and creation live only in the build closure; original payload publication is injected. Rebuilding the Adapter loses original creation, even if caller retains OwnerResult. Adapter.reconcile is absent.", + "source": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-registration-adapter.py", + "symbol": "build/execute/verify" + }, + { + "fact": "Durable rows keep attempt_id/operation and exact pins/created history but only digest(evidence identifier), digest(session reference) and digest(grant reference), not original owner payload or recoverable evidence identifier. Journal.load returns StepState and drops persisted attempt context.", + "source": "/home/worsch/ops-warden/src/warden/case_run.py", + "symbol": "Journal.save/load" + }, + { + "fact": "Crash recovery appends recovered state without invocation/evidence; historical intent rows remain but latest may have no original attempt identity. reconcile creates a fresh attempt identity and calls Adapter.reconcile(new_invocation), supplying no original attempt reference.", + "source": "/home/worsch/ops-warden/src/warden/case_run.py", + "symbol": "Executor.run/reconcile/_attempt" + }, + { + "fact": "Read-only compatibility projection takes latest rows and explicitly returns native_authenticated false. It is not a holder authenticator or recovery authority.", + "source": "/home/worsch/net-kingdom/tools/security-case-types/security_case_evidence.py", + "symbol": "read_journal/check_steps" + }, + { + "fact": "Existing authenticated POST/v1/events and privileged tenant-filtered GET/v1/events/{event_id} can supply custody/readback, but this source review found no registration publisher/class admission or owner authenticator wiring to that surface. Generic custody readiness is not creation attribution.", + "source": "/home/worsch/audit-core/audit_core/ingestion.py", + "symbol": "_read/normalize" + }, + { + "fact": "Sender credential restricts allowed source/tenant; may_write does not imply may_read. Evidence defaults attributive; rollback-load-bearing source requires explicit owner declaration and emission atomicity/detection contract.", + "source": "/home/worsch/audit-core/audit_core/senders.py", + "symbol": "SenderIdentity" + } + ], + "disposition": "Existing seams inspected; no admitted original-attempt holder/readback matches. Source contract review only; recovery remains refused.", + "implementation_disposition": "No source guard/adapter change is justified until the listed existing owner contracts identify authority. Existing fail-closed behavior is retained.", + "minimal_exact_owner_facts_before_implementation": [ + { + "fact": "Approve exact original-intent lookup in existing Journal history and how original Invocation/evidence identifier is handed to a fixed reconciler alongside the fresh reconcile Invocation. Current method supplies only fresh attempt. Preserve historical rows and current no-replay behavior.", + "owner": "ops-warden; existing WARDEN-WP-0044-T03" + }, + { + "fact": "Name the actual existing publish/authenticate holder and its bounded authenticated original-attempt readback; supply public interface/source/tenant/principal provenance references and loss/unavailable/ambiguous dispositions. No secret value or new backend is requested.", + "owner": "NetKingdom registration evidence owner with Warden admission" + }, + { + "fact": "Admit the registration source/event class and load-bearing completeness/intent-to-result custody contract, concrete event-id/original-attempt mapping, normalized-data equality/redaction policy and separate tenant-scoped reader. Generic POST acceptance or counts do not authenticate native creation.", + "owner": "audit-core only if actual selected holder" + }, + { + "fact": "Name actual original and current session evidence purposes and verifier/capability source; original revocation does not authorize a new session, and each new reconcile/rollback attempt must revoke its own parent.", + "owner": "Warden caller-session/revocation owner" + } + ], + "native_acceptance": false, + "proposed_recovery_sequence_through_existing_seams": [ + "Re-admit exact case/type/descriptor/catalog/acceptance and new current caller principal/actor/lane through normal Executor.admit. No old session is resurrected.", + "Under existing Journal process lock, owner retrieves original intended run attempt from immutable history: exact step/target/pins and original attempt_id/operation. Fresh reconcile attempt_id is distinct and must never substitute for this original identity.", + "The selected admitted owner lookup authenticates exact original netkingdom.keycape-registration.attempt.v1 bytes by original attempt_id and admitted source scope. A case-supplied path, JSON payload or evidence identifier is not a capability. Journal fingerprints only detect correspondence after independent authentication.", + "Validate original payload against original full Invocation, current admission pins, reviewed adapter/helper/checker source, created-only SUCCESS (not NO_CHANGE), exact owner/target, before/after UID/resourceVersion and original session-revocation evidence. Tenant/realm provenance must come from the actual admitted owner/session context; Invocation has no independent tenant field, so do not add a caller label as a substitute.", + "Independently attest original result/session evidence; inspect current native registry through the maintained contained owner helper and match original exact created entry plus unchanged postcreation UID/resourceVersion. Hash equality alone and same client_id are insufficient.", + "Bind lookup result and original provenance to the NEW reconcile attempt and newly revoked parent-session evidence. Preserve original record and current uncertainty. Only after owner-reviewed provenance hydration and normal kernel verification could subsequent independently authorized rollback consider that exact creation.", + "If original receipt was never durably published, is missing/ambiguous/stale, shows NO_CHANGE, mismatches tenant/case/source/principal, or native revision drifted, retain UNCERTAIN and refuse add replay and undo. Do not infer FAILED_BEFORE from missing evidence. Lost-write/readback cases require attended owner reconciliation; no automatic creation attribution is introduced." + ], + "retry_authorized": false, + "reviewed_existing_holder_candidates": [ + { + "holder": "Warden private SQLite Journal", + "not_sufficient": "Has only hashed evidence references and reducer state; it cannot authenticate original creation or supply missing owner bytes.", + "use": "Original intent/sequence lookup from existing immutable history rows after source/owner integrity checks." + }, + { + "holder": "Actual registration owner publish/authenticate callbacks", + "not_sufficient": "No native implementation, named holder or authenticated readback capability is present. The in-test dict authenticator is synthetic only.", + "use": "The existing fixed injected owner capability is the intended successful-attempt custody seam." + }, + { + "holder": "Audit Core existing event custody/readback", + "not_sufficient": "Not selected or admitted for registration; no invented registration sender, token, event authority, runtime verifier or new backend is created.", + "use": "A concrete existing provider to consider, with source/tenant-scoped sender and separate reader through existing owner admission process." + }, + { + "holder": "State Hub progress/request, JSON receipt, current matching registry", + "not_sufficient": "No creation custody/provenance guarantee. A current matching entry cannot distinguish an original successful write from preexisting or same-byte foreign creation.", + "use": "Diagnostic/source references only." + } + ], + "rollback_authorized": false, + "schema": "custodian.registration-original-attempt-review.v1", + "targeted_existing_fixture_coverage": { + "existing_cases": [ + "test_process_loss_does_not_reconstruct_created_authority", + "test_missing_or_tampered_evidence_never_verifies_or_authorizes_undo", + "test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo" + ], + "limits": "Current synthetic Kubernetes/dict trust tests prove refusal; none supply original native custody. No duplicate fixture framework or fake native tests added.", + "not_rerun": true, + "source": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/test_keycape_registration_adapter.py" + }, + "task": "NK-WP-0048-T15", + "task_done": false +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/register-client.proposed-descriptor.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/register-client.proposed-descriptor.json new file mode 100644 index 00000000..4d378f8e --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/register-client.proposed-descriptor.json @@ -0,0 +1 @@ +{"actor":"human","adapter":"net-kingdom/keycape-registration@v1","adapter_source":"sha256:7db1caa4d1e73e8f65b6744af53bcdce628bcd86732f74bdc125f85c531a22d1","allowed_created":["keycape-client"],"effect":"change","lane":"key-cape-oidc-login","owner":"net-kingdom","retry_safe":false,"revocation_scopes":["parent-session"],"step":"register-client","target_parameter":"client_id","version":"warden.case.execution.v1"} \ No newline at end of file diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-manifest.json new file mode 100644 index 00000000..072d2b89 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-manifest.json @@ -0,0 +1,323 @@ +{ + "original_audit_immutable": { + "expected_sha256": "sha256:ab803e795af61fd027f5930d127592316133de38b68a8fe61b89a1f9803a9ff2", + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json" + }, + "sources": [ + { + "bytes": 16474, + "path": "/home/worsch/net-kingdom/security-case-types/oidc-browser-relying-party/type.yaml", + "sha256": "sha256:f705c64e4875e9b8e18a912fb51c135e77898926d6a451f5cb74ab3c0cbe4d1c" + }, + { + "bytes": 1717, + "path": "/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml", + "sha256": "sha256:bcc2c6d5bae0d28242b3cdb71e74d8ca297c2afe04766b55d53597f86893351d" + }, + { + "bytes": 19052, + "path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml", + "sha256": "sha256:9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578" + }, + { + "bytes": 722, + "path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml", + "sha256": "sha256:1c868c1da7d9077fae97bc6bc029706ec3dc418cfeaae30dc0f92b5b4ba6f2ab" + }, + { + "bytes": 4214, + "path": "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json", + "sha256": "sha256:2dcc220febf125a17b3769f7014f18b63979d7121e0f7056a2b0d8b1ae6031b0" + }, + { + "bytes": 60503, + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "sha256:b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f" + }, + { + "bytes": 11186, + "path": "/home/worsch/net-kingdom/AGENTS.md", + "sha256": "sha256:95158b1d5c15e6cf8be980f5c0e3b48aeef252654846273887f40516b3fa6a78" + }, + { + "bytes": 13132, + "path": "/home/worsch/ops-warden/AGENTS.md", + "sha256": "sha256:aa03031516b886b254d8c4b1fafa160c063c74aa0115ba51af3dd7326dccfad6" + }, + { + "bytes": 12019, + "path": "/home/worsch/net-kingdom/SECURITY-COMPANION.md", + "sha256": "sha256:06374445ca888549f1bf79527d1345d94918d7a7ec363160d8427d0e7a31d643" + }, + { + "bytes": 23003, + "path": "/home/worsch/ops-warden/INTENT.md", + "sha256": "sha256:3e9382fefa52ee0970dfac133cc799656e5034760b26dccc1bf9bab65fc538d9" + }, + { + "bytes": 10233, + "path": "/home/worsch/net-kingdom/canon/standards/security-case-types_v0.1.md", + "sha256": "sha256:a4fda906d5138d2594a1f8d047c7c28e1cdf96b1eae051f543b9a5e5852bcb5e" + }, + { + "bytes": 8821, + "path": "/home/worsch/net-kingdom/docs/security-case-execution-owner-review.md", + "sha256": "sha256:0f1637bfddbbdf50d336974791b7fbf4646efe7e32ca04beb3bf52effd0a28e6" + }, + { + "bytes": 5229, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/registration-adapter.md", + "sha256": "sha256:2fadcbd28e34566173428bcb92e42ac464ef73c03909072d0fc2ee988b175e29" + }, + { + "bytes": 8813, + "path": "/home/worsch/ops-warden/docs/security-case-execution-kernel-v1.md", + "sha256": "sha256:0eb563dbaea739fba928d04708c2c2bdac592783bbe68e1271041b0d1b1994cb" + }, + { + "bytes": 13901, + "path": "/home/worsch/ops-warden/workplans/WARDEN-WP-0044-security-case-follow-through.md", + "sha256": "sha256:1df57687200f6a60a2a6f26a4066ce1e93ae663fc4e43db3884d04dc1d6e874e" + }, + { + "bytes": 13867, + "path": "/home/worsch/audit-core/docs/audit-backend-contract.md", + "sha256": "sha256:a80ebeac99bd88b1ec55a2c0c3a25220749908e237d7d3c048f7e867bb0a9b1a" + }, + { + "bytes": 1917, + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/browser-checker-environment-r2/build-receipt.json", + "sha256": "sha256:1a3bb61a958afdbe46664384963a53e275a5a6b53741bda9244e28f58b4453ff" + }, + { + "bytes": 1073, + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-16/browser-checker-artifact-next/coordinator-build-review.json", + "sha256": "sha256:621702e9149d59fa187af2f6e5d140dab3b261bbe25a02bbc1f0ac5f0731b233" + }, + { + "bytes": 11813, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-registration-adapter.py", + "sha256": "sha256:d7e3643cc794223dfaa310775eacbbeb4d353f9382e4481322d704d6b7ab1c51", + "symbols": {} + }, + { + "bytes": 27272, + "path": "/home/worsch/ops-warden/src/warden/case_run.py", + "sha256": "sha256:afb5ce9c59b9748f85c9f1d4af04b255087632c58de8dcd8c9426fc1ed4db068", + "symbols": { + "Executor": { + "end_line": 710, + "line": 320 + }, + "Journal": { + "end_line": 317, + "line": 183 + }, + "_attempt": { + "end_line": 575, + "line": 566 + }, + "_result": { + "end_line": 532, + "line": 490 + }, + "admit": { + "end_line": 488, + "line": 344 + }, + "load": { + "end_line": 274, + "line": 221 + }, + "reconcile": { + "end_line": 710, + "line": 646 + }, + "rollback": { + "end_line": 644, + "line": 613 + }, + "run": { + "end_line": 611, + "line": 577 + }, + "save": { + "end_line": 317, + "line": 276 + } + } + }, + { + "bytes": 5456, + "path": "/home/worsch/ops-warden/src/warden/case_receipt_state.py", + "sha256": "sha256:a2cda7f187e77bd76d4d209505638de44a587fae0bc033ec75c23ee9ea9f73bc", + "symbols": { + "begin_rollback": { + "end_line": 138, + "line": 134 + }, + "recover": { + "end_line": 120, + "line": 114 + } + } + }, + { + "bytes": 4438, + "path": "/home/worsch/ops-warden/src/warden/case_inputs.py", + "sha256": "sha256:1334b0cd9897e763cfea2d306e997c659f3f284ecc3f9612140c2104835da7c7", + "symbols": { + "BrowserInputs": { + "end_line": 98, + "line": 42 + }, + "target": { + "end_line": 98, + "line": 48 + } + } + }, + { + "bytes": 11783, + "path": "/home/worsch/net-kingdom/tools/security-case-types/security_case_evidence.py", + "sha256": "sha256:da8efa59c52ad73283397ebe639ae259d0cb9c6348b5cb829135c24230dcdc75", + "symbols": { + "audit": { + "end_line": 205, + "line": 193 + }, + "check_steps": { + "end_line": 190, + "line": 131 + }, + "read_journal": { + "end_line": 128, + "line": 103 + } + } + }, + { + "bytes": 36729, + "path": "/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py", + "sha256": "sha256:1bcc62e9bc374c711363295549f3cd5bb0b32952671ed4b08fddc7f74742959b", + "symbols": { + "load_type": { + "end_line": 452, + "line": 419 + }, + "validate_execution_descriptors": { + "end_line": 215, + "line": 194 + } + } + }, + { + "bytes": 17073, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/test_keycape_registration_adapter.py", + "sha256": "sha256:cc5956d811db031e437ebca60bf70eb41177c87db75cc9478fe84075ad224464", + "symbols": { + "test_kernel_lost_readback_retains_uncertain_and_refuses_replay_and_undo": { + "end_line": 305, + "line": 289 + }, + "test_process_loss_does_not_reconstruct_created_authority": { + "end_line": 215, + "line": 209 + } + } + }, + { + "bytes": 38172, + "path": "/home/worsch/audit-core/audit_core/ingestion.py", + "sha256": "sha256:f5a225a204cf77d0ac5aa49298f2e4acd6f559e47fa4f19407672486537e97c6", + "symbols": { + "_read": { + "end_line": 333, + "line": 247 + }, + "normalize": { + "end_line": 679, + "line": 625 + } + } + }, + { + "bytes": 20214, + "path": "/home/worsch/audit-core/audit_core/senders.py", + "sha256": "sha256:bc091ce63dc2cd0fcdc9f26423b258cb94a6db863daced6706c11dba3bbf67e1", + "symbols": { + "SenderIdentity": { + "end_line": 185, + "line": 44 + }, + "evidence_declaration": { + "end_line": 156, + "line": 139 + } + } + }, + { + "bytes": 7438, + "path": "/home/worsch/audit-core/audit_core/interface.py", + "sha256": "sha256:4ecc5f6bdfe04181cce02ec5547fbfded0101868085909f315ea7d4c9eb9b573", + "symbols": { + "AcceptResult": { + "end_line": 146, + "line": 142 + }, + "AuditEvent": { + "end_line": 117, + "line": 82 + } + } + }, + { + "bytes": 9872, + "path": "/home/worsch/railiance-platform/scripts/keycape_client_secret_generate.py", + "sha256": "sha256:9576cd211cfc06526ec4cc9bd0a5b06f0f59287a68931bb2d6e3592a951ddc7d", + "symbols": { + "check_case": { + "end_line": 123, + "line": 98 + }, + "record_state_hub": { + "end_line": 191, + "line": 181 + }, + "run": { + "end_line": 178, + "line": 126 + } + } + }, + { + "bytes": 15565, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/keycape-client.py", + "sha256": "sha256:4b63161cf3365d34dd684a3116e2c935baaf7f6aa4b30983f6883546db3d6591", + "symbols": {} + }, + { + "bytes": 7017, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/portal-client-rollout.py", + "sha256": "sha256:158e1d36eb881cdd0a2eda91b472adea5e8fde5061e00d26dda368580aeb871f", + "symbols": {} + }, + { + "bytes": 13089, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/openbao-client-config.py", + "sha256": "sha256:1b908b4c36134212d78f9fbe7a2a201eb3ced06d31bb1dcea4a59d80689d84b1", + "symbols": {} + }, + { + "bytes": 1691, + "path": "/home/worsch/net-kingdom/sso-mfa/k8s/keycape/register-user-engine-portal.py", + "sha256": "sha256:67173edc44f5457e7b6a3e0fb2321b398159cfce5dea8ead01eabf835fb38d76", + "symbols": {} + }, + { + "bytes": 13633409, + "path": "/tmp/nk-checker-environment-r2-rebuild/keycape", + "sha256": "sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5" + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-verification.json b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-verification.json new file mode 100644 index 00000000..4278a4f9 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-registration-r1/source-verification.json @@ -0,0 +1,87 @@ +{ + "canonical_hashes": { + "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/decision/acknowledgment.json": "sha256:2dcc220febf125a17b3769f7014f18b63979d7121e0f7056a2b0d8b1ae6031b0", + "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml": "sha256:1c868c1da7d9077fae97bc6bc029706ec3dc418cfeaae30dc0f92b5b4ba6f2ab", + "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/type.yaml": "sha256:9e60ff569fb0d860a2bbde7bbb0991a54d4b0688f62b56df0fa5d161fd624578", + "/home/worsch/net-kingdom/security-case-types/oidc-browser-relying-party/type.yaml": "sha256:f705c64e4875e9b8e18a912fb51c135e77898926d6a451f5cb74ab3c0cbe4d1c", + "/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml": "sha256:bcc2c6d5bae0d28242b3cdb71e74d8ca297c2afe04766b55d53597f86893351d", + "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md": "sha256:b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f" + }, + "canonical_pre_post_hashes_equal": true, + "checker_rehash_matches_delivered_artifact": true, + "checks": [ + { + "argv": [ + "/usr/bin/python3", + "-B", + "/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py", + "render", + "/home/worsch/net-kingdom/security-cases/forgejo-netkingdom-oidc.yaml", + "--types", + "/home/worsch/net-kingdom/security-case-types", + "--repos-root", + "/home/worsch", + "--allow-unimplemented" + ], + "execution_permitted": false, + "render_digest": "sha256:e64b56e4590b57b858303fcda1a474693e3dd821bc83df26646fe78fc345498a", + "returncode": 0, + "stderr": "", + "stdout_sha256": "sha256:186461a1dc2d587ccc0cc9ea6e51f05214d6cfe94f4aa0764e3150ab197ad3cf", + "type": "oidc-browser-relying-party@1.1" + }, + { + "argv": [ + "/usr/bin/python3", + "-B", + "/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py", + "render", + "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml", + "--types", + "/home/worsch/net-kingdom/security-case-types", + "--version-root", + "1.2=/home/worsch/net-kingdom/security-case-type-revisions/1.2", + "--repos-root", + "/home/worsch", + "--allow-unimplemented" + ], + "execution_permitted": false, + "render_digest": "sha256:c0afd5576cdae0cbc807eccb2b9fa87ac668f15e32ec7cf79d295bdb23c75b35", + "returncode": 0, + "stderr": "", + "stdout_sha256": "sha256:96b25108335e2cf5f96af481fe8a7735831c8320d81b50f7c6e6d4e53d0c0f02", + "type": "oidc-browser-relying-party@1.2" + }, + { + "argv": [ + "/usr/bin/python3", + "-B", + "/home/worsch/net-kingdom/tools/security-case-types/security_case_validator.py", + "validate-case", + "/home/worsch/net-kingdom/security-case-type-revisions/1.2/oidc-browser-relying-party/examples/forgejo.yaml", + "--types", + "/home/worsch/net-kingdom/security-case-types", + "--version-root", + "1.2=/home/worsch/net-kingdom/security-case-type-revisions/1.2" + ], + "returncode": 1, + "stderr": "ERROR case.spec.type: type 'oidc-browser-relying-party' is 'acknowledged'; only implemented types accept cases\n", + "stdout_sha256": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ], + "closed_descriptor_count": 1, + "complete_review_step_count": 7, + "descriptor_round_trip": true, + "knowledge": { + "cards": [ + "start", + "evidence" + ], + "package_digest": "8d1d6a9d4d07fec7b619618de7dfe2254c1790f85f4198c7fe19db9751c02", + "package_version": "0.2.6", + "status": "withheld source changed; direct owner source reviewed, no offline guidance used as authority" + }, + "native_execution": false, + "observed_at": "2026-10-17T02:10:28.924934+00:00", + "tests_added_or_rerun": false +}