Files
felhom-agent/REPORT.md
T

47 lines
3.3 KiB
Markdown

# 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` (rides `WrapIdentityBundle`/
`UnwrapIdentityBundle`, self-verified by `escrow.Create`); `AttachResticPassword` (mirrors `AttachWGKey`);
`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 via `Options.EscrowStagePath` (default `StagedResticPasswordPath`).
- `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 successful `escrow.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 carries `ResticRepoPassword` byte-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_EntropyAndFormat` is 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.