Record populated pilot capture and prepare encrypted export
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1abf1-7e95-7141-87c9-ee78332bf790
This commit is contained in:
parent
8fd2c9772d
commit
d2e1377354
11 changed files with 713 additions and 8 deletions
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-user-return.v1",
|
||||
"reported_on": "2026-11-06",
|
||||
"workplan": "RAPPS-WP-0014",
|
||||
"task": "RAPPS-WP-0014-T03",
|
||||
"run_id": "20261105T233543Z-89bfbe04dece",
|
||||
"evidence_kind": "user_reported",
|
||||
"two_accounts_work_after_restart": true,
|
||||
"user_report": "Both accounts work. The Ausschreibung is no longer listed on the \u00dcbersicht; everything else seems as before.",
|
||||
"human_restart_check": "confirmed_with_overview_followup",
|
||||
"overview_omission_reported": true,
|
||||
"overview_followup": {
|
||||
"deployed_source_revision": "c067993037f1cdeeb7b22d5600b51c649bc239db",
|
||||
"source_file": "vergabe_teilnahme/apps/ausschreibungen/views.py",
|
||||
"function": "dashboard",
|
||||
"ongoing_list_filter": "status__range=(1, 9); latest ten by geaendert_am",
|
||||
"final_statuses_omitted": [
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13
|
||||
],
|
||||
"fixture_current_status": "not_reported; clarification requested",
|
||||
"explanation": "A final status would explain exclusion; phase 8 alone is included. No live status or data-loss cause is inferred."
|
||||
},
|
||||
"provider_publication_verified": false,
|
||||
"restore_verified": false,
|
||||
"authentication_policy_changed": false
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-three-store-capture.v1",
|
||||
"run_id": "20261105T233543Z-89bfbe04dece",
|
||||
"status": "captured_and_resumed",
|
||||
"database": "vergabe_demo_company",
|
||||
"helm_revision": 4,
|
||||
"app_resumed": true,
|
||||
"off_host_verified": false,
|
||||
"restore_verified": false,
|
||||
"media_files": 1,
|
||||
"media_bytes": 803,
|
||||
"media_logical_sha256": "24fe90da88973ac03c8a475dff93c5866cebd797aeecdca2286989a1250779ed",
|
||||
"fixture_document_sha256": "23a6850fa2391a58280c8515361ca29e9e92fa65fdadc36be7b44b552192e381",
|
||||
"sqlite": {
|
||||
"tables": 9,
|
||||
"rows": 7,
|
||||
"logical_sha256": "579dedb0e6a6b30f6cf3a5cec27ae423dbdaf0de959837cb9d697f6d5a789258",
|
||||
"linked_issue_found": true,
|
||||
"integrity_verified": true
|
||||
},
|
||||
"stores_sha256": "6affa22da26badb4daceb87acf62d4eba57bfbfc2d60da0823b607c449596d66",
|
||||
"stores_bytes": 3489,
|
||||
"database_sha256": "8758ebd2e2b6c9e75742c42f2d32f71596522f5aade3a7212ed5a04c3cf3476c",
|
||||
"database_bytes": 169232,
|
||||
"database_tables": 39,
|
||||
"database_rows": 247,
|
||||
"database_logical_sha256": "33191c43c437f1b05da410a3f22989c86ce50f4fca8fd32d40fbb327b8b73765",
|
||||
"writers_quiesced": true,
|
||||
"anonymous_document_http_status": 302,
|
||||
"anonymous_document_denied": true,
|
||||
"helper_cleanup_confirmed": true,
|
||||
"restart_fixture_verified": true,
|
||||
"elapsed_seconds": 98.61,
|
||||
"evidence_kind": "user_reported_terminal_output",
|
||||
"reported_on": "2026-11-06",
|
||||
"workplan": "RAPPS-WP-0014",
|
||||
"task": "RAPPS-WP-0014-T03",
|
||||
"command": "python3 tools/vergabe_pilot_snapshot_remote.py --execute",
|
||||
"founder_executed_reviewed_change": true,
|
||||
"elapsed_seconds_scope": "Whole helper operation after preflight; not separately measured outage duration",
|
||||
"human_two_account_post_restart_walkthrough": "confirmed_with_overview_followup",
|
||||
"production_data_restored": false,
|
||||
"human_return_receipt": "2026-11-06-vergabe-post-restart-user-return.json"
|
||||
}
|
||||
85
docs/proposals/2026-11-06-vergabe-recovery-export/README.md
Normal file
85
docs/proposals/2026-11-06-vergabe-recovery-export/README.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Export the populated Vergabe recovery point
|
||||
|
||||
The founder's [native capture receipt](../../evidence/2026-11-06-vergabe-three-store-capture-return.json)
|
||||
passes for run `20261105T233543Z-89bfbe04dece`. The app has resumed and both
|
||||
accounts work, with the [overview UI follow-up](../../evidence/2026-11-06-vergabe-post-restart-user-return.json).
|
||||
This step transfers the frozen point; it needs no further application pause.
|
||||
[Exact scope, pins and validation](plan.json).
|
||||
|
||||
## Founder workstation command
|
||||
|
||||
```bash
|
||||
git pull --ff-only
|
||||
python3 tools/vergabe_pilot_export_remote.py --fetch
|
||||
```
|
||||
|
||||
Default without `--fetch` reviews locally. `--fetch` uses the same existing
|
||||
interactive SSH/sudo lane as inventory and capture. The agent does not execute
|
||||
the founder's credential path. No remote checkout is needed.
|
||||
|
||||
The node helper requires the successful capture receipt and the exact database
|
||||
and stores sizes/hashes from the returned receipt. It packages only
|
||||
`database.dump`, `stores.tar.gz`, `manifest.private.json`, `receipt.json` and a
|
||||
generated packet manifest. Raw SQLite copies/work directories are excluded.
|
||||
|
||||
Using the existing platform **public** age recipient, it encrypts on railiance01
|
||||
and retains the encrypted point plus its hash manifest in the root-private run
|
||||
directory. A temporary plaintext package exists only inside that protected
|
||||
directory and is removed after sealing. The original capture is preserved.
|
||||
An interrupted, inconsistent seal stops for review rather than being overwritten.
|
||||
|
||||
The helper copies ciphertext and safe transfer metadata to two 0600 files in
|
||||
the existing founder SSH account's home (`tegwick`), named
|
||||
`vergabe-pilot-20261105T233543Z-89bfbe04dece.{zip.age,transfer.json}`.
|
||||
Only those encrypted handoff files are made readable by that account; the
|
||||
private capture files remain root-only. Existing different handoff bytes refuse.
|
||||
|
||||
The wrapper uses scp to fetch the pair into a private temporary directory, then
|
||||
checks the source run/image/database, captured database/store hashes, encrypted
|
||||
size and ciphertext hash. Only a verified pair becomes the final directory:
|
||||
|
||||
```text
|
||||
~/.local/state/vergabe-pilot-recovery/20261105T233543Z-89bfbe04dece/
|
||||
```
|
||||
|
||||
It refuses a destination inside a Git tree. Files are 0600 and the directory is
|
||||
0700. An already verified pair can be reused on retry. Successful final JSON
|
||||
has `status: encrypted_workstation_copy_verified` and includes the local path.
|
||||
Return that JSON, without opening or pasting backup contents.
|
||||
|
||||
No Kubernetes/database access, application change, OpenBao access, provider call
|
||||
or recovery-key retrieval occurs. Age must already be available on the node at
|
||||
one of the standard or existing platform vendor paths. Missing age fails before
|
||||
sealing; this command does not install tools or alter the platform configuration.
|
||||
|
||||
## What this establishes
|
||||
|
||||
The encrypted bytes are now copied to the founder's workstation outside the
|
||||
production node, with transport hashes verified. This is a separate milestone
|
||||
from publication to the declared backup provider. The receipt keeps
|
||||
`provider_publication_verified`, `decryption_verified` and `restore_verified`
|
||||
false. Public-key encryption alone does not prove the escrow identity can recover
|
||||
the point, and no recurring protection or accepted recovery objective is inferred.
|
||||
|
||||
Credential routing confirms the existing `railiance-backup-offsite-lane` belongs
|
||||
to railiance-platform. Its Nextcloud file-drop credential is create-only;
|
||||
independent readback uses the Backup account, and age decryption uses recovery
|
||||
escrow in a contained founder login. Reuse those owner helpers for publication
|
||||
and readback; do not borrow another application's Scaleway publisher identity.
|
||||
No new credential lane, role, provider folder, retention change or timer is
|
||||
created by this export. The upload-only token is not readback authority.
|
||||
|
||||
After provider readback, rehearse an isolated restore of this matched point with
|
||||
outgoing integrations disabled. Verify every PostgreSQL table digest, documents
|
||||
and local issue linkage, restored account behavior, source/image availability and
|
||||
elapsed recovery time. Compatible rollback, access denial and named backup/support
|
||||
ownership, cadence, retention and accepted RPO/RTO remain T03 requirements.
|
||||
|
||||
## Validation
|
||||
|
||||
`python3 -m unittest discover -s tests -p test_vergabe_pilot_export.py`: seven
|
||||
synthetic checks pass. They include actual age encryption/decryption, complete
|
||||
packet comparison, changed capture/ciphertext rejection, unsafe source refusal,
|
||||
handoff preservation, verified transfer/retry and Git destination refusal.
|
||||
No native backup or real key is read by those tests. Native export remains
|
||||
founder-executed and unverified until its receipt returns.
|
||||
49
docs/proposals/2026-11-06-vergabe-recovery-export/plan.json
Normal file
49
docs/proposals/2026-11-06-vergabe-recovery-export/plan.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"schema": "railiance.vergabe-pilot-recovery-export-plan.v1",
|
||||
"prepared_on": "2026-11-06",
|
||||
"workplan": "RAPPS-WP-0014",
|
||||
"task": "RAPPS-WP-0014-T03",
|
||||
"run_id": "20261105T233543Z-89bfbe04dece",
|
||||
"sources": {
|
||||
"vergabe_pilot_recovery_store": "724a2dd9db8a0f57e1efa709ec989d8a47c681a86b1fca923bfdfea1698ae23c",
|
||||
"vergabe_pilot_export": "b45733fa10ae59b56563045c43c53b5f824a74e1114f68fbed28404f14b43e3a"
|
||||
},
|
||||
"execution": "Founder workstation --fetch: interactive SSH/sudo on railiance01, followed by scp of ciphertext and a safe manifest",
|
||||
"source": "/var/lib/vergabe-pilot-recovery/20261105T233543Z-89bfbe04dece/",
|
||||
"scope": [
|
||||
"Verify accepted capture receipt and pinned database/stores byte sizes and SHA256",
|
||||
"Package only database.dump, stores.tar.gz, manifest.private.json, receipt.json and generated packet.json",
|
||||
"Encrypt on the node to the existing platform public age recipient",
|
||||
"Create mode-0600 encrypted handoff files for the existing founder SSH account",
|
||||
"Copy and checksum-verify ciphertext and transfer metadata in a private workstation directory outside Git"
|
||||
],
|
||||
"recipient": "age1zvryunvjhvpkmasskauga2heeg0ztnte9ymgppvjge36ekumk50syr3tsz",
|
||||
"recipient_source": "railiance-platform/lib/railiance-backup-common.sh",
|
||||
"node_ciphertext": "recovery-point.zip.age",
|
||||
"node_public_manifest": "seal.json",
|
||||
"founder_handoff_basename": "vergabe-pilot-20261105T233543Z-89bfbe04dece",
|
||||
"workstation_directory": "~/.local/state/vergabe-pilot-recovery/20261105T233543Z-89bfbe04dece/",
|
||||
"application_mutations": false,
|
||||
"database_access": false,
|
||||
"secret_reads": false,
|
||||
"openbao_access": false,
|
||||
"provider_access": false,
|
||||
"provider_publication_verified": false,
|
||||
"decryption_verified": false,
|
||||
"restore_verified": false,
|
||||
"next_provider_route": {
|
||||
"id": "railiance-backup-offsite-lane",
|
||||
"owner_repo": "railiance-platform",
|
||||
"provider": "Existing Nextcloud create-only file-drop lane; independent Backup account for readback; age escrow for contained decrypt verification",
|
||||
"route_only_not_publication_evidence": true
|
||||
},
|
||||
"validation": {
|
||||
"unit_cases_passed": 7,
|
||||
"actual_age_synthetic_round_trip": true,
|
||||
"tampered_capture_or_ciphertext_refused": true,
|
||||
"existing_handoff_not_overwritten": true,
|
||||
"transport_retry_uses_verified_pair": true,
|
||||
"git_destination_refused": true,
|
||||
"native_export_executed": false
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,14 @@ data. A failed check stops before any capture mutation.
|
|||
|
||||
## Prepared capture, after the founder's go
|
||||
|
||||
Executed by the founder: run `20261105T233543Z-89bfbe04dece` reports
|
||||
[`captured_and_resumed`](../../evidence/2026-11-06-vergabe-three-store-capture-return.json).
|
||||
The matched populated point and restart checks pass; the full helper took
|
||||
98.61 seconds. Both accounts work after restart, with an overview-list UI
|
||||
follow-up. Off-host publication and isolated restore remain open. The command
|
||||
below is retained for reproducibility; **do not recapture this accepted point**.
|
||||
Next: [encrypt and fetch the frozen point](../2026-11-06-vergabe-recovery-export/README.md).
|
||||
|
||||
Live production changes require the founder's go for this change under
|
||||
`the-custodian/docs/agent-environment-orientation.md` section 0. The following
|
||||
command is prepared for that later maintenance window:
|
||||
|
|
|
|||
|
|
@ -24,10 +24,21 @@ passes at Helm revision 4 with the expected healthy deployment/database and both
|
|||
Bound claims. The [November 6 capture check](evidence/2026-11-06-vergabe-capture-preflight-return.json)
|
||||
also passes: two active members and OIDC identities, fixture 1/1/1, matching file,
|
||||
valid local-state header, anonymous download denial, no pending migrations and
|
||||
the reader Pod server dry-run. Next is the founder-approved pause/capture/resume
|
||||
in the [three-store recovery packet](proposals/2026-11-06-vergabe-three-store-capture/README.md).
|
||||
the reader Pod server dry-run. The founder-approved capture then executed using
|
||||
the [three-store recovery packet](proposals/2026-11-06-vergabe-three-store-capture/README.md).
|
||||
Neither preflight nor synthetic validation satisfies the pilot recovery gate.
|
||||
|
||||
The [populated capture and resume](evidence/2026-11-06-vergabe-three-store-capture-return.json)
|
||||
pass: 39 PostgreSQL tables / 247 rows, one PDF and SQLite integrity/link checks;
|
||||
the helper was removed. Total operation time was 98.61 seconds, including
|
||||
resume/postflight, rather than a separately measured outage duration.
|
||||
The [human restart return](evidence/2026-11-06-vergabe-post-restart-user-return.json)
|
||||
confirms both accounts work and everything else appears as before, except the
|
||||
tender is absent from Übersicht. The deployed dashboard lists only status 1–9;
|
||||
final statuses 10–13 would explain exclusion. The actual current status is not
|
||||
yet reported, so this remains a UI follow-up. Off-host publication and isolated
|
||||
restore remain unverified.
|
||||
|
||||
The other session does not update automatically, and a fresh login was needed
|
||||
after a short interval. The user wants a full working day without renewed login
|
||||
and would prefer no OTP at initial app sign-in, with refinement explicitly
|
||||
|
|
@ -93,7 +104,8 @@ could not read native node, Deployment and PVC status. The founder's subsequent
|
|||
[capture preflight](evidence/2026-11-06-vergabe-capture-preflight-return.json)
|
||||
clear that blocker at Helm revision 4. They use the founder's own terminal and
|
||||
existing SSH/sudo lane; the agent receives only sanitized receipts. Native
|
||||
capture and restart have not run.
|
||||
capture and automated restart verification subsequently passed; see the capture
|
||||
receipt above. No additional pause is needed to transfer that frozen point.
|
||||
|
||||
After the populated workflow, prepare the exact attended recovery action from
|
||||
the existing [pilot recovery contract](vergabe-teilnahme-pilot.md#persistence-and-recovery)
|
||||
|
|
@ -122,8 +134,8 @@ and [deployment binding](vergabe-demo-company-binding.md). Its receipt must cove
|
|||
Existing database-only backup/restore targets default to historical `vergabe_db`
|
||||
and omit both file stores. They cannot establish this three-store recovery claim.
|
||||
The two-account functional walkthrough is user-confirmed with UI follow-up.
|
||||
The attended capture/restart action is prepared and its live preflight passes;
|
||||
execution awaits the founder's go. Off-host publication, isolated native restore
|
||||
and rollback remain outstanding.
|
||||
The attended capture/restart action has executed successfully, with automated
|
||||
and human restart checks (overview follow-up above). Off-host publication,
|
||||
isolated restore and rollback remain outstanding.
|
||||
Logged-in account deactivation remains a separate owner-run access-control check
|
||||
from the pilot contract. No account is disabled as part of these walkthrough steps.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,14 @@
|
|||
Updated 2026-11-06 under RAPPS-WP-0014 and VERGABE-WP-0019.
|
||||
Release binding is complete (RAPPS-WP-0014-T02). Recovery and invited-recipient acceptance remain open.
|
||||
|
||||
November 6 recovery update: the founder's matched PostgreSQL/media/SQLite capture
|
||||
and app resume pass at revision 4; the full operation took 98.61 seconds. Both
|
||||
accounts work after restart, with an overview-list UI follow-up. See the
|
||||
[capture receipt](evidence/2026-11-06-vergabe-three-store-capture-return.json).
|
||||
Provider publication/readback, isolated restore, rollback/access and operating
|
||||
ownership remain open. The accepted point can be transferred without another
|
||||
pause using the [encrypted export packet](proposals/2026-11-06-vergabe-recovery-export/README.md).
|
||||
|
||||
| Item | Current binding |
|
||||
| --- | --- |
|
||||
| Tenant | tenant:trial:demo-company, active/version 1; three native memberships and one linked directory identity |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue