net-kingdom/tools/bootstrap-recovery
tegwick 17a8fa1495
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
feat(recovery): verify scoped delivery and create first full offsite bundle
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
2026-10-16 09:21:55 +02:00
..
capture-identity.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
check-privacyidea-database.py Prepare bounded off-host privacyIDEA recovery drill 2026-10-16 00:09:13 +02:00
fetch-privacyidea-backup.py Prepare bounded off-host privacyIDEA recovery drill 2026-10-16 00:09:13 +02:00
identity-backup-profile.json fix(recovery): bind admitted host and record live provider scope approval 2026-10-16 07:44:36 +02:00
identity-bundle.py fix(recovery): bind admitted host and record live provider scope approval 2026-10-16 07:44:36 +02:00
identity-credential-setup.py security(recovery): fence agent reads before publishing backup credentials 2026-10-16 07:49:48 +02:00
identity-custody.json feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
identity-files.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
identity-isolation.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
identity-offsite.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
identity-retention.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
identity-runtime.py feat(recovery): verify scoped delivery and create first full offsite bundle 2026-10-16 09:21:55 +02:00
install-identity-backup.py fix(recovery): bind admitted host and record live provider scope approval 2026-10-16 07:44:36 +02:00
inventory-scaleway.py Inventory off-host recovery assets through existing bounded backup routes 2026-10-15 23:58:41 +02:00
inventory-storage-share.py Prepare bounded off-host privacyIDEA recovery drill 2026-10-16 00:09:13 +02:00
prepare-identity-coverage.py Record off-host database recovery and prepare identity backup coverage 2026-10-16 00:32:50 +02:00
README.md Record off-host database recovery and prepare identity backup coverage 2026-10-16 00:32:50 +02:00
retrieve-identity.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00
verify-bundle.py Harden remaining bootstrap custody callers and prepare isolated recovery 2026-10-15 22:57:14 +02:00
verify-identity-delivery.py feat(recovery): verify scoped delivery and create first full offsite bundle 2026-10-16 09:21:55 +02:00
verify-identity.py feat(recovery): prepare full identity backup and bootstrap handoff 2026-10-16 01:37:11 +02:00

Bootstrap recovery transport check

Owner work: NK-WP-0049. Follow the exact recovery ceremony.

verify-bundle.py validates a digest-bound age-encrypted secrets/ tar archive using an explicit private temporary key and registered keys/age.pub. It checks an exact required-file list, unrelated wrong-key refusal, safe isolated file publication/readback and staging removal. No service or cluster is contacted.

It refuses links, special/duplicate/unreviewed entries, oversized content, private age keys in the bundle, wrong digest/recipient and existing receipt destinations. Only a closed metadata receipt leaves the process. Current service credentials, independent/off-host custody, production acceptance and revocation remain separate owner evidence. Same-UID/process-memory isolation and forensic secure erasure are not provided by this local checker.

Tests use real age encryption/decryption with disposable keys and malicious archive fixtures, never production credentials:

python3 -m pytest -q tests/test_bootstrap_recovery_transport.py

inventory-storage-share.py is a silent read-only child of the existing attended Platform Backup-account procedure. It checks the caller's OIDC/admin scope, reuses the owner custody accessor, and exports only bounded DAV names and sizes. Warden revokes and cleans up the session. It never reads an age key or object content and contains provider errors/redirects/proxies.

inventory-scaleway.py lists bounded metadata in the fixed backup bucket/prefix using the existing scoped runtime delivery and pinned primary cluster. It uses neither the bootstrap API key nor object GET/write/delete operations. Run through the already admitted caller with cached boto3 1.40.18; it emits only its safe receipt. Both inventories explicitly state their bounds and cannot prove asset absence outside them, ciphertext integrity, decryption or native recovery.

fetch-privacyidea-backup.py retrieves only the fixed reviewed PI ciphertext under the same attended Platform Backup-account procedure. Strong ETag binding, exact length, digest and private no-overwrite output are required. It reads no age key. check-privacyidea-database.py then runs through temporary human custody, checks the transfer lineage/digest and recipient, tests wrong-key refusal and restores the decrypted custom-format dump into pinned local PostgreSQL with no network, ports or host data mounts. Only three fixed table counts are exported. It removes the disposable database and plaintext and records cleanup. It does not prove token decryption, audit signing continuity or full identity recovery. See the exact prepared command in the ceremony, rather than inventing new inputs.

NK49_RUN_DISPOSABLE_POSTGRES_TEST=1 python3 -m pytest -q \
  tests/test_privacyidea_offhost_recovery.py \
  tests/test_storage_share_inventory.py tests/test_scaleway_backup_inventory.py

identity-backup-profile.json prepares missing full service coverage and names the exact current workload/PVC/credential dependencies, proposed provider paths and remaining implementation/admission gates. It is a proposal, not a new live publisher grant. prepare-identity-coverage.py --receipt NEW_PATH verifies the primary cluster and current deployment/PVC/reference bindings using metadata only. It refuses replacement resources, unobserved/unready deployments and new unreviewed references. It has no Secret-data, pod-exec, mutation or upload route. Its receipt says prepared_not_admitted; it cannot prove a backup exists.