diff --git a/docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json b/docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json new file mode 100644 index 00000000..00dd05a3 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-gates-r1/native-gate-audit.json @@ -0,0 +1,3643 @@ +{ + "schema": "netkingdom-native-gate-audit.v1", + "observed_at": "2026-10-17T02:04:44.628210+00:00", + "scope": "Source and Hub GET read-only audit; artifact-only write, no privileged APIs, private reads, messages, canonical updates, workplans or test reruns.", + "summary": { + "total_gates": 16, + "native_accepted": 0, + "native_open": 16, + "owner_source_files": 30, + "verified_task_bindings": 200, + "all_workplan_statuses_match": true, + "all_task_statuses_and_parents_match": true + }, + "completed_do_not_repeat": [ + "STATE-WP-0095 all10tasks done; owner200cbd0a; exact approved guard image4cc4 atHelm77 and8native rollback cases,18CURRENT rows unchanged", + "RMGR-WP-0019 all6tasks done; owner3bcb1e1c; ordinary Cluster pipeline20/20bindings/frozen3omitted", + "RMGR-WP-0021-T05 done; actual six configured-hook clean/key/unavailable cases and independent cleanup accepted", + "NK-WP-0048-T20 andT21 done; source/disposable LLDAP/PostgreSQL proof", + "NK-WP-0049-T37 done;65actual SOPS regression cases" + ], + "authority": { + "mode": "supervised", + "runtime_enforcement_not_inferred": true, + "autopilot_granted": false, + "new_privileged_proposals_owned_by": "root with fresh exact supervisor approval as required", + "residual_freeze": "APPROVAL-WP-0002 source and Hub flavor residual; Hub flavor_promotion_reason null. Reference its evidence requirements, do not implement without explicit scoped promotion." + }, + "source_refs": [ + { + "path": "/home/worsch/the-custodian/AGENTS.md", + "sha256": "633f3026fec7a00e75b7db2773543abb9c95af0146be30b35205ea807d2d4b18" + }, + { + "path": "/home/worsch/the-custodian/docs/netkingdom-target-security-architecture.md", + "sha256": "3a74cbd71dc22514033906f6029de1d3e113640bc5faab94f8d58c62e0c86203" + }, + { + "path": "/home/worsch/the-custodian/docs/netkingdom-target-implementation.md", + "sha256": "02ee43e554f05ad0376271531b4de0699fdb64f97b5b839184eb50283703ba0f" + }, + { + "path": "/home/worsch/the-custodian/docs/agent-autonomy-decision.md", + "sha256": "4f65dfd2b56b67cd64eb9577644d574d2e687adcfd8b5bdb65a2e0d14f8bf1ff" + }, + { + "path": "/home/worsch/the-custodian/.kaizen/agents/custodian-codex/supervision.json", + "sha256": "4a4b0e61df23f1499916c04d85e61c558df810f43f485abf84792acfbbb66016" + }, + { + "path": "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/guard-successor-execution-r2/verified-receiving-return.json", + "sha256": "09958bd69367cc6903e2a21a56eb81b6a8a46c2a1907afc93f787cd63732e92a" + } + ], + "owner_refs": [ + { + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0009-glas-claude-native-delivery.md", + "sha256": "9f97a7bc3724fdac82dacc6821d57a57061c7b1243792aedf814c3bd3173bbdc", + "workplan": "SECRETS-WP-0009" + }, + { + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md", + "sha256": "04c9f7432216205b0ded3abc49042988e7730d1a3014f919d60456192fa7fd6c", + "workplan": "SECRETS-WP-0013" + }, + { + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md", + "sha256": "6cb4ec3500cddd5156235f1a493d7a979227a6b04eb037bacd23073fd1328efe", + "workplan": "SECRETS-WP-0014" + }, + { + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md", + "sha256": "b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b", + "workplan": "SECRETS-WP-0015" + }, + { + "path": "/home/worsch/railiance-platform/workplans/RPF-WP-0035-credential-lane-implementation.md", + "sha256": "139e4a6dd53f02cd184ebb12a5c30bcbfd0993cf9fdf1f42a1aa27b0823f32cf", + "workplan": "RPF-WP-0035" + }, + { + "path": "/home/worsch/access-engine/workplans/FLEX-WP-0024-decision-envelope-authenticity.md", + "sha256": "cc94a493c23c16a3baa718b75ef5d48a596c6386c11534d50fd4839a6f0448f2", + "workplan": "FLEX-WP-0024" + }, + { + "path": "/home/worsch/approval-engine/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md", + "sha256": "9e0d1292516c4fc25c4521ab1dda3b3aecc1559260eb630a4bf1af5f0f10a4f5", + "workplan": "APPROVAL-WP-0002" + }, + { + "path": "/home/worsch/approval-engine/workplans/APPROVAL-WP-0004-exact-consume-source-provenance.md", + "sha256": "90a96e90641090b07986515310fb317d2769c2ed5a36121c3d545264054cc5ce", + "workplan": "APPROVAL-WP-0004" + }, + { + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048" + }, + { + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049" + }, + { + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0050-playwright-consumer-registration.md", + "sha256": "0be0b643409d0731d4924c95566facdef58b1c65c5c1276f7f308ebfb2271fb7", + "workplan": "NK-WP-0050" + }, + { + "path": "/home/worsch/glas-harness/workplans/GLAS-WP-0012-first-local-profile-production-proof.md", + "sha256": "881ab0f5ba3bb43f5404c8f4cd23f9628e014992ba88fc13f541f0fa8b7b1eaa", + "workplan": "GLAS-WP-0012" + }, + { + "path": "/home/worsch/sand-boxer/workplans/SAND-WP-0014-owner-mediated-execution.md", + "sha256": "1e8d225c0bb0eb2c894709ed49a2cb0a0af0449fb6eab0971b13524cd133a9d7", + "workplan": "SAND-WP-0014" + }, + { + "path": "/home/worsch/rein-aharness/workplans/REINAH-WP-0008-simpler-metered-retry.md", + "sha256": "9aac375bdb2e93c57cd513ab8cd5bf0c0979a0699ea0181e6d405899d906bf68", + "workplan": "REINAH-WP-0008" + }, + { + "path": "/home/worsch/key-cape/workplans/KEY-WP-0040-mfa-attended-run-findings.md", + "sha256": "c213d8ad5ef2471d1ab8672502b561b9fee84b110575366c09148add83ad9d79", + "workplan": "KEY-WP-0040" + }, + { + "path": "/home/worsch/user-engine/workplans/USER-WP-0026-account-recovery.md", + "sha256": "b4c2e5e9e17140a4c3a6fce85ac795c07121a82cd48008419d2dd943d38d5d76", + "workplan": "USER-WP-0026" + }, + { + "path": "/home/worsch/railiance-forge/workplans/FORGE-WP-0006-independent-secret-detection.md", + "sha256": "fbcf3f75e884f6c90554c05525d787f61cfc2b915a206e6010bed447e7a720eb", + "workplan": "FORGE-WP-0006" + }, + { + "path": "/home/worsch/repo-manager/workplans/RMGR-WP-0019-historical-source-admission.md", + "sha256": "189372458e1b072451eb64333e38f849835c16dba5bb69deed2a17794644986d", + "workplan": "RMGR-WP-0019" + }, + { + "path": "/home/worsch/repo-manager/workplans/RMGR-WP-0021-secret-detection-controls.md", + "sha256": "966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d", + "workplan": "RMGR-WP-0021" + }, + { + "path": "/home/worsch/activity-core/workplans/ACTIVITY-WP-0047-daily-security-flow-adoption.md", + "sha256": "e0b83b570da688abb405bed165d81db7cf49bc7ff11ef9a8ad86cbee2dc651db", + "workplan": "ACTIVITY-WP-0047" + }, + { + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md", + "sha256": "dd7b1afa47e5c1b78eee1be9df2b61d9c5b3ef1f9dea25f13e2631daacd5ada9", + "workplan": "CUST-WP-0071" + }, + { + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0073-agent-credential-separation.md", + "sha256": "8cbf27819b4d8c689c6afadf0dd3eabe8a8cd4b399d20f05a5e7fe8749b9b43a", + "workplan": "CUST-WP-0073" + }, + { + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0079-deterministic-security-flow.md", + "sha256": "f4ad3299c90f84f49e5867b3d358582c3faea65db4a2a4f595cf1a7f2b806097", + "workplan": "CUST-WP-0079" + }, + { + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080" + }, + { + "path": "/home/worsch/audit-core/workplans/AUDIT-WP-0009-evidence-role-conformance.md", + "sha256": "5869955cd50eb501032af1d3d5ff0dd9f35f773e82d351528b400361bdd73d33", + "workplan": "AUDIT-WP-0009" + }, + { + "path": "/home/worsch/audit-core/workplans/AUDIT-WP-0015-independent-evidence-returns.md", + "sha256": "3b2d120dd9118e1eed8d8d6104beceebb78e02a3c2946bf3f804cd3bc9506490", + "workplan": "AUDIT-WP-0015" + }, + { + "path": "/home/worsch/reuse-surface/workplans/REUSE-WP-0025-private-source-reader-boundary.md", + "sha256": "7ebc371800c0be11e4a707d6e89915c1c659b469c65e2c2ee239c8b7144e8744", + "workplan": "REUSE-WP-0025" + }, + { + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0017-netkingdom-signer-runtime-storage-review.md", + "sha256": "76810b497e04548e3b22a28973303198f25aba5b47847e24b69024f8d07e39b7", + "workplan": "RCLUSTER-WP-0017" + }, + { + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "sha256": "96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b", + "workplan": "RCLUSTER-WP-0018" + }, + { + "path": "/home/worsch/state-hub/workplans/STATE-WP-0095-historical-source-receiving.md", + "sha256": "31bea1d5b54f9f6e5bc01d11d271c3a86ac76389350b467ba568b9dc93e41c61", + "workplan": "STATE-WP-0095" + } + ], + "gates": [ + { + "gate": "TSA-01", + "native_status": "open", + "owners": [ + "Access Engine", + "Secrets Engine", + "Platform", + "Cluster" + ], + "existing_tasks": [ + { + "id": "FLEX-WP-0024-T06", + "path": "/home/worsch/access-engine/workplans/FLEX-WP-0024-decision-envelope-authenticity.md", + "sha256": "cc94a493c23c16a3baa718b75ef5d48a596c6386c11534d50fd4839a6f0448f2", + "workplan": "FLEX-WP-0024", + "workplan_status": "active", + "workplan_flavor": null, + "task_status": "progress", + "uuid": "7f785b52-bf62-5884-8d34-670d70bc9023" + }, + { + "id": "SECRETS-WP-0014-T02", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md", + "sha256": "6cb4ec3500cddd5156235f1a493d7a979227a6b04eb037bacd23073fd1328efe", + "workplan": "SECRETS-WP-0014", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "877782e5-045b-5186-8b95-82e25db21a5a" + }, + { + "id": "SECRETS-WP-0014-T03", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md", + "sha256": "6cb4ec3500cddd5156235f1a493d7a979227a6b04eb037bacd23073fd1328efe", + "workplan": "SECRETS-WP-0014", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "85aa4c78-b66d-5201-8e31-0ed50e7eaeec" + }, + { + "id": "RCLUSTER-WP-0017-T02", + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0017-netkingdom-signer-runtime-storage-review.md", + "sha256": "76810b497e04548e3b22a28973303198f25aba5b47847e24b69024f8d07e39b7", + "workplan": "RCLUSTER-WP-0017", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "7f4320c6-8bb5-598e-9b9a-65565091276f" + }, + { + "id": "RCLUSTER-WP-0017-T03", + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0017-netkingdom-signer-runtime-storage-review.md", + "sha256": "76810b497e04548e3b22a28973303198f25aba5b47847e24b69024f8d07e39b7", + "workplan": "RCLUSTER-WP-0017", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "747a8d77-5c02-5b26-ba9c-385f75f3ac1c" + } + ], + "delivered_evidence": "Signed producer and strict fixed verifier; actual local producer-to-consumer proof; normal immutable image, release bundle, inert installed CLI, seven-resource server dry-run. Eleven authorization sites across ten handlers remain the initial PEP denominator.", + "next_native_deliverable": "Execute independently admitted stopped/running signer rollout and one-use custody; install independent public trust/caller binding, then native ALLOW and all refusal/rotation cases at the inventoried PEPs.", + "real_blocker": "Actual founder entity/expiry, held window, approved CCR-2026-0050, exact storage/PVC/PV evidence and final owner custody dispositions remain missing. Server dry-run is not runtime assent.", + "closure_requires": "Every denominator site and consumer pin admitted; forged/altered/wrong pin/key/unsigned/expired/rotation refusals recorded against exact deployed source/package/identity.", + "independent_preparation_now": "Refresh source-only rollout R2 / custody P4 closure matrix and enumerate unresolved owner facts; do not repeat completed dry-run or inert installation.", + "priority": 1 + }, + { + "gate": "TSA-02", + "native_status": "open", + "owners": [ + "Platform", + "Secrets Engine", + "Approval Engine" + ], + "existing_tasks": [ + { + "id": "RPF-WP-0035-T12", + "path": "/home/worsch/railiance-platform/workplans/RPF-WP-0035-credential-lane-implementation.md", + "sha256": "139e4a6dd53f02cd184ebb12a5c30bcbfd0993cf9fdf1f42a1aa27b0823f32cf", + "workplan": "RPF-WP-0035", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "914bf383-c13f-5247-9af0-91d7e3a4784a" + }, + { + "id": "SECRETS-WP-0013-T01", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md", + "sha256": "04c9f7432216205b0ded3abc49042988e7730d1a3014f919d60456192fa7fd6c", + "workplan": "SECRETS-WP-0013", + "workplan_status": "proposed", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "b2f0d462-a542-518b-a26b-b7ec07b3c7c1" + }, + { + "id": "SECRETS-WP-0013-T03", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md", + "sha256": "04c9f7432216205b0ded3abc49042988e7730d1a3014f919d60456192fa7fd6c", + "workplan": "SECRETS-WP-0013", + "workplan_status": "proposed", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "5f8f7c41-5921-543f-a7c6-0b1350ea6d82" + }, + { + "id": "APPROVAL-WP-0002-T01", + "path": "/home/worsch/approval-engine/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md", + "sha256": "9e0d1292516c4fc25c4521ab1dda3b3aecc1559260eb630a4bf1af5f0f10a4f5", + "workplan": "APPROVAL-WP-0002", + "workplan_status": "blocked", + "workplan_flavor": "residual", + "task_status": "wait", + "uuid": "dc4523f5-e0af-5734-a0ef-07aa7f2b2a27" + }, + { + "id": "APPROVAL-WP-0002-T05", + "path": "/home/worsch/approval-engine/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md", + "sha256": "9e0d1292516c4fc25c4521ab1dda3b3aecc1559260eb630a4bf1af5f0f10a4f5", + "workplan": "APPROVAL-WP-0002", + "workplan_status": "blocked", + "workplan_flavor": "residual", + "task_status": "wait", + "uuid": "3196fb77-3df0-5358-ae12-2d07bac12041" + } + ], + "delivered_evidence": "Exact approval/decision binding and consume-confirm-effect seam; actual local source servers and disposable OpenBao effect/readback. Approval0004 source tasks are done.", + "next_native_deliverable": "Admit exact native metadata execute-ccr action, reviewed readiness baseline and target readback; prove actor/tenant/body/expiry/replay/unavailable refusals through the actual served PEP.", + "real_blocker": "Independent mediated-contract acceptance, task entitlement, native issuer/profile provenance and founder exact native effect approval remain absent. APPROVAL0002 is residual with no Hub promotion reason; do not implement it absent explicit scoped promotion.", + "closure_requires": "Authoritative approval consumption confirmation precedes exact single bounded effect; accepted tenant/issuer provenance and complete positive/negative native outcome receipts.", + "independent_preparation_now": "Prepare exact T12/T01 native request and effect baseline/recovery packet; list residual owner evidence prerequisite without implementing residual scope.", + "priority": 2 + }, + { + "gate": "TSA-03", + "native_status": "open", + "owners": [ + "Platform", + "Secrets Engine" + ], + "existing_tasks": [ + { + "id": "RPF-WP-0035-T12", + "path": "/home/worsch/railiance-platform/workplans/RPF-WP-0035-credential-lane-implementation.md", + "sha256": "139e4a6dd53f02cd184ebb12a5c30bcbfd0993cf9fdf1f42a1aa27b0823f32cf", + "workplan": "RPF-WP-0035", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "914bf383-c13f-5247-9af0-91d7e3a4784a" + }, + { + "id": "SECRETS-WP-0013-T03", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md", + "sha256": "04c9f7432216205b0ded3abc49042988e7730d1a3014f919d60456192fa7fd6c", + "workplan": "SECRETS-WP-0013", + "workplan_status": "proposed", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "5f8f7c41-5921-543f-a7c6-0b1350ea6d82" + } + ], + "delivered_evidence": "Durable reservation/call intent, uncertainty and cleanup source plus disposable process/OpenBao cases delivered.", + "next_native_deliverable": "Run exact admitted ledger restart/concurrency and consumed-before-effect failure scenarios, independently reconcile target state and prove scoped cleanup/revocation with no replay.", + "real_blocker": "Same entitlement and native acceptance boundary as TSA-02; fixture ledger and disposable target do not establish production persistence or cleanup owner authority.", + "closure_requires": "Lost response remains unknown until authoritative reconciliation; changed/competing request refused; every durable cleanup obligation demonstrably survives and completes or stays owned.", + "independent_preparation_now": "Prepare bounded native fault plan and cleanup owner/receipt requirements against current exact operation.", + "priority": 2 + }, + { + "gate": "TSA-04", + "native_status": "open", + "owners": [ + "NetKingdom", + "Mason", + "Warden", + "KeyCape", + "Platform", + "Apps", + "rapp-postgres" + ], + "existing_tasks": [ + { + "id": "NK-WP-0048-T06", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c" + }, + { + "id": "NK-WP-0048-T12", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "7ce4eee3-cd47-55a9-bfa5-4f1835d4d6fd" + }, + { + "id": "NK-WP-0048-T14", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "fce95440-a25b-5f27-8ef3-a3d182099113" + }, + { + "id": "NK-WP-0048-T15", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "1b825705-4848-5edc-832f-b1622cd9bdb7" + }, + { + "id": "NK-WP-0048-T16", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "200bf500-5084-5ae7-be26-3033fe1f296e" + } + ], + "delivered_evidence": "Registration adapter/checker build, producer compatibility and caller containment published; 14 disposable LLDAP oracles and 21 real disposable PostgreSQL oracles delivered. NK48 T20/T21 are done.", + "next_native_deliverable": "First native Forgejo KnownSecurityCase with complete admitted descriptors, trusted callbacks, CNPG continuity and all-LDAP-writer exclusion, delivered custody, login/denial, revocation and rollback.", + "real_blocker": "Dedicated CNPG consumer/placement/lease/TLS/recovery, independent exact-content checkpoint and case/source/principal callbacks, all-writer fencing/CAS/ABA exclusion, restart evidence holder and native executable custody/type admission remain unresolved.", + "closure_requires": "Independent Mason structure, Warden evidence admission, Platform custody/delivery, Apps actual human login/group denial, scoped rollback/revocation and retained uncertainty receipts for the exact case.", + "independent_preparation_now": "T15 authenticated lost-process recovery contract and T16 complete descriptor composition can advance independently in source; T14 must use existing rapp-postgres admission contract.", + "priority": 1 + }, + { + "gate": "TSA-05", + "native_status": "open", + "owners": [ + "KeyCape", + "User Engine", + "NetKingdom", + "Custodian" + ], + "existing_tasks": [ + { + "id": "KEY-WP-0040-T01", + "path": "/home/worsch/key-cape/workplans/KEY-WP-0040-mfa-attended-run-findings.md", + "sha256": "c213d8ad5ef2471d1ab8672502b561b9fee84b110575366c09148add83ad9d79", + "workplan": "KEY-WP-0040", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "b385602d-714a-5fdb-b40b-bd870420f28e" + }, + { + "id": "KEY-WP-0040-T02", + "path": "/home/worsch/key-cape/workplans/KEY-WP-0040-mfa-attended-run-findings.md", + "sha256": "c213d8ad5ef2471d1ab8672502b561b9fee84b110575366c09148add83ad9d79", + "workplan": "KEY-WP-0040", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "3ad155dd-15ef-5522-bdf9-c78832728553" + }, + { + "id": "USER-WP-0026-T03", + "path": "/home/worsch/user-engine/workplans/USER-WP-0026-account-recovery.md", + "sha256": "b4c2e5e9e17140a4c3a6fce85ac795c07121a82cd48008419d2dd943d38d5d76", + "workplan": "USER-WP-0026", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "95e9a6d4-7e57-5483-97c5-3f4a45bb6767" + }, + { + "id": "NK-WP-0050-T02", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0050-playwright-consumer-registration.md", + "sha256": "0be0b643409d0731d4924c95566facdef58b1c65c5c1276f7f308ebfb2271fb7", + "workplan": "NK-WP-0050", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "a9dadd07-f136-5dc7-9229-7a9dbb941f0d" + }, + { + "id": "NK-WP-0050-T03", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0050-playwright-consumer-registration.md", + "sha256": "0be0b643409d0731d4924c95566facdef58b1c65c5c1276f7f308ebfb2271fb7", + "workplan": "NK-WP-0050", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "5a3aaf57-de5c-5a03-bc99-9bcf2fc5d95e" + }, + { + "id": "CUST-WP-0080-T05", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "ed8b909a-23bf-5e5f-b600-e477fbae136b" + } + ], + "delivered_evidence": "Recovery/journey source and Playwright registration preservation/custody source exist; native human/agent consumer acceptance remains open.", + "next_native_deliverable": "Complete real-factor U08 recovery and portal positive readback, then actual separately admitted human and agent Playwright sign-in/denial using delivered identity and individual transport.", + "real_blocker": "KEY40 remains progress; User26 positive net-kingdom-admins readback is attended and catalogue-management restoration is required before customers. NK50 activation, native auth and custody/transport admission remain missing.", + "closure_requires": "Real human and bounded agent journeys use the intended issuer/factor/claims and denied paths; exact delivery/revocation and recovery evidence, no source-only completion.", + "independent_preparation_now": "Prepare named journey/identity/transport acceptance matrix from existing NK50/CUST80 scope; keep real-factor and custody inputs with their owners.", + "priority": 3 + }, + { + "gate": "TSA-06", + "native_status": "open", + "owners": [ + "Glas", + "Sand-boxer", + "rein-aharness", + "Secrets", + "Platform", + "Forge" + ], + "existing_tasks": [ + { + "id": "GLAS-WP-0012-T02", + "path": "/home/worsch/glas-harness/workplans/GLAS-WP-0012-first-local-profile-production-proof.md", + "sha256": "881ab0f5ba3bb43f5404c8f4cd23f9628e014992ba88fc13f541f0fa8b7b1eaa", + "workplan": "GLAS-WP-0012", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "4209f564-a9ee-57f9-9522-3708988801ef" + }, + { + "id": "GLAS-WP-0012-T03", + "path": "/home/worsch/glas-harness/workplans/GLAS-WP-0012-first-local-profile-production-proof.md", + "sha256": "881ab0f5ba3bb43f5404c8f4cd23f9628e014992ba88fc13f541f0fa8b7b1eaa", + "workplan": "GLAS-WP-0012", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "c660808a-1724-555c-bc59-7318870d3591" + }, + { + "id": "GLAS-WP-0012-T04", + "path": "/home/worsch/glas-harness/workplans/GLAS-WP-0012-first-local-profile-production-proof.md", + "sha256": "881ab0f5ba3bb43f5404c8f4cd23f9628e014992ba88fc13f541f0fa8b7b1eaa", + "workplan": "GLAS-WP-0012", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "3e791432-8f37-54bd-a44a-55eeff11ac19" + }, + { + "id": "GLAS-WP-0012-T05", + "path": "/home/worsch/glas-harness/workplans/GLAS-WP-0012-first-local-profile-production-proof.md", + "sha256": "881ab0f5ba3bb43f5404c8f4cd23f9628e014992ba88fc13f541f0fa8b7b1eaa", + "workplan": "GLAS-WP-0012", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "f7635cf6-e044-52d4-8242-0512e0ccbd7b" + }, + { + "id": "REINAH-WP-0008-T07", + "path": "/home/worsch/rein-aharness/workplans/REINAH-WP-0008-simpler-metered-retry.md", + "sha256": "9aac375bdb2e93c57cd513ab8cd5bf0c0979a0699ea0181e6d405899d906bf68", + "workplan": "REINAH-WP-0008", + "workplan_status": "blocked", + "workplan_flavor": null, + "task_status": "wait", + "uuid": "80318842-ccaa-5484-a54a-3d9981eaec8b" + }, + { + "id": "SAND-WP-0014-T05", + "path": "/home/worsch/sand-boxer/workplans/SAND-WP-0014-owner-mediated-execution.md", + "sha256": "1e8d225c0bb0eb2c894709ed49a2cb0a0af0449fb6eab0971b13524cd133a9d7", + "workplan": "SAND-WP-0014", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "c6812fd4-bb7b-5be0-8344-a122496fe5bc" + }, + { + "id": "SECRETS-WP-0009-T03", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0009-glas-claude-native-delivery.md", + "sha256": "9f97a7bc3724fdac82dacc6821d57a57061c7b1243792aedf814c3bd3173bbdc", + "workplan": "SECRETS-WP-0009", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "f8069c8a-ad6b-5d0b-9a36-c2326699437d" + }, + { + "id": "CUST-WP-0073-T02", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0073-agent-credential-separation.md", + "sha256": "8cbf27819b4d8c689c6afadf0dd3eabe8a8cd4b399d20f05a5e7fe8749b9b43a", + "workplan": "CUST-WP-0073", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "4b88b0b7-dc7e-5612-aa5d-1a08f0530c35" + }, + { + "id": "FORGE-WP-0006-T03", + "path": "/home/worsch/railiance-forge/workplans/FORGE-WP-0006-independent-secret-detection.md", + "sha256": "fbcf3f75e884f6c90554c05525d787f61cfc2b915a206e6010bed447e7a720eb", + "workplan": "FORGE-WP-0006", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "e65f9093-f615-5af9-a2c0-21e17ff35dcf" + } + ], + "delivered_evidence": "Combined immutable runtime rebuilt; actual isolated manager/gateway proof passes synthetic credential delivery, read denial, cancellation and cleanup. Profile1.1.1 remains unverified. Runner loopback listener defect repaired separately.", + "next_native_deliverable": "Admit runtime through actual owner, execute bounded real-model rein acceptance, migrate actual assignment to isolated identity and prove per-job runner credential/repository-workflow abuse refusals.", + "real_blocker": "Model-call cost/scope and runtime custody/owner launch not admitted; actual assignment migration not done; host jobs share privileged runner authority and workflow authority/checks remain open.", + "closure_requires": "Actual identified task cannot read inherited host credentials or escape tool effects; real task cancellation/revocation and credential isolation proven; runner abuse matrix covers declared jobs/workflows.", + "independent_preparation_now": "Prepare exact real-model task/cost/egress proposal using existing GLAS T06 runner and immutable runtime; no new sandbox design or rerun of synthetic manager proof.", + "priority": 2 + }, + { + "gate": "TSA-07", + "native_status": "open", + "owners": [ + "Secrets Engine", + "NetKingdom", + "credential and consumer owners" + ], + "existing_tasks": [ + { + "id": "NK-WP-0049-T02", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "479d6970-6516-50f5-9436-bb5b56d58aad" + }, + { + "id": "NK-WP-0049-T21", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "77aa42be-7a39-5d93-8042-03d78b4094b4" + }, + { + "id": "NK-WP-0049-T22", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "3ea6bf00-a87f-58ea-bdce-328c13a03a55" + } + ], + "delivered_evidence": "Historical/current caller inventory and lifecycle source exist; backup custody grants cover only named backup lanes. Whole current owner/consumer denominator and lifecycle acceptance are incomplete.", + "next_native_deliverable": "Finish metadata-only caller/provider/consumer ledger, unknown/orphan and native-identity elimination dispositions, then sampled replacement/adoption/old-refusal/deletion at real owner boundaries.", + "real_blocker": "Current caller and legacy lane dispositions, consumer-selected replacement entitlement and owner acceptance inputs are missing. Founder exposure-rotation deferral remains binding.", + "closure_requires": "Admitted current denominator, explicit unknown/orphan findings, simplified lanes and complete native replacement/deletion semantics including old credential refusal without reopening deferred rotations.", + "independent_preparation_now": "Complete public-source inventory and owner dependency table under NK49 T02; do not fetch values, rotate credentials or claim absent assessment means absent control.", + "priority": 3 + }, + { + "gate": "TSA-08", + "native_status": "open", + "owners": [ + "NetKingdom", + "Cluster", + "Secrets", + "Platform", + "root recovery owners" + ], + "existing_tasks": [ + { + "id": "NK-WP-0049-T17", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "b47f9975-d6d7-5bb8-93ce-886deb1dfa70" + }, + { + "id": "NK-WP-0049-T19", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2" + }, + { + "id": "NK-WP-0049-T18", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "141dd773-c1fa-56c1-a852-bbe2372e5125" + }, + { + "id": "NK-WP-0049-T33", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "56c8d469-7a10-5d50-a30e-95cbf3cd4756" + }, + { + "id": "NK-WP-0049-T35", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "1bfd1703-589f-5511-bad5-812d860e4a71" + }, + { + "id": "NK-WP-0049-T36", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "sha256": "678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "workplan": "NK-WP-0049", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "8b72334b-fc27-5707-a189-bad345eaf3bc" + }, + { + "id": "RCLUSTER-WP-0018-T02", + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "sha256": "96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b", + "workplan": "RCLUSTER-WP-0018", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "90836435-917f-504c-a711-3f29ece348e3" + }, + { + "id": "RCLUSTER-WP-0018-T05", + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "sha256": "96d52b6dbae056399159632d50b32ccc6662e4f6d3677af154f7c8a3d618334b", + "workplan": "RCLUSTER-WP-0018", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "5bc67a22-0991-5625-86a6-f749560d8a0e" + }, + { + "id": "SECRETS-WP-0015-T03", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md", + "sha256": "b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b", + "workplan": "SECRETS-WP-0015", + "workplan_status": "ready", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "6262a915-7655-50be-b9f7-481f816d7335" + }, + { + "id": "SECRETS-WP-0015-T04", + "path": "/home/worsch/secrets-engine/workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md", + "sha256": "b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b", + "workplan": "SECRETS-WP-0015", + "workplan_status": "ready", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "aeec6eb0-39e2-5f7c-8f5d-778133edfc73" + } + ], + "delivered_evidence": "Independent off-host archive retrieval/recovery, actual LLDAP user authentication, retained privacyIDEA token-material decryption and old/new audit signature continuity verified. Real SOPS 65-case compatibility and synthetic KeyCape lifecycle delivered.", + "next_native_deliverable": "Prove original isolated Authelia/OIDC, retained-token real-factor MFA and selected KeyCape service consumer continuity with ordinary issuer unavailable; measure full restore/reconnect/audit RTO/RPO.", + "real_blocker": "Original TLS artifact/provider/private custody independent of outage remains unknown; current selected Secrets consumer requires attended OpenBao memory read and refuses file fallback. Exact owner-held restore/private admission and retained factor selection remain required.", + "closure_requires": "Actual original trust/key pairing or explicitly accepted reissue, independently admitted custody, successful existing-token MFA, original service authentication and consumer continuity plus measured RTO/RPO.", + "independent_preparation_now": "RCLUSTER18 T02 public metadata identification and T05 future archive disposition; SECRETS15 T03 exact outage-compatible consumer/custody plan. No new provider, file fallback or private read.", + "priority": 1 + }, + { + "gate": "TSA-09", + "native_status": "open", + "owners": [ + "Audit Core", + "Approval", + "Access", + "Tenant", + "Secrets emitting owners" + ], + "existing_tasks": [ + { + "id": "APPROVAL-WP-0002-T04", + "path": "/home/worsch/approval-engine/workplans/APPROVAL-WP-0002-production-readiness-and-consumer-adoption.md", + "sha256": "9e0d1292516c4fc25c4521ab1dda3b3aecc1559260eb630a4bf1af5f0f10a4f5", + "workplan": "APPROVAL-WP-0002", + "workplan_status": "blocked", + "workplan_flavor": "residual", + "task_status": "wait", + "uuid": "777a5cf5-c1db-5e07-8de6-ab109db5ccdc" + }, + { + "id": "AUDIT-WP-0015-T01", + "path": "/home/worsch/audit-core/workplans/AUDIT-WP-0015-independent-evidence-returns.md", + "sha256": "3b2d120dd9118e1eed8d8d6104beceebb78e02a3c2946bf3f804cd3bc9506490", + "workplan": "AUDIT-WP-0015", + "workplan_status": "blocked", + "workplan_flavor": null, + "task_status": "wait", + "uuid": "5fa2bfe4-df47-58a1-9240-80e2ad224617" + }, + { + "id": "FLEX-WP-0024-T06", + "path": "/home/worsch/access-engine/workplans/FLEX-WP-0024-decision-envelope-authenticity.md", + "sha256": "cc94a493c23c16a3baa718b75ef5d48a596c6386c11534d50fd4839a6f0448f2", + "workplan": "FLEX-WP-0024", + "workplan_status": "active", + "workplan_flavor": null, + "task_status": "progress", + "uuid": "7f785b52-bf62-5884-8d34-670d70bc9023" + }, + { + "id": "RPF-WP-0035-T12", + "path": "/home/worsch/railiance-platform/workplans/RPF-WP-0035-credential-lane-implementation.md", + "sha256": "139e4a6dd53f02cd184ebb12a5c30bcbfd0993cf9fdf1f42a1aa27b0823f32cf", + "workplan": "RPF-WP-0035", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "914bf383-c13f-5247-9af0-91d7e3a4784a" + } + ], + "delivered_evidence": "Audit receiver/custody infrastructure and AUDIT0009 implementation are done; complete-ledger reconciliation source and bounded fixture pass. Native Access initial signer keeps audit delivery disabled.", + "next_native_deliverable": "Admit first protected-operation source/class inventory and cadence; drain its atomic outbox, independently retain full producer ledger and read back every event with boundary/lag/duplicate accounting and missing-class findings.", + "real_blocker": "Current source/class/cadence admission, runtime producer emission and independent receiver reconciliation are not established. AUDIT15 offsite chain-head custody owner/task and readback remain open. Approval0002 remains unpromoted residual.", + "closure_requires": "All expected effect classes and IDs reconcile at actual receiver acceptance time; concurrent boundary arrivals settle and missing/quiet classes produce findings; durable independent custody continuity evidenced.", + "independent_preparation_now": "Reuse completed AUDIT0009 and existing Access reconciliation contract; prepare exact class inventory/ledger/receiver receipt packet, no residual implementation or invented custody.", + "priority": 3 + }, + { + "gate": "TSA-10", + "native_status": "open", + "owners": [ + "Forge", + "Repo Manager", + "Apps", + "private response owner" + ], + "existing_tasks": [ + { + "id": "FORGE-WP-0006-T02", + "path": "/home/worsch/railiance-forge/workplans/FORGE-WP-0006-independent-secret-detection.md", + "sha256": "fbcf3f75e884f6c90554c05525d787f61cfc2b915a206e6010bed447e7a720eb", + "workplan": "FORGE-WP-0006", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "210e7935-944a-5720-b356-18b48a68aa5e" + }, + { + "id": "FORGE-WP-0006-T03", + "path": "/home/worsch/railiance-forge/workplans/FORGE-WP-0006-independent-secret-detection.md", + "sha256": "fbcf3f75e884f6c90554c05525d787f61cfc2b915a206e6010bed447e7a720eb", + "workplan": "FORGE-WP-0006", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "e65f9093-f615-5af9-a2c0-21e17ff35dcf" + }, + { + "id": "RMGR-WP-0021-T03", + "path": "/home/worsch/repo-manager/workplans/RMGR-WP-0021-secret-detection-controls.md", + "sha256": "966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d", + "workplan": "RMGR-WP-0021", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "0ab44bd9-00d8-5470-ad45-7350e7868d0a" + }, + { + "id": "RMGR-WP-0021-T04", + "path": "/home/worsch/repo-manager/workplans/RMGR-WP-0021-secret-detection-controls.md", + "sha256": "966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d", + "workplan": "RMGR-WP-0021", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "44272818-db49-58a2-83b1-d2f9e9d5976c" + } + ], + "delivered_evidence": "22 workstation roots have admitted hooks; source/actual-hook batching/unavailability/cleanup T05 is done. Latest declared server inventory is 167 repos:166 admitted profiles, ID55 builtin-only. Receive expansion and template/custody recovery evidenced.", + "next_native_deliverable": "Execute existing FORGE6-ROUTES-001 r2 attended private disposable repository route suite; close declared CI authority/checks, repository55/submodules, import/mirror/new-repo coverage and private synthetic finding-to-response handling.", + "real_blocker": "Production authenticated HTTPS/API/frontend and session revocation remain unverified; repository55 has missing upstream sources; clone/fetch bypass receive-pack; CI workflow authority/required checks and private response are open.", + "closure_requires": "Complete admitted path/repository denominator with explicit uncovered scope; real positive/refusal native receipts and required checks/provenance; approved private finding classification/routing/resolution and exception lifecycle.", + "independent_preparation_now": "Prepare T04 synthetic metadata-only finding route and exact private review plan; inventory current source-path coverage without rerunning completed scanner T05.", + "priority": 2 + }, + { + "gate": "TSA-11", + "native_status": "open", + "owners": [ + "Reuse Surface", + "Repo Manager", + "provider owners" + ], + "existing_tasks": [ + { + "id": "CUST-WP-0080-T06", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29" + }, + { + "id": "REUSE-WP-0025-T03", + "path": "/home/worsch/reuse-surface/workplans/REUSE-WP-0025-private-source-reader-boundary.md", + "sha256": "7ebc371800c0be11e4a707d6e89915c1c659b469c65e2c2ee239c8b7144e8744", + "workplan": "REUSE-WP-0025", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "789bb918-4848-5bdf-bfd4-8ee42877addb" + } + ], + "delivered_evidence": "70 reviewed IDs hosted exactly once on16Oct, 60 local indexes passed stronger parity; corrected two descriptions. Discovery delivered separately from full target closure.", + "next_native_deliverable": "Admit usable source links, current limits/version aliases and each package-family disposition, then show recurring drift detection and correction with receiver/readback evidence.", + "real_blocker": "70/70 dated snapshot does not prove source/package-family completion, recurring observation or every consumer resolver. REUSE25 native follow-through remains wait and cannot be inferred from Cust81 historical success.", + "closure_requires": "All reviewed capabilities retain exact owner/index parity and usable revisioned discovery; drift loop actually runs, reports and reconciles changes; package families explicitly dispositioned.", + "independent_preparation_now": "Prepare complete 70-row source-link/version/package-family audit from current public indexes and existing CUST80T06 obligation; do not redeploy discovery.", + "priority": 3 + }, + { + "gate": "TSA-12", + "native_status": "open", + "owners": [ + "Activity Core", + "rein-aharness", + "Coordination", + "Custodian" + ], + "existing_tasks": [ + { + "id": "ACTIVITY-WP-0047-T02", + "path": "/home/worsch/activity-core/workplans/ACTIVITY-WP-0047-daily-security-flow-adoption.md", + "sha256": "e0b83b570da688abb405bed165d81db7cf49bc7ff11ef9a8ad86cbee2dc651db", + "workplan": "ACTIVITY-WP-0047", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "d0d5fddd-2d73-5156-aac3-49837aec2988" + }, + { + "id": "ACTIVITY-WP-0047-T03", + "path": "/home/worsch/activity-core/workplans/ACTIVITY-WP-0047-daily-security-flow-adoption.md", + "sha256": "e0b83b570da688abb405bed165d81db7cf49bc7ff11ef9a8ad86cbee2dc651db", + "workplan": "ACTIVITY-WP-0047", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "d692a3eb-7878-5405-931c-e11db494f803" + }, + { + "id": "CUST-WP-0079-T03", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0079-deterministic-security-flow.md", + "sha256": "f4ad3299c90f84f49e5867b3d358582c3faea65db4a2a4f595cf1a7f2b806097", + "workplan": "CUST-WP-0079", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "1be0569c-221d-5925-a0ff-fd2af88e52b1" + }, + { + "id": "CUST-WP-0079-T05", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0079-deterministic-security-flow.md", + "sha256": "f4ad3299c90f84f49e5867b3d358582c3faea65db4a2a4f595cf1a7f2b806097", + "workplan": "CUST-WP-0079", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "8a3dc219-8982-5903-9407-e1b549d4544c" + } + ], + "delivered_evidence": "Schedule source accepted but enabled false; no unassisted activation proof. Source/report/checkpoint tooling and coordination cases exist.", + "next_native_deliverable": "Obtain claiming rein workstation-checkout/Hub acceptance, publish enablement through owner release/admin-sync, manual trigger, then observe scheduled unassisted completed ops_run/report/checkpoint/changed-state notification without duplicates.", + "real_blocker": "Claiming execution runtime acceptance missing; unavailable workstation user systemd bus precludes host timer substitute. Source cadence adoption alone supplies no runtime/receiver receipt.", + "closure_requires": "Actual accepted schedule fires independently; report/checkpoint and changed-state delivery received; owner action followed by native remeasurement; applicable fleet cadence shows its required observation window.", + "independent_preparation_now": "Prepare exact existing fixed-command readiness and owner activation packet; do not add another scheduler or create worker wakeups.", + "priority": 2 + }, + { + "gate": "TSA-13", + "native_status": "open", + "owners": [ + "NetKingdom", + "Access", + "Secrets", + "provider and consumer owners" + ], + "existing_tasks": [ + { + "id": "NK-WP-0048-T06", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c" + }, + { + "id": "NK-WP-0048-T16", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "200bf500-5084-5ae7-be26-3033fe1f296e" + }, + { + "id": "FLEX-WP-0024-T06", + "path": "/home/worsch/access-engine/workplans/FLEX-WP-0024-decision-envelope-authenticity.md", + "sha256": "cc94a493c23c16a3baa718b75ef5d48a596c6386c11534d50fd4839a6f0448f2", + "workplan": "FLEX-WP-0024", + "workplan_status": "active", + "workplan_flavor": null, + "task_status": "progress", + "uuid": "7f785b52-bf62-5884-8d34-670d70bc9023" + }, + { + "id": "CUST-WP-0080-T06", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29" + } + ], + "delivered_evidence": "Producer-format compatibility and cross-language/source fixtures delivered for initial seams; no two accepted real consumers.", + "next_native_deliverable": "Admit existing shared adapters for two named real consumers with version compatibility, denied-path parity, upgrades and rollback receipts.", + "real_blocker": "First native consumer remains unaccepted; second actual consumer and owner/version lock not admitted. Fixture parity is insufficient.", + "closure_requires": "Two actual consumers reuse same producer-owned format with exact contract/version pins; positive and denied outcomes, upgrade and rollback work without a second PDP.", + "independent_preparation_now": "Assemble source-only two-consumer compatibility matrix and identify actual owner dependencies under existing CUST80T06, preserving first-case ordering.", + "priority": 4 + }, + { + "gate": "TSA-14", + "native_status": "open", + "owners": [ + "NetKingdom", + "package and provider owners" + ], + "existing_tasks": [ + { + "id": "NK-WP-0048-T06", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c" + }, + { + "id": "NK-WP-0048-T07", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "c3c9c3ae-4f23-5ba7-9e6f-e63bcf29b9f7" + }, + { + "id": "NK-WP-0048-T16", + "path": "/home/worsch/net-kingdom/workplans/NK-WP-0048-security-case-types.md", + "sha256": "b737bfae4802c122b21619695a169d7d082672af96314b1709860dd5aff2a60f", + "workplan": "NK-WP-0048", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "200bf500-5084-5ae7-be26-3033fe1f296e" + }, + { + "id": "CUST-WP-0080-T06", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29" + } + ], + "delivered_evidence": "Case type/schema, provider declarations and local thin package source exist; independent second clean installation is pending.", + "next_native_deliverable": "Lock one minimal admitted profile with dependency/optional-provider declarations and owner adapters; verify second clean install, full journeys and upgrade/recovery instructions.", + "real_blocker": "First known case and ordinary type/version admission remain open; local declaration/package tuple alone is not central registration, placement or runtime trust. T07 waits on T06.", + "closure_requires": "Independent second installation from locked package/provider versions produces complete positive/negative journeys and tested upgrade/recovery, with no hidden checkout or ambient credential dependency.", + "independent_preparation_now": "Document exact minimal profile lock/dependency closure from existing source; do not enqueue later types or implement T07 before T06 acceptance.", + "priority": 4 + }, + { + "gate": "TSA-15", + "native_status": "open", + "owners": [ + "Resource Control", + "telemetry", + "consumer owners", + "Custodian" + ], + "existing_tasks": [ + { + "id": "CUST-WP-0071-T02", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md", + "sha256": "dd7b1afa47e5c1b78eee1be9df2b61d9c5b3ef1f9dea25f13e2631daacd5ada9", + "workplan": "CUST-WP-0071", + "workplan_status": "blocked", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "82192370-2fd7-5363-88d2-3c67889d3d68" + }, + { + "id": "CUST-WP-0071-T03", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md", + "sha256": "dd7b1afa47e5c1b78eee1be9df2b61d9c5b3ef1f9dea25f13e2631daacd5ada9", + "workplan": "CUST-WP-0071", + "workplan_status": "blocked", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "6dc67558-eb1e-5bb6-a667-986f884dd495" + }, + { + "id": "CUST-WP-0071-T04", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md", + "sha256": "dd7b1afa47e5c1b78eee1be9df2b61d9c5b3ef1f9dea25f13e2631daacd5ada9", + "workplan": "CUST-WP-0071", + "workplan_status": "blocked", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "944f98e2-7e42-5894-925b-752423f3a1cc" + }, + { + "id": "CUST-WP-0071-T05", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md", + "sha256": "dd7b1afa47e5c1b78eee1be9df2b61d9c5b3ef1f9dea25f13e2631daacd5ada9", + "workplan": "CUST-WP-0071", + "workplan_status": "blocked", + "workplan_flavor": "planning", + "task_status": "wait", + "uuid": "20ddd4d7-d85d-5b95-bb0a-7b0ca8af76ca" + }, + { + "id": "RMGR-WP-0021-T05", + "path": "/home/worsch/repo-manager/workplans/RMGR-WP-0021-secret-detection-controls.md", + "sha256": "966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d", + "workplan": "RMGR-WP-0021", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "done", + "uuid": "25fbe694-41d8-5232-bce0-4ed362387d5a" + }, + { + "id": "CUST-WP-0080-T06", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29" + } + ], + "delivered_evidence": "Staged scanner warm generated 1/16/64-blob medians recorded with one-blob regression retained. Runtime headroom observations are dated and not reservations. Scanner T05 complete.", + "next_native_deliverable": "Admit representative operational baselines and repeats for onboarding touches/time, p50/p95 decision/effect latency, scanner tails/failure, resource/headroom and owner effort with equal control coverage.", + "real_blocker": "Representative pilot load/customer workflow and owner-native telemetry/effort samples missing; local fixture medians do not establish workload tails or production benefit.", + "closure_requires": "Comparable before/after denominators and unchanged controls, including adverse results and overhead, demonstrate actual operational improvement under representative use.", + "independent_preparation_now": "Prepare measurement protocol and missing baseline/owner matrix; preserve scanner results without another broad benchmark run.", + "priority": 4 + }, + { + "gate": "TSA-16", + "native_status": "open", + "owners": [ + "Custodian", + "governance and all owner records" + ], + "existing_tasks": [ + { + "id": "CUST-WP-0080-T04", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "todo", + "uuid": "82378b0f-7004-5c2f-9683-b356a1227576" + }, + { + "id": "CUST-WP-0080-T06", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md", + "sha256": "d8723566dbdfd8140b89d7e12ba2aeabf3fdf704b501dd899ab056e440981536", + "workplan": "CUST-WP-0080", + "workplan_status": "active", + "workplan_flavor": "implementation", + "task_status": "progress", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29" + }, + { + "id": "CUST-WP-0073-T04", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0073-agent-credential-separation.md", + "sha256": "8cbf27819b4d8c689c6afadf0dd3eabe8a8cd4b399d20f05a5e7fe8749b9b43a", + "workplan": "CUST-WP-0073", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "90725511-4e31-549f-b567-47feff1a9ca4" + }, + { + "id": "CUST-WP-0079-T04", + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0079-deterministic-security-flow.md", + "sha256": "f4ad3299c90f84f49e5867b3d358582c3faea65db4a2a4f595cf1a7f2b806097", + "workplan": "CUST-WP-0079", + "workplan_status": "blocked", + "workplan_flavor": "implementation", + "task_status": "wait", + "uuid": "5dd52156-09a8-5781-b288-99ae822f59a6" + } + ], + "delivered_evidence": "Architecture/SEC-DSM ledger, source owners, decisions and supervised record exist. State95 and RMGR19 finished after exact approved Helm77 guard; historical failure retained as approved exception.", + "next_native_deliverable": "Reconcile all sixteen gate receipts and SEC-DSM close-down controls to exact native proof/authority, retained deferrals and explicit residual promotion dispositions.", + "real_blocker": "All fifteen other native gates remain open; existing record grants no autopilot. APPROVAL0002 residual has no Hub promotion reason. Old source prose contains stale waits despite current task status.", + "closure_requires": "Requirement-by-requirement independent audit covers every named denominator and authoritative receipt, no invented owner assent, source/native separation, no implicit new authority or residual promotion.", + "independent_preparation_now": "This audit is a bounded current checkpoint under T04; root can reconcile stale narrative and exact publication, but do not mark native target complete.", + "priority": 1 + } + ], + "priority_preparation_candidates": [ + { + "rank": 1, + "tasks": [ + "RCLUSTER-WP-0018-T02", + "RCLUSTER-WP-0018-T05" + ], + "deliverable": "Exact public-only original TLS artifact/provider/custody metadata disposition and future archive requirement handoff. Existing source and tool already published.", + "native_gate_effect": "Unblocks TSA08 attempt preparation; cannot close TSA08 alone." + }, + { + "rank": 2, + "tasks": [ + "SECRETS-WP-0015-T03" + ], + "deliverable": "Exact original selected service consumer continuity/custody proof plan compatible with issuer/OpenBao outage; no file fallback or credentials.", + "native_gate_effect": "Unblocks TSA08/T18 selected consumer; native T04 remains human gated." + }, + { + "rank": 3, + "tasks": [ + "NK-WP-0048-T15", + "NK-WP-0048-T16" + ], + "deliverable": "Authenticated original-attempt evidence lookup/restart contract and complete machine descriptor/callback/type-version proposal, using delivered checker.", + "native_gate_effect": "Removes source blockers to TSA04; CNPG/all-writer/native owner admission remains." + }, + { + "rank": 4, + "tasks": [ + "GLAS-WP-0012-T03", + "GLAS-WP-0012-T04" + ], + "deliverable": "Exact immutable-runtime launch and bounded real-model task proposal with cost/egress/cleanup and actual task isolation receipts.", + "native_gate_effect": "Can satisfy named Glas profile slice only after runtime owner/supervisor assent; TSA06 runner/assignment denominator stays open." + }, + { + "rank": 5, + "tasks": [ + "FLEX-WP-0024-T06", + "RCLUSTER-WP-0017-T02", + "RCLUSTER-WP-0017-T03" + ], + "deliverable": "Finalize existing R2/P4 signer/storage/custody review using actual founder entity/window/CCR and admitted storage evidence.", + "native_gate_effect": "First exact native pin may be accepted after owner assent; TSA01 entire PEP denominator remains open." + }, + { + "rank": 6, + "tasks": [ + "RMGR-WP-0021-T04" + ], + "deliverable": "Synthetic private metadata-only finding route and exact review/exception/resolution plan; preserve deferred real rotations.", + "native_gate_effect": "Private response slice of TSA10 only; native path/CI coverage still open." + }, + { + "rank": 7, + "tasks": [ + "ACTIVITY-WP-0047-T02", + "ACTIVITY-WP-0047-T03" + ], + "deliverable": "Claiming rein readiness, owner activation and first scheduled unassisted fire/readback.", + "native_gate_effect": "Can satisfy CUST79T03 slice after native execution; broader TSA12 cadence/change/remeasurement remains." + } + ], + "narrative_drift_findings": [ + { + "path": "/home/worsch/railiance-cluster/workplans/RCLUSTER-WP-0018-keycape-original-tls-recovery.md", + "finding": "Historical narrative still says STATE95T07/RMGR19T06 remain wait; source and Hub now done/finished. Retain historical failure while refreshing current checkpoint; this is not a fresh runtime blocker." + }, + { + "path": "/home/worsch/the-custodian/workplans/CUST-WP-0079-deterministic-security-flow.md", + "finding": "T06 blocker text still lists RPF-WP-0044-T08 coulombcore check; actual source status is done (seen during audit). Do not reopen completed work from stale prose." + } + ], + "hub_validation": { + "observed_at": "2026-10-17T02:04:44.628210+00:00", + "checks": [ + { + "workplan": "SECRETS-WP-0009", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "SECRETS-WP-0009-T01", + "uuid": "4f1cf242-3aec-56a8-b958-5d53823875e0", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Define the exact native read lane", + "hub_error": null + }, + { + "id": "SECRETS-WP-0009-T02", + "uuid": "fa4a3e87-0854-5e2b-af44-facd5b25f443", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Support data-only delivery policies", + "hub_error": null + }, + { + "id": "SECRETS-WP-0009-T03", + "uuid": "f8069c8a-ad6b-5d0b-9a36-c2326699437d", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Activate the approved native lane and verify real owner delivery", + "hub_error": null + } + ] + }, + { + "workplan": "SECRETS-WP-0013", + "source_status": "proposed", + "hub_status": "proposed", + "status_matches": true, + "hub_flavor": "planning", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "SECRETS-WP-0013-T01", + "uuid": "b2f0d462-a542-518b-a26b-b7ec07b3c7c1", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Define the exact mediated execution contract", + "hub_error": null + }, + { + "id": "SECRETS-WP-0013-T02", + "uuid": "4ad61917-506d-5c12-a715-3d336e6b95e0", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prevent consumption without execution readiness", + "hub_error": null + }, + { + "id": "SECRETS-WP-0013-T03", + "uuid": "5f8f7c41-5921-543f-a7c6-0b1350ea6d82", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement and prove one native metadata action", + "hub_error": null + } + ] + }, + { + "workplan": "SECRETS-WP-0014", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "SECRETS-WP-0014-T01", + "uuid": "8baba9a3-3513-5f02-bafe-ed9dce743173", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prevent the Check credential from leaving the admitted local transport", + "hub_error": null + }, + { + "id": "SECRETS-WP-0014-T02", + "uuid": "877782e5-045b-5186-8b95-82e25db21a5a", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement independently anchored responder authentication", + "hub_error": null + }, + { + "id": "SECRETS-WP-0014-T03", + "uuid": "85aa4c78-b66d-5201-8e31-0ed50e7eaeec", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify the admitted native consumer and rotation path", + "hub_error": null + } + ] + }, + { + "workplan": "SECRETS-WP-0015", + "source_status": "ready", + "hub_status": "ready", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "SECRETS-WP-0015-T01", + "uuid": "a3e0e243-edac-5ade-a3d5-f58dac41633a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish exact current intended source selector", + "hub_error": null + }, + { + "id": "SECRETS-WP-0015-T02", + "uuid": "eab3b758-10ce-5464-b5f7-3a152ee1327a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver bounded offline public source selector preflight", + "hub_error": null + }, + { + "id": "SECRETS-WP-0015-T03", + "uuid": "6262a915-7655-50be-b9f7-481f816d7335", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare outage-compatible original consumer proof without custody bypass", + "hub_error": null + }, + { + "id": "SECRETS-WP-0015-T04", + "uuid": "aeec6eb0-39e2-5f7c-8f5d-778133edfc73", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify the separately admitted actual isolated consumer result", + "hub_error": null + } + ] + }, + { + "workplan": "RPF-WP-0035", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "RPF-WP-0035-T01", + "uuid": "0f3606bb-e95b-5484-8a57-bcdd6e3916fd", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Consolidate completed designs and owner dependencies", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T02", + "uuid": "e0c82ea9-05a5-537e-8fbf-67534263572e", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Accept and provision secrets-engine service JWT login", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T03", + "uuid": "f47e5bc5-6f3c-54bb-aa35-260ad03892ba", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement the platform operator-write CCR contract and Fluid lane", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T04", + "uuid": "35a85846-61d5-54ce-8b18-ede45733d53c", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Accept the needed signing lane and deliver it to the owning runtime", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T05", + "uuid": "e15d62c9-e5da-5721-a135-87c050f7851c", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit KeyCape approval-engine client custody and delivery", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T07", + "uuid": "0dd7c9a5-65a0-53fc-b6c3-5ad96ee56f7b", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Dispose of the ungoverned whynot-design npm duplicate", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T06", + "uuid": "68bff751-e48b-548b-8fb4-dfb3b16210c2", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit the separate approval client-side readers", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T08", + "uuid": "0ef52c26-2669-5cd1-8149-b1f6fcdda6cb", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit the two factory audit-sender custody lanes", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T09", + "uuid": "7c753be6-42f1-58a6-a4a4-a7ed686f461f", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Founder approval of the CCR-2026-0033 custody child", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T10", + "uuid": "af2d4dba-f83a-5819-9a8b-671bae799364", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Retire the approval-engine-operator client delivery and custody (CCR-2026-0018)", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T11", + "uuid": "7952c8cd-c066-5b72-a025-78d24341c1ab", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Complete independent service-JWT source preparation and execution design", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T12", + "uuid": "914bf383-c13f-5247-9af0-91d7e3a4784a", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement and prove the separately approved task execution entitlement", + "hub_error": null + }, + { + "id": "RPF-WP-0035-T13", + "uuid": "8f6966fa-6e9a-58b2-8b40-c47340ec19d1", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Complete independent KEY39 v4 lifecycle source review preparation", + "hub_error": null + } + ] + }, + { + "workplan": "FLEX-WP-0024", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": null, + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "FLEX-WP-0024-T01", + "uuid": "b8fad80d-5c44-5e26-a632-5096e0c0f3c5", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "1. Publish the stance and stop publishing bare Service names", + "hub_error": null + }, + { + "id": "FLEX-WP-0024-T02", + "uuid": "5482f3cd-36cb-55e0-8c52-0ca2340ed4d7", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "2. Choose the signature shape and key custody", + "hub_error": null + }, + { + "id": "FLEX-WP-0024-T03", + "uuid": "041612ea-1be4-5997-8c32-49f8bcc50855", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "3. Implement signing and verification", + "hub_error": null + }, + { + "id": "FLEX-WP-0024-T04", + "uuid": "82d6b75e-e2c6-5e3d-a897-fbdfb7c9094e", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "4. Report the gap to gate-house", + "hub_error": null + }, + { + "id": "FLEX-WP-0024-T05", + "uuid": "cfe4d275-9f02-5090-8391-06eea59d45c5", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "5. Wire owner signing into the decision pin and retained deployment charts", + "hub_error": null + }, + { + "id": "FLEX-WP-0024-T06", + "uuid": "7f785b52-bf62-5884-8d34-670d70bc9023", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "6. Admit custody, consumer trust, exact packages and native signed decisions", + "hub_error": null + } + ] + }, + { + "workplan": "APPROVAL-WP-0002", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "residual", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "APPROVAL-WP-0002-T01", + "uuid": "dc4523f5-e0af-5734-a0ef-07aa7f2b2a27", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Authenticate lifecycle mutations and approver evidence", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0002-T02", + "uuid": "2bef94ca-9482-5eff-9bd9-39adef292a78", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Harden durable storage and migrations", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0002-T03", + "uuid": "f0aa2e6d-19e6-5b43-886c-efa4e3de5f22", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Package and deploy the service", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0002-T04", + "uuid": "777a5cf5-c1db-5e07-8de6-ab109db5ccdc", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Wire outbox delivery and reconciliation", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0002-T05", + "uuid": "3196fb77-3df0-5358-ae12-2d07bac12041", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove one live PEP consumption path", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0002-T06", + "uuid": "1c6d6936-1a16-5f41-ba7d-5cfbd4231bf9", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Make presentation exclusion a tested binding contract", + "hub_error": null + } + ] + }, + { + "workplan": "APPROVAL-WP-0004", + "source_status": "finished", + "hub_status": "finished", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "APPROVAL-WP-0004-T01", + "uuid": "b0b0a5a9-f7e7-508b-96d0-4b02457b16fc", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Preserve verified consumer and approved operation in the use source row", + "hub_error": null + }, + { + "id": "APPROVAL-WP-0004-T02", + "uuid": "2b932ef8-e143-5bb7-856e-4cba4fb22c09", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Integrate independently reviewed source and synchronize work records", + "hub_error": null + } + ] + }, + { + "workplan": "NK-WP-0048", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "NK-WP-0048-T01", + "uuid": "930ac3e9-20ec-5473-98cd-3fe8fddb730f", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "NK-WP-0048-T02", + "uuid": "19c25d96-a55c-58f0-9168-3fdbc4955fc2", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T01 \u2014 Accept the terminology and the canon", + "hub_error": null + }, + { + "id": "NK-WP-0048-T03", + "uuid": "e487975b-73b1-516c-971d-da4cbbb93063", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T02 \u2014 Inventory the de-facto types already built by hand", + "hub_error": null + }, + { + "id": "NK-WP-0048-T04", + "uuid": "2fffe112-7d55-5680-9952-78d74f44f87f", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T03 \u2014 Schema, template and validator", + "hub_error": null + }, + { + "id": "NK-WP-0048-T05", + "uuid": "3d987d3d-0797-538b-86e4-51185a327ae2", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T04 \u2014 Define the first type: browser OIDC relying party", + "hub_error": null + }, + { + "id": "NK-WP-0048-T06", + "uuid": "d9b26bcf-a7c6-59a2-92a0-f913d76a203c", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T05 \u2014 Acknowledge the type through informed-decision", + "hub_error": null + }, + { + "id": "NK-WP-0048-T07", + "uuid": "c3c9c3ae-4f23-5ba7-9e6f-e63bcf29b9f7", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T06 \u2014 First KnownSecurityCase: Forgejo", + "hub_error": null + }, + { + "id": "NK-WP-0048-T08", + "uuid": "8e519082-dc8b-5e46-b660-03d03e55dcf6", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T07 \u2014 Queue the next types", + "hub_error": null + }, + { + "id": "NK-WP-0048-T09", + "uuid": "0ee12dfc-8260-5038-bd39-cc7fb4113be0", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T08 \u2014 identity-provisioner: ensure service-access groups", + "hub_error": null + }, + { + "id": "NK-WP-0048-T10", + "uuid": "4b06ca97-c1e4-5680-bf22-ab75ab1646a4", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T10 \u2014 Source compatibility checker for Mason and Warden evidence", + "hub_error": null + }, + { + "id": "NK-WP-0048-T11", + "uuid": "ef2a0119-f59e-5e45-9519-115da9df7b85", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T11 \u2014 Validate the optional machine-descriptor pin contract", + "hub_error": null + }, + { + "id": "NK-WP-0048-T12", + "uuid": "7ce4eee3-cd47-55a9-bfa5-4f1835d4d6fd", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T12 \u2014 Prepare NetKingdom-owned attended step adapters", + "hub_error": null + }, + { + "id": "NK-WP-0048-T13", + "uuid": "b264c10b-565c-5d29-b788-03cf5fbd2883", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T13 \u2014 Prepare the fixed registration adapter source candidate", + "hub_error": null + }, + { + "id": "NK-WP-0048-T14", + "uuid": "fce95440-a25b-5f27-8ef3-a3d182099113", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T14 \u2014 Admit governed group rollback against native owner boundaries", + "hub_error": null + }, + { + "id": "NK-WP-0048-T15", + "uuid": "1b825705-4848-5edc-832f-b1622cd9bdb7", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T15 \u2014 Define authenticated recovery for lost registration process state", + "hub_error": null + }, + { + "id": "NK-WP-0048-T16", + "uuid": "200bf500-5084-5ae7-be26-3033fe1f296e", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T16 \u2014 Select and review the actual machine descriptor composition", + "hub_error": null + }, + { + "id": "NK-WP-0048-T17", + "uuid": "8c3e4baa-a218-5996-af9e-fe1153a46dac", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T17 \u2014 Build and exercise the exact offline config-checker artifact", + "hub_error": null + }, + { + "id": "NK-WP-0048-T18", + "uuid": "9c45da71-fb4c-5f20-9065-90f448f37c64", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T18 \u2014 Make checker input and executable selection deterministic", + "hub_error": null + }, + { + "id": "NK-WP-0048-T19", + "uuid": "f50fdcd1-00be-5c3c-be0c-345aa2126032", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T19 \u2014 Bind checker execution to verified immutable attempt bytes", + "hub_error": null + }, + { + "id": "NK-WP-0048-T20", + "uuid": "863fcbdb-e246-51ba-87ca-a2f44d01d6f8", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T20 \u2014 Prepare durable group provenance and prove disposable LLDAP compatibility", + "hub_error": null + }, + { + "id": "NK-WP-0048-T21", + "uuid": "afe78e4d-408a-516a-ab92-e212e8a2d11d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "T21 \u2014 Implement the PostgreSQL journal and prove disposable SQL compatibility", + "hub_error": null + } + ] + }, + { + "workplan": "NK-WP-0049", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "NK-WP-0049-T01", + "uuid": "d7ca8d5f-c5ff-5cba-bd25-038cb53ffe4e", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Remove secret-bearing output and ambient root discovery", + "hub_error": null + }, + { + "id": "NK-WP-0049-T04", + "uuid": "04c4e8be-5bd8-5d5c-99b1-79d8ae758462", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Harden custody, SOPS and rotation source entry points", + "hub_error": null + }, + { + "id": "NK-WP-0049-T05", + "uuid": "e8e38f42-609e-5c07-a8e6-e73c8eb4ae95", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Repair component, diagnostic, LDAP and resolver callers", + "hub_error": null + }, + { + "id": "NK-WP-0049-T06", + "uuid": "a5f50891-c5b2-513b-8670-e1915ee52015", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Inventory source callers and retire remaining unsafe delivery paths", + "hub_error": null + }, + { + "id": "NK-WP-0049-T07", + "uuid": "2d7302a2-319a-5633-bf58-d51ccd25ebf6", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Discover off-host coverage and recover the existing PI database", + "hub_error": null + }, + { + "id": "NK-WP-0049-T08", + "uuid": "317ca173-c784-5329-9810-5e3d300604b8", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement the full identity capture and archive recovery toolchain", + "hub_error": null + }, + { + "id": "NK-WP-0049-T09", + "uuid": "4a47eb2a-7e42-5ae7-9df1-f5ede746eca1", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit and verify the two scoped backup credential deliveries", + "hub_error": null + }, + { + "id": "NK-WP-0049-T10", + "uuid": "0519444c-d559-5455-aa27-8c5dc8b832b0", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Apply capture isolation and install the guarded node runtime", + "hub_error": null + }, + { + "id": "NK-WP-0049-T11", + "uuid": "d69af493-4026-56a8-a526-c267d90dce18", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Connect recovery to Railiance bootstrap and reuse discovery", + "hub_error": null + }, + { + "id": "NK-WP-0049-T12", + "uuid": "decb415a-8012-521c-9dbe-d73c6ff0bbfb", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Create and verify the first full off-host identity bundle", + "hub_error": null + }, + { + "id": "NK-WP-0049-T13", + "uuid": "602d4921-cfac-5e5b-9993-4fbf67195c7d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Independently retrieve and recover the complete actual archive", + "hub_error": null + }, + { + "id": "NK-WP-0049-T14", + "uuid": "eaf0708f-b3b7-5531-8172-95edf30c3a19", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Activate and prove the complete recurring backup and retention job", + "hub_error": null + }, + { + "id": "NK-WP-0049-T02", + "uuid": "479d6970-6516-50f5-9436-bb5b56d58aad", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Map current callers, owners and native acceptance gaps", + "hub_error": null + }, + { + "id": "NK-WP-0049-T15", + "uuid": "1d1eb903-a4b0-5bc4-a421-0b842d7f68ae", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare the isolated full-service restore and acceptance packet", + "hub_error": null + }, + { + "id": "NK-WP-0049-T16", + "uuid": "b64d4d6a-e851-58d1-9929-f03343147de0", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove restored LLDAP directory and existing-user authentication", + "hub_error": null + }, + { + "id": "NK-WP-0049-T17", + "uuid": "b47f9975-d6d7-5bb8-93ce-886deb1dfa70", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove restored Authelia storage and OIDC continuity", + "hub_error": null + }, + { + "id": "NK-WP-0049-T19", + "uuid": "6f8af1a7-2a3f-5fa8-8202-83103ebd55b2", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove retained privacyIDEA token decryption and existing-token MFA", + "hub_error": null + }, + { + "id": "NK-WP-0049-T20", + "uuid": "375fa8f9-b8a5-5048-97a7-ec141aa7c45d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove historical and new privacyIDEA audit-signature continuity", + "hub_error": null + }, + { + "id": "NK-WP-0049-T18", + "uuid": "141dd773-c1fa-56c1-a852-bbe2372e5125", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove restored KeyCape issuer, policy and consumer continuity", + "hub_error": null + }, + { + "id": "NK-WP-0049-T21", + "uuid": "77aa42be-7a39-5d93-8042-03d78b4094b4", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify current caller and provider admission at their actual boundaries", + "hub_error": null + }, + { + "id": "NK-WP-0049-T22", + "uuid": "3ea6bf00-a87f-58ea-bdce-328c13a03a55", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Resolve historical credential and configuration-preserving rotation dispositions", + "hub_error": null + }, + { + "id": "NK-WP-0049-T23", + "uuid": "1ec537ee-dfee-5576-be36-a81bdba417d1", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Provide retrieval that works when OpenBao and SSO are unavailable", + "hub_error": null + }, + { + "id": "NK-WP-0049-T24", + "uuid": "474f5a78-a643-59c6-bcf9-fc4a908dfcb0", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Record owner disposition for second-provider and external monitoring gaps", + "hub_error": null + }, + { + "id": "NK-WP-0049-T25", + "uuid": "1c5ea7a1-edf7-5072-b36b-8be7f827957a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver and verify the offline retrieval adapter and recovery tools kit", + "hub_error": null + }, + { + "id": "NK-WP-0049-T26", + "uuid": "94d054fe-e5d8-5ddf-8e48-80714123d184", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Publish and verify the disaster recovery guide on Storage Share", + "hub_error": null + }, + { + "id": "NK-WP-0049-T27", + "uuid": "e273e803-bee7-5d90-bc51-ecc08c0c8eff", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Draft the isolated service restore packet and observe candidate images", + "hub_error": null + }, + { + "id": "NK-WP-0049-T28", + "uuid": "4829b091-76d2-5b10-bdfc-032800190c0a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Stage and verify the five exact service images for local offline recovery", + "hub_error": null + }, + { + "id": "NK-WP-0049-T29", + "uuid": "2f8c73b0-1cdd-5b22-99b6-017ccde4454b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare and verify the bounded native LLDAP recovery executor", + "hub_error": null + }, + { + "id": "NK-WP-0049-T30", + "uuid": "6e4a43db-9be2-5662-bdbf-1595fce03052", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare the bounded native privacyIDEA token-material and audit executor", + "hub_error": null + }, + { + "id": "NK-WP-0049-T31", + "uuid": "26383841-8076-5c53-bbd1-9db64e32544a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify retained privacyIDEA token material inside the isolated provider", + "hub_error": null + }, + { + "id": "NK-WP-0049-T32", + "uuid": "cd78dbb7-a8f2-5754-8788-6eb1b7d97741", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver isolated KeyCape restore source and synthetic lifecycle proof", + "hub_error": null + }, + { + "id": "NK-WP-0049-T33", + "uuid": "56c8d469-7a10-5d50-a30e-95cbf3cd4756", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare the exact owner-held KeyCape recovery attempt", + "hub_error": null + }, + { + "id": "NK-WP-0049-T34", + "uuid": "821b3a56-6f36-5812-abc9-5a00e37cb2e7", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver attended custody, metadata preflight and private manifest preparation source", + "hub_error": null + }, + { + "id": "NK-WP-0049-T35", + "uuid": "1bfd1703-589f-5511-bad5-812d860e4a71", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish original KeyCape TLS and trust recovery ownership for outage use", + "hub_error": null + }, + { + "id": "NK-WP-0049-T36", + "uuid": "8b72334b-fc27-5707-a189-bad345eaf3bc", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare selected original service registration and private admission bindings", + "hub_error": null + }, + { + "id": "NK-WP-0049-T37", + "uuid": "3403e266-d63b-5ce1-b891-3bfeac93d28c", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify actual SOPS compatibility and sealed-descriptor read/write custody", + "hub_error": null + }, + { + "id": "NK-WP-0049-T03", + "uuid": "d68cd4d3-1ba3-530e-88f9-26ebb8dd6eac", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Accept remaining recovery and caller evidence and close the G08 handoff", + "hub_error": null + } + ] + }, + { + "workplan": "NK-WP-0050", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "NK-WP-0050-T01", + "uuid": "64893d94-9717-5812-b8e3-7cabe095fcdc", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare exact registrations and preservation checks", + "hub_error": null + }, + { + "id": "NK-WP-0050-T02", + "uuid": "a9dadd07-f136-5dc7-9229-7a9dbb941f0d", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver custody integration and guarded registration activation", + "hub_error": null + }, + { + "id": "NK-WP-0050-T03", + "uuid": "5a3aaf57-de5c-5a03-bc99-9bcf2fc5d95e", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify issuer and real consumer acceptance", + "hub_error": null + } + ] + }, + { + "workplan": "GLAS-WP-0012", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "GLAS-WP-0012-T01", + "uuid": "711aeb7e-4664-5078-8c65-3fe6f46f7999", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish the exact local baseline and acceptance requirements", + "hub_error": null + }, + { + "id": "GLAS-WP-0012-T02", + "uuid": "4209f564-a9ee-57f9-9522-3708988801ef", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Resolve and verify the owner runtime, credential, and egress contract", + "hub_error": null + }, + { + "id": "GLAS-WP-0012-T03", + "uuid": "c660808a-1724-555c-bc59-7318870d3591", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review and validate the versioned Glas proof candidate", + "hub_error": null + }, + { + "id": "GLAS-WP-0012-T04", + "uuid": "3e791432-8f37-54bd-a44a-55eeff11ac19", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove one real bounded rein task inside the sandbox", + "hub_error": null + }, + { + "id": "GLAS-WP-0012-T05", + "uuid": "f7635cf6-e044-52d4-8242-0512e0ccbd7b", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Publish evidence and mark only the proven profile ready", + "hub_error": null + }, + { + "id": "GLAS-WP-0012-T06", + "uuid": "d0c26709-549f-540a-8250-1fd1b2e4960a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare the real-rein acceptance runner", + "hub_error": null + } + ] + }, + { + "workplan": "SAND-WP-0014", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "SAND-WP-0014-T01", + "uuid": "1b4349de-7027-5f01-8deb-122772e1404d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Define the governed execution contract", + "hub_error": null + }, + { + "id": "SAND-WP-0014-T02", + "uuid": "59f9af7c-7cd7-5e86-849f-5dfc7a3a06ee", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement owner-mediated bwrap execution", + "hub_error": null + }, + { + "id": "SAND-WP-0014-T03", + "uuid": "4fc7d747-13d5-58e7-b89e-b72e845515aa", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Remove direct namespace-entry guidance", + "hub_error": null + }, + { + "id": "SAND-WP-0014-T04", + "uuid": "c7ada937-4430-59d7-b3a6-9f3f36e9a907", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify unit and local namespace behavior", + "hub_error": null + }, + { + "id": "SAND-WP-0014-T05", + "uuid": "c6812fd4-bb7b-5be0-8344-a122496fe5bc", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prove one governed rein and coordinate consumers", + "hub_error": null + } + ] + }, + { + "workplan": "REINAH-WP-0008", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": null, + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "REINAH-WP-0008-T01", + "uuid": "c6536c8d-7862-5de6-ad2b-401077b60c04", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "A. Free rehearsal on the host", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T02", + "uuid": "6a413f5a-4ac2-5d5e-9b19-71b33445c0a9", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "B. Release holds that provably cost nothing", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T03", + "uuid": "87457216-2371-51ca-b3d4-3917e6f180a2", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "D. One owner command for renewal", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T04", + "uuid": "898e02af-51bb-5e8d-93d0-ae908466c612", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "C. Envelopes that cover several attempts (decision)", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T05", + "uuid": "b486e86b-9d0f-501d-a394-771b40f771ee", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "E. Ship the owner runtime as a container image (decision)", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T06", + "uuid": "4cf721e6-724b-5c64-91bb-67b098bb97af", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "F. Approvals per envelope (decision)", + "hub_error": null + }, + { + "id": "REINAH-WP-0008-T07", + "uuid": "80318842-ccaa-5484-a54a-3d9981eaec8b", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Retry on the corrected runtime", + "hub_error": null + } + ] + }, + { + "workplan": "KEY-WP-0040", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "KEY-WP-0040-T01", + "uuid": "b385602d-714a-5fdb-b40b-bd870420f28e", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Recovery preview rejects valid input (F6)", + "hub_error": null + }, + { + "id": "KEY-WP-0040-T02", + "uuid": "3ad155dd-15ef-5522-bdf9-c78832728553", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Link the OTP prompt to lost-authenticator help (F3)", + "hub_error": null + } + ] + }, + { + "workplan": "USER-WP-0026", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "USER-WP-0026-T01", + "uuid": "86324ec8-cf2f-5e9e-bb60-670c4d792828", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement and validate recovery", + "hub_error": null + }, + { + "id": "USER-WP-0026-T02", + "uuid": "ad5b0a77-d8ec-5e07-9a9e-2fa231a6f792", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Publish and verify the recovery flow", + "hub_error": null + }, + { + "id": "USER-WP-0026-T03", + "uuid": "95e9a6d4-7e57-5483-97c5-3f4a45bb6767", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Discover workload access from authoritative application records", + "hub_error": null + } + ] + }, + { + "workplan": "FORGE-WP-0006", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "FORGE-WP-0006-T01", + "uuid": "cd81bc07-e3b9-55f4-bafd-e78d271497ee", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement introduced-history refusal and verify the protocol", + "hub_error": null + }, + { + "id": "FORGE-WP-0006-T02", + "uuid": "210e7935-944a-5720-b356-18b48a68aa5e", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit the inventory and activate a reviewed server profile", + "hub_error": null + }, + { + "id": "FORGE-WP-0006-T03", + "uuid": "e65f9093-f615-5af9-a2c0-21e17ff35dcf", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify CI independence, detection response and complete coverage", + "hub_error": null + } + ] + }, + { + "workplan": "RMGR-WP-0019", + "source_status": "finished", + "hub_status": "finished", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "RMGR-WP-0019-T01", + "uuid": "d78a622e-39f9-5923-b4e1-f70fdc17fb42", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review exact historical receiving contract", + "hub_error": null + }, + { + "id": "RMGR-WP-0019-T02", + "uuid": "95240c81-1805-5365-9b35-d238621a16bf", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Enable exact frozen registrar exceptions after receiving deployment", + "hub_error": null + }, + { + "id": "RMGR-WP-0019-T03", + "uuid": "682eea14-a4a8-5f33-9a9f-8f2f1ac8288d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Run normal owner sync and verify preserved identities", + "hub_error": null + }, + { + "id": "RMGR-WP-0019-T04", + "uuid": "1ccb06c6-ad30-5847-8704-e5628ba81f35", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare exact cluster registrar successor", + "hub_error": null + }, + { + "id": "RMGR-WP-0019-T05", + "uuid": "36f47e21-42d0-5aef-b065-4a5dd3af0726", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit cluster registrar successor only after receiving verification", + "hub_error": null + }, + { + "id": "RMGR-WP-0019-T06", + "uuid": "4d1675b6-f49f-5b01-8d76-bbf2030d1b34", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Run ordinary cluster owner publication and verify preservation", + "hub_error": null + } + ] + }, + { + "workplan": "RMGR-WP-0021", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "RMGR-WP-0021-T01", + "uuid": "d3d20c18-5a5f-5f8a-b5c4-a22b4b662ebe", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Provide a bounded content-silent staged-object scanner adapter", + "hub_error": null + }, + { + "id": "RMGR-WP-0021-T02", + "uuid": "e27817e6-b298-581f-b99a-05ec459be749", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Admit the tool and activate local prevention for the reviewed repositories", + "hub_error": null + }, + { + "id": "RMGR-WP-0021-T03", + "uuid": "0ab44bd9-00d8-5470-ad45-7350e7868d0a", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish independent forge and CI detection coverage", + "hub_error": null + }, + { + "id": "RMGR-WP-0021-T04", + "uuid": "44272818-db49-58a2-83b1-d2f9e9d5976c", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify private finding-to-response handling", + "hub_error": null + }, + { + "id": "RMGR-WP-0021-T05", + "uuid": "25fbe694-41d8-5232-bce0-4ed362387d5a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Publish measured staged-scanner batching and verify runtime routing", + "hub_error": null + } + ] + }, + { + "workplan": "ACTIVITY-WP-0047", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "ACTIVITY-WP-0047-T01", + "uuid": "cbe8cfe2-43ef-5a31-b163-c473572754b7", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Source definition", + "hub_error": null + }, + { + "id": "ACTIVITY-WP-0047-T02", + "uuid": "d0d5fddd-2d73-5156-aac3-49837aec2988", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Activation", + "hub_error": null + }, + { + "id": "ACTIVITY-WP-0047-T03", + "uuid": "d692a3eb-7878-5405-931c-e11db494f803", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "First unassisted fire", + "hub_error": null + } + ] + }, + { + "workplan": "CUST-WP-0071", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "planning", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "CUST-WP-0071-T01", + "uuid": "4ae8eb8d-f8c5-5256-ae50-c323cfd73d7a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Reconcile live capacity, demand and ownership evidence", + "hub_error": null + }, + { + "id": "CUST-WP-0071-T02", + "uuid": "82192370-2fd7-5363-88d2-3c67889d3d68", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Measure the Vergabe prototype under representative pilot use", + "hub_error": null + }, + { + "id": "CUST-WP-0071-T03", + "uuid": "6dc67558-eb1e-5bb6-a667-986f884dd495", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review ecosystem allocations and reserve operating room", + "hub_error": null + }, + { + "id": "CUST-WP-0071-T04", + "uuid": "944f98e2-7e42-5894-925b-752423f3a1cc", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Apply accepted sizing changes and verify their effects", + "hub_error": null + }, + { + "id": "CUST-WP-0071-T05", + "uuid": "20ddd4d7-d85d-5b95-bb0a-7b0ca8af76ca", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish the regular weekly workload-demand and allocation assessment", + "hub_error": null + } + ] + }, + { + "workplan": "CUST-WP-0073", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "CUST-WP-0073-T01", + "uuid": "4781bb99-020f-59f6-be13-e3b8777d3fd8", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Decide the identity model", + "hub_error": null + }, + { + "id": "CUST-WP-0073-T02", + "uuid": "4b88b0b7-dc7e-5612-aa5d-1a08f0530c35", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Build and hand out the agent identity", + "hub_error": null + }, + { + "id": "CUST-WP-0073-T03", + "uuid": "5abbfcae-eb65-5b62-a7fa-f4f698f95312", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Reject last-applied annotations on Secrets", + "hub_error": null + }, + { + "id": "CUST-WP-0073-T04", + "uuid": "90725511-4e31-549f-b567-47feff1a9ca4", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Fleet guidance and harness guards", + "hub_error": null + }, + { + "id": "CUST-WP-0073-T05", + "uuid": "1b41b532-38a2-5f39-b387-28737934811a", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Rotate what was exposed", + "hub_error": null + } + ] + }, + { + "workplan": "CUST-WP-0079", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "CUST-WP-0079-T01", + "uuid": "618b32bb-3b30-5c31-b054-65b455d62b0b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Founder decision batch and hub/repo decision sync", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T02", + "uuid": "2764581a-ff8f-5a05-90bd-3dc6bd058ae5", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deterministic tooling", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T03", + "uuid": "1be0569c-221d-5925-a0ff-fd2af88e52b1", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Schedule the flow report and decision sync", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T04", + "uuid": "5dd52156-09a8-5781-b288-99ae822f59a6", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Encode the standing change rule as a policy-nexus guardrail", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T05", + "uuid": "8a3dc219-8982-5903-9407-e1b549d4544c", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Stop agent-authored index and sync commits", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T06", + "uuid": "e3da807f-9a6e-513f-82dc-3714a489e7bf", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Attended window #1", + "hub_error": null + }, + { + "id": "CUST-WP-0079-T07", + "uuid": "91ec924c-b305-5a63-925d-087a3b927d60", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Re-engage the coding agent with the renewed goal", + "hub_error": null + } + ] + }, + { + "workplan": "CUST-WP-0080", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "CUST-WP-0080-T01", + "uuid": "c770f7e1-25eb-53ec-9a37-1f7794077ff8", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review canon and map actual architecture", + "hub_error": null + }, + { + "id": "CUST-WP-0080-T02", + "uuid": "5973026f-8ca9-5882-99fe-65a54bc250ac", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Inspect and optimize the blueprint before planning closure", + "hub_error": null + }, + { + "id": "CUST-WP-0080-T03", + "uuid": "87637402-02f1-57c1-8fbc-4141598af8e3", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Close source defects and reconcile uncovered lifecycle gaps", + "hub_error": null + }, + { + "id": "CUST-WP-0080-T04", + "uuid": "82378b0f-7004-5c2f-9683-b356a1227576", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify native closure against every requirement", + "hub_error": null + }, + { + "id": "CUST-WP-0080-T05", + "uuid": "ed8b909a-23bf-5e5f-b600-e477fbae136b", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Coordinate self-service Playwright identity delivery", + "hub_error": null + }, + { + "id": "CUST-WP-0080-T06", + "uuid": "6aca534c-5c7a-556f-b6b6-406433670c29", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish the target architecture and drive the restructuring", + "hub_error": null + } + ] + }, + { + "workplan": "AUDIT-WP-0009", + "source_status": "finished", + "hub_status": "finished", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "AUDIT-WP-0009-T01", + "uuid": "f545b0e4-8c99-5186-affd-ce9a41209ed7", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T02", + "uuid": "6de9945f-4dd1-57dd-898a-f59c35b1df6c", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T03", + "uuid": "acae6085-ada7-51b2-8dc0-4abac7f7e7b3", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T04", + "uuid": "f36470af-4019-54b2-96d7-e049d867c7db", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T05", + "uuid": "382575ca-1801-5a32-a93d-90a8b9c8adbf", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T06", + "uuid": "0a8d6eed-75dd-5aaa-bf86-60be9dadca03", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T07", + "uuid": "f572dfeb-0d1b-58d6-be83-405125189028", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T08", + "uuid": "f7b513ee-af48-5c5a-a34e-3e9922d29b76", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T09", + "uuid": "fd4a4ac3-e525-57c1-9179-e0fcd0226913", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T10", + "uuid": "ac3464fd-3df9-51a1-b1f4-3bf3c60e4265", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T11", + "uuid": "96e0cbd5-e3ce-5807-8f64-41244671327b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Tasks", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T12", + "uuid": "712ba035-edad-5528-8293-56375553d85a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Operate the scheduled attestation and independent offsite return", + "hub_error": null + }, + { + "id": "AUDIT-WP-0009-T13", + "uuid": "cfe3e530-28e5-515e-a5e5-a9ca4b960054", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Answer flex-auth's B3: which repository is the \u00a74 source of evidence", + "hub_error": null + } + ] + }, + { + "workplan": "AUDIT-WP-0015", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": null, + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "AUDIT-WP-0015-T01", + "uuid": "5fa2bfe4-df47-58a1-9240-80e2ad224617", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Obtain independent offsite chain-head readback", + "hub_error": null + }, + { + "id": "AUDIT-WP-0015-T02", + "uuid": "e8a9cd4f-0267-524a-8ddd-5e1cec33e3af", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Record refreshed E2 and asm-t08 owner prerequisites", + "hub_error": null + } + ] + }, + { + "workplan": "REUSE-WP-0025", + "source_status": "blocked", + "hub_status": "blocked", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "REUSE-WP-0025-T01", + "uuid": "1f841e28-fc55-5b12-bb51-bb3291f17d8b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Independent consumer review", + "hub_error": null + }, + { + "id": "REUSE-WP-0025-T02", + "uuid": "a9e794f6-a894-52e6-bd93-4781e05c6a55", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare native boundary and verification helper", + "hub_error": null + }, + { + "id": "REUSE-WP-0025-T03", + "uuid": "789bb918-4848-5bdf-bfd4-8ee42877addb", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review, publish and verify deployed consumer", + "hub_error": null + } + ] + }, + { + "workplan": "RCLUSTER-WP-0017", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "RCLUSTER-WP-0017-T01", + "uuid": "6ee408cd-c055-532d-bc80-f64c9bdf143b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review exact runtime and storage source boundary", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0017-T02", + "uuid": "7f4320c6-8bb5-598e-9b9a-65565091276f", + "source_status": "progress", + "hub_status": "progress", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Review the bounded native preflight and storage action", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0017-T03", + "uuid": "747a8d77-5c02-5b26-ba9c-385f75f3ac1c", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify the approved runtime and storage result", + "hub_error": null + } + ] + }, + { + "workplan": "RCLUSTER-WP-0018", + "source_status": "active", + "hub_status": "active", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "RCLUSTER-WP-0018-T01", + "uuid": "7280193d-0d59-5b78-a2d3-96ebd127127f", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Record source boundary and public-only metadata preparation", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0018-T02", + "uuid": "90836435-917f-504c-a711-3f29ece348e3", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Establish exact independent original TLS artifact and provider custody metadata", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0018-T03", + "uuid": "5dfa9a3a-2639-5cf6-b0a4-13eef417d47a", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare safe isolated original extraction or explicit reissue alternative", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0018-T04", + "uuid": "021b07bb-65bc-5743-bac5-4294b4be74f6", + "source_status": "wait", + "hub_status": "wait", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify admitted original TLS recovery through the actual owner boundary", + "hub_error": null + }, + { + "id": "RCLUSTER-WP-0018-T05", + "uuid": "5bc67a22-0991-5625-86a6-f749560d8a0e", + "source_status": "todo", + "hub_status": "todo", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Disposition original TLS coverage in the future identity archive contract", + "hub_error": null + } + ] + }, + { + "workplan": "STATE-WP-0095", + "source_status": "finished", + "hub_status": "finished", + "status_matches": true, + "hub_flavor": "implementation", + "hub_flavor_promotion_reason": null, + "tasks": [ + { + "id": "STATE-WP-0095-T01", + "uuid": "6a5f87bb-e63d-5e20-b9fc-c1b5cd403ff7", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify source bindings and shared views", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T02", + "uuid": "ebb24194-e4cc-5130-aaa6-663f2ea2c822", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Implement preservation receiving and global collision refusal", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T03", + "uuid": "e8566341-cf6e-5b9c-ad80-8564d14cd52a", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver receiving through normal deployment and verify owner return", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T04", + "uuid": "3bbb311f-194e-5862-8aed-358a580f22b4", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify normal historical replay preserves existing identities", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T05", + "uuid": "339b9a37-181c-5599-9a89-0393e199bd4b", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Prepare exact cluster source preservation and refusal cases", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T06", + "uuid": "6af973b4-1964-5d4d-a2f8-8dbd4c01fda4", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver reviewed cluster receiving successor before registrar admission", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T07", + "uuid": "cfd1ea99-e75b-542e-a434-acefb62f3c7d", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Verify ordinary cluster receiving and immutable historical rows", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T08", + "uuid": "2dd9b04f-2250-5a8a-b5bc-c8a009872858", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Fix policy-compatible Secret-template server dry-run preparation", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T09", + "uuid": "8be8f13b-6352-5295-9755-de6fbfb13593", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Guard immutable historical index bindings in CLI and receiving API", + "hub_error": null + }, + { + "id": "STATE-WP-0095-T10", + "uuid": "88585c69-d9b9-5e1f-a256-6416ff71e824", + "source_status": "done", + "hub_status": "done", + "status_matches": true, + "workplan_matches": true, + "hub_title": "Deliver and verify the ordinary-binding guard successor", + "hub_error": null + } + ] + } + ] + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/README.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/README.md new file mode 100644 index 00000000..746f837c --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/README.md @@ -0,0 +1,62 @@ +# Original identity recovery preparation — 17 October 2026 + +This packet advances NK-WP-0049-T33/T35/T36, RCLUSTER-WP-0018-T02 and +SECRETS-WP-0015-T03 through source preparation. No owner or founder assent is +created. No native recovery, private archive read, credential retrieval, token +exchange, OpenBao login, rotation or production action occurred. + +The existing consumer's eight-field public selector passes its offline AST-only +checker against the reviewed `service_auth.py` hash. See selector-preflight.json. +The TLS source still names kc.coulomb.social, sso/kc-tls, +ClusterIssuer/letsencrypt-prod and Traefik. The identity archive excludes kc-tls; +same-host encrypted cluster backups do not establish independent original +certificate/key/trust recovery. Fetching today's public endpoint certificate +would not establish the archive-time original or independent private custody. + +## Exact next deliverables + +1. RCLUSTER-WP-0018-T02: the actual custody/provider owner supplies the fields in + owner-declaration.template.json: independently recoverable original artifact, + public certificate/chain/trust provenance and hashes, private custody entry + point reference and outage prerequisites. Alternatively, the existing owners + and founder explicitly accept a concrete reissue disposition naming the + changed continuity claim, dependencies and outage limitations. Neither path + is decided by this packet. Original TLS and accepted reissue are distinct. +2. SECRETS-WP-0015-T03: review consumer-proof-plan.md and disposition its outage + dependency with the actual service/custody owners. Public source correspondence + is established; exact archive presence/uniqueness and current recovery assent + remain absent. Existing consumer custody depends on attended OpenBao OIDC and + forbids a client-secret file. Do not silently replace that source with an + archive value or injected callback. +3. NetKingdom reviews the narrow adapter change in selector-uniqueness.patch. + It requires exactly one matching registration in the already-restored payload + before further runtime/private inputs. Current KeyCape Go configuration also + rejects duplicate IDs; this change makes the adapter's own check explicit, + and is not evidence of a native duplicate-registration exploit. Original + behavior and focused regression receipts are retained separately. +4. T33 assembles the complete admission and exact six-argument command only when + those prerequisites are reviewed. See next-attempt-proposal.json. Missing + TLS/custody/assent fields remain null and the proposal is non-executable. + +Changes to the adapter require a fresh dependency/admission binding. Frozen +historical fixture/attempt receipts are not rewritten as results of this change. +Only the normal owner publication and projection process may publish canonical +source; root coordinates that process. No task is marked done by this packet. + +## Foreign waits and authority + +Read-only Hub observations are retained in hub-readback.json. The latest cases +observed are `nk49-t35-rcluster18` receipt +`a2e5ed16-0da0-4ab9-bc0a-d82bd0a393f1`, `nk49-t36-secrets15` receipt +`8a73a503-7479-426b-b2ad-e88f32e4c7e8`, and `secrets15-nk49-readiness` +receipt `3f905339-a4c9-428e-9cbd-fa490c144c7a`. All remain waiting. Cluster +publication is already evidenced; the older unpublished-Cluster reason is +historical and superseded. No worker wake, message or Hub write was performed. + +Custodian supervision is supervised and grants no authority. The Emergent +Security start retrieval returned package 0.2.6, digest +`8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02`, +withheld because upstream sources changed. Current owner instructions, +environment orientation, Security Companion and identity/start card source were +read directly; package guidance is orientation only. Routing discovery is +recorded in routing-discovery.json and supplies no credential authority. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/consumer-proof-plan.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/consumer-proof-plan.md new file mode 100644 index 00000000..f14b7384 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/consumer-proof-plan.md @@ -0,0 +1,69 @@ +# Proposed bounded consumer proof and custody plan + +Draft source plan for SECRETS-WP-0015-T03. Actual source-owner review and any +custody/scope disposition remain required; this is not another owner's review. + +The selector is secrets-engine-openbao as both client ID and audience, +KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET as producer environment name, +service:secrets-engine, tenant:platform, role secrets-engine, granted +openbao:login and denied openbao:admin. No new registration, secret or grant is +proposed. Historical 7 October issuer and 10 October consumer proof predate the +16 October ciphertext but cannot prove its private contents or current assent. + +## Claims and their actual dependencies + +| Claim | Evidence required | Present limit | +| --- | --- | --- | +| Current intended consumer selector | Offline AST constants and strict eight-field selector correspondence | Passed; no credential source or network exercised | +| Original archived registration | Exact admitted ciphertext, private authenticated restoration, exactly one matching registration, exact producer env binding | Not observed; must remain inside owner custody | +| Original isolated issuer behavior | Pinned image/executable, exact issuer and original TLS/trust bindings, native positive signature/claim checks and unrelated-secret/excess-scope refusals | TLS/private admission incomplete; no native action performed | +| Selected secrets-engine consumer continuity | Actual consumer uses its accepted source and validation flow against admitted target; signature verification belongs to receiving OpenBao | Consumer's ordinary source and resource server require OpenBao; not established by issuer verify-client | +| Backend protected operation | Existing SECRETS-WP-0008/0013 entitlement and execution contracts | Separate gate; login does not grant protected work | +| Retained-factor MFA | NK-WP-0049-T19's separate factor/browser proof | Service client cannot prove it | + +`engine_auth.login_service_jwt` constructs OpenBaoOidcClientSecretSource, +performs an attended operator OIDC login, reads the exact platform KV field +in memory, exchanges the service secret at KeyCape, then logs in to OpenBao's +keycape-services role. This cyclic dependency does not establish recovery when +ordinary KeyCape and OpenBao are unavailable. `preflight_service_jwt` checks +claims without cryptographic verification; invoking it alone cannot establish +consumer acceptance. Constructor injection of a secret source is not permission +to bypass the production factory's source contract. + +The owner must choose a concrete supported continuity scope: admit the bounded +isolated issuer proof while retaining actual consumer continuity as an open +gate, or supply an existing independently recoverable private provider/custody +path compatible with the accepted consumer contract. A new fallback source, +file copy, production redirect or recovered-OpenBao deployment would be a +separately reviewed change. This packet chooses none and narrows no gate. + +## Required reviewed attempt binding + +Bind original ciphertext SHA-256 and verified transfer; canonical source and +dependency hashes; selected original client and exact-one registration check; +pinned KeyCape image and executable; original issuer, public certificate/chain/ +trust hashes and validity/SANs; owner-held TLS/ciphertext locations; versioned +ciphertext-derived private manifest mode; fixed local Docker target and a fresh +safe receipt path. Private manifest digest and credential values stay inside +custody. Do not reuse a digest from the pre-change adapter source closure. + +Before any later key prompt, the existing public preflight must refuse missing, +changed or ambiguous public admission, source, target and selector metadata. +After restoration, the adapter's exact-one check must refuse absent, duplicate +or misbound clients before further environment, signer or native-check access. +It cannot inspect private archived registrations before decryption. The native +attempt must independently refuse wrong unrelated secret, openbao:admin, +wrong issuer/trust/executable/source and failed cleanup; transport failure alone +is never credential-denial evidence. Keep generated fixtures separate from +actual archive acceptance and from real predecessor-rotation proof. + +Use the existing attempt's 1800-second total deadline and native verifier's +150-second bound only after owners review the complete revision. No retry may +convert failure or uncertainty into success. On binding, startup, native denial, +timeout or cleanup uncertainty, abort, retain only the sanitized receipt and +explicit obligations, and use exact session-scoped cleanup. The isolated attempt +changes no production service, so production rollback is not an implicit action. +Record removal of exact session containers/tmpfs, descriptor/child lifetime, +and all cleanup failures; independent receipt verification precedes acceptance. +Owner/cost/risk/deadline assumptions remain unapproved until the existing review +path resolves them. Founder-deferred rotation stays deferred. diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/focused-regressions.stderr.txt b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/focused-regressions.stderr.txt new file mode 100644 index 00000000..391d0e21 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/focused-regressions.stderr.txt @@ -0,0 +1,19 @@ +.E........................................................................... +====================================================================== +ERROR: test_manifest_binds_current_candidate_and_existing_fixture_factory (test_isolated_keycape_fixture_plan.FixturePreparationTests.test_manifest_binds_current_candidate_and_existing_fixture_factory) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_fixture_plan.py", line 44, in test_manifest_binds_current_candidate_and_existing_fixture_factory + manifest=f.reviewed_manifest(digest) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/worsch/net-kingdom/tests/run_isolated_keycape_native_fixture.py", line 48, in reviewed_manifest + require('sha256:'+hashlib.sha256((ROOT/name).read_bytes()).hexdigest()==digest) + File "/home/worsch/net-kingdom/tests/run_isolated_keycape_native_fixture.py", line 40, in require + if not condition:raise RuntimeError('synthetic_fixture_refused') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +RuntimeError: synthetic_fixture_refused + +---------------------------------------------------------------------- +Ran 77 tests in 3.045s + +FAILED (errors=1) diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/focused-regressions.stdout.txt b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/focused-regressions.stdout.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/hub-readback.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/hub-readback.json new file mode 100644 index 00000000..0b9f94a8 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/hub-readback.json @@ -0,0 +1,143 @@ +{ + "observed_at": "2026-10-17T02:06:06.866758+00:00", + "read_only": true, + "tasks": [ + { + "source_id": "NK-WP-0049-T33", + "id": "56c8d469-7a10-5d50-a30e-95cbf3cd4756", + "workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804", + "status": "wait", + "needs_human": false, + "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." + }, + { + "source_id": "NK-WP-0049-T35", + "id": "1bfd1703-589f-5511-bad5-812d860e4a71", + "workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804", + "status": "progress", + "needs_human": false, + "blocking_reason": null + }, + { + "source_id": "NK-WP-0049-T36", + "id": "8b72334b-fc27-5707-a189-bad345eaf3bc", + "workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804", + "status": "progress", + "needs_human": false, + "blocking_reason": null + }, + { + "source_id": "RCLUSTER-WP-0018-T02", + "id": "90836435-917f-504c-a711-3f29ece348e3", + "workplan_id": "e0a7813d-c916-5e49-84b2-5e5b30441891", + "status": "todo", + "needs_human": false, + "blocking_reason": null + }, + { + "source_id": "SECRETS-WP-0015-T03", + "id": "6262a915-7655-50be-b9f7-481f816d7335", + "workplan_id": "68a0642e-4908-5260-89c9-3adce60e6a4d", + "status": "todo", + "needs_human": false, + "blocking_reason": null + }, + { + "source_id": "SECRETS-WP-0015-T04", + "id": "aeec6eb0-39e2-5f7c-8f5d-778133edfc73", + "workplan_id": "68a0642e-4908-5260-89c9-3adce60e6a4d", + "status": "wait", + "needs_human": true, + "blocking_reason": "Await exact consumer proof/custody plan plus original TLS/private admission readiness; actual attended owner path/authority remains required." + } + ], + "latest_foreign_waits": [ + { + "workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804", + "id": "a2e5ed16-0da0-4ab9-bc0a-d82bd0a393f1", + "topic_id": null, + "task_id": null, + "decision_id": null, + "event_type": "coordination_receipt", + "summary": "Cluster WP18 published and verified with five tasks; T02 still requires exact independent original TLS artifact/provider/custody metadata. Publication and current-baseline maintenance proof give no TLS/native assent.", + "detail": { + "state": "waiting", + "flavor": "implementation", + "reason": "Cluster WP18 published and verified with five tasks; T02 still requires exact independent original TLS artifact/provider/custody metadata. Publication and current-baseline maintenance proof give no TLS/native assent.", + "case_id": "nk49-t35-rcluster18", + "observer": "codex", + "scenario_type": "cross_owner_wait", + "obligor_task_id": "RCLUSTER-WP-0018-T02", + "native_acceptance": false, + "beneficiary_task_id": "NK-WP-0049-T35", + "obligor_workplan_id": "RCLUSTER-WP-0018", + "coordination_context": "CUST-WP-0080", + "human_gate_never_woken": true, + "beneficiary_workplan_id": "NK-WP-0049", + "runtime_worker_injection_enabled": false + }, + "author": "codex", + "session_id": null, + "created_at": "2026-10-17T00:39:42.467089Z", + "workstream_id": "17d315f0-829e-57c7-85cc-3a7914152804" + }, + { + "workplan_id": "68a0642e-4908-5260-89c9-3adce60e6a4d", + "id": "3f905339-a4c9-428e-9cbd-fa490c144c7a", + "topic_id": null, + "task_id": null, + "decision_id": null, + "event_type": "coordination_receipt", + "summary": "Observed cross-owner case secrets15-nk49-readiness: Foreign source readiness remains incomplete; beneficiary also has a separate attended human gate", + "detail": { + "state": "waiting", + "flavor": "implementation", + "reason": "Foreign source readiness remains incomplete; beneficiary also has a separate attended human gate", + "case_id": "secrets15-nk49-readiness", + "observer": "codex", + "scenario_type": "cross_owner_wait", + "obligor_task_id": "NK-WP-0049-T33", + "native_acceptance": false, + "beneficiary_task_id": "SECRETS-WP-0015-T04", + "obligor_workplan_id": "NK-WP-0049", + "coordination_context": "CUST-WP-0080", + "human_gate_never_woken": true, + "beneficiary_workplan_id": "SECRETS-WP-0015", + "runtime_worker_injection_enabled": false + }, + "author": "codex", + "session_id": null, + "created_at": "2026-10-16T23:44:28.741512Z", + "workstream_id": "68a0642e-4908-5260-89c9-3adce60e6a4d" + }, + { + "workplan_id": "17d315f0-829e-57c7-85cc-3a7914152804", + "id": "8a73a503-7479-426b-b2ad-e88f32e4c7e8", + "topic_id": null, + "task_id": null, + "decision_id": null, + "event_type": "coordination_receipt", + "summary": "Observed cross-owner case nk49-t36-secrets15: SECRETS-WP-0015 published c59bbf56 and exact4task/2edge bindings observed; T03 remains todo for outage-compatible consumer preparation, no native assent.", + "detail": { + "state": "waiting", + "flavor": "implementation", + "reason": "SECRETS-WP-0015 published c59bbf56 and exact4task/2edge bindings observed; T03 remains todo for outage-compatible consumer preparation, no native assent.", + "case_id": "nk49-t36-secrets15", + "observer": "codex", + "scenario_type": "cross_owner_wait", + "obligor_task_id": "SECRETS-WP-0015-T03", + "native_acceptance": false, + "beneficiary_task_id": "NK-WP-0049-T36", + "obligor_workplan_id": "SECRETS-WP-0015", + "coordination_context": "CUST-WP-0080", + "human_gate_never_woken": true, + "beneficiary_workplan_id": "NK-WP-0049", + "runtime_worker_injection_enabled": false + }, + "author": "codex", + "session_id": null, + "created_at": "2026-10-16T23:44:28.363998Z", + "workstream_id": "17d315f0-829e-57c7-85cc-3a7914152804" + } + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/manifest.json new file mode 100644 index 00000000..d80f26c3 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/manifest.json @@ -0,0 +1,38 @@ +{ + "schema": "custodian.native-identity-source-packet.v1", + "created_at": "2026-10-17T02:08:34.423600+00:00", + "status": "source_prepared_review_pending_no_native_acceptance", + "proposal_id": "nk49-original-identity-attempt-20261017", + "original_revision": 1, + "original_proposal_digest": "sha256:8cc9ee58131d41c9bd2951c233c3d2c5916fb6ea0572e73cc99b287adc61f858", + "canonical_source_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" + ], + "files": { + "README.md": "sha256:fae49e17e652226c024ac0eae9d5fd967a82fa3b37441a448380edfe2ba07879", + "consumer-proof-plan.md": "sha256:0d47336d44c2e354a7e1c862fcb96bb097fdae7042e9c85caf1c978fba314693", + "focused-regressions.stderr.txt": "sha256:c28f2305fc55ba0571b9e23fd7fd7482b50e85e352c25be0677b9d86882f1ec1", + "focused-regressions.stdout.txt": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "hub-readback.json": "sha256:f01ff4e13bf8aad12cb042607ed7ca96ec58673e47edb343176addc45467d5f8", + "next-attempt-proposal.json": "sha256:8cc9ee58131d41c9bd2951c233c3d2c5916fb6ea0572e73cc99b287adc61f858", + "original-behavior-regression.txt": "sha256:1da5266b47ce0be90bfd4056a7b019fde31566654180bc1be4bedd6805e6cb3d", + "owner-declaration.template.json": "sha256:57268212a2f1d1c34fdc2f6587a26724468ee2045c9a88d8523b74452f8f3c09", + "owner-source.patch": "sha256:d02de220d28a293ad22e1781b9d0f42b0bf69456de785a30022851eb723b83e7", + "postimages/tests/isolated-keycape-native-fixture-manifest.json": "sha256:936ee435be04b27f391391e7dda02def69e153bde3adcce92d569f33f308db2e", + "postimages/tests/test_isolated_keycape_recovery.py": "sha256:5f729e077db51dd6b17d00dc3eb71c0e652849f55fe68505a07befa663c91dea", + "postimages/tools/bootstrap-recovery/isolated-keycape.py": "sha256:86f37add7221e4c73e3f9d878c09a3cc81061627cbf024ed6887d973d929b718", + "postimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md": "sha256:5830c429f58a0317b28c7b4bcf22a1b46e6d01b41378cdae95f947c6d9317e44", + "preimages/tests/isolated-keycape-native-fixture-manifest.json": "sha256:1dcefbc7ca7b0c2be33135b1b7977b89ba657223ecbb1310cc691d151b3d916e", + "preimages/tests/test_isolated_keycape_recovery.py": "sha256:247e9a87f5be2ee9f20f7edbb4a9f612ab7cb0cd940392c3caeca8b046605f55", + "preimages/tools/bootstrap-recovery/isolated-keycape.py": "sha256:f67627b7d1647d75187dd899874efe22383bc91de5d97dabb9801076668ab3c2", + "preimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md": "sha256:678ec04b73b57c026001791706c05c5d4d5a508a32f17210ae8ad03ab15d53b8", + "routing-discovery.json": "sha256:763a36b7da8a6476d50e4f377eee3415b7e1460deea1d3827064a200955350e4", + "selector-preflight.json": "sha256:b3946e11ce91b7a9d3e24e4e218e21739f12216cf4621fc216fccc2147439d41", + "selector-uniqueness.patch": "sha256:55aa1efad828e6c466ec92430e94eb4366b0b8470bc790ccfa056fb0b3125853", + "source-references.json": "sha256:a6484b77be832733ceba7b11563ca73b472b9f17f02c89002575d9a0e1e3a42b", + "verification.json": "sha256:4d2beb8cd1871c13de7f6b5fe0ffe6c2d20b5ff5c1e39537200f9fc0e8d04b43" + } +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/next-attempt-proposal.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/next-attempt-proposal.json new file mode 100644 index 00000000..0e040030 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/next-attempt-proposal.json @@ -0,0 +1,69 @@ +{ + "proposal_id": "nk49-original-identity-attempt-20261017", + "revision": 1, + "status": "incomplete_not_executable_not_approved", + "target": { + "docker_endpoint": "unix:///var/run/docker.sock", + "engine_id": "74f93783-6cef-43a8-a3c4-f62586cd3bc1", + "engine_name": "bnt-lap001", + "production_contact": false + }, + "archive": { + "ciphertext_sha256": "sha256:7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30", + "manifest_binding_mode": "ciphertext-derived-v1", + "verified_transfer_receipt_reference": null + }, + "public_original_identity": { + "issuer": null, + "tls_certificate_chain_sha256": null, + "trust_sha256": null, + "owner_originality_provenance_reference": null, + "private_custody_entrypoint_reference": null + }, + "candidate_selector": { + "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" + }, + "selector_status": "current_source_correspondence_only_no_archive_or_owner_assent", + "current_owner_assent_reference": null, + "reviewed_complete_source_closure_reference": null, + "exact_admission_sha256": null, + "nonexecutable_command_shape": [ + "bash", + "tools/bootstrap-recovery/run-isolated-keycape.sh", + "", + "", + "", + "", + "", + "" + ], + "verification": [ + "Pre-input metadata/source/dependency/target checks before hidden prompt", + "Authenticated archive validation and exact-one original selector before further runtime/private reads", + "Pinned original-image issuer/JWKS/TLS/native positive and negative checks", + "Independent sanitized receipt and exact cleanup verification" + ], + "rollback_and_abort": "Abort on any refusal/failure/uncertainty; exact session-scoped removal and safe evidence only. No production rollback or broad cleanup authorized.", + "deadline_seconds": 1800, + "native_checker_timeout_seconds": 150, + "cost_estimate_eur": null, + "credible_loss_bound_eur": null, + "estimate_status": "Unknown for actual custody/native operation; supervisor must evaluate concrete completed proposal. No budget or authority granted.", + "supervisor_disposition": null, + "approved_revision_digest": null, + "executed_revision_digest": null, + "actual_outcome": null, + "blocked_on": [ + "Original independent TLS public identity/trust provenance and private custody, or explicit accepted reissue/continuity disposition", + "Exact archive-to-selector binding and current actual owner recovery assent", + "Consumer outage-compatible accepted source/proof scope", + "Complete re-reviewed source/dependency closure after adapter guard change" + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/original-behavior-regression.txt b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/original-behavior-regression.txt new file mode 100644 index 00000000..aa252abc --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/original-behavior-regression.txt @@ -0,0 +1,65 @@ +test_absent_original_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_absent_original_selector_refused_before_further_inputs) ... ERROR +test_conflicting_duplicate_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_conflicting_duplicate_selector_refused_before_further_inputs) ... ERROR +test_empty_registry_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_empty_registry_refused_before_further_inputs) ... ERROR +test_identical_duplicate_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_identical_duplicate_selector_refused_before_further_inputs) ... ERROR + +====================================================================== +ERROR: test_absent_original_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_absent_original_selector_refused_before_further_inputs) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 77, in test_absent_original_selector_refused_before_further_inputs + self.assert_refused_before_further_inputs([dict(self.client(),clientId='unrelated')]) + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 71, in assert_refused_before_further_inputs + with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py", line 325, in run_verifier + issuer = session['issuer'] + ~~~~~~~^^^^^^^^^^ +KeyError: 'issuer' + +====================================================================== +ERROR: test_conflicting_duplicate_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_conflicting_duplicate_selector_refused_before_further_inputs) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 81, in test_conflicting_duplicate_selector_refused_before_further_inputs + self.assert_refused_before_further_inputs([self.client(),dict(self.client(),secretRef='env:OTHER')]) + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 71, in assert_refused_before_further_inputs + with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py", line 325, in run_verifier + issuer = session['issuer'] + ~~~~~~~^^^^^^^^^^ +KeyError: 'issuer' + +====================================================================== +ERROR: test_empty_registry_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_empty_registry_refused_before_further_inputs) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 83, in test_empty_registry_refused_before_further_inputs + self.assert_refused_before_further_inputs([]) + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 71, in assert_refused_before_further_inputs + with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py", line 325, in run_verifier + issuer = session['issuer'] + ~~~~~~~^^^^^^^^^^ +KeyError: 'issuer' + +====================================================================== +ERROR: test_identical_duplicate_selector_refused_before_further_inputs (selector_regressions.OriginalSelectorTests.test_identical_duplicate_selector_refused_before_further_inputs) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 79, in test_identical_duplicate_selector_refused_before_further_inputs + self.assert_refused_before_further_inputs([self.client(),self.client()]) + File "/home/worsch/net-kingdom/tests/test_isolated_keycape_recovery.py", line 71, in assert_refused_before_further_inputs + with self.assertRaises(a.Refused):a.run_verifier({},admission,payload) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py", line 325, in run_verifier + issuer = session['issuer'] + ~~~~~~~^^^^^^^^^^ +KeyError: 'issuer' + +---------------------------------------------------------------------- +Ran 4 tests in 0.023s + +FAILED (errors=4) diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-declaration.template.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-declaration.template.json new file mode 100644 index 00000000..3b653622 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-declaration.template.json @@ -0,0 +1,38 @@ +{ + "status": "draft_for_actual_owners_no_assent", + "tls": { + "source_owner": "railiance-cluster", + "namespace_intent_owner": "net-kingdom", + "original_private_custody_owner": null, + "provider": null, + "artifact_reference": null, + "capture_time": null, + "capture_binding_to_archive_attempt": null, + "independent_private_custody_entrypoint_reference": null, + "outage_prerequisites": null, + "public_metadata_receipt": null, + "reissue_disposition_reference": null, + "accepted_continuity_scope": null, + "owner_review_reference": null + }, + "consumer": { + "source_owner": "secrets-engine", + "selector": { + "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" + }, + "current_recovery_assent_reference": null, + "exact_archived_registration_uniqueness_receipt": null, + "archive_to_consumer_binding_receipt": null, + "outage_compatible_private_custody_plan_reference": null, + "continuity_scope_disposition_reference": null, + "owner_review_reference": null + }, + "instruction": "Actual owners fill references through existing processes; agents do not fabricate owner/founder assent. Never include values, private manifest digest or executable approval tokens." +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-source.patch b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-source.patch new file mode 100644 index 00000000..76ce0490 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/owner-source.patch @@ -0,0 +1,136 @@ +--- 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,24 @@ + `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 diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/isolated-keycape-native-fixture-manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/isolated-keycape-native-fixture-manifest.json new file mode 100644 index 00000000..53d6b54e --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/isolated-keycape-native-fixture-manifest.json @@ -0,0 +1,124 @@ +{ + "schema": "nk49.keycape-native-fixture-proposal.v1", + "status": "prepared_not_executed_not_approved", + "source_sha256": { + "sso-mfa/bootstrap/sops-private.py": "sha256:acac68e2936ed38b7d7c9e35eb4619647c99c117a3928a1c5ce704b570906780", + "sso-mfa/k8s/privacyidea/key-custody-remote.py": "sha256:27b2b885c81923d85054e3999c5613e104fe627779b2b50398ed9bed5088f47e", + "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: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", + "tools/bootstrap-recovery/fetch-privacyidea-backup.py": "sha256:233160e1206643a5cf7ad05141d733f0a75aff651190e27f77515a124ff0a59f", + "tools/bootstrap-recovery/identity-backup-profile.json": "sha256:40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1", + "tools/bootstrap-recovery/identity-bundle.py": "sha256:524a03c065db4307fcde83d33af39503f3de19cb6ef3a8ca72c991d4a8c08ee6", + "tools/bootstrap-recovery/identity-credential-setup.py": "sha256:ddd6127fa331c0185523ec3bb22d743a791edd56a2e6af7ad8d7949b7c051141", + "tools/bootstrap-recovery/identity-custody.json": "sha256:f8aee8487ed01d7940b82676bb4a5c8d61f51b6c598521b8b8a73588aaea4d4f", + "tools/bootstrap-recovery/identity-files.py": "sha256:d0063a9eedd3610e3d45bd2d834aae83cff74e4b3504d138b3548f427e89331d", + "tools/bootstrap-recovery/identity-isolation.py": "sha256:88d1e13112a44c79571825af89d3fe5b01fa490cff2653badef4c62a45c844f1", + "tools/bootstrap-recovery/identity-offsite.py": "sha256:e7c31fa9ee081961af873348ee3b4829a645d40c7dc7f1e22c564aa9ed01bc49", + "tools/bootstrap-recovery/identity-retention.py": "sha256:a41ea4759f69c35548149fc8d0d5ace547f16cf9fe4c9dac10b119a4d0becdec", + "tools/bootstrap-recovery/identity-runtime.py": "sha256:a2c0acf567c204705b90be64d561d0fda2285e0fc71a962d6e1b149f571e1940", + "tools/bootstrap-recovery/install-identity-backup.py": "sha256:5c612a2a51c9b59aad8cc01d418c2f563cbd92c62dc1fa8be994e5fb59df90f1", + "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: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", + "tools/bootstrap-recovery/recovery-kit.py": "sha256:6fa0f1494dccaf003b6c6396c5de8b36faa2b276eeb16badd04383f5efb71e66", + "tools/bootstrap-recovery/retrieve-identity-offline.py": "sha256:3421dbb3f3280a001d33ea2deb12ab609404a0b4254cd43c21518d77d166f972", + "tools/bootstrap-recovery/retrieve-identity.py": "sha256:ec123d47a07305253570dacab7e103f8c193a23f20c9fc87466ea4a95ae0ec13", + "tools/bootstrap-recovery/run-isolated-keycape.sh": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668", + "tools/bootstrap-recovery/verify-bundle.py": "sha256:885b05a2011e711228e42e316bda70bbe0d97d481383d61aa8469d0f10452370", + "tools/bootstrap-recovery/verify-identity-delivery.py": "sha256:63658d1976806f8d0ce80ba8f750bbcfdca59da936b6eb6a78a250f0e53710f1", + "tools/bootstrap-recovery/verify-identity.py": "sha256:039864d0141b552887752bf17cfdcf1bef4bdc9126f946a9c0533e4fd54ebf4f", + "sso-mfa/bootstrap/sops-custody-unlock.sh": "sha256:86c527a8ae0d0cca66a2345c566b25fbff5bc52c1e22c725548c0fbb2f86a58e", + "sso-mfa/bootstrap/sops-custody-fd.py": "sha256:df29eaba83ec6b5fc311664dcf4b22d8f3c8ed7274ed8e6c419ada0dcd169c0f", + "tools/bootstrap-recovery/prepare-isolated-keycape.py": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288", + "tests/test_prepare_isolated_keycape.py": "sha256:4b0871f9a11a3940983464f1b40eca1613110b1cb3cb9694f4891d58e14c700a", + "tests/test_sealed_custody.py": "sha256:f0fa07c89e2419464dbee0489462864a4533770417a554b1ab1d1ed5d7b6c49f", + "tests/test_private_manifest_binding.py": "sha256:2e7ee16af65390343435b7210ef191aa2a10e9dcbb8759ed95fa8bf6fb81893b" + }, + "fixed_endpoint": "unix:///var/run/docker.sock", + "engine_id": "74f93783-6cef-43a8-a3c4-f62586cd3bc1", + "engine_name": "bnt-lap001", + "images": [ + "forgejo.coulomb.social/coulomb/key-cape@sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010", + "ghcr.io/gpappsoft/privacyidea-docker@sha256:af7841adad262f129e0c1d4f553af13f21cb2f4dc713533f316cfe43ed0b4473" + ], + "pull_policy": "never", + "synthetic_issuer": "https://nk49-fixture.invalid", + "cases": [ + "positive", + "hard-parent-loss", + "deadline", + "nonzero-after-accept" + ], + "limits": { + "sequential_cases": true, + "max_live_service_containers": 2, + "max_tmpfs_volumes": 4, + "max_public_probe_containers": 1, + "service_memory_bytes_each": 536870912, + "service_cpus_each": 1, + "tmpfs_volume_bytes_each": 33554432, + "host_tmpfs_fixture_limit_expected_bytes": 8388608, + "execution_deadline_seconds": { + "deadline_case": 20, + "other_cases": 120 + }, + "driver_wait_seconds_per_case": 150 + }, + "resources": { + "container_names": "nk49-kc--{transport,issuer,image-probe}", + "volume_names": "nk49-kc--v{0,1,2,3}", + "label": "net-kingdom.recovery-run=", + "host_plaintext": "exact private /dev/shm/nk49-keycape-- registered before writes", + "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; 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", + "original-image KeyCape service/client exchange within same loopback-only namespace", + "exact owned quiescent removal and bounded safe receipts" + ], + "forbidden": [ + "Docker execution before independent approval", + "image pulls/builds/pushes", + "production routes/ports/host networking/host directory mounts", + "OpenBao/Kubernetes/provider APIs", + "actual identity archive, age key, TLS key, user password, factor or client secret" + ], + "cleanup": "candidate exact ownership/volume-driver/inode checks; quiesce fresh owner SID/PGID via pidfds first; retained inflight uncertainty never accepted even on absent readback", + "oracles": [ + "positive issuer-native verify-client must establish original-hostname HTTPS trust; helper alone never suffices", + "same original single RS256 key-1 JWKS and exact config/registry/policy/history/lock/deliveries", + "correct service exchange and explicit wrong-secret/excess-scope denial through existing native verifier", + "hard-parent-loss and tightened deadline both quiesce before exact resource/plaintext cleanup", + "after real Docker run accepts a synthetic container, inject returncode1; require failed recovery and sticky daemon uncertainty after cleanup" + ], + "proposed_command": [ + "python3", + "tests/run_isolated_keycape_native_fixture.py", + "--execute-reviewed-fixture", + "--expected-manifest-sha256", + "", + "--case", + "positive" + ], + "extended_command": [ + "python3", + "tests/run_isolated_keycape_native_fixture.py", + "--execute-reviewed-fixture", + "--expected-manifest-sha256", + "", + "--case", + "all" + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/test_isolated_keycape_recovery.py b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/test_isolated_keycape_recovery.py new file mode 100644 index 00000000..b2a4455c --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tests/test_isolated_keycape_recovery.py @@ -0,0 +1,262 @@ +import base64 +import hashlib +import importlib.util +import io +import json +import subprocess +import tarfile +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +SOURCE=Path(__file__).parents[1]/'tools/bootstrap-recovery/isolated-keycape.py' +spec=importlib.util.spec_from_file_location('adapter',SOURCE) +a=importlib.util.module_from_spec(spec);spec.loader.exec_module(a) + +class ArchiveTests(unittest.TestCase): + def setUp(self): + self.tmp=tempfile.TemporaryDirectory();self.addCleanup(self.tmp.cleanup) + self.root=Path(self.tmp.name) + config={'data':{k:base64.b64encode(v).decode() for k,v in {'config.yaml':b'issuer: https://issuer.example','key.pem':b'fixture-key'}.items()}} + self.values={'resources/sso/secret/keycape-config.json':json.dumps(config).encode(), + 'resources/sso/deployment/keycape.json':json.dumps({'spec':{'template':{'spec':{'containers':[{'name':'keycape','image':a.IMAGE,'env':[ + {'name':'KEYCAPE_CONFIG','value':'/etc/keycape/config.yaml'}, + {'name':'KEYCAPE_POLICY_PATH','value':'/var/lib/keycape-policy/policy.json'}, + {'name':'KEYCAPE_ORIGINAL_SECRET','valueFrom':{'secretKeyRef':{'name':'client','key':'secret'}}}]}]}}}}).encode(), + 'resources/sso/secret/client.json':json.dumps({'data':{'secret':base64.b64encode(b'fixture-private').decode()}}).encode(), + 'data/keycape/policy.json':b'{}','data/keycape/receipts/one.json':b'{"original":true}'} + for name,value in self.values.items(): + p=self.root/name;p.parent.mkdir(parents=True,exist_ok=True);p.write_bytes(value);p.chmod(0o600) + self.manifest={'profile':{'components':[{'namespace':'sso','deployment':'keycape','secret_refs':['keycape-config','client'],'configmap_refs':[]}]}, + 'files':[{'path':k,'bytes':len(v),'sha256':hashlib.sha256(v).hexdigest()} for k,v in self.values.items()]} + def payload(self): + digest=hashlib.sha256(json.dumps(self.manifest,sort_keys=True,separators=(',',':')).encode()).hexdigest() + return a.private_payload(self.root,self.manifest,digest) + def test_original_state_and_secret_delivery_retained(self): + p=self.payload();self.assertEqual(p['env']['KEYCAPE_ORIGINAL_SECRET'],'fixture-private') + self.assertEqual(base64.b64decode(p['files']['/var/lib/keycape-policy/receipts/one.json']),b'{"original":true}') + def test_archive_digest_refused(self): + with self.assertRaises(a.Refused):a.private_payload(self.root,self.manifest,'0'*64) + def test_changed_file_refused(self): + (self.root/'data/keycape/policy.json').write_text('{"changed":true}') + with self.assertRaises(a.Refused):self.payload() + def test_symlink_refused(self): + p=self.root/'data/keycape/policy.json';p.unlink();p.symlink_to('/etc/hostname') + with self.assertRaises(Exception):self.payload() + def test_duplicate_manifest_refused(self): + self.manifest['files'].append(self.manifest['files'][0]) + with self.assertRaises(a.Refused):self.payload() + def test_image_mismatch_refused(self): + d=json.loads(self.values['resources/sso/deployment/keycape.json']);d['spec']['template']['spec']['containers'][0]['image']='keycape:latest' + raw=json.dumps(d).encode();p=self.root/'resources/sso/deployment/keycape.json';p.write_bytes(raw) + 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): + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import rsa + self.key=rsa.generate_private_key(public_exponent=65537,key_size=2048).private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()) + self.cfg=b'issuer: https://issuer.example\nclients:\n- clientId: existing\n clientType: confidential\n secretRef: env:KEYCAPE_ORIGINAL_SECRET\n grantTypes: [client_credentials]\n' + self.files={'/etc/keycape/config.yaml':self.cfg,'/etc/keycape/key.pem':self.key,'/var/lib/keycape-policy/policy.json':b'{}'} + self.payload={'env':{'KEYCAPE_ORIGINAL_SECRET':'fixture-private'},'files':{k:base64.b64encode(v).decode() for k,v in self.files.items()}} + self.admission={'issuer':'https://issuer.example','verifier_sha256':hashlib.sha256(b'binary').hexdigest(), + 'trust_path':'/trust.pem','trust_sha256':hashlib.sha256(b'original-trust').hexdigest(), + 'consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET','scope':'read','audience':'consumer', + 'subject':'service:existing','tenant':'tenant:platform','roles':'reader','deny_scope':'write'}} + self.session={'issuer':'isolated','volumes':{x:{'target':x} for x in ('/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls')}} + self.output=''.join('PASS '+x+'\n' for x in ['discovery and endpoint origin','exchange and JWKS signature for granted scopes','access-token claim bindings','principal_type is service','sub matches the registration','tenant matches the registration','roles present','granted scope carries no excess grant','predecessor secret refused','excess scope refused: write']) + def file(self,container,path): + return {**self.files,'/etc/hosts':b'127.0.0.1 issuer.example\n','/keycape':b'binary','/trust.pem':b'original-trust'}[path] + def command(self,argv,**kwargs): + if argv[1:3]==['container','inspect']:return json.dumps(['KEYCAPE_ORIGINAL_SECRET=fixture-private','SSL_CERT_FILE=/trust.pem']).encode() + output=io.BytesIO() + with tarfile.open(fileobj=output,mode='w') as t: + m=tarfile.TarInfo('policy.json');m.size=2;t.addfile(m,io.BytesIO(b'{}')) + return output.getvalue() + def verify(self,code=0,output=None): + with patch.object(a,'check_jwks'),patch.object(a,'runtime_file',return_value=b'original-trust'),patch.object(a,'runtime_files',side_effect=lambda session,paths=(),tree=False:({k:v for k,v in self.files.items() if k.startswith('/var/lib/keycape-policy/')} if tree else dict(self.files))),patch.object(a,'container_file',side_effect=self.file),patch.object(a,'command',side_effect=self.command),patch.object(a.subprocess,'run',return_value=subprocess.CompletedProcess([],code,b'',(self.output if output is None else output).encode())) as run: + result=a.run_verifier(self.session,self.admission,self.payload) + argv=run.call_args.args[0] + self.assertNotIn('fixture-private',' '.join(argv)) + self.assertIn('-previous-secret-env',argv) + return result + def test_original_registration_and_unrelated_secret(self): + r=self.verify();self.assertTrue(r['wrong_unrelated_secret_explicitly_refused']);self.assertNotIn('fixture-private',json.dumps(r)) + def test_transport_failure_never_counts_as_wrong_secret(self): + with self.assertRaises(a.Refused):self.verify(1,'FAIL discovery and endpoint origin: TLS failure\n') + def test_missing_explicit_rejection_never_counts(self): + with self.assertRaises(a.Refused):self.verify(0,self.output.replace('PASS predecessor secret refused\n','')) + def test_fail_line_refused_even_zero_exit(self): + with self.assertRaises(a.Refused):self.verify(0,self.output+'FAIL transport\n') + def test_security_environment_override_refused(self): + original=self.command + def altered(argv,**kwargs): + if argv[1:3]==['container','inspect']:return json.dumps(['KEYCAPE_ORIGINAL_SECRET=fixture-private','SSL_CERT_FILE=/trust.pem','SSL_CERT_DIR=/unreviewed']).encode() + return original(argv,**kwargs) + with patch.object(self,'command',side_effect=altered): + with self.assertRaises(a.Refused):self.verify() + def test_http_issuer_refused(self): + self.admission['issuer']='http://issuer.example' + with self.assertRaises(a.Refused):self.verify() + def test_changed_trust_refused(self): + self.admission['trust_sha256']='0'*64 + with self.assertRaises(a.Refused):self.verify() + def test_config_drift_refused(self): + self.payload['files']['/etc/keycape/config.yaml']=base64.b64encode(b'changed').decode() + with self.assertRaises(a.Refused):self.verify() + +class PublicReadinessTransportTests(unittest.TestCase): + def test_provider_probe_failure_is_closed_false_data_not_failed_docker_exec(self): + output=io.StringIO() + with patch('sys.stdin',io.StringIO('{}')),patch('sys.stdout',output): + exec(compile(a.JWKS_TRANSPORT,'','exec',optimize=2),{}) + self.assertEqual(json.loads(output.getvalue()),{'original_public_signing_key_in_live_jwks':False}) + +class BoundaryTests(unittest.TestCase): + def test_remote_docker_refused_before_info(self): + session={'run_id':'a'*32,'containers':['nk49-kc-'+('a'*32)+'-worker'],'worker':'nk49-kc-'+('a'*32)+'-worker','issuer':'nk49-kc-'+('a'*32)+'-worker'} + with patch.object(a,'command',return_value=b'[{"Endpoints":{"docker":{"Host":"tcp://remote:2375"}}}]') as command: + with self.assertRaises(a.Refused):a.inspect_session(session) + self.assertEqual(command.call_count,1) + def test_failed_verifier_cleanup_is_attempted(self): + receipt={};admission={'session':{},'ciphertext_sha256':'a'*64,'manifest_sha256':'b'*64,'verifier_sha256':'c'*64,'trust_sha256':'d'*64,'consumer':{x:'yes' for x in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope')}} + with patch.object(a,'inspect_session'),patch.object(a,'private_payload',return_value={}),patch.object(a,'run_verifier',side_effect=a.Refused),patch.object(a,'cleanup') as cleanup: + with self.assertRaises(a.Refused):a.native_checks(Path('/unused'),{},admission,receipt) + cleanup.assert_called_once();self.assertTrue(receipt['container_cleanup_verified']);self.assertEqual(receipt['status'],'failed') + + def test_cleanup_failure_overrides_success(self): + admission={'session':{},'ciphertext_sha256':'a'*64,'manifest_sha256':'b'*64,'verifier_sha256':'c'*64,'trust_sha256':'d'*64,'consumer':{x:'yes' for x in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope')}} + result={x:True for x in ('native_service_registration_verified','wrong_unrelated_secret_explicitly_refused','denied_scopes_refused','original_config_registry_policy_receipts_equal','original_https_issuer_and_trust_preserved','original_public_signing_key_in_live_jwks')} + result['public_signing_spki_sha256']='e'*64;receipt={} + with patch.object(a,'inspect_session'),patch.object(a,'private_payload',return_value={}),patch.object(a,'run_verifier',return_value=result),patch.object(a,'cleanup',side_effect=a.Refused): + with self.assertRaises(a.Refused):a.native_checks(Path('/unused'),{},admission,receipt) + self.assertEqual(receipt['status'],'failed');self.assertFalse(receipt['container_cleanup_verified']) + +class ContainmentTests(unittest.TestCase): + def inspect(self,overrides=None,launch=None,mounts=None): + name='nk49-kc-'+('a'*32)+'-issuer' + session={'run_id':'a'*32,'containers':[name],'issuer':name,'worker':name,'images':{name:a.IMAGE}} + host={'NetworkMode':'none','ReadonlyRootfs':True,'Privileged':False,'CapDrop':['ALL'],'SecurityOpt':['no-new-privileges']} + host.update(overrides or {}) + def command(argv,**kwargs): + if argv[1:3]==['context','inspect']:return b'[{"Endpoints":{"docker":{"Host":"unix:///var/run/docker.sock"}}}]' + if argv[1]=='info':return b'{"ID":"74f93783-6cef-43a8-a3c4-f62586cd3bc1","Name":"bnt-lap001","OSType":"linux"}' + if argv[-1]=='{{.Id}}':return b'anchor-id' + if '"path"' in argv[-1]:return json.dumps(launch or {'entrypoint':['/keycape'],'cmd':None,'path':'/keycape','args':[]}).encode() + return json.dumps({'host':host,'mounts':mounts or [],'labels':{a.LABEL:'a'*32},'image':a.IMAGE,'user':'1000:1000'}).encode() + with patch.object(a,'command',side_effect=command),patch.dict('os.environ',{'DOCKER_HOST':'unix:///var/run/docker.sock'}):a.inspect_session(session) + def test_minimal_network_none_admitted(self):self.inspect() + def test_image_declared_anonymous_disk_volume_remains_refused(self): + with self.assertRaises(a.Refused): + self.inspect(mounts=[{'Type':'volume','Name':'anonymous-fixture','Destination':'/privacyidea/etc/persistent','RW':True}]) + + def test_alternate_same_image_command_refused(self): + with self.assertRaises(a.Refused):self.inspect(launch={'entrypoint':['/keycape'],'cmd':['check-config'],'path':'/keycape','args':['check-config']}) + def test_cap_add_refused(self): + with self.assertRaises(a.Refused):self.inspect({'CapAdd':['NET_ADMIN']}) + def test_devices_refused(self): + with self.assertRaises(a.Refused):self.inspect({'Devices':[{'PathOnHost':'/dev/mem'}]}) + def test_device_requests_refused(self): + with self.assertRaises(a.Refused):self.inspect({'DeviceRequests':[{'Driver':'nvidia'}]}) + def test_host_namespace_refused(self): + for field in ('PidMode','IpcMode','UTSMode','UsernsMode','CgroupnsMode'): + with self.subTest(field=field),self.assertRaises(a.Refused):self.inspect({field:'host'}) + def test_security_override_refused(self): + with self.assertRaises(a.Refused):self.inspect({'SecurityOpt':['no-new-privileges','seccomp=unconfined']}) + +class CleanupTests(unittest.TestCase): + def test_partial_cleanup_attempts_every_owned_container(self): + session={'run_id':'a'*32,'containers':['first','second','third']};receipt={} + removed=[] + def command(argv,**kwargs): + if argv[1:3]==['container','inspect']:return ('a'*32).encode() + if argv[1]=='rm': + removed.append(argv[-1]) + if argv[-1]=='third':raise a.Refused() + return b'' + if argv[1:3]==['container','ls']: + name=next(x for x in argv if x.startswith('name=^/')).removeprefix('name=^/').removesuffix('$') + return (name+'\n').encode() if name=='third' or name not in removed else b'' + return b'' + with patch.object(a,'command',side_effect=command): + with self.assertRaises(a.Refused):a.cleanup(session,receipt) + self.assertEqual(removed,['third','second','first']) + self.assertEqual([r['status'] for r in receipt['container_cleanup_obligations']],['still_present','absence_verified','absence_verified']) + def test_ownership_mismatch_does_not_remove_and_continues(self): + session={'run_id':'a'*32,'containers':['first','second']};receipt={};removed=[] + def command(argv,**kwargs): + if argv[1:3]==['container','inspect']:return (('b' if argv[3]=='second' else 'a')*32).encode() + if argv[1]=='rm':removed.append(argv[-1]) + if argv[1:3]==['container','ls']: + name=next(x for x in argv if x.startswith('name=^/')).removeprefix('name=^/').removesuffix('$') + return (name+'\n').encode() if name not in removed else b'' + return b'' + with patch.object(a,'command',side_effect=command): + with self.assertRaises(a.Refused):a.cleanup(session,receipt) + self.assertEqual(removed,['first']) + self.assertEqual(receipt['container_cleanup_obligations'][0]['status'],'ownership_mismatch_not_removed') + def test_inspect_failure_retains_uncertain_obligation(self): + receipt={} + with patch.object(a,'command',side_effect=a.Refused): + with self.assertRaises(a.Refused):a.cleanup({'run_id':'a'*32,'containers':['exact-owned-name']},receipt) + self.assertEqual(receipt['container_cleanup_obligations'],[{'container':'exact-owned-name','status':'unverified'}]) + +class JWKSTests(unittest.TestCase): + def execute(self,n='123',endpoint='https://issuer.example/jwks',resolved='127.0.0.1',extra=False,kid='key-1'): + request={'issuer':'https://issuer.example','trust':'public-certificate','n':'123','e':'65537'} + def enc(i):return base64.urlsafe_b64encode(int(i).to_bytes((int(i).bit_length()+7)//8,'big')).decode().rstrip('=') + responses=[{'issuer':'https://issuer.example','jwks_uri':endpoint},{'keys':[{'kty':'RSA','kid':kid,'use':'sig','alg':'RS256','n':enc(n),'e':enc(65537)}]}] + if extra:responses[1]['keys'].append(dict(responses[1]['keys'][0],kid='key-2')) + class Response: + def __init__(self,value):self.value=value + def __enter__(self):return self + def __exit__(self,*args):pass + def read(self,*args):return json.dumps(self.value).encode() + class Opener: + def open(self,*args,**kwargs):return Response(responses.pop(0)) + with patch('sys.stdin',io.StringIO(json.dumps(request))),patch('sys.stdout',io.StringIO()),patch('socket.getaddrinfo',return_value=[(2,1,6,'',(resolved,443))]),patch('ssl.create_default_context'),patch('urllib.request.build_opener',return_value=Opener()): + exec(compile(a.JWKS_PROBE,'','exec',optimize=2),{}) + def test_exact_original_public_key(self):self.execute() + def test_extra_signing_key_refused_under_optimization(self): + with self.assertRaises(ValueError):self.execute(extra=True) + def test_wrong_kid_refused_under_optimization(self): + with self.assertRaises(ValueError):self.execute(kid='replacement') + def test_wrong_live_signing_key_refused(self): + with self.assertRaises(ValueError):self.execute(n='124') + def test_cross_origin_jwks_refused(self): + with self.assertRaises(ValueError):self.execute(endpoint='https://production.example/jwks') + def test_production_dns_refused_before_fetch(self): + with self.assertRaises(ValueError):self.execute(resolved='192.0.2.1') + +if __name__=='__main__':unittest.main() diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tools/bootstrap-recovery/isolated-keycape.py b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tools/bootstrap-recovery/isolated-keycape.py new file mode 100644 index 00000000..44a3a117 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/tools/bootstrap-recovery/isolated-keycape.py @@ -0,0 +1,487 @@ +#!/usr/bin/env python3 +"""T18 native adapter for an owner-admitted, already restored isolated session. + +Called after identity-bundle.restore, never with an unvalidated directory. This +module does not provision TLS, grant credentials, or claim downstream acceptance. +The existing decrypt/tmpfs wrapper remains responsible for archive cleanup. +""" +import base64 +import hashlib +import importlib.util +import json +import io +import os +import secrets +import tarfile +import time +import re +import subprocess +from pathlib import Path + +HERE = Path(__file__).resolve().parent +IMAGE = 'forgejo.coulomb.social/coulomb/key-cape@sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010' +LABEL = 'net-kingdom.recovery-run' + + +class Refused(Exception): + pass + + +def load_bundle(): + spec = importlib.util.spec_from_file_location('identity_bundle', HERE / 'identity-bundle.py') + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def manifest_binding_mode(admission,transfer): + """Versioned private-manifest binding; legacy explicit digests stay valid.""" + mode=admission.get('manifest_binding_mode','explicit-digest-v1') + if mode not in ('explicit-digest-v1','ciphertext-derived-v1'):raise Refused() + if (not isinstance(admission.get('ciphertext_sha256'),str) + or not re.fullmatch('[a-f0-9]{64}',admission['ciphertext_sha256']) + or admission['ciphertext_sha256']!=transfer.get('ciphertext_sha256') + or transfer.get('independent_owner_retrieval_verified') is not True):raise Refused() + if mode=='explicit-digest-v1': + if not isinstance(admission.get('manifest_sha256'),str) or not re.fullmatch('[a-f0-9]{64}',admission['manifest_sha256']):raise Refused() + elif 'manifest_sha256' in admission:raise Refused() + return mode + + +def private_manifest_admission(admission,manifest): + # Only called after the fixed ciphertext bytes were hashed, authenticated + # decryption succeeded and bundle.restore checked the complete archive. + # Never return this enriched private object in a safe receipt/checkpoint. + digest=hashlib.sha256(json.dumps(manifest,sort_keys=True,separators=(',',':')).encode()).hexdigest() + mode=admission.get('manifest_binding_mode','explicit-digest-v1') + if mode=='explicit-digest-v1': + if digest!=admission['manifest_sha256']:raise Refused() + elif mode!='ciphertext-derived-v1' or 'manifest_sha256' in admission:raise Refused() + return {**admission,'manifest_sha256':digest} + + +def private_payload(root, manifest, expected_manifest_sha256): + """Bind the complete validated archive before selecting KeyCape material. + + Private hashes never enter the public receipt. The digest is supplied by the + existing private archive admission, not inferred from an untrusted manifest. + """ + encoded = json.dumps(manifest, sort_keys=True, separators=(',', ':')).encode() + if hashlib.sha256(encoded).hexdigest() != expected_manifest_sha256: + raise Refused() + entries = manifest['files'] + if len(entries) != len({e['path'] for e in entries}): + raise Refused() + values = {} + bundle = load_bundle() + for entry in entries: + if not bundle.allowed(entry['path'], manifest['profile']): + raise Refused() + path = root / entry['path'] + bundle.private(path) + value = path.read_bytes() + if len(value) != entry['bytes'] or hashlib.sha256(value).hexdigest() != entry['sha256']: + raise Refused() + values[entry['path']] = value + deployment = json.loads(values['resources/sso/deployment/keycape.json']) + main = next(c for c in deployment['spec']['template']['spec']['containers'] if c['name'] == 'keycape') + if main.get('command') or main.get('args') or main.get('envFrom'): + raise Refused() + if main['image'] != IMAGE: + # Mutable-tag/historical mismatches need a separate explicit owner admission. + raise Refused() + secret = json.loads(values['resources/sso/secret/keycape-config.json'])['data'] + files = {'/etc/keycape/' + name: base64.b64decode(secret[name], validate=True) + for name in ('config.yaml', 'key.pem')} + for path, value in values.items(): + if path.startswith('data/keycape/'): + relative = path.removeprefix('data/keycape/') + files['/var/lib/keycape-policy/' + relative] = value + if '/var/lib/keycape-policy/policy.json' not in files: + raise Refused() + if 'resources/sso/secret/keycape-factor-read.json' in values: + factor=json.loads(values['resources/sso/secret/keycape-factor-read.json'])['data'] + files['/etc/keycape-factor/admin-token']=base64.b64decode(factor['admin-token'],validate=True) + # Resolve original delivered environment, including all referenced secrets. + env = {} + for item in main.get('env', []): + if not re.fullmatch(r'KEYCAPE_[A-Z0-9_]+',item['name']):raise Refused() + if item['name'] in env: + raise Refused() + if 'value' in item: + env[item['name']] = item['value'] + else: + ref = item['valueFrom']['secretKeyRef'] + source = json.loads(values['resources/sso/secret/' + ref['name'] + '.json'])['data'] + env[item['name']] = base64.b64decode(source[ref['key']], validate=True).decode() + if env.get('KEYCAPE_CONFIG') != '/etc/keycape/config.yaml' or env.get('KEYCAPE_POLICY_PATH') != '/var/lib/keycape-policy/policy.json': + raise Refused() + return {'files': {p: base64.b64encode(v).decode() for p, v in files.items()}, 'env': env} + + +ENDPOINT = 'unix:///var/run/docker.sock' +EXECUTION = None + + +def docker_environment(environment=None): + # Even an admitted daemon exposed by another Unix socket is outside this + # exact session binding. Conflicting ambient routing is refused, not ignored. + for source in (os.environ, environment or {}): + if source.get('DOCKER_HOST') not in (None,'',ENDPOINT):raise Refused() + if source.get('DOCKER_CONTEXT') not in (None,'','default'):raise Refused() + if any(source.get(k) for k in ('DOCKER_TLS_VERIFY','DOCKER_CERT_PATH')):raise Refused() + env=dict(os.environ if environment is None else environment) + for key in ('DOCKER_CONTEXT','DOCKER_TLS_VERIFY','DOCKER_CERT_PATH'):env.pop(key,None) + env['DOCKER_HOST']=ENDPOINT + return env + + +def process(argv, **kwargs): + marker=None + if EXECUTION is not None and (kwargs.get('start_new_session') or kwargs.get('process_group') not in (None,-1)):raise Refused() + if argv[0]=='docker': + argv=['docker','--host',ENDPOINT,*argv[1:]] + kwargs['env']=docker_environment(kwargs.get('env')) + if EXECUTION is not None: + if (os.getpid()!=EXECUTION['pid'] or os.getsid(0)!=EXECUTION['sid'] or os.getpgrp()!=EXECUTION['pgid'] + or time.monotonic()>=EXECUTION['deadline']):raise Refused() + marker=Path(EXECUTION['staging']+'-docker-inflight') + fd=os.open(marker,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + os.close(fd) + try: + result=subprocess.run(argv,**kwargs) + if marker is not None and result.returncode!=0: + fd=os.open(Path(EXECUTION['staging']+'-docker-uncertain'),os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW,0o600);os.close(fd) + return result + except BaseException: + # Parent loss leaves .docker-inflight; caught timeout/transport failures + # retain a sticky uncertainty marker even if later cleanup can run. + if marker is not None: + fd=os.open(Path(EXECUTION['staging']+'-docker-uncertain'),os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW,0o600);os.close(fd) + raise + finally: + if marker is not None: + try:marker.unlink() + except FileNotFoundError:pass + + +def command(argv, **kwargs): + maximum = kwargs.pop('max_output', 32768) + result = process(argv, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + timeout=kwargs.pop('timeout', 180), **kwargs) + if result.returncode or len(result.stdout) > maximum: + raise Refused() + return result.stdout + + +def inspect_session(session, worker_only=False): + """No credential environment is read by Docker inspect or returned to caller.""" + if not re.fullmatch(r'[a-f0-9]{32}', session['run_id']): + raise Refused() + names = session['containers'] + if not names or len(names) > 12 or len(set(names)) != len(names): + raise Refused() + for name in names: + if not re.fullmatch(r'nk49-kc-' + session['run_id'] + r'-[a-z0-9-]{1,24}', name): + raise Refused() + if session['worker'] not in names or session['issuer'] not in names: + raise Refused() + import os + contexts=json.loads(command(['docker','context','inspect'])) + endpoints=[contexts[0]['Endpoints']['docker']['Host'],os.environ.get('DOCKER_HOST') or ENDPOINT] + if not all(x==ENDPOINT for x in endpoints):raise Refused() + info = json.loads(command(['docker', 'info', '--format', '{"ID":{{json .ID}},"Name":{{json .Name}},"OSType":{{json .OSType}}}'])) + if info != {'ID': '74f93783-6cef-43a8-a3c4-f62586cd3bc1', 'Name': 'bnt-lap001', 'OSType': 'linux'}: + raise Refused() + # The worker is the anchor; all dependencies/TLS/issuer share its network-none namespace. + anchor = command(['docker', 'container', 'inspect', session['worker'], '--format', '{{.Id}}']).decode().strip() + for name,spec in session.get('volumes',{}).items(): + volume=json.loads(command(['docker','volume','inspect',name])) + expected={'type':'tmpfs','device':'tmpfs','o':'size=33554432,uid=1000,gid=1000,mode=0700,nosuid,nodev,noexec'} + if len(volume)!=1 or volume[0]['Driver']!='local' or volume[0].get('Scope')!='local' or volume[0].get('Options')!=expected or spec['options']!=expected or volume[0].get('Labels',{}).get(LABEL)!=session['run_id']:raise Refused() + for name in names: + obj = json.loads(command(['docker', 'container', 'inspect', name, '--format', + '{"host":{{json .HostConfig}},"mounts":{{json .Mounts}},"labels":{{json .Config.Labels}},"image":{{json .Config.Image}},"user":{{json .Config.User}},"entrypoint":{{json .Config.Entrypoint}},"cmd":{{json .Config.Cmd}}}'])) + host = obj['host'] + mounts=obj['mounts'] + destinations=[m['Destination'] for m in mounts] + if len(destinations)!=len(set(destinations)):raise Refused() + for volume,expected_spec in session.get('volumes',{}).items(): + matches=[m for m in mounts if m['Destination']==expected_spec['target']] + if len(matches)!=1 or matches[0]['Type']!='volume' or matches[0]['Name']!=volume or matches[0]['RW']!=(name==session['worker'] or expected_spec['target']=='/var/lib/keycape-policy'):raise Refused() + if (obj['labels'].get(LABEL) != session['run_id'] or not obj['user'] or obj['user'].split(':')[0] in ('0', 'root') + or not host['ReadonlyRootfs'] or host['Privileged'] or host.get('Binds') or host.get('PortBindings') + or host.get('PidMode') or host.get('IpcMode') == 'host' + or host.get('UTSMode') or host.get('UsernsMode') == 'host' or host.get('CgroupnsMode') == 'host' + or host.get('Sysctls',{}) not in ({},{'net.ipv4.ip_unprivileged_port_start':'0'} if name==session['worker'] else {}) + or host.get('CapAdd') or host.get('Devices') or host.get('DeviceRequests') or host.get('VolumesFrom') + or host.get('CapDrop') != ['ALL'] + or host.get('SecurityOpt') not in (['no-new-privileges'], ['no-new-privileges:true']) + or any(m['Type']!='tmpfs' and not (m['Type']=='volume' and m['Name'] in session.get('volumes',{}) and m['Destination']==session['volumes'][m['Name']]['target']) for m in obj['mounts']) + or host['NetworkMode'] != ('none' if name == session['worker'] else 'container:' + anchor) + or obj['image'] != session['images'][name] or '@sha256:' not in obj['image']): + raise Refused() + if worker_only:return + if session['images'][session['issuer']] != IMAGE: + raise Refused() + # Known admitted archive has no command/args override; image default /keycape + # must be the actual issuer executable, not an alternate same-image command. + launch=json.loads(command(['docker','container','inspect',session['issuer'],'--format', + '{"entrypoint":{{json .Config.Entrypoint}},"cmd":{{json .Config.Cmd}},"path":{{json .Path}},"args":{{json .Args}}}'])) + if launch != {'entrypoint':['/keycape'],'cmd':None,'path':'/keycape','args':[]}: + raise Refused() + + +def container_file(container, path): + # Docker streams one tar member into memory; never materialize private files. + raw = command(['docker', 'cp', container + ':' + path, '-'], max_output=128*1024*1024) + with tarfile.open(fileobj=io.BytesIO(raw), mode='r:') as archive: + members = archive.getmembers() + if len(members) != 1 or not members[0].isfile() or members[0].size > 96*1024*1024: + raise Refused() + return archive.extractfile(members[0]).read() + + +JWKS_PROBE = r""" +import base64,ipaddress,json,socket,ssl,sys,urllib.request +from urllib.parse import urlsplit +p=json.load(sys.stdin);issuer=p['issuer'];origin=urlsplit(issuer) +def require(condition): + if not condition:raise ValueError('public_jwks_binding_refused') +require(origin.scheme=='https') +resolved=socket.getaddrinfo(origin.hostname,origin.port or 443,type=socket.SOCK_STREAM) +require(bool(resolved) and all(ipaddress.ip_address(x[4][0]).is_loopback for x in resolved)) +class NoRedirect(urllib.request.HTTPRedirectHandler): + def redirect_request(self,*args,**kwargs):return None +opener=urllib.request.build_opener(urllib.request.ProxyHandler({}),NoRedirect(), + urllib.request.HTTPSHandler(context=ssl.create_default_context(cadata=p['trust']))) +def get(url): + u=urlsplit(url) + require((u.scheme,u.hostname,u.port or 443)==(origin.scheme,origin.hostname,origin.port or 443)) + require(not u.username and not u.password and not u.fragment) + with opener.open(url,timeout=10) as response: + raw=response.read(1024*1024+1);require(len(raw)<=1024*1024) + return json.loads(raw) +d=get(issuer.rstrip('/')+'/.well-known/openid-configuration');require(d['issuer']==issuer) +keys=get(d['jwks_uri'])['keys'] +def integer(value):return int.from_bytes(base64.urlsafe_b64decode(value+'='*(-len(value)%4)),'big') +# The exact admitted owner release constructs one key, kid key-1. Reject every +# extra key, including irrelevant keys: a native successful exchange can then +# only have used the original signer through the existing verifier. +require(isinstance(keys,list) and len(keys)==1) +k=keys[0] +require(k.get('kty')=='RSA' and k.get('kid')=='key-1' and k.get('use')=='sig' and k.get('alg')=='RS256') +require(integer(k['n'])==int(p['n']) and integer(k['e'])==int(p['e'])) +print('{"original_public_signing_key_in_live_jwks":true}') +""" + +# A failed public readiness probe is closed data, not a failing Docker RPC. +# Transport/CLI nonzero remains uncertain; no deliberately failing exec is +# retried as if daemon acceptance had been established. +JWKS_TRANSPORT = ("import contextlib,io\ntry:\n" + " with contextlib.redirect_stdout(io.StringIO()):\n" + " exec(" + repr(JWKS_PROBE) + ")\n" + "except Exception:\n print('{\"original_public_signing_key_in_live_jwks\":false}')\n" + "else:\n print('{\"original_public_signing_key_in_live_jwks\":true}')\n") + + +def check_jwks(session, admission, public_numbers): + trust=runtime_file(session,admission['trust_path']).decode() + request={'issuer':admission['issuer'],'trust':trust,'n':str(public_numbers.n),'e':str(public_numbers.e)} + result=json.loads(command(['docker','exec','-i',session['worker'],'python3','-c',JWKS_TRANSPORT],input=json.dumps(request).encode())) + if result != {'original_public_signing_key_in_live_jwks': True}:raise Refused() + + +RUNTIME_FILES = r""" +import base64,json,sys +from pathlib import Path +p=json.load(sys.stdin) +roots=('/etc/keycape/','/var/lib/keycape-policy/','/etc/keycape-factor/','/recovery-tls/') +result={} +paths=[] +if p.get('tree'): + paths=list(Path('/var/lib/keycape-policy').rglob('*')) +else:paths=[Path(x) for x in p['paths']] +for f in paths: + if f.is_dir():continue + if not str(f).startswith(roots) or not f.is_file() or any(x.is_symlink() for x in (f,*f.parents)) or f.stat().st_size>8*1024*1024:raise ValueError() + result[str(f)]=base64.b64encode(f.read_bytes()).decode() + if len(result)>4096:raise ValueError() +print(json.dumps(result)) +""" + + +def runtime_files(session, paths=(), tree=False): + raw=command(['docker','exec','-i',session['worker'],'python3','-c',RUNTIME_FILES], + input=json.dumps({'paths':list(paths),'tree':tree}).encode(),max_output=48*1024*1024) + return {k:base64.b64decode(v,validate=True) for k,v in json.loads(raw).items()} + + +def runtime_file(session,path): + return runtime_files(session,[path])[path] + + +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 + import ipaddress + address = urlsplit(admission['issuer']) + if (address.scheme != 'https' or not address.hostname or address.username or address.password + or address.query or address.fragment): + raise Refused() + if hashlib.sha256(container_file(issuer, '/keycape')).hexdigest() != admission['verifier_sha256']: + raise Refused() + if hashlib.sha256(runtime_file(session, admission['trust_path'])).hexdigest() != admission['trust_sha256']: + raise Refused() + # Capture private environment only in owner process memory, never receipt. + environment = json.loads(command(['docker','container','inspect',issuer,'--format','{{json .Config.Env}}'])) + env = dict(item.split('=',1) for item in environment) + if len(env)!=len(environment):raise Refused() + if set(env)-set(payload['env'])-{'PATH','HOME','HOSTNAME','SSL_CERT_FILE'}:raise Refused() + if env.get('SSL_CERT_FILE') != admission['trust_path'] or any(k.lower().endswith('_proxy') and v for k,v in env.items()): + raise Refused() + if {k:v for k,v in env.items() if k.startswith('KEYCAPE_')}!={k:v for k,v in payload['env'].items() if k.startswith('KEYCAPE_')}:raise Refused() + for name,value in payload['env'].items(): + if env.get(name) != value: + raise Refused() + files = {k:base64.b64decode(v,validate=True) for k,v in payload['files'].items()} + def equal(): + if runtime_files(session,files)!=files:raise Refused() + durable=runtime_files(session,tree=True) + if durable!={k:v for k,v in files.items() if k.startswith('/var/lib/keycape-policy/')}: + raise Refused() + equal() + 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) + check_jwks(session,admission,key.public_key().public_numbers()) + wrong = secrets.token_urlsafe(48) + if wrong == env[consumer['secret_env']]:raise Refused() + args = ['docker','exec','--env','NK49_UNRELATED_NEGATIVE_SECRET='+wrong,issuer,'/keycape','verify-client', + '-issuer',admission['issuer'],'-previous-secret-env','NK49_UNRELATED_NEGATIVE_SECRET'] + flags = {'client_id':'client-id','secret_env':'secret-env','audience':'audience','scope':'scope', + 'subject':'expect-subject','tenant':'expect-tenant','roles':'expect-roles','deny_scope':'deny-scope'} + for name,flag in flags.items():args+=['-'+flag,consumer[name]] + # Native command reports on stderr. Do not return or print its raw response. + result = process(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE,timeout=150) + raw = (result.stdout+result.stderr).decode() + required = ['discovery and endpoint origin','exchange and JWKS signature for granted scopes','access-token claim bindings', + 'principal_type is service','sub matches the registration','tenant matches the registration','roles present', + 'granted scope carries no excess grant','predecessor secret refused'] + required += ['excess scope refused: '+scope for scope in consumer['deny_scope'].split()] + if result.returncode or any('PASS '+name+'\n' not in raw for name in required) or 'FAIL ' in raw: + raise Refused() + equal() + from cryptography.hazmat.primitives import serialization + key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) + check_jwks(session,admission,key.public_key().public_numbers()) + public=key.public_key().public_bytes(serialization.Encoding.DER,serialization.PublicFormat.SubjectPublicKeyInfo) + return {'native_service_registration_verified':True,'wrong_unrelated_secret_explicitly_refused':True, + 'denied_scopes_refused':True,'original_config_registry_policy_receipts_equal':True, + 'public_signing_spki_sha256':hashlib.sha256(public).hexdigest(), + 'original_https_issuer_and_trust_preserved':True,'original_public_signing_key_in_live_jwks':True} + + +def cleanup(session, receipt=None): + """Attempt every owned cleanup even when one obligation fails. + + Preserve exact safe container names and outcomes so the owner can recover an + uncertain/partial cleanup. An inspect/daemon failure never means absence. + """ + obligations = [] + failed = False + for name in reversed(session['containers']): + row = {'container': name, 'status': 'unverified'} + obligations.append(row) + try: + present=command(['docker','container','ls','--all','--filter','name=^/'+name+'$','--format','{{.Names}}']).decode().splitlines() + if not present: + row['status']='absence_verified' + continue + label = command(['docker', 'container', 'inspect', name, '--format', + '{{index .Config.Labels "' + LABEL + '"}}']).decode().strip() + if label != session['run_id']: + row['status'] = 'ownership_mismatch_not_removed' + failed = True + continue + # A failed remove is followed by a successful explicit inventory; + # interrupted remove may actually have completed. + try: + command(['docker', 'rm', '--force', '--volumes', name]) + except Exception: + pass + remaining = command(['docker','container','ls','--all','--filter', + 'name=^/' + name + '$','--format','{{.Names}}']).decode().splitlines() + if remaining: + row['status'] = 'still_present' + failed = True + else: + row['status'] = 'absence_verified' + except Exception: + failed = True + if receipt is not None: + receipt['container_cleanup_obligations'] = obligations + if failed: + raise Refused() + + + +def native_checks(root, manifest, admission, receipt, cleanup_session=True): + """Owner wrapper provides a reviewed session after existing restore pipeline. + + Admission must bind ciphertext, canonical private manifest digest, executable + and trust bytes, exact image/target list, original issuer and selected consumer. + None of these admission fields grant authority or carry a client secret. + """ + session = admission['session'] + # Validate ownership/containment before permitting either exec or cleanup. + inspect_session(session) + receipt.update(status='failed', source_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + ciphertext_sha256=admission['ciphertext_sha256'], production_contacted=False, + human_mfa_proven=False, downstream_consumer_reconnect_proven=False, + container_cleanup_verified=False) + try: + for field in ('ciphertext_sha256', 'manifest_sha256', 'verifier_sha256', 'trust_sha256'): + if not re.fullmatch('[a-f0-9]{64}', admission[field]): + raise Refused() + for field in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope'): + if not isinstance(admission['consumer'].get(field), str) or not admission['consumer'][field].strip(): + raise Refused() + payload = private_payload(root, manifest, admission['manifest_sha256']) + result = run_verifier(session, admission, payload) + required = {'native_service_registration_verified','wrong_unrelated_secret_explicitly_refused', + 'denied_scopes_refused','original_config_registry_policy_receipts_equal', + 'original_https_issuer_and_trust_preserved','original_public_signing_key_in_live_jwks'} + if any(result.get(k) is not True for k in required) or not re.fullmatch('[a-f0-9]{64}', result.get('public_signing_spki_sha256','')): + raise Refused() + # Closed receipt allowlist: never copy arbitrary worker output. + receipt.update({k: True for k in required}) + receipt['public_signing_spki_sha256'] = result['public_signing_spki_sha256'] + receipt['status'] = 'isolated_keycape_native_registration_checked' + finally: + try: + if cleanup_session: + cleanup(session, receipt) + receipt['container_cleanup_verified'] = True + except Exception: + receipt['status'] = 'failed' + raise diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md new file mode 100644 index 00000000..e14d24bd --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/postimages/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.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/preimages/tests/isolated-keycape-native-fixture-manifest.json b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tests/isolated-keycape-native-fixture-manifest.json new file mode 100644 index 00000000..a9254547 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tests/isolated-keycape-native-fixture-manifest.json @@ -0,0 +1,124 @@ +{ + "schema": "nk49.keycape-native-fixture-proposal.v1", + "status": "prepared_not_executed_not_approved", + "source_sha256": { + "sso-mfa/bootstrap/sops-private.py": "sha256:acac68e2936ed38b7d7c9e35eb4619647c99c117a3928a1c5ce704b570906780", + "sso-mfa/k8s/privacyidea/key-custody-remote.py": "sha256:27b2b885c81923d85054e3999c5613e104fe627779b2b50398ed9bed5088f47e", + "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_session.py": "sha256:cbdf51efde26eff337e9303a2c431f80b333b8846d763eb62853f81eb3f13e2c", + "tools/bootstrap-recovery/capture-identity.py": "sha256:47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705", + "tools/bootstrap-recovery/check-privacyidea-database.py": "sha256:90f454c87998d7f5d625e3c6656c3418f8f56275dc1879a9d19ed605431b94a4", + "tools/bootstrap-recovery/fetch-privacyidea-backup.py": "sha256:233160e1206643a5cf7ad05141d733f0a75aff651190e27f77515a124ff0a59f", + "tools/bootstrap-recovery/identity-backup-profile.json": "sha256:40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1", + "tools/bootstrap-recovery/identity-bundle.py": "sha256:524a03c065db4307fcde83d33af39503f3de19cb6ef3a8ca72c991d4a8c08ee6", + "tools/bootstrap-recovery/identity-credential-setup.py": "sha256:ddd6127fa331c0185523ec3bb22d743a791edd56a2e6af7ad8d7949b7c051141", + "tools/bootstrap-recovery/identity-custody.json": "sha256:f8aee8487ed01d7940b82676bb4a5c8d61f51b6c598521b8b8a73588aaea4d4f", + "tools/bootstrap-recovery/identity-files.py": "sha256:d0063a9eedd3610e3d45bd2d834aae83cff74e4b3504d138b3548f427e89331d", + "tools/bootstrap-recovery/identity-isolation.py": "sha256:88d1e13112a44c79571825af89d3fe5b01fa490cff2653badef4c62a45c844f1", + "tools/bootstrap-recovery/identity-offsite.py": "sha256:e7c31fa9ee081961af873348ee3b4829a645d40c7dc7f1e22c564aa9ed01bc49", + "tools/bootstrap-recovery/identity-retention.py": "sha256:a41ea4759f69c35548149fc8d0d5ace547f16cf9fe4c9dac10b119a4d0becdec", + "tools/bootstrap-recovery/identity-runtime.py": "sha256:a2c0acf567c204705b90be64d561d0fda2285e0fc71a962d6e1b149f571e1940", + "tools/bootstrap-recovery/install-identity-backup.py": "sha256:5c612a2a51c9b59aad8cc01d418c2f563cbd92c62dc1fa8be994e5fb59df90f1", + "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-lldap.py": "sha256:35bfa8411186ad936a199bd450c7e18c2ad51059301a6db9650e6bd055ab1b81", + "tools/bootstrap-recovery/isolated-privacyidea.py": "sha256:4df7196678aac1ad594f32abf45c68dc21a9d2760d9e8a536a215a4a3c5d277f", + "tools/bootstrap-recovery/prepare-identity-coverage.py": "sha256:cd5f3067d28b4c7cc93ed08b8cf3869218bdecf7c54b5dffed22d697de71dbb1", + "tools/bootstrap-recovery/recovery-kit.py": "sha256:6fa0f1494dccaf003b6c6396c5de8b36faa2b276eeb16badd04383f5efb71e66", + "tools/bootstrap-recovery/retrieve-identity-offline.py": "sha256:3421dbb3f3280a001d33ea2deb12ab609404a0b4254cd43c21518d77d166f972", + "tools/bootstrap-recovery/retrieve-identity.py": "sha256:ec123d47a07305253570dacab7e103f8c193a23f20c9fc87466ea4a95ae0ec13", + "tools/bootstrap-recovery/run-isolated-keycape.sh": "sha256:0d994c9c14ebdffdbf7879bd7562042531083d0e8955424d0ae099898a141668", + "tools/bootstrap-recovery/verify-bundle.py": "sha256:885b05a2011e711228e42e316bda70bbe0d97d481383d61aa8469d0f10452370", + "tools/bootstrap-recovery/verify-identity-delivery.py": "sha256:63658d1976806f8d0ce80ba8f750bbcfdca59da936b6eb6a78a250f0e53710f1", + "tools/bootstrap-recovery/verify-identity.py": "sha256:039864d0141b552887752bf17cfdcf1bef4bdc9126f946a9c0533e4fd54ebf4f", + "sso-mfa/bootstrap/sops-custody-unlock.sh": "sha256:86c527a8ae0d0cca66a2345c566b25fbff5bc52c1e22c725548c0fbb2f86a58e", + "sso-mfa/bootstrap/sops-custody-fd.py": "sha256:df29eaba83ec6b5fc311664dcf4b22d8f3c8ed7274ed8e6c419ada0dcd169c0f", + "tools/bootstrap-recovery/prepare-isolated-keycape.py": "sha256:5098bdfa4e0ad30627c1716e5e355a2c78dca6ccc607bd2148a2e06126632288", + "tests/test_prepare_isolated_keycape.py": "sha256:4b0871f9a11a3940983464f1b40eca1613110b1cb3cb9694f4891d58e14c700a", + "tests/test_sealed_custody.py": "sha256:f0fa07c89e2419464dbee0489462864a4533770417a554b1ab1d1ed5d7b6c49f", + "tests/test_private_manifest_binding.py": "sha256:2e7ee16af65390343435b7210ef191aa2a10e9dcbb8759ed95fa8bf6fb81893b" + }, + "fixed_endpoint": "unix:///var/run/docker.sock", + "engine_id": "74f93783-6cef-43a8-a3c4-f62586cd3bc1", + "engine_name": "bnt-lap001", + "images": [ + "forgejo.coulomb.social/coulomb/key-cape@sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010", + "ghcr.io/gpappsoft/privacyidea-docker@sha256:af7841adad262f129e0c1d4f553af13f21cb2f4dc713533f316cfe43ed0b4473" + ], + "pull_policy": "never", + "synthetic_issuer": "https://nk49-fixture.invalid", + "cases": [ + "positive", + "hard-parent-loss", + "deadline", + "nonzero-after-accept" + ], + "limits": { + "sequential_cases": true, + "max_live_service_containers": 2, + "max_tmpfs_volumes": 4, + "max_public_probe_containers": 1, + "service_memory_bytes_each": 536870912, + "service_cpus_each": 1, + "tmpfs_volume_bytes_each": 33554432, + "host_tmpfs_fixture_limit_expected_bytes": 8388608, + "execution_deadline_seconds": { + "deadline_case": 20, + "other_cases": 120 + }, + "driver_wait_seconds_per_case": 150 + }, + "resources": { + "container_names": "nk49-kc--{transport,issuer,image-probe}", + "volume_names": "nk49-kc--v{0,1,2,3}", + "label": "net-kingdom.recovery-run=", + "host_plaintext": "exact private /dev/shm/nk49-keycape-- registered before writes", + "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", + "mutations": [ + "conditional creation of exact fresh local containers and local-driver tmpfs volumes", + "private synthetic file import to those volumes", + "original-image KeyCape service/client exchange within same loopback-only namespace", + "exact owned quiescent removal and bounded safe receipts" + ], + "forbidden": [ + "Docker execution before independent approval", + "image pulls/builds/pushes", + "production routes/ports/host networking/host directory mounts", + "OpenBao/Kubernetes/provider APIs", + "actual identity archive, age key, TLS key, user password, factor or client secret" + ], + "cleanup": "candidate exact ownership/volume-driver/inode checks; quiesce fresh owner SID/PGID via pidfds first; retained inflight uncertainty never accepted even on absent readback", + "oracles": [ + "positive issuer-native verify-client must establish original-hostname HTTPS trust; helper alone never suffices", + "same original single RS256 key-1 JWKS and exact config/registry/policy/history/lock/deliveries", + "correct service exchange and explicit wrong-secret/excess-scope denial through existing native verifier", + "hard-parent-loss and tightened deadline both quiesce before exact resource/plaintext cleanup", + "after real Docker run accepts a synthetic container, inject returncode1; require failed recovery and sticky daemon uncertainty after cleanup" + ], + "proposed_command": [ + "python3", + "tests/run_isolated_keycape_native_fixture.py", + "--execute-reviewed-fixture", + "--expected-manifest-sha256", + "", + "--case", + "positive" + ], + "extended_command": [ + "python3", + "tests/run_isolated_keycape_native_fixture.py", + "--execute-reviewed-fixture", + "--expected-manifest-sha256", + "", + "--case", + "all" + ] +} diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tests/test_isolated_keycape_recovery.py b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tests/test_isolated_keycape_recovery.py new file mode 100644 index 00000000..cf780aee --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tests/test_isolated_keycape_recovery.py @@ -0,0 +1,234 @@ +import base64 +import hashlib +import importlib.util +import io +import json +import subprocess +import tarfile +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +SOURCE=Path(__file__).parents[1]/'tools/bootstrap-recovery/isolated-keycape.py' +spec=importlib.util.spec_from_file_location('adapter',SOURCE) +a=importlib.util.module_from_spec(spec);spec.loader.exec_module(a) + +class ArchiveTests(unittest.TestCase): + def setUp(self): + self.tmp=tempfile.TemporaryDirectory();self.addCleanup(self.tmp.cleanup) + self.root=Path(self.tmp.name) + config={'data':{k:base64.b64encode(v).decode() for k,v in {'config.yaml':b'issuer: https://issuer.example','key.pem':b'fixture-key'}.items()}} + self.values={'resources/sso/secret/keycape-config.json':json.dumps(config).encode(), + 'resources/sso/deployment/keycape.json':json.dumps({'spec':{'template':{'spec':{'containers':[{'name':'keycape','image':a.IMAGE,'env':[ + {'name':'KEYCAPE_CONFIG','value':'/etc/keycape/config.yaml'}, + {'name':'KEYCAPE_POLICY_PATH','value':'/var/lib/keycape-policy/policy.json'}, + {'name':'KEYCAPE_ORIGINAL_SECRET','valueFrom':{'secretKeyRef':{'name':'client','key':'secret'}}}]}]}}}}).encode(), + 'resources/sso/secret/client.json':json.dumps({'data':{'secret':base64.b64encode(b'fixture-private').decode()}}).encode(), + 'data/keycape/policy.json':b'{}','data/keycape/receipts/one.json':b'{"original":true}'} + for name,value in self.values.items(): + p=self.root/name;p.parent.mkdir(parents=True,exist_ok=True);p.write_bytes(value);p.chmod(0o600) + self.manifest={'profile':{'components':[{'namespace':'sso','deployment':'keycape','secret_refs':['keycape-config','client'],'configmap_refs':[]}]}, + 'files':[{'path':k,'bytes':len(v),'sha256':hashlib.sha256(v).hexdigest()} for k,v in self.values.items()]} + def payload(self): + digest=hashlib.sha256(json.dumps(self.manifest,sort_keys=True,separators=(',',':')).encode()).hexdigest() + return a.private_payload(self.root,self.manifest,digest) + def test_original_state_and_secret_delivery_retained(self): + p=self.payload();self.assertEqual(p['env']['KEYCAPE_ORIGINAL_SECRET'],'fixture-private') + self.assertEqual(base64.b64decode(p['files']['/var/lib/keycape-policy/receipts/one.json']),b'{"original":true}') + def test_archive_digest_refused(self): + with self.assertRaises(a.Refused):a.private_payload(self.root,self.manifest,'0'*64) + def test_changed_file_refused(self): + (self.root/'data/keycape/policy.json').write_text('{"changed":true}') + with self.assertRaises(a.Refused):self.payload() + def test_symlink_refused(self): + p=self.root/'data/keycape/policy.json';p.unlink();p.symlink_to('/etc/hostname') + with self.assertRaises(Exception):self.payload() + def test_duplicate_manifest_refused(self): + self.manifest['files'].append(self.manifest['files'][0]) + with self.assertRaises(a.Refused):self.payload() + def test_image_mismatch_refused(self): + d=json.loads(self.values['resources/sso/deployment/keycape.json']);d['spec']['template']['spec']['containers'][0]['image']='keycape:latest' + raw=json.dumps(d).encode();p=self.root/'resources/sso/deployment/keycape.json';p.write_bytes(raw) + 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 NativeTests(unittest.TestCase): + def setUp(self): + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import rsa + self.key=rsa.generate_private_key(public_exponent=65537,key_size=2048).private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()) + self.cfg=b'issuer: https://issuer.example\nclients:\n- clientId: existing\n clientType: confidential\n secretRef: env:KEYCAPE_ORIGINAL_SECRET\n grantTypes: [client_credentials]\n' + self.files={'/etc/keycape/config.yaml':self.cfg,'/etc/keycape/key.pem':self.key,'/var/lib/keycape-policy/policy.json':b'{}'} + self.payload={'env':{'KEYCAPE_ORIGINAL_SECRET':'fixture-private'},'files':{k:base64.b64encode(v).decode() for k,v in self.files.items()}} + self.admission={'issuer':'https://issuer.example','verifier_sha256':hashlib.sha256(b'binary').hexdigest(), + 'trust_path':'/trust.pem','trust_sha256':hashlib.sha256(b'original-trust').hexdigest(), + 'consumer':{'client_id':'existing','secret_env':'KEYCAPE_ORIGINAL_SECRET','scope':'read','audience':'consumer', + 'subject':'service:existing','tenant':'tenant:platform','roles':'reader','deny_scope':'write'}} + self.session={'issuer':'isolated','volumes':{x:{'target':x} for x in ('/etc/keycape','/var/lib/keycape-policy','/etc/keycape-factor','/recovery-tls')}} + self.output=''.join('PASS '+x+'\n' for x in ['discovery and endpoint origin','exchange and JWKS signature for granted scopes','access-token claim bindings','principal_type is service','sub matches the registration','tenant matches the registration','roles present','granted scope carries no excess grant','predecessor secret refused','excess scope refused: write']) + def file(self,container,path): + return {**self.files,'/etc/hosts':b'127.0.0.1 issuer.example\n','/keycape':b'binary','/trust.pem':b'original-trust'}[path] + def command(self,argv,**kwargs): + if argv[1:3]==['container','inspect']:return json.dumps(['KEYCAPE_ORIGINAL_SECRET=fixture-private','SSL_CERT_FILE=/trust.pem']).encode() + output=io.BytesIO() + with tarfile.open(fileobj=output,mode='w') as t: + m=tarfile.TarInfo('policy.json');m.size=2;t.addfile(m,io.BytesIO(b'{}')) + return output.getvalue() + def verify(self,code=0,output=None): + with patch.object(a,'check_jwks'),patch.object(a,'runtime_file',return_value=b'original-trust'),patch.object(a,'runtime_files',side_effect=lambda session,paths=(),tree=False:({k:v for k,v in self.files.items() if k.startswith('/var/lib/keycape-policy/')} if tree else dict(self.files))),patch.object(a,'container_file',side_effect=self.file),patch.object(a,'command',side_effect=self.command),patch.object(a.subprocess,'run',return_value=subprocess.CompletedProcess([],code,b'',(self.output if output is None else output).encode())) as run: + result=a.run_verifier(self.session,self.admission,self.payload) + argv=run.call_args.args[0] + self.assertNotIn('fixture-private',' '.join(argv)) + self.assertIn('-previous-secret-env',argv) + return result + def test_original_registration_and_unrelated_secret(self): + r=self.verify();self.assertTrue(r['wrong_unrelated_secret_explicitly_refused']);self.assertNotIn('fixture-private',json.dumps(r)) + def test_transport_failure_never_counts_as_wrong_secret(self): + with self.assertRaises(a.Refused):self.verify(1,'FAIL discovery and endpoint origin: TLS failure\n') + def test_missing_explicit_rejection_never_counts(self): + with self.assertRaises(a.Refused):self.verify(0,self.output.replace('PASS predecessor secret refused\n','')) + def test_fail_line_refused_even_zero_exit(self): + with self.assertRaises(a.Refused):self.verify(0,self.output+'FAIL transport\n') + def test_security_environment_override_refused(self): + original=self.command + def altered(argv,**kwargs): + if argv[1:3]==['container','inspect']:return json.dumps(['KEYCAPE_ORIGINAL_SECRET=fixture-private','SSL_CERT_FILE=/trust.pem','SSL_CERT_DIR=/unreviewed']).encode() + return original(argv,**kwargs) + with patch.object(self,'command',side_effect=altered): + with self.assertRaises(a.Refused):self.verify() + def test_http_issuer_refused(self): + self.admission['issuer']='http://issuer.example' + with self.assertRaises(a.Refused):self.verify() + def test_changed_trust_refused(self): + self.admission['trust_sha256']='0'*64 + with self.assertRaises(a.Refused):self.verify() + def test_config_drift_refused(self): + self.payload['files']['/etc/keycape/config.yaml']=base64.b64encode(b'changed').decode() + with self.assertRaises(a.Refused):self.verify() + +class PublicReadinessTransportTests(unittest.TestCase): + def test_provider_probe_failure_is_closed_false_data_not_failed_docker_exec(self): + output=io.StringIO() + with patch('sys.stdin',io.StringIO('{}')),patch('sys.stdout',output): + exec(compile(a.JWKS_TRANSPORT,'','exec',optimize=2),{}) + self.assertEqual(json.loads(output.getvalue()),{'original_public_signing_key_in_live_jwks':False}) + +class BoundaryTests(unittest.TestCase): + def test_remote_docker_refused_before_info(self): + session={'run_id':'a'*32,'containers':['nk49-kc-'+('a'*32)+'-worker'],'worker':'nk49-kc-'+('a'*32)+'-worker','issuer':'nk49-kc-'+('a'*32)+'-worker'} + with patch.object(a,'command',return_value=b'[{"Endpoints":{"docker":{"Host":"tcp://remote:2375"}}}]') as command: + with self.assertRaises(a.Refused):a.inspect_session(session) + self.assertEqual(command.call_count,1) + def test_failed_verifier_cleanup_is_attempted(self): + receipt={};admission={'session':{},'ciphertext_sha256':'a'*64,'manifest_sha256':'b'*64,'verifier_sha256':'c'*64,'trust_sha256':'d'*64,'consumer':{x:'yes' for x in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope')}} + with patch.object(a,'inspect_session'),patch.object(a,'private_payload',return_value={}),patch.object(a,'run_verifier',side_effect=a.Refused),patch.object(a,'cleanup') as cleanup: + with self.assertRaises(a.Refused):a.native_checks(Path('/unused'),{},admission,receipt) + cleanup.assert_called_once();self.assertTrue(receipt['container_cleanup_verified']);self.assertEqual(receipt['status'],'failed') + + def test_cleanup_failure_overrides_success(self): + admission={'session':{},'ciphertext_sha256':'a'*64,'manifest_sha256':'b'*64,'verifier_sha256':'c'*64,'trust_sha256':'d'*64,'consumer':{x:'yes' for x in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope')}} + result={x:True for x in ('native_service_registration_verified','wrong_unrelated_secret_explicitly_refused','denied_scopes_refused','original_config_registry_policy_receipts_equal','original_https_issuer_and_trust_preserved','original_public_signing_key_in_live_jwks')} + result['public_signing_spki_sha256']='e'*64;receipt={} + with patch.object(a,'inspect_session'),patch.object(a,'private_payload',return_value={}),patch.object(a,'run_verifier',return_value=result),patch.object(a,'cleanup',side_effect=a.Refused): + with self.assertRaises(a.Refused):a.native_checks(Path('/unused'),{},admission,receipt) + self.assertEqual(receipt['status'],'failed');self.assertFalse(receipt['container_cleanup_verified']) + +class ContainmentTests(unittest.TestCase): + def inspect(self,overrides=None,launch=None,mounts=None): + name='nk49-kc-'+('a'*32)+'-issuer' + session={'run_id':'a'*32,'containers':[name],'issuer':name,'worker':name,'images':{name:a.IMAGE}} + host={'NetworkMode':'none','ReadonlyRootfs':True,'Privileged':False,'CapDrop':['ALL'],'SecurityOpt':['no-new-privileges']} + host.update(overrides or {}) + def command(argv,**kwargs): + if argv[1:3]==['context','inspect']:return b'[{"Endpoints":{"docker":{"Host":"unix:///var/run/docker.sock"}}}]' + if argv[1]=='info':return b'{"ID":"74f93783-6cef-43a8-a3c4-f62586cd3bc1","Name":"bnt-lap001","OSType":"linux"}' + if argv[-1]=='{{.Id}}':return b'anchor-id' + if '"path"' in argv[-1]:return json.dumps(launch or {'entrypoint':['/keycape'],'cmd':None,'path':'/keycape','args':[]}).encode() + return json.dumps({'host':host,'mounts':mounts or [],'labels':{a.LABEL:'a'*32},'image':a.IMAGE,'user':'1000:1000'}).encode() + with patch.object(a,'command',side_effect=command),patch.dict('os.environ',{'DOCKER_HOST':'unix:///var/run/docker.sock'}):a.inspect_session(session) + def test_minimal_network_none_admitted(self):self.inspect() + def test_image_declared_anonymous_disk_volume_remains_refused(self): + with self.assertRaises(a.Refused): + self.inspect(mounts=[{'Type':'volume','Name':'anonymous-fixture','Destination':'/privacyidea/etc/persistent','RW':True}]) + + def test_alternate_same_image_command_refused(self): + with self.assertRaises(a.Refused):self.inspect(launch={'entrypoint':['/keycape'],'cmd':['check-config'],'path':'/keycape','args':['check-config']}) + def test_cap_add_refused(self): + with self.assertRaises(a.Refused):self.inspect({'CapAdd':['NET_ADMIN']}) + def test_devices_refused(self): + with self.assertRaises(a.Refused):self.inspect({'Devices':[{'PathOnHost':'/dev/mem'}]}) + def test_device_requests_refused(self): + with self.assertRaises(a.Refused):self.inspect({'DeviceRequests':[{'Driver':'nvidia'}]}) + def test_host_namespace_refused(self): + for field in ('PidMode','IpcMode','UTSMode','UsernsMode','CgroupnsMode'): + with self.subTest(field=field),self.assertRaises(a.Refused):self.inspect({field:'host'}) + def test_security_override_refused(self): + with self.assertRaises(a.Refused):self.inspect({'SecurityOpt':['no-new-privileges','seccomp=unconfined']}) + +class CleanupTests(unittest.TestCase): + def test_partial_cleanup_attempts_every_owned_container(self): + session={'run_id':'a'*32,'containers':['first','second','third']};receipt={} + removed=[] + def command(argv,**kwargs): + if argv[1:3]==['container','inspect']:return ('a'*32).encode() + if argv[1]=='rm': + removed.append(argv[-1]) + if argv[-1]=='third':raise a.Refused() + return b'' + if argv[1:3]==['container','ls']: + name=next(x for x in argv if x.startswith('name=^/')).removeprefix('name=^/').removesuffix('$') + return (name+'\n').encode() if name=='third' or name not in removed else b'' + return b'' + with patch.object(a,'command',side_effect=command): + with self.assertRaises(a.Refused):a.cleanup(session,receipt) + self.assertEqual(removed,['third','second','first']) + self.assertEqual([r['status'] for r in receipt['container_cleanup_obligations']],['still_present','absence_verified','absence_verified']) + def test_ownership_mismatch_does_not_remove_and_continues(self): + session={'run_id':'a'*32,'containers':['first','second']};receipt={};removed=[] + def command(argv,**kwargs): + if argv[1:3]==['container','inspect']:return (('b' if argv[3]=='second' else 'a')*32).encode() + if argv[1]=='rm':removed.append(argv[-1]) + if argv[1:3]==['container','ls']: + name=next(x for x in argv if x.startswith('name=^/')).removeprefix('name=^/').removesuffix('$') + return (name+'\n').encode() if name not in removed else b'' + return b'' + with patch.object(a,'command',side_effect=command): + with self.assertRaises(a.Refused):a.cleanup(session,receipt) + self.assertEqual(removed,['first']) + self.assertEqual(receipt['container_cleanup_obligations'][0]['status'],'ownership_mismatch_not_removed') + def test_inspect_failure_retains_uncertain_obligation(self): + receipt={} + with patch.object(a,'command',side_effect=a.Refused): + with self.assertRaises(a.Refused):a.cleanup({'run_id':'a'*32,'containers':['exact-owned-name']},receipt) + self.assertEqual(receipt['container_cleanup_obligations'],[{'container':'exact-owned-name','status':'unverified'}]) + +class JWKSTests(unittest.TestCase): + def execute(self,n='123',endpoint='https://issuer.example/jwks',resolved='127.0.0.1',extra=False,kid='key-1'): + request={'issuer':'https://issuer.example','trust':'public-certificate','n':'123','e':'65537'} + def enc(i):return base64.urlsafe_b64encode(int(i).to_bytes((int(i).bit_length()+7)//8,'big')).decode().rstrip('=') + responses=[{'issuer':'https://issuer.example','jwks_uri':endpoint},{'keys':[{'kty':'RSA','kid':kid,'use':'sig','alg':'RS256','n':enc(n),'e':enc(65537)}]}] + if extra:responses[1]['keys'].append(dict(responses[1]['keys'][0],kid='key-2')) + class Response: + def __init__(self,value):self.value=value + def __enter__(self):return self + def __exit__(self,*args):pass + def read(self,*args):return json.dumps(self.value).encode() + class Opener: + def open(self,*args,**kwargs):return Response(responses.pop(0)) + with patch('sys.stdin',io.StringIO(json.dumps(request))),patch('sys.stdout',io.StringIO()),patch('socket.getaddrinfo',return_value=[(2,1,6,'',(resolved,443))]),patch('ssl.create_default_context'),patch('urllib.request.build_opener',return_value=Opener()): + exec(compile(a.JWKS_PROBE,'','exec',optimize=2),{}) + def test_exact_original_public_key(self):self.execute() + def test_extra_signing_key_refused_under_optimization(self): + with self.assertRaises(ValueError):self.execute(extra=True) + def test_wrong_kid_refused_under_optimization(self): + with self.assertRaises(ValueError):self.execute(kid='replacement') + def test_wrong_live_signing_key_refused(self): + with self.assertRaises(ValueError):self.execute(n='124') + def test_cross_origin_jwks_refused(self): + with self.assertRaises(ValueError):self.execute(endpoint='https://production.example/jwks') + def test_production_dns_refused_before_fetch(self): + with self.assertRaises(ValueError):self.execute(resolved='192.0.2.1') + +if __name__=='__main__':unittest.main() diff --git a/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py new file mode 100644 index 00000000..4cc40e65 --- /dev/null +++ b/docs/changes/netkingdom-target-2026-10-17/native-identity-r1/preimages/tools/bootstrap-recovery/isolated-keycape.py @@ -0,0 +1,478 @@ +#!/usr/bin/env python3 +"""T18 native adapter for an owner-admitted, already restored isolated session. + +Called after identity-bundle.restore, never with an unvalidated directory. This +module does not provision TLS, grant credentials, or claim downstream acceptance. +The existing decrypt/tmpfs wrapper remains responsible for archive cleanup. +""" +import base64 +import hashlib +import importlib.util +import json +import io +import os +import secrets +import tarfile +import time +import re +import subprocess +from pathlib import Path + +HERE = Path(__file__).resolve().parent +IMAGE = 'forgejo.coulomb.social/coulomb/key-cape@sha256:cdec9dd7c515f7e0a6169fc3fa560ee2cc47bf40d899755dec808c362f5ce010' +LABEL = 'net-kingdom.recovery-run' + + +class Refused(Exception): + pass + + +def load_bundle(): + spec = importlib.util.spec_from_file_location('identity_bundle', HERE / 'identity-bundle.py') + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def manifest_binding_mode(admission,transfer): + """Versioned private-manifest binding; legacy explicit digests stay valid.""" + mode=admission.get('manifest_binding_mode','explicit-digest-v1') + if mode not in ('explicit-digest-v1','ciphertext-derived-v1'):raise Refused() + if (not isinstance(admission.get('ciphertext_sha256'),str) + or not re.fullmatch('[a-f0-9]{64}',admission['ciphertext_sha256']) + or admission['ciphertext_sha256']!=transfer.get('ciphertext_sha256') + or transfer.get('independent_owner_retrieval_verified') is not True):raise Refused() + if mode=='explicit-digest-v1': + if not isinstance(admission.get('manifest_sha256'),str) or not re.fullmatch('[a-f0-9]{64}',admission['manifest_sha256']):raise Refused() + elif 'manifest_sha256' in admission:raise Refused() + return mode + + +def private_manifest_admission(admission,manifest): + # Only called after the fixed ciphertext bytes were hashed, authenticated + # decryption succeeded and bundle.restore checked the complete archive. + # Never return this enriched private object in a safe receipt/checkpoint. + digest=hashlib.sha256(json.dumps(manifest,sort_keys=True,separators=(',',':')).encode()).hexdigest() + mode=admission.get('manifest_binding_mode','explicit-digest-v1') + if mode=='explicit-digest-v1': + if digest!=admission['manifest_sha256']:raise Refused() + elif mode!='ciphertext-derived-v1' or 'manifest_sha256' in admission:raise Refused() + return {**admission,'manifest_sha256':digest} + + +def private_payload(root, manifest, expected_manifest_sha256): + """Bind the complete validated archive before selecting KeyCape material. + + Private hashes never enter the public receipt. The digest is supplied by the + existing private archive admission, not inferred from an untrusted manifest. + """ + encoded = json.dumps(manifest, sort_keys=True, separators=(',', ':')).encode() + if hashlib.sha256(encoded).hexdigest() != expected_manifest_sha256: + raise Refused() + entries = manifest['files'] + if len(entries) != len({e['path'] for e in entries}): + raise Refused() + values = {} + bundle = load_bundle() + for entry in entries: + if not bundle.allowed(entry['path'], manifest['profile']): + raise Refused() + path = root / entry['path'] + bundle.private(path) + value = path.read_bytes() + if len(value) != entry['bytes'] or hashlib.sha256(value).hexdigest() != entry['sha256']: + raise Refused() + values[entry['path']] = value + deployment = json.loads(values['resources/sso/deployment/keycape.json']) + main = next(c for c in deployment['spec']['template']['spec']['containers'] if c['name'] == 'keycape') + if main.get('command') or main.get('args') or main.get('envFrom'): + raise Refused() + if main['image'] != IMAGE: + # Mutable-tag/historical mismatches need a separate explicit owner admission. + raise Refused() + secret = json.loads(values['resources/sso/secret/keycape-config.json'])['data'] + files = {'/etc/keycape/' + name: base64.b64decode(secret[name], validate=True) + for name in ('config.yaml', 'key.pem')} + for path, value in values.items(): + if path.startswith('data/keycape/'): + relative = path.removeprefix('data/keycape/') + files['/var/lib/keycape-policy/' + relative] = value + if '/var/lib/keycape-policy/policy.json' not in files: + raise Refused() + if 'resources/sso/secret/keycape-factor-read.json' in values: + factor=json.loads(values['resources/sso/secret/keycape-factor-read.json'])['data'] + files['/etc/keycape-factor/admin-token']=base64.b64decode(factor['admin-token'],validate=True) + # Resolve original delivered environment, including all referenced secrets. + env = {} + for item in main.get('env', []): + if not re.fullmatch(r'KEYCAPE_[A-Z0-9_]+',item['name']):raise Refused() + if item['name'] in env: + raise Refused() + if 'value' in item: + env[item['name']] = item['value'] + else: + ref = item['valueFrom']['secretKeyRef'] + source = json.loads(values['resources/sso/secret/' + ref['name'] + '.json'])['data'] + env[item['name']] = base64.b64decode(source[ref['key']], validate=True).decode() + if env.get('KEYCAPE_CONFIG') != '/etc/keycape/config.yaml' or env.get('KEYCAPE_POLICY_PATH') != '/var/lib/keycape-policy/policy.json': + raise Refused() + return {'files': {p: base64.b64encode(v).decode() for p, v in files.items()}, 'env': env} + + +ENDPOINT = 'unix:///var/run/docker.sock' +EXECUTION = None + + +def docker_environment(environment=None): + # Even an admitted daemon exposed by another Unix socket is outside this + # exact session binding. Conflicting ambient routing is refused, not ignored. + for source in (os.environ, environment or {}): + if source.get('DOCKER_HOST') not in (None,'',ENDPOINT):raise Refused() + if source.get('DOCKER_CONTEXT') not in (None,'','default'):raise Refused() + if any(source.get(k) for k in ('DOCKER_TLS_VERIFY','DOCKER_CERT_PATH')):raise Refused() + env=dict(os.environ if environment is None else environment) + for key in ('DOCKER_CONTEXT','DOCKER_TLS_VERIFY','DOCKER_CERT_PATH'):env.pop(key,None) + env['DOCKER_HOST']=ENDPOINT + return env + + +def process(argv, **kwargs): + marker=None + if EXECUTION is not None and (kwargs.get('start_new_session') or kwargs.get('process_group') not in (None,-1)):raise Refused() + if argv[0]=='docker': + argv=['docker','--host',ENDPOINT,*argv[1:]] + kwargs['env']=docker_environment(kwargs.get('env')) + if EXECUTION is not None: + if (os.getpid()!=EXECUTION['pid'] or os.getsid(0)!=EXECUTION['sid'] or os.getpgrp()!=EXECUTION['pgid'] + or time.monotonic()>=EXECUTION['deadline']):raise Refused() + marker=Path(EXECUTION['staging']+'-docker-inflight') + fd=os.open(marker,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600) + os.close(fd) + try: + result=subprocess.run(argv,**kwargs) + if marker is not None and result.returncode!=0: + fd=os.open(Path(EXECUTION['staging']+'-docker-uncertain'),os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW,0o600);os.close(fd) + return result + except BaseException: + # Parent loss leaves .docker-inflight; caught timeout/transport failures + # retain a sticky uncertainty marker even if later cleanup can run. + if marker is not None: + fd=os.open(Path(EXECUTION['staging']+'-docker-uncertain'),os.O_WRONLY|os.O_CREAT|os.O_NOFOLLOW,0o600);os.close(fd) + raise + finally: + if marker is not None: + try:marker.unlink() + except FileNotFoundError:pass + + +def command(argv, **kwargs): + maximum = kwargs.pop('max_output', 32768) + result = process(argv, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + timeout=kwargs.pop('timeout', 180), **kwargs) + if result.returncode or len(result.stdout) > maximum: + raise Refused() + return result.stdout + + +def inspect_session(session, worker_only=False): + """No credential environment is read by Docker inspect or returned to caller.""" + if not re.fullmatch(r'[a-f0-9]{32}', session['run_id']): + raise Refused() + names = session['containers'] + if not names or len(names) > 12 or len(set(names)) != len(names): + raise Refused() + for name in names: + if not re.fullmatch(r'nk49-kc-' + session['run_id'] + r'-[a-z0-9-]{1,24}', name): + raise Refused() + if session['worker'] not in names or session['issuer'] not in names: + raise Refused() + import os + contexts=json.loads(command(['docker','context','inspect'])) + endpoints=[contexts[0]['Endpoints']['docker']['Host'],os.environ.get('DOCKER_HOST') or ENDPOINT] + if not all(x==ENDPOINT for x in endpoints):raise Refused() + info = json.loads(command(['docker', 'info', '--format', '{"ID":{{json .ID}},"Name":{{json .Name}},"OSType":{{json .OSType}}}'])) + if info != {'ID': '74f93783-6cef-43a8-a3c4-f62586cd3bc1', 'Name': 'bnt-lap001', 'OSType': 'linux'}: + raise Refused() + # The worker is the anchor; all dependencies/TLS/issuer share its network-none namespace. + anchor = command(['docker', 'container', 'inspect', session['worker'], '--format', '{{.Id}}']).decode().strip() + for name,spec in session.get('volumes',{}).items(): + volume=json.loads(command(['docker','volume','inspect',name])) + expected={'type':'tmpfs','device':'tmpfs','o':'size=33554432,uid=1000,gid=1000,mode=0700,nosuid,nodev,noexec'} + if len(volume)!=1 or volume[0]['Driver']!='local' or volume[0].get('Scope')!='local' or volume[0].get('Options')!=expected or spec['options']!=expected or volume[0].get('Labels',{}).get(LABEL)!=session['run_id']:raise Refused() + for name in names: + obj = json.loads(command(['docker', 'container', 'inspect', name, '--format', + '{"host":{{json .HostConfig}},"mounts":{{json .Mounts}},"labels":{{json .Config.Labels}},"image":{{json .Config.Image}},"user":{{json .Config.User}},"entrypoint":{{json .Config.Entrypoint}},"cmd":{{json .Config.Cmd}}}'])) + host = obj['host'] + mounts=obj['mounts'] + destinations=[m['Destination'] for m in mounts] + if len(destinations)!=len(set(destinations)):raise Refused() + for volume,expected_spec in session.get('volumes',{}).items(): + matches=[m for m in mounts if m['Destination']==expected_spec['target']] + if len(matches)!=1 or matches[0]['Type']!='volume' or matches[0]['Name']!=volume or matches[0]['RW']!=(name==session['worker'] or expected_spec['target']=='/var/lib/keycape-policy'):raise Refused() + if (obj['labels'].get(LABEL) != session['run_id'] or not obj['user'] or obj['user'].split(':')[0] in ('0', 'root') + or not host['ReadonlyRootfs'] or host['Privileged'] or host.get('Binds') or host.get('PortBindings') + or host.get('PidMode') or host.get('IpcMode') == 'host' + or host.get('UTSMode') or host.get('UsernsMode') == 'host' or host.get('CgroupnsMode') == 'host' + or host.get('Sysctls',{}) not in ({},{'net.ipv4.ip_unprivileged_port_start':'0'} if name==session['worker'] else {}) + or host.get('CapAdd') or host.get('Devices') or host.get('DeviceRequests') or host.get('VolumesFrom') + or host.get('CapDrop') != ['ALL'] + or host.get('SecurityOpt') not in (['no-new-privileges'], ['no-new-privileges:true']) + or any(m['Type']!='tmpfs' and not (m['Type']=='volume' and m['Name'] in session.get('volumes',{}) and m['Destination']==session['volumes'][m['Name']]['target']) for m in obj['mounts']) + or host['NetworkMode'] != ('none' if name == session['worker'] else 'container:' + anchor) + or obj['image'] != session['images'][name] or '@sha256:' not in obj['image']): + raise Refused() + if worker_only:return + if session['images'][session['issuer']] != IMAGE: + raise Refused() + # Known admitted archive has no command/args override; image default /keycape + # must be the actual issuer executable, not an alternate same-image command. + launch=json.loads(command(['docker','container','inspect',session['issuer'],'--format', + '{"entrypoint":{{json .Config.Entrypoint}},"cmd":{{json .Config.Cmd}},"path":{{json .Path}},"args":{{json .Args}}}'])) + if launch != {'entrypoint':['/keycape'],'cmd':None,'path':'/keycape','args':[]}: + raise Refused() + + +def container_file(container, path): + # Docker streams one tar member into memory; never materialize private files. + raw = command(['docker', 'cp', container + ':' + path, '-'], max_output=128*1024*1024) + with tarfile.open(fileobj=io.BytesIO(raw), mode='r:') as archive: + members = archive.getmembers() + if len(members) != 1 or not members[0].isfile() or members[0].size > 96*1024*1024: + raise Refused() + return archive.extractfile(members[0]).read() + + +JWKS_PROBE = r""" +import base64,ipaddress,json,socket,ssl,sys,urllib.request +from urllib.parse import urlsplit +p=json.load(sys.stdin);issuer=p['issuer'];origin=urlsplit(issuer) +def require(condition): + if not condition:raise ValueError('public_jwks_binding_refused') +require(origin.scheme=='https') +resolved=socket.getaddrinfo(origin.hostname,origin.port or 443,type=socket.SOCK_STREAM) +require(bool(resolved) and all(ipaddress.ip_address(x[4][0]).is_loopback for x in resolved)) +class NoRedirect(urllib.request.HTTPRedirectHandler): + def redirect_request(self,*args,**kwargs):return None +opener=urllib.request.build_opener(urllib.request.ProxyHandler({}),NoRedirect(), + urllib.request.HTTPSHandler(context=ssl.create_default_context(cadata=p['trust']))) +def get(url): + u=urlsplit(url) + require((u.scheme,u.hostname,u.port or 443)==(origin.scheme,origin.hostname,origin.port or 443)) + require(not u.username and not u.password and not u.fragment) + with opener.open(url,timeout=10) as response: + raw=response.read(1024*1024+1);require(len(raw)<=1024*1024) + return json.loads(raw) +d=get(issuer.rstrip('/')+'/.well-known/openid-configuration');require(d['issuer']==issuer) +keys=get(d['jwks_uri'])['keys'] +def integer(value):return int.from_bytes(base64.urlsafe_b64decode(value+'='*(-len(value)%4)),'big') +# The exact admitted owner release constructs one key, kid key-1. Reject every +# extra key, including irrelevant keys: a native successful exchange can then +# only have used the original signer through the existing verifier. +require(isinstance(keys,list) and len(keys)==1) +k=keys[0] +require(k.get('kty')=='RSA' and k.get('kid')=='key-1' and k.get('use')=='sig' and k.get('alg')=='RS256') +require(integer(k['n'])==int(p['n']) and integer(k['e'])==int(p['e'])) +print('{"original_public_signing_key_in_live_jwks":true}') +""" + +# A failed public readiness probe is closed data, not a failing Docker RPC. +# Transport/CLI nonzero remains uncertain; no deliberately failing exec is +# retried as if daemon acceptance had been established. +JWKS_TRANSPORT = ("import contextlib,io\ntry:\n" + " with contextlib.redirect_stdout(io.StringIO()):\n" + " exec(" + repr(JWKS_PROBE) + ")\n" + "except Exception:\n print('{\"original_public_signing_key_in_live_jwks\":false}')\n" + "else:\n print('{\"original_public_signing_key_in_live_jwks\":true}')\n") + + +def check_jwks(session, admission, public_numbers): + trust=runtime_file(session,admission['trust_path']).decode() + request={'issuer':admission['issuer'],'trust':trust,'n':str(public_numbers.n),'e':str(public_numbers.e)} + result=json.loads(command(['docker','exec','-i',session['worker'],'python3','-c',JWKS_TRANSPORT],input=json.dumps(request).encode())) + if result != {'original_public_signing_key_in_live_jwks': True}:raise Refused() + + +RUNTIME_FILES = r""" +import base64,json,sys +from pathlib import Path +p=json.load(sys.stdin) +roots=('/etc/keycape/','/var/lib/keycape-policy/','/etc/keycape-factor/','/recovery-tls/') +result={} +paths=[] +if p.get('tree'): + paths=list(Path('/var/lib/keycape-policy').rglob('*')) +else:paths=[Path(x) for x in p['paths']] +for f in paths: + if f.is_dir():continue + if not str(f).startswith(roots) or not f.is_file() or any(x.is_symlink() for x in (f,*f.parents)) or f.stat().st_size>8*1024*1024:raise ValueError() + result[str(f)]=base64.b64encode(f.read_bytes()).decode() + if len(result)>4096:raise ValueError() +print(json.dumps(result)) +""" + + +def runtime_files(session, paths=(), tree=False): + raw=command(['docker','exec','-i',session['worker'],'python3','-c',RUNTIME_FILES], + input=json.dumps({'paths':list(paths),'tree':tree}).encode(),max_output=48*1024*1024) + return {k:base64.b64decode(v,validate=True) for k,v in json.loads(raw).items()} + + +def runtime_file(session,path): + return runtime_files(session,[path])[path] + + +def run_verifier(session, admission, payload): + 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 + import ipaddress + address = urlsplit(admission['issuer']) + if (address.scheme != 'https' or not address.hostname or address.username or address.password + or address.query or address.fragment): + raise Refused() + if hashlib.sha256(container_file(issuer, '/keycape')).hexdigest() != admission['verifier_sha256']: + raise Refused() + if hashlib.sha256(runtime_file(session, admission['trust_path'])).hexdigest() != admission['trust_sha256']: + raise Refused() + # Capture private environment only in owner process memory, never receipt. + environment = json.loads(command(['docker','container','inspect',issuer,'--format','{{json .Config.Env}}'])) + env = dict(item.split('=',1) for item in environment) + if len(env)!=len(environment):raise Refused() + if set(env)-set(payload['env'])-{'PATH','HOME','HOSTNAME','SSL_CERT_FILE'}:raise Refused() + if env.get('SSL_CERT_FILE') != admission['trust_path'] or any(k.lower().endswith('_proxy') and v for k,v in env.items()): + raise Refused() + if {k:v for k,v in env.items() if k.startswith('KEYCAPE_')}!={k:v for k,v in payload['env'].items() if k.startswith('KEYCAPE_')}:raise Refused() + for name,value in payload['env'].items(): + if env.get(name) != value: + raise Refused() + files = {k:base64.b64decode(v,validate=True) for k,v in payload['files'].items()} + def equal(): + if runtime_files(session,files)!=files:raise Refused() + durable=runtime_files(session,tree=True) + 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'])): + raise Refused() + from cryptography.hazmat.primitives import serialization + key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) + check_jwks(session,admission,key.public_key().public_numbers()) + wrong = secrets.token_urlsafe(48) + if wrong == env[consumer['secret_env']]:raise Refused() + args = ['docker','exec','--env','NK49_UNRELATED_NEGATIVE_SECRET='+wrong,issuer,'/keycape','verify-client', + '-issuer',admission['issuer'],'-previous-secret-env','NK49_UNRELATED_NEGATIVE_SECRET'] + flags = {'client_id':'client-id','secret_env':'secret-env','audience':'audience','scope':'scope', + 'subject':'expect-subject','tenant':'expect-tenant','roles':'expect-roles','deny_scope':'deny-scope'} + for name,flag in flags.items():args+=['-'+flag,consumer[name]] + # Native command reports on stderr. Do not return or print its raw response. + result = process(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE,timeout=150) + raw = (result.stdout+result.stderr).decode() + required = ['discovery and endpoint origin','exchange and JWKS signature for granted scopes','access-token claim bindings', + 'principal_type is service','sub matches the registration','tenant matches the registration','roles present', + 'granted scope carries no excess grant','predecessor secret refused'] + required += ['excess scope refused: '+scope for scope in consumer['deny_scope'].split()] + if result.returncode or any('PASS '+name+'\n' not in raw for name in required) or 'FAIL ' in raw: + raise Refused() + equal() + from cryptography.hazmat.primitives import serialization + key=serialization.load_pem_private_key(files['/etc/keycape/key.pem'],password=None) + check_jwks(session,admission,key.public_key().public_numbers()) + public=key.public_key().public_bytes(serialization.Encoding.DER,serialization.PublicFormat.SubjectPublicKeyInfo) + return {'native_service_registration_verified':True,'wrong_unrelated_secret_explicitly_refused':True, + 'denied_scopes_refused':True,'original_config_registry_policy_receipts_equal':True, + 'public_signing_spki_sha256':hashlib.sha256(public).hexdigest(), + 'original_https_issuer_and_trust_preserved':True,'original_public_signing_key_in_live_jwks':True} + + +def cleanup(session, receipt=None): + """Attempt every owned cleanup even when one obligation fails. + + Preserve exact safe container names and outcomes so the owner can recover an + uncertain/partial cleanup. An inspect/daemon failure never means absence. + """ + obligations = [] + failed = False + for name in reversed(session['containers']): + row = {'container': name, 'status': 'unverified'} + obligations.append(row) + try: + present=command(['docker','container','ls','--all','--filter','name=^/'+name+'$','--format','{{.Names}}']).decode().splitlines() + if not present: + row['status']='absence_verified' + continue + label = command(['docker', 'container', 'inspect', name, '--format', + '{{index .Config.Labels "' + LABEL + '"}}']).decode().strip() + if label != session['run_id']: + row['status'] = 'ownership_mismatch_not_removed' + failed = True + continue + # A failed remove is followed by a successful explicit inventory; + # interrupted remove may actually have completed. + try: + command(['docker', 'rm', '--force', '--volumes', name]) + except Exception: + pass + remaining = command(['docker','container','ls','--all','--filter', + 'name=^/' + name + '$','--format','{{.Names}}']).decode().splitlines() + if remaining: + row['status'] = 'still_present' + failed = True + else: + row['status'] = 'absence_verified' + except Exception: + failed = True + if receipt is not None: + receipt['container_cleanup_obligations'] = obligations + if failed: + raise Refused() + + + +def native_checks(root, manifest, admission, receipt, cleanup_session=True): + """Owner wrapper provides a reviewed session after existing restore pipeline. + + Admission must bind ciphertext, canonical private manifest digest, executable + and trust bytes, exact image/target list, original issuer and selected consumer. + None of these admission fields grant authority or carry a client secret. + """ + session = admission['session'] + # Validate ownership/containment before permitting either exec or cleanup. + inspect_session(session) + receipt.update(status='failed', source_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(), + ciphertext_sha256=admission['ciphertext_sha256'], production_contacted=False, + human_mfa_proven=False, downstream_consumer_reconnect_proven=False, + container_cleanup_verified=False) + try: + for field in ('ciphertext_sha256', 'manifest_sha256', 'verifier_sha256', 'trust_sha256'): + if not re.fullmatch('[a-f0-9]{64}', admission[field]): + raise Refused() + for field in ('client_id','secret_env','audience','scope','subject','tenant','roles','deny_scope'): + if not isinstance(admission['consumer'].get(field), str) or not admission['consumer'][field].strip(): + raise Refused() + payload = private_payload(root, manifest, admission['manifest_sha256']) + result = run_verifier(session, admission, payload) + required = {'native_service_registration_verified','wrong_unrelated_secret_explicitly_refused', + 'denied_scopes_refused','original_config_registry_policy_receipts_equal', + 'original_https_issuer_and_trust_preserved','original_public_signing_key_in_live_jwks'} + if any(result.get(k) is not True for k in required) or not re.fullmatch('[a-f0-9]{64}', result.get('public_signing_spki_sha256','')): + raise Refused() + # Closed receipt allowlist: never copy arbitrary worker output. + receipt.update({k: True for k in required}) + receipt['public_signing_spki_sha256'] = result['public_signing_spki_sha256'] + receipt['status'] = 'isolated_keycape_native_registration_checked' + finally: + try: + if cleanup_session: + cleanup(session, receipt) + receipt['container_cleanup_verified'] = True + except Exception: + receipt['status'] = 'failed' + raise