From cb26dc7e839eca56b65bdaaf524f58b89138c411 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 9 Jul 2026 23:26:16 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20SLICE=203=20=E2=80=94=20hub=20README,?= =?UTF-8?q?=20REPORT,=20CONTEXT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6 --- CONTEXT.md | 12 ++++++++++++ REPORT.md | 49 +++++++++++++++++++++++++------------------------ hub/README.md | 7 ++++++- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 58dcbba..04ca582 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -3,6 +3,18 @@ > Created with the REUSE.md rollout (2026-07-03). Authoritative history: `hub/CHANGELOG.md` (hub), > `website/CHANGELOG.md`, `scripts/CHANGELOG.md`; end-of-task detail in `REPORT.md`. +- **2026-07-09 — SLICE 3 hub-verified escrow auto-confirm SHIPPED+LIVE (hub v0.40.0 + controller v0.108.0 + + agent v0.79.0).** Replaces the operator-trust confirm with a verified fact: ceremony hashes the sealed + repo password (agent, `restic_pw_sha256,omitempty` on the escrow upload — contract test moved in lockstep) + → hub stores it (additive `host_escrow` migration, NULL on legacy rows) + serves + `escrow:{identity_blob_present,restic_pw_sha256,created_at}` in the report ACK → controller + (`report.EscrowAutoConfirmer`) flips pending→escrowed ONLY on hash match with its local repo password. + **Red-proofed core: blob-presence alone never confirms** (stale blob = false custody claim); mismatch + warns once per hash naming the ceremony; never un-confirms; flip wipes the agent-staged secret. Hashers + pinned by the same cross-repo vector. Manual confirm = deprecated fallback (legacy blobs — demo included, + hash-NULL verified live; the escrowed demo produced zero confirm activity = Scenario E live). Full happy + chain proves out at the next real enable (Peti). NEXT: SLICE 4 soft-quota, Peti runbook. + - **2026-07-09 — offsite hardening bundle SHIPPED+LIVE (hub v0.39.0 + controller v0.107.0 + agent v0.78.0).** The e2e's sharp edges closed before slices 3–4: **F4** "Re-issue offsite credentials" (explicit operator recovery for consumed-password dead-ends — exactly-1 label scope, fresh one-time secret, ConfigVersion diff --git a/REPORT.md b/REPORT.md index 89bf8a1..4761811 100644 --- a/REPORT.md +++ b/REPORT.md @@ -2,32 +2,33 @@ > **Overwrite** this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in [hub/CHANGELOG.md](hub/CHANGELOG.md); the scripts history lives in [scripts/CHANGELOG.md](scripts/CHANGELOG.md). -## TASK — offsite provisioning hardening (F2/F4/F5 + key-auth-first + staged-secret wipe) — 2026-07-09 — DEPLOYED +## TASK — offsite SLICE 3: hub-verified escrow auto-confirm — 2026-07-09 — DEPLOYED -**Shipped (felhom.eu):** hub **v0.39.0** `17cc67f` + bump `17d9af5` — LIVE (Synced/Healthy, provisioner -enabled). Bundle pairs: controller **v0.107.0** (key-auth-first bridge + wipe-on-escrowed; live on 9201) + -agent **v0.78.0** (`DELETE /escrow/stage-secret`; live on felhom-pve, 56/56). All three green-gated with -companion red-proofs. +**Shipped (felhom.eu):** hub **v0.40.0** `49d1233` + bump `c24d4af` — LIVE (Synced/Healthy). Chain pairs: +agent **v0.79.0** (felhom-pve, 56/56) + controller **v0.108.0** (9201, healthy) — all live. Operator-free +task (Viktor ran nothing). -**Hub changes:** -- **F4 (pilot-gating) — "Re-issue offsite credentials":** `Provisioner.ReissueCredentials` + UI button - (confirm-gated, shown only when provisioned) + `POST /configs/{id}/offsite-reissue`. Resets the - sub-account password (or dedicated-box password via the new `hetznerapi.ResetBoxPassword`), stores a - FRESH one-time secret, re-saves the config unchanged → `ConfigVersion` bump → the stuck guest's next - refresh re-runs the bridge. **Hard-scoped:** refuses unless the `felhom-customer=` label lookup finds - exactly 1 resource (red-proofed). Explicit action only — never implicit rotation. Password never logged. -- **F2:** `scanWithRetry` — the host-key scan retries through fresh-subaccount DNS lag (2/4/8/16/30s ≈ 60s, - inside the F1 3-min detached ctx; fail-closed past budget; red-proofed). -- **F5:** the config form disables its submit buttons + shows an in-flight notice on submit (the re-click - bait that caused live F1). +**The verification chain:** the ceremony hashes the staged repo password it seals (agent) → the hub stores +`restic_pw_sha256` alongside the escrow blob (additive migration; NULL on legacy rows) and serves +`escrow:{identity_blob_present, restic_pw_sha256, created_at}` in the **report ACK** → the controller flips +offbox `EscrowState` pending→escrowed ONLY on `sha256(local repo_password)` match. **Blob-presence alone +never confirms** — a stale blob (re-provision/inject/history) would be a false custody claim re-opening the +fork-4 gap; this is the red-proofed core (blob-present-only check → stale-blob test flips → FAIL). +Mismatch → pending + loud warn naming the ceremony (deduped per hash); never un-confirms. On flip the +agent-staged secret is wiped (v0.107.0 path). The two hashers are pinned by the SAME cross-repo test vector +(trimmed-string sha256). Manual confirm-escrow → documented deprecated fallback for legacy hash-less blobs. -**One-off cleanup (executed):** the staged secret lingering on felhom-pve from the e2e's Option-A confirm -was wiped through the NEW agent endpoint (controller container → pinned local API → `{"removed":true}`), -verified gone; idempotent re-wipe returned `{"removed":false}`. No secret printed. +**Hub specifics:** `host_escrow.restic_pw_sha256` migration; `SaveHostEscrow`/`HostEscrow`/`GetHostEscrow` +NULL-safe; `GetEscrowStatusForCustomer` (hosts⋈host_escrow, latest-updated wins); ACK object omitted when +no escrow row (fresh customers stay silently pending); `TestEscrowUploadContract` mirrors agent v0.79.0. -**Deliberately NOT exercised live:** the F4 reset itself (it would rotate the demo's working credential — -touching it is forbidden; a live exercise needs a throwaway customer under supervision). Unit red-proofs -cover the guards. F5 is template JS — verified on the next operator save. +**Live state check (no operator action):** migration applied on the production DB — all 3 legacy rows +(demo included) read hash-NULL; the demo's `escrowed` target produced **zero** `escrow-confirm` controller +log lines after reports through the new hub (Scenario E — never-revisit — proven live for free); no hub +errors. -**NEXT:** SLICE 3 (escrow auto-confirm — inherits wipe-on-escrowed), SLICE 4 (soft-quota on `quota_gb`), -NEW-box restore round-trip → retire the old-box archive, Peti onboarding runbook. +**NOT yet live-exercised:** the full happy chain (fresh enable → ceremony records the hash → ACK → +auto-flip) — the first real offsite enable (Peti onboarding) proves it; unit red-proofs carry the logic. + +**NEXT:** SLICE 4 (soft-quota on `quota_gb`), Peti onboarding runbook (live-exercises auto-confirm + F4 +re-issue), NEW-box restore round-trip → retire the old-box archive. diff --git a/hub/README.md b/hub/README.md index e84df01..80597bd 100644 --- a/hub/README.md +++ b/hub/README.md @@ -89,7 +89,12 @@ host-key scan retries through fresh-subaccount DNS lag (~60s ladder, F2); the sa in-flight notice (F5); and **"Re-issue offsite credentials"** (F4, `POST /configs/{id}/offsite-reissue`) is the explicit recovery for a consumed-password dead-end — resets ONLY the resource labelled for that customer (refuses unless exactly 1), stores a fresh one-time secret, bumps `ConfigVersion`. Never implicit rotation. -SLICE 3 (escrow auto-confirm) and SLICE 4 (soft-quota) follow. +**SLICE 3 (v0.40.0) — hub-verified escrow auto-confirm:** the agent's ceremony upload carries +`restic_pw_sha256` (non-reversible hash of the sealed offsite repo password — safe to store/serve); the hub +stores it on `host_escrow` (NULL on legacy rows) and serves +`escrow:{identity_blob_present, restic_pw_sha256, created_at}` in the **report ACK**; the controller +auto-confirms its pending offbox escrow ONLY on a hash match with its current repo password (blob-presence +alone never confirms). SLICE 4 (soft-quota) follows. ### Infrastructure Backup — RETIRED (Phase-1, 2026-06-16, hub v0.12.0)