v0.105.0: fork-4 offsite password custody — hand-off + atomicity gate + DR inject + coord
Pairs with agent v0.77.0. StageEscrowSecret pushes the repo password to the agent (POST /escrow/stage-secret) at offsite-enable → EscrowState="pending". Atomicity gate: RunOffboxBackup (scheduler + handler) refuses until EscrowState="escrowed" (operator POST /backup/offbox/confirm-escrow after the escrow ceremony) — no un-recoverable offsite ciphertext can exist. DR: POST /backup/offbox/inject-password pre-places a recovered 64-hex password 0600 (honored by WriteOffboxSecrets' IsNotExist guard; refuses clobber without force). DR recipe gains non-secret offsite_restic coords (DRResticCoord); SFTP key regenerated at DR, not escrowed. New settings.OffboxTarget.EscrowState. Tests + atomicity & inject companion red-proofs green; UI gates pass. NOT yet live-validated (supervised ceremony). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1,5 +1,33 @@
|
||||
## Changelog
|
||||
|
||||
### v0.105.0 — fork-4: offsite password custody hand-off + atomicity gate + DR inject + DR coord (2026-07-09)
|
||||
|
||||
Pairs with agent v0.77.0 to make the restic-offsite repo password recoverable at DR (rides the customer-R
|
||||
escrow) and forbids an un-escrowed offsite copy from existing. Validated design: custody spike `febdc56`.
|
||||
|
||||
- **Hand-off** (`internal/agentapi/client.go`): `StageEscrowSecret` pushes the repo password to the agent's
|
||||
`POST /escrow/stage-secret` over the authenticated pinned local-API channel (value never logged). The
|
||||
enable flow (`internal/web/offbox_handlers.go`) reads the 0600 password via a new
|
||||
`Manager.PushOffboxPasswordForEscrow` (the handler never sees the value) and marks `EscrowState="pending"`.
|
||||
- **Atomicity gate** (`internal/backup/offbox.go`): `OffboxRunnable()`/`offboxEscrowed()` — `RunOffboxBackup`
|
||||
(and thus the daily scheduler + the run handler) **refuses to run until `EscrowState=="escrowed"`**, so no
|
||||
un-recoverable offsite ciphertext can exist. `OffboxConfigured()` is unchanged (config/UI still work).
|
||||
New `settings.OffboxTarget.EscrowState` (`""|"pending"|"escrowed"`, additive, preserved across edits).
|
||||
- **Confirm + DR inject** (`internal/web`): `POST /backup/offbox/confirm-escrow` (operator, after the escrow
|
||||
ceremony) → escrowed; `POST /backup/offbox/inject-password` (DR) → `Manager.InjectOffboxPassword`
|
||||
pre-places a recovered 64-hex password 0600 (tmp+rename), refusing to clobber without `force` — a
|
||||
subsequent `WriteOffboxSecrets` then uses it (the pre-place seam). `/backups` shows a pending-escrow
|
||||
notice + confirm button.
|
||||
- **DR recipe** (`internal/report/dr_recipe.go`): `DRRecipeAppHalf.OffsiteRestic *DRResticCoord`
|
||||
{host,user,port,repo_path} — coordinates ONLY (the password is escrowed, the SFTP key is regenerable);
|
||||
populated from `Manager.OffboxCoord()`; clears the `_NoSecrets` regex.
|
||||
- Tests: atomicity (pending blocks run; confirm enables) **+ companion red-proof** (gate disabled → runs
|
||||
while pending → FAIL); DR inject pre-place honored + refuse-clobber + companion (no-inject generates a
|
||||
DIFFERENT password); `OffboxCoord`; agent stage endpoint (0600 + non-secret ack + cross-guest 403 +
|
||||
value-not-in-log); `DRResticCoord` no-secrets. Web: run-gate + confirm + inject endpoints.
|
||||
- **NOT yet live-validated** — the supervised escrow ceremony (enable→stage→escrow-create→confirm→gated run)
|
||||
is the operator-run follow-up.
|
||||
|
||||
### v0.104.0 — off-box unit discovery (durable, deployment-independent) + no-silent-success (2026-07-09)
|
||||
|
||||
Fixes the off-box mis-resolution + silent-success landmine surfaced by the Storage-Box spike and pinned by
|
||||
|
||||
Reference in New Issue
Block a user