3.3 KiB
REPORT — agent v0.125.0: open the sealed bundle, return one field (2026-08-04, R-199 links 7–8)
Released and deployed. Published sha256 f7d8339b53d92a6c45be7eaf189469a041b6b00b758a64511c0479beae7016b3,
verified by independent download before install; running on demo-felhom (felhom-agent --version
→ 0.125.0, systemctl is-active → active). NOT vouched — vouching stays the operator's act.
What shipped
internal/escrow/recover.go—OffsiteKeyRecoverer: fetch → unseal → extract, with distinct errors for "no blob", "the bundle predates the field", and "the code did not open it".internal/hub/client.go—FetchIdentityEscrow(link 6's first client, ever).internal/localapi/escrow_recover.go+ route registration — link 7's first production caller.cmd/felhom-agent/main.go— the production wiring, and the §8.6 selftest message fix.
The result
Proven live on demo-felhom, 2026-08-04: the recovered offsite repository password's sha256 equals
the one on the box's disk, and equals the hash the hub had independently recorded. A deliberately wrong
code five minutes earlier produced
escrow: the recovery code did not unwrap the identity escrow … exit status 1 and wrote nothing —
which also proves the fetch and the unseal ran independently of the success.
R persisted nowhere, searched rather than claimed: 0 agent-journal lines, 0 controller-log lines,
0 files under /tmp, /var/tmp, /var/lib/felhom-agent, /root, 0 leftover felhom-idesc-* staging
dirs — with a positive control (a planted copy found, then removed and not found) so the sweep is a
measurement.
Tests
go build ./... && go vet ./... && go test ./... — rc=0; agent_gates.py --fast — OK.
New: internal/escrow/recover_test.go (real age crypto) and
cmd/felhom-agent/escrow_recover_wiring_test.go (AST).
Red-proofs, both observed failing:
- Returning
bundle.PBSTokeninstead ofResticRepoPassword→ "the recovered key is not the sealed repository password (len 24 vs 64)". That is the mutation that mattered — every field of that bundle is a non-empty string that looks like a secret. _ = escrowRecovererwith theOptions.EscrowRecoveryfield dropped → the AST test fails with "localapi.Options … carries no EscrowRecovery field".
One red-proof did NOT work on the first attempt and is recorded, not quietly redone: the R-leak mutation wrote R into the walked directory and the test still passed, because a later failing call overwrote the leak file with a different code while the test scanned only for the first. The test was wrong. It now asserts the TMPDIR tree is EMPTY (nothing in the test creates anything there), with the content scan kept as defence in depth. Re-run: FAIL, "the unseal left 1 file(s) behind under TMPDIR". A second mutation (commenting the wiring line) failed to compile, which is not a red-proof either; the compiling version is above.
Scope
Links 6–8 only. Nothing installs a recovered password, reopens a repository, or restores a file — R-200's remaining half and R-201.
Observation
ageBinary is the hardcoded /usr/bin/age with no config override. Present on demo-felhom (1.2.1); a
host that installs age elsewhere would fail the unseal at the last step with no configuration escape.