docs: slice 10C escrow consumption productionized (doc 03 §8a/§9)
Agent-only implementation (felhom-agent v0.17.0 escrow.Consume); no hub code change. 10C done; 10D is the last piece of slice 10. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,41 +4,28 @@
|
||||
|
||||
---
|
||||
|
||||
# REPORT — Slice 10B (hub half): signed-op job completion (hub v0.10.0) (2026-06-10)
|
||||
# REPORT — Slice 10C (docs only): escrow consumption productionized (2026-06-10)
|
||||
|
||||
## Type
|
||||
|
||||
TASK (CC-implemented). The hub half of slice 10B. Pairs with `felhom-agent` v0.16.0 (the signing CLI
|
||||
+ verify-and-execute machinery + the storage-wipe consumer).
|
||||
Documentation update for **slice 10C** (implementation is **agent-only**: `felhom-agent` v0.17.0 —
|
||||
`escrow.Consume`). **No hub code change** — 10C reads a restore directive it is given; 10D wires the
|
||||
hub side (serving the blob + expected fingerprint + PBS connection, prompting for R).
|
||||
|
||||
## What changed (hub)
|
||||
## What changed (doc 03 — host-agent)
|
||||
|
||||
Small by design — the hub stores + serves the operator-signed blobs **opaquely** (it holds no signing
|
||||
key, can neither forge nor open them; the agent verifies + executes). 10B adds the **completion** path.
|
||||
|
||||
### Store + API
|
||||
- **`DELETE /api/v1/hosts/{host_id}/jobs/{job_id}`** (per-host key, **self-scoped**; global key may
|
||||
clear any) — the agent calls it after executing OR terminally rejecting a job. Idempotent. Store:
|
||||
`DeleteSignedJob`.
|
||||
- Reused unchanged from 10A: `POST /admin/hosts/{id}/jobs` (operator enqueue), `GET /hosts/{id}/jobs`
|
||||
(agent fetch), `has_signed_ops` envelope flag. The signed blob stays opaque on the wire (a base64
|
||||
`{op_blob_b64, sig_armored}` envelope) — **no jobs-wire golden change**.
|
||||
|
||||
## Tests (green)
|
||||
- `DELETE …/jobs/{id}` self-scoped (host A cannot clear host B's job → 403) + idempotent.
|
||||
|
||||
## Docs
|
||||
- Doc 03 §4 (the operator-signed path is LIVE: gate → pending op → offline signature → verify
|
||||
(pinned key / nonce-burn / expiry / host + durable-id anti-retarget) → execute; key floor: not in
|
||||
the hub, not in the agent), §6 (the 8C data-bearing wipe now completes via 10B), §9 slice table
|
||||
(**10B done**; 10C escrow-consumption spike-validated, 10D DR capstone pending).
|
||||
|
||||
## Security framing (why the hub stays minimal)
|
||||
The hub is deliberately a dumb queue here: it cannot forge a signed op (no key) and the agent never
|
||||
trusts a queued blob until the pinned-key verify passes. A **compromised hub queuing a forged blob is
|
||||
rejected** by the agent (tested in felhom-agent). That is the whole point of the offline-key design.
|
||||
- **§8a**: escrow **consumption** is now a real, tested path (`escrow.Consume` = **Unwrap →
|
||||
fingerprint-gate → install**), replacing the throwaway spike harness. The spike findings are baked
|
||||
in: F-C2 (install the raw key where the restore reads it), **F-C3** (wrong R fails closed), **F-C4**
|
||||
(fingerprint-gate *before* any multi-GB restore), **F-C6** (blob read-only/retryable, `K` never
|
||||
mutated). **Zero-knowledge holds end-to-end**: the hub serves the blob + expected fingerprint + PBS
|
||||
connection; **R comes from the customer by hand, never the hub** — a hub compromise alone cannot
|
||||
decrypt.
|
||||
- **§9 slice table**: **10C done**. **10D** (DR capstone — re-enroll in restore mode, serve the
|
||||
directive, consume, restore guests + identity, reuse the 10B gate for restore-overwrite, the
|
||||
re-enrollment-auth fork) is the last piece of slice 10.
|
||||
|
||||
## Pending
|
||||
- Build + deploy hub v0.10.0 (+ agent v0.16.0) and live-validate the full loop on the demo: a
|
||||
data-bearing wipe → `pending_signature` → offline-signed → queued → agent verifies + wipes the
|
||||
device; replay + non-pinned-key rejected.
|
||||
|
||||
- Live validation runs against the demo (agent v0.17.0): create escrow → `Consume` → restore real
|
||||
data with the consumed key; wrong R → clean failure, nothing installed; live `K` byte-unchanged.
|
||||
|
||||
Reference in New Issue
Block a user