Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
3.3 KiB
REPORT — agent v0.77.0: fork-4 escrow the offsite restic repo password under R
Date: 2026-07-09 · Class: implementation (agent). Baseline: main @ 7f07393 (v0.76.0) →
0c22b9b (v0.77.0). Pairs with controller v0.105.0. Design validated by the custody spike
(felhom.eu/documentation/audits/SPIKE-restic-password-custody-2026-07-09.md, febdc56).
What shipped
Makes the restic-offsite repo password recoverable at DR by riding the existing customer-recovery-code (R)
zero-knowledge escrow (age-under-R, in IdentityBundle). Additive; the PBS-K escrow path is untouched.
internal/escrow/identity.go:IdentityBundle.ResticRepoPassword(ridesWrapIdentityBundle/UnwrapIdentityBundle, self-verified byescrow.Create);AttachResticPassword(mirrorsAttachWGKey);StagedResticPasswordPath+WipeStagedResticPassword.internal/localapi:POST /escrow/stage-secret(withGuest+scopedFromBody) stages the controller-pushed password 0600 (atomic tmp+rename), never logged (field name only), overwritten on re-push. Stage path injectable viaOptions.EscrowStagePath(defaultStagedResticPasswordPath).cmd/felhom-agent/main.go(runSelftestEscrowCreate): auto-injects the staged password into the bundle (mirrors the WG-key auto-inject) and wipes the staging file after a successfulescrow.Create.
Files changed (commit 0c22b9b)
internal/escrow/identity.go, internal/escrow/identity_test.go, internal/localapi/server.go,
internal/localapi/escrow_stage.go (new), internal/localapi/escrow_stage_test.go (new),
cmd/felhom-agent/main.go, CHANGELOG.md, CONTEXT.md.
Tests
Green gate go build ./... && go vet ./... && go test ./... on the build host (age present) — all green.
New tests:
TestIdentity_RoundTrip_CarriesResticPassword— the bundle carriesResticRepoPasswordbyte-exact, the blob does not leak the plaintext, and a wrong R fails closed (no bundle).TestAttachResticPassword— missing staged file → clean no-attach; present → trimmed value attached; empty → error.TestStageEscrowSecret_StagesScopesAndHidesValue— the pushed secret is staged 0600, the ack is{ok,data.staged:true}(no value echoed), a cross-guest push is 403 and does not overwrite the staged file.TestStageEscrowSecret_NoSecretInLog— the staged value never appears in a captured log buffer. Note:TestGenerateRecoveryCode_EntropyAndFormatis the documented pre-existing flake (a hyphenated wordlist word splits to 11) — re-run passes; unrelated to this change.
Deploy verification
Built felhom-agent 0.77.0 (go build -ldflags -X main.version=0.77.0), installed on felhom-pve (prior
binary backed up to felhom-agent.bak-0.76.0), systemctl restart felhom-agent → --version = 0.77.0,
systemctl is-active = active, capabilities self-check ok=56 total=56 degraded=0, local-api listening
on 192.168.0.162:8443, no errors/panics.
NOT yet live-validated
The supervised escrow ceremony (enable → stage → --selftest=escrow-create with a real R → confirm →
gated run) is the operator-run follow-up — NOT run here. The stage endpoint is deployed and unit-proven.
No agent publish (publish-agent.sh) / Day-0 manifest bump was done — that is a separate operator step.