v0.127.0: customer-facing escrow ceremony wizard (/backup/escrow) + Scenario-F stale-blob re-check — one-shot R reveal (no-store, typed-back), re-stage-first start order, agent version gate (MinAgent 0.88.0), escrowed-state hash re-check with card warning (never flips, never blocks); manual-confirm button removed (endpoint stays deprecated)

This commit is contained in:
2026-07-13 19:01:31 +02:00
parent 51c871ad9b
commit 08a966b92f
13 changed files with 1419 additions and 16 deletions
+40
View File
@@ -1,5 +1,45 @@
## Changelog
### v0.127.0 — customer-facing escrow ceremony wizard + stale-blob re-check (2026-07-13) — MinAgent: 0.88.0 (wizard only; everything else unchanged)
The missing friend-alpha piece: the recovery-code ceremony moves from operator-SSH to a
customer-driveable wizard (`/backup/escrow`). R is displayed EXACTLY ONCE in the browser
(one-shot claim, typed-back confirm); operator ruling F1 2026-07-13 accepts the single CF-tunnel
transit (same trust class as the claim code — threat model in felhom.eu
RUNBOOK-escrow-ceremony.md). Mechanics validated by SPIKE-controller-escrow-2026-07-13.
- **Wizard** (`templates/backups_escrow.html` + `web/escrow_handlers.go`): preflight checklist →
warning copy (re-ceremony adds the supersede warning) → password re-auth (rides the LOGIN rate
limiter) → run (poll 2 s) → one-shot reveal ("Ez a kód többé nem jeleníthető meg.") →
typed-back (two random words, client-side only — R never leaves the page's JS scope; no
copy-to-clipboard by design) → finish. Void/expired → the honest "újra nem kérhető le" state.
Page + claim response `Cache-Control: no-store`; R is NEVER templated server-side, logged, or
persisted.
- **Start-handler order (load-bearing):** re-auth → **re-stage-first** (offbox configured →
`PushOffboxPasswordForEscrow`; failure ABORTS — a ceremony without the staged secret mints the
forbidden hash-less blob) → agent version gate (`AgentVersion()` ≥ 0.88.0, header absent =
older, fail-closed) → trigger. Every refusal exits with the agent untouched (seam-asserted).
- **agentapi** (`agentapi/escrow.go`): `EscrowPreflight` / `EscrowCeremonyStart` /
`EscrowCeremonyStatus` / `EscrowCeremonyClaim` (status-aware; 410 = void; claim body never
logged) over the existing envelope helpers.
- **Scenario F — stale-blob re-check** (`report/escrow_confirm.go`): `Reconcile` no longer
early-returns on non-pending; an ESCROWED box compares the ACK hash every cycle — mismatch OR
a present blob with an EMPTY hash (the spike's hash-less supersession) sets an in-memory stale
flag (surfaced on the Távoli mentés card: "A letétben lévő helyreállítási csomag nem fedi a
jelenlegi távoli mentési jelszót") + ONE warn per distinct hub hash (`warnedHash` reuse;
hash-less dedupes under a sentinel). State NEVER flips; runs NEVER block; a matching hash (or
a fresh auto-confirm) clears the flag. NOTE: the live demo's legacy hash-less blob will show
this warning honestly — the wizard is the fix.
- **Card rework** (`templates/backups_remote.html`): the deprecated manual-confirm BUTTON is gone
(the endpoint stays for legacy blobs); states: pending → "Helyreállítási kód szükséges" + CTA;
escrowed+stale → warning + "Új helyreállítási kód készítése"; escrowed clean → secondary link;
agent < 0.88.0 → "az ügynök frissítése szükséges" note, no CTA.
- Tests: call-order (stage BEFORE trigger, from pending AND escrowed), Scenario C no-stage,
security gates (wrong password 401 + rate-limit counter, 429 lockout, passwordless 403, stage
failure 502 pre-trigger, old agent 409, busy 409 — agent seam call-count 0 in each), claim
proxy no-store + 410, §8 stale truth table incl. dedupe + clear, template render states. §10
red-proofs demonstrated (felhom.eu REPORT).
### docs — controller.yaml.example: hub api_key literal scrubbed (2026-07-13)
The example carried the REAL hub global bearer key (the `manifests/hub.yaml` committed literal,