Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883
8.6 KiB
WP-0029 provider recovery procedure
Primary platform backup is Scaleway (RESOURCE-WP-0002). This procedure covers the independent Nextcloud secondary-copy lane.
Scope: invalidate the exposed Nextcloud upload predecessor and prove replacement encrypted upload and offsite recovery under CCR-2026-0004. The route is a Nextcloud file-drop share, not a platform-admin OpenBao credential. OpenBao administration does not confer Nextcloud share-owner authority.
Required owner inputs
- Nextcloud share owner/account and the reviewed share-management session.
- A replacement file-drop share/token delivered through protected custody; never chat, argv, Git or State Hub. Record only custody coordinates.
- Owner-authorized retrieval access for the encrypted offsite artifact. Do not assume an upload-only file-drop token can list or download backups.
- A protected reference to the predecessor for a bounded rejection probe, or accepted provider-side revocation evidence. Do not reconstruct it into logs.
Execution order
- Confirm current OpenBao KV version and preserve every existing field. The
lane contains
AGE_PRIVATE_KEY; replacing only upload fields must use CAS and preserve recovery escrow. Never use a partialkv putthat drops it. - Confirm the exact Nextcloud share and all backup consumers. Besides the
workstation helpers, activity-core consumes
NC_WEBDAV_TOKENandNC_WEBDAV_URLthrough ExternalSecretactcore-backup-offsite. Coordinate its next invocation so process-cached credentials cannot produce a false replacement-success claim. - Create the replacement under provider authority. Verify its permissions match the file-drop lane; no production delete/admin authority is needed. Seed both upload fields through contained OpenBao CAS and verify delivery with boolean comparisons. Keep provider secrets out of evidence.
- Upload a uniquely named age-encrypted artifact with the replacement. Require HTTP 200/201/204; redirects and network errors are not success. Record only artifact identity and safe status. A synthetic fixture can prove transport, but it does not establish Forgejo application recovery.
- Invalidate the predecessor at the provider. Verify rejection with the old credential in protected memory against the same bounded operation. A 401/403 or accepted provider invalidation receipt is evidence; a timeout is not. Preserve existing retained backup objects and access to their encryption key.
- Retrieve the newly uploaded encrypted artifact through the separate owner recovery path, decrypt in a protected temporary directory, and verify its expected content. For Forgejo restore acceptance, use a fetched real backup and the owning isolated restore procedure with repository/blob/database checks. Require the local fetched artifact to exist before invoking the historical infra drill: that script otherwise creates a fresh production dump, which cannot prove offsite recovery.
- Record provider invalidation, replacement KV version, upload/download, decryption, isolated restore and cleanup receipts. Mark T02 done only after the agreed recovery checks pass. No receipt may contain the predecessor's value, fingerprint, length or shape.
Recovery-key exposure remains separate
CCR-2026-0004 records historical exposure of the age recovery key as well as upload credentials. Upload-share rotation alone must not clear that taint. Retain old age recovery material until all retained artifacts are accounted for and any owner-approved re-encryption is complete. Do not silently rotate or discard the age key as part of this upload-token repair.
Prepared transport
lib/railiance-backup-common.sh passes curl credentials and credential-bearing
URLs via stdin configuration, disables curlrc, suppresses backend diagnostics,
requires HTTPS and rejects non-success responses. The Python backend streams
the artifact, refuses redirects and suppresses credential-bearing exception
text. These source changes are preparation; no provider rotation, upload or
restore is claimed by their tests.
Dedicated Backup account (2026-09-05)
The operator-provisioned account is Backup on nx4069.your-storageshare.de.
Its credentials remain in OpenBao KVv2 operators/nextcloud/backup, fields
BACKUP_USERNAME and BACKUP_PASSWORD (API operators/data/nextcloud/backup).
The UI's secrets/ prefix is not a separate KV mount.
Future uploads use the account's /railiance-backups folder through a dedicated
create-only share. Only its derived NC_WEBDAV_TOKEN and NC_WEBDAV_URL enter
the existing workload lane and activity-core ExternalSecret; the account password
is not a production credential. Recovery download and cleanup use operator
account authority. Preserve AGE_PRIVATE_KEY and all unrelated KV fields with CAS.
The server-reported quota is 10 GiB (10,737,418,240 bytes). This is a hard capacity limit shared by the account's files. Retention counts such as 14 daily and four weekly backups do not guarantee they fit. Check quota before large uploads; a quota rejection is a failed backup. Pruning retained backups requires an explicit retention decision and operator authority; upload jobs cannot delete. Existing Bernd-owned backups remain in their original location and require their existing recovery access. This cutover neither migrates them nor revokes Bernd's personal account or old share.
scripts/migrate_nextcloud_backup_account.py performs the attended account,
quota, create-only share, encrypted fixture recovery and CAS checks. Run it only
through warden access openbao-platform-admin-login --exec -- ..., with a fresh
private receipt path and --confirm 'MIGRATE TO Backup'. The helper is silent;
receipts contain only status and metadata. Review a failed receipt before retrying:
a failure can leave the dedicated folder/share or an identified test fixture, and
a cleanup failure after CAS can occur after credentials have already changed.
Refresh actcore-backup-offsite, verify delivery by contained comparison, and
restart its three environment consumers (actcore-api, actcore-event-router,
actcore-worker). Record their readiness and loaded-value comparisons.
Real archive acceptance
capture_forgejo_archive.py requires the exact producer's successful exit marker,
checks every transferred chunk's length and the complete SHA-256 against the
producer, then validates ZIP structure and member CRCs before encryption. The
2026-09-05 recovery attempt exposed a truncated September 4 encrypted archive;
successful age decryption and upload alone cannot certify backup completeness.
verify_nextcloud_offsite_restore.py streams a real encrypted archive through
the current upload lane and downloads it separately through owner recovery
custody. It emits a hash-bound transfer receipt. Run this silent helper through
the attended Warden envelope, with fresh private staging and receipt paths.
restore_forgejo_offsite_locally.py requires both that receipt and the fetched
archive. Its disposable local Docker network is internal, exposes no host ports,
and uses an independent database password/configuration. Production app.ini is
never activated. It checks database import, application health, repository API
and clone/fsck, and package blob integrity; cleanup removes its named containers,
anonymous volumes, network and extracted staging. Remaining fetched plaintext
must be removed after the acceptance receipt is preserved.
This bounded application-data recovery does not test replacement runners or prove that every restored package can be installed or every image pulled. Package-consumer acceptance and broader disaster-recovery guarantees remain with their owning assurance tasks. Full backups share the account's 10 GiB quota; a newly measured archive size must inform the separate retention decision.
WSL attended-login browser repair
If this host has no xdg-open, x-www-browser or www-browser, the installed
Bao browser launcher cannot open its login page. Warden contains that output,
so this presents as a failed callback before the owner command starts. Use:
python3 scripts/openbao-attended-exec.py -- /absolute/path/to/reviewed-silent-command
The wrapper keeps Warden's openbao-platform-admin-login --exec envelope and
adds a repository-scoped launcher only when all native providers are absent.
The launcher allows only the Keycloak HTTPS host and exact local OIDC callback;
it sends the URL to Windows PowerShell through stdin without recording it.
No token helper or captured Warden output may be inspected. A receipt written
by the owner command proves handoff; session cleanup is assessed separately
from the final Warden exit status.