hub: opaque PBS recovery-code escrow storage (v0.8.0) + doc 03 §8a posture model

Slice-7 close-out (hub half). PUT /api/v1/hosts/{host_id}/escrow (per-host key)
stores the agent's OPAQUE R-wrapped blob verbatim against the host; the hub never
decrypts it (no recovery code, no decrypt path). host_escrow table + Save/GetHostEscrow.
Tests: verbatim store, rotation last-write-wins, 401/403/400 auth+body, wire contract.

doc 03 §8a rewritten into the key-custody posture model: separation principle,
topology matrix, default + anti-lockout ladder, SSH-vs-key, breach/legal, integrity
caveat. Corrected: hub opaque storage is slice 7 (this task); serving is slice 10.
Slice table + §13 updated.

No secrets committed (R/K never appear; spike findings + docs use placeholders).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 07:46:33 +02:00
parent fe7d0850a5
commit 7eb3772000
6 changed files with 372 additions and 72 deletions
+24
View File
@@ -1,5 +1,29 @@
# Felhom Hub — Changelog
## v0.8.0 — opaque PBS recovery-code escrow storage (slice 7, doc 03 §8a) (2026-06-10)
Hub half of slice-7 close-out: store the agent's **opaque** `R`-wrapped PBS-key escrow blob. The
default posture is zero-knowledge — the hub holds ciphertext it **cannot open** (it has no recovery
code; there is no decrypt path). Pairs with felhom-agent v0.9.0 (escrow creation). Consumption /
restore-mode serving is slice 10.
### Added
- **`PUT /api/v1/hosts/{host_id}/escrow`** — authed with the **per-host key** (a host may only write
its own escrow; the global operator key is also accepted). Body mirrors the agent's emit struct
(`blob_b64`, `key_fingerprint`, `posture`, `created_at`). Stores the decoded **opaque bytes
verbatim**; rotation is last-write-wins. No serving this slice.
- **`host_escrow`** table (`host_id` PK, `blob` BLOB, fingerprint/posture/created_at). Store methods
`SaveHostEscrow` / `GetHostEscrow` (`HostEscrow`). The hub never transforms or decrypts the blob.
### Tests
- Stores the opaque blob **verbatim** (round-trips byte-identical); rotation last-write-wins;
rejects an absent/wrong key (401) and a host writing another host's escrow (403); bad/empty
base64 → 400; the wire-contract key-set matches the agent's emit struct.
### Security note
The hub stores ciphertext only — holding the blob does NOT let Felhom read customer data
(separation principle, doc 03 §8a). The per-host-key gate scopes writes to the owning host.
## v0.7.5 — restore-test "passed with warnings" visibility (2026-06-09)
Hub half of `TASK — Restore-test must not false-fail on benign start warnings` (Phase B). The