From 31f483966cdfca4df1d326dee3ec0b6d33ea0e5e Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 16 Oct 2026 20:04:44 +0200 Subject: [PATCH] Accept independent outage recovery and Storage Share guide publication Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2 --- docs/bootstrap-recovery-ceremony.md | 8 +- .../actual-offline-publication.json | 34 ++++++++ .../actual-offline-recovery.json | 39 +++++++++ .../actual-offline-review.json | 16 ++++ .../actual-offline-transfer.json | 21 +++++ docs/storage-share-recovery-publication.md | 47 +++++++++++ .../capability.security.bootstrap-recovery.md | 10 ++- tools/bootstrap-recovery/README.md | 3 +- ...-bootstrap-secret-free-recovery-handoff.md | 81 ++++++++++--------- 9 files changed, 213 insertions(+), 46 deletions(-) create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-publication.json create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-recovery.json create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-review.json create mode 100644 docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-transfer.json create mode 100644 docs/storage-share-recovery-publication.md diff --git a/docs/bootstrap-recovery-ceremony.md b/docs/bootstrap-recovery-ceremony.md index 0333858..62c8639 100644 --- a/docs/bootstrap-recovery-ceremony.md +++ b/docs/bootstrap-recovery-ceremony.md @@ -8,9 +8,11 @@ Approved execution is recorded in decisions40bfae40 and5edd5203; this document records their scope and evidence. **Outage quick start:** [Storage Share disaster recovery guide](disaster-recovery-storage-share.md). -The independently prompted provider download and offline tools ZIP are prepared; -actual outage-path retrieval and guide publication are separately tracked in -T23/T26. The [isolated service restore packet](identity-service-restore-packet.md) +The guide and standalone tools ZIP were published and read back on 2026-10-16. +The operator independently retrieved the protected bundle without OpenBao/SSO +and passed the full archive/native PostgreSQL check. T23/T26 are done; see +[the accepted publication and drill record](storage-share-recovery-publication.md). +The [isolated service restore packet](identity-service-restore-packet.md) contains the draft native-service sequence and remaining T15 admission inputs. ## What has been established diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-publication.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-publication.json new file mode 100644 index 0000000..6eb1e86 --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-publication.json @@ -0,0 +1,34 @@ +{ + "schema": "netkingdom.recovery-kit.v1", + "status": "published_readback_verified", + "secret_values_exported": false, + "new_grants_created": false, + "files": [ + { + "name": "net-kingdom-recovery-57d1940947aa25ff-START-HERE.md", + "bytes": 8381, + "sha256": "1531675f2e7d3713a3a7fc28a5143fb24f201b19cd05d14c59ee485a0bc11e61", + "etag": "\"34e2a2b663670144cd0d0b9aed156455\"", + "readback_verified": true + }, + { + "name": "net-kingdom-recovery-57d1940947aa25ff.zip", + "bytes": 34930, + "sha256": "57d1940947aa25ff83d0f25ddf30090eb40595cccaab64225de882a2fd59ea2f", + "etag": "\"eb3029b41135eb740878f4b12745f0b3\"", + "readback_verified": true + }, + { + "name": "net-kingdom-recovery-57d1940947aa25ff.zip.sha256", + "bytes": 108, + "sha256": "102d1cd25662650a7a181039f6646883d72a9d976551a8950279d8936ca22171", + "etag": "\"51268aeac620038c4d66ec54376efe44\"", + "readback_verified": true + } + ], + "folder": "Backup/railiance-backups/net-kingdom-identity", + "provider": "Storage Share", + "credential_source": "prompt", + "offline_retrieval_verified": true, + "finished_at": "2026-10-16T18:01:01.639515+00:00" +} diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-recovery.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-recovery.json new file mode 100644 index 0000000..3b64c17 --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-recovery.json @@ -0,0 +1,39 @@ +{ + "schema": "netkingdom.identity-recovery.v1", + "status": "identity_archive_verified", + "started_at": "2026-10-16T18:01:57.282452+00:00", + "production_contacted": false, + "secret_values_exported": false, + "container_cleanup_verified": true, + "temporary_plaintext_cleanup_verified": true, + "source_sha256": "039864d0141b552887752bf17cfdcf1bef4bdc9126f946a9c0533e4fd54ebf4f", + "ciphertext_sha256": "7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30", + "artifact": "net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age", + "registered_recipient_match": true, + "wrong_key_refused": true, + "checks": { + "sqlite_integrity_passed": true, + "privacyidea_key_format_and_pair_passed": true, + "keycape_signing_key_format_passed": true, + "policy_json_present": true, + "database_custom_format_present": true, + "native_identity_recovery_proven": false + }, + "manifest_file_count": 36, + "all_manifest_hashes_verified": true, + "profile_sha256": "40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1", + "database_restore": { + "image": "postgres@sha256:ff23cdce56cac62ada6f66013e1a50864c0abbe79d132d40b6e05bd80f378a70", + "image_id": "sha256:ff23cdce56cac62ada6f66013e1a50864c0abbe79d132d40b6e05bd80f378a70", + "pg_restore_version": "pg_restore (PostgreSQL) 16.14 (Debian 16.14-1.pgdg13+1)", + "aggregate_row_counts": { + "token": 5, + "resolver": 2, + "realm": 2 + } + }, + "full_service_authentication_proven": false, + "existing_token_decryption_proven": false, + "audit_signature_continuity_proven": false, + "finished_at": "2026-10-16T18:02:11.395426+00:00" +} diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-review.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-review.json new file mode 100644 index 0000000..4763fd7 --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-review.json @@ -0,0 +1,16 @@ +{ + "schema": "netkingdom.actual-offline-recovery-review.v1", + "status": "verified", + "accepted_at": "2026-10-16T18:02:11.395426+00:00", + "publication_receipt": "actual-offline-publication.json", + "transfer_receipt": "actual-offline-transfer.json", + "recovery_receipt": "actual-offline-recovery.json", + "source_commit": "fbdd62b7ede49d5837a2f374511d06e1bffd3a23", + "three_published_objects_match_current_reproducible_build": true, + "local_ciphertext_sha256_rechecked": true, + "native_archive_verifier_source_matches": true, + "operator_confirmed_independent_access_and_hidden_key_run": true, + "agent_received_private_credentials": false, + "openbao_sso_contacted_for_retrieval": false, + "scope": "Existing identity ciphertext retrieval and archive/database recovery; no deliberate production shutdown, service authentication, retained MFA-token decryption or historical audit-signature continuity test." +} diff --git a/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-transfer.json b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-transfer.json new file mode 100644 index 0000000..0f99d6b --- /dev/null +++ b/docs/evidence/2026-10-16-identity-outage-recovery/actual-offline-transfer.json @@ -0,0 +1,21 @@ +{ + "schema": "netkingdom.identity-offsite.v1", + "provider": "Storage Share", + "folder": "Backup/railiance-backups/net-kingdom-identity", + "artifact": "net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age", + "ciphertext_bytes": 109738344, + "ciphertext_sha256": "7117b3fe1e4840c86b301c94c85e6b16709e5626bb0884bd0580bde630e30e30", + "etag": "\"28ec1f7014e492de4c40e1ae75502f08\"", + "status": "readback_verified", + "fetched_path": "/tmp/nk49-identity-fetched-v0x96qlx/net-kingdom-identity-20261016T063159Z-5882771aa2ce.tar.age", + "independent_owner_retrieval_verified": true, + "credential_source": "independently_held_provider_access", + "provider_auth_mode": "account", + "openbao_contacted": false, + "sso_contacted": false, + "provider_writes_performed": false, + "age_private_key_used": false, + "secret_values_exported": false, + "object_unchanged_during_transfer": true, + "downloaded_at": "2026-10-16T18:01:01.639298+00:00" +} diff --git a/docs/storage-share-recovery-publication.md b/docs/storage-share-recovery-publication.md new file mode 100644 index 0000000..f1bb687 --- /dev/null +++ b/docs/storage-share-recovery-publication.md @@ -0,0 +1,47 @@ +# Published recovery guide and accepted independent retrieval + +Accepted 2026-10-16. Owner work: NK-WP-0049-T23 and T26, both done. + +At , sign into the independently accessible +**Backup** account and navigate to `railiance-backups/net-kingdom-identity/`. +The following files sit beside the encrypted identity backups: + +| File | Purpose | +| --- | --- | +| `net-kingdom-recovery-57d1940947aa25ff-START-HERE.md` | Disaster recovery instructions | +| `net-kingdom-recovery-57d1940947aa25ff.zip` | Standalone recovery tools, guides, trusted fallback receipt and per-file checksums | +| `net-kingdom-recovery-57d1940947aa25ff.zip.sha256` | ZIP checksum | + +Trusted ZIP SHA256, independently recorded in this repository: + +```text +57d1940947aa25ff83d0f25ddf30090eb40595cccaab64225de882a2fd59ea2f +``` + +All three published objects passed exact readback with strong ETag, length and +content checks. Their recorded hashes match the reproducible local build. +Keep an independent copy and the trusted digest outside the identity/provider +dependency; the checksum beside the ZIP alone is not an independent trust anchor. + +The operator then retrieved the protected original identity generation using +independently held provider access, without OpenBao or SSO. The read-only +download's ETag, 109,738,344-byte size and ciphertext SHA256 matched the trusted +fallback. The human-held age key matched the registered recipient. Wrong-key +refusal, all 36 manifest hashes, SQLite integrity, original key-pair checks and +an isolated PostgreSQL 16.14 restore passed. Disposable database and temporary +plaintext cleanup passed. No private credentials were sent to the agent. + +Evidence: + +- [Publication receipt](evidence/2026-10-16-identity-outage-recovery/actual-offline-publication.json) +- [Independent transfer receipt](evidence/2026-10-16-identity-outage-recovery/actual-offline-transfer.json) +- [Archive recovery receipt](evidence/2026-10-16-identity-outage-recovery/actual-offline-recovery.json) +- [Reconciliation review](evidence/2026-10-16-identity-outage-recovery/actual-offline-review.json) + +The published guide is the exact pre-drill revision. This dated acceptance note +records the subsequent successful drill; it does not claim a later republication. +Production services were not deliberately stopped. The recovery path avoided +OpenBao/SSO; restored-service authentication, existing-token MFA and historical +audit-signature continuity remain separate acceptance under T15–T20. +Use the [isolated service restore packet](identity-service-restore-packet.md) +for that next stage. diff --git a/registry/capabilities/capability.security.bootstrap-recovery.md b/registry/capabilities/capability.security.bootstrap-recovery.md index 57b156c..5d9b6e0 100644 --- a/registry/capabilities/capability.security.bootstrap-recovery.md +++ b/registry/capabilities/capability.security.bootstrap-recovery.md @@ -52,8 +52,8 @@ discovery: privacyIDEA keys plus linked PostgreSQL dump - Public-recipient age sealing, Storage Share create/readback, separate retention and attended independent-key archive verification - - Railiance bootstrap handoff and a prepared independent-provider download path - requiring neither OpenBao nor SSO; actual outage-path owner drill remains pending + - Railiance bootstrap handoff and actual independent-provider retrieval requiring + neither OpenBao nor SSO; operator archive recovery passed on 2026-10-16 excludes: - Source repairs and disposable native fixtures do not prove estate root isolation or recovery @@ -75,6 +75,7 @@ availability: - tools/bootstrap-recovery/run-offline-recovery.sh - docs/disaster-recovery-storage-share.md - docs/identity-service-restore-packet.md + - docs/storage-share-recovery-publication.md - tools/bootstrap-recovery/verify-identity.py consumption_modes: - CLI @@ -152,7 +153,8 @@ For an outage, use [the Storage Share recovery guide](../../docs/disaster-recove and the self-contained kit built by `tools/bootstrap-recovery/recovery-kit.py`. The private operator handoff publishes the versioned guide/kit with readback, retrieves the protected generation using independently held provider access, -and prompts separately for the human-held age key. Source/fixture preparation -passed; consult NK-WP-0049-T23/T26 for actual outage drill/publication acceptance. +and prompts separately for the human-held age key. Actual publication/readback +and independent outage-path archive recovery passed on 2026-10-16; T23/T26 are +done. See [the published location and trusted kit digest](../../docs/storage-share-recovery-publication.md). The [isolated service packet](../../docs/identity-service-restore-packet.md) records the remaining service-owner admission and native tests. diff --git a/tools/bootstrap-recovery/README.md b/tools/bootstrap-recovery/README.md index b7f1ff8..f7b4656 100644 --- a/tools/bootstrap-recovery/README.md +++ b/tools/bootstrap-recovery/README.md @@ -13,7 +13,8 @@ three new versioned guide/ZIP/checksum files beside the backups with exact readback. `run-offline-recovery.sh` is the owner's private two-prompt handoff for publication, outage-path retrieval and the existing archive recovery check. Run secret prompts in the owner's own terminal, never an agent-captured PTY. -Source/fixture checks do not replace the actual owner drill/publication receipts. +Actual owner publication/readback and outage-path archive recovery passed on +2026-10-16; see the [published location and receipts](../../docs/storage-share-recovery-publication.md). Service restore admission remains in the [isolated restore packet](../../docs/identity-service-restore-packet.md). diff --git a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md index bd27bcd..51af634 100644 --- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -28,15 +28,16 @@ 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:** 14 tasks done; 2 in progress; 1 ready to start (`todo`); -10 waiting on explicit prerequisites. These are task counts, not an effort-based +**Current position:** 16 tasks done; 2 in progress; 1 ready to start (`todo`); +8 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; -owner execution/publication and service admission remain explicit gates. +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), execute independent offline retrieval (T23) and -guide publication (T26), and record residual-scope handoffs (T24). After owner admission, execute the individual native service and +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. @@ -591,35 +592,32 @@ source retirement as provider revocation. ```task id: NK-WP-0049-T23 -status: wait +status: done priority: high assignee: codex depends_on: [NK-WP-0049-T13, NK-WP-0049-T25] -blocking_reason: "Await the operator-run private independent-provider download and hidden-key recovery drill; bounded tooling and self-contained kit are prepared in T25." state_hub_task_id: "1ec537ee-dfee-5576-be36-a81bdba417d1" ``` **Accountable worker:** codex. Service/credential-owner acceptance remains with the named owner boundary. -The previous independent retrieval succeeded through a healthy attended OpenBao -path. Source/fixture preparation of a separate offline adapter is now complete -in T25. Actual independently held provider access has not yet been exercised -for this outage path; no completed drill is claimed. +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. -**Unblock action:** operator runs the prepared private terminal handoff -`bash tools/bootstrap-recovery/run-offline-recovery.sh` (combined guide -publication and known-generation retrieval) or the standalone read-only -`retrieve-identity-offline.py` command in the guide. Independently held provider -access and age key go only into the respective hidden prompts; inspect safe -receipts and perform the real archive recovery check. Never use a captured agent -PTY for secret entry. T26 separately tracks actual guide publication. - -**Done when:** the owner can retrieve the exact off-host bundle without relying -on the failed OpenBao/SSO instance, run the existing hidden-key checker, and -verify refusal/cleanup. Use the credential-owner route before obtaining inputs; -a new provider grant or broader scope needs its own approval. Source fixtures -alone do not close the actual outage-path proof. +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 @@ -688,11 +686,10 @@ evidence directory. This source correction does not complete T23/T26. ```task id: NK-WP-0049-T26 -status: wait +status: done priority: high assignee: codex depends_on: [NK-WP-0049-T25, NK-WP-0049-T27] -blocking_reason: "Await private operator provider-access execution of the prepared publication command and actual three-object readback receipts; guide and kit are built." state_hub_task_id: "94d054fe-e5d8-5ddf-8e48-80714123d184" ``` @@ -706,18 +703,26 @@ 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. -**Unblock action:** operator runs `run-offline-recovery.sh`, or the reviewed -`recovery-kit.py --publish` command through the existing attended Backup-account -owner conduit. Existing publisher/retention workload grants are not repurposed. -The user authorized this documentation upload; no new grant is required by the -prepared command. The first owner run (`/tmp/nk49-offline-handoff-VKv337zo`) -failed before private input/publication; the terminal bug is fixed in T25 and -the rebuilt kit is ready for a fresh owner run. Credentials remain private; no provider permissions are widened. +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. -**Done when:** the versioned START-HERE guide, self-contained ZIP and ZIP SHA256 -file are present beside the identity backups with exact conditional-create and -ETag/length/content readback proof, and their folder/name/digests are recorded for -future discovery. Local build or attempted upload alone does not close this task. +**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 @@ -753,7 +758,7 @@ 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 acceptance and independent outage retrieval; full archive recovery and backup activation are already complete." +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" ```