docs: v0.78.0 REPORT — DELETE stage-secret deployed felhom-pve (56/56), live-validated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-09 22:47:22 +02:00
parent 98ea1ed49c
commit bd9e777f41
+22 -39
View File
@@ -1,46 +1,29 @@
# REPORT — agent v0.77.0: fork-4 escrow the offsite restic repo password under R
# REPORT — agent v0.78.0: DELETE /escrow/stage-secret (fork-4 hygiene) — DEPLOYED
**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`).
**Date:** 2026-07-09 · **Class:** implementation (agent, small). **Baseline:** v0.77.0 → **v0.78.0**, live
on felhom-pve (`felhom-agent 0.78.0`, capabilities self-check **56/56, degraded=0**). Part of the offsite
hardening bundle: pairs with controller v0.107.0 (calls this on every `EscrowState` flip to `escrowed`) and
hub v0.39.0 (F4/F2/F5).
## 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`.
`internal/localapi`: **`DELETE /escrow/stage-secret`** (withGuest, bearer-authed) — removes the staged
offsite restic repo password (+ any stale `.tmp` partial). **Idempotent:** an absent file is a clean 200
`{removed:false}`. Closes the fork-4 hygiene gap where a confirm WITHOUT a fresh ceremony (the password
already escrowed — the live e2e's Option-A close) left the transient 0600 staging file behind indefinitely
(only the escrow-create ceremony wiped it before).
## 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.
`TestWipeStagedEscrowSecret`: stage → wipe (EFFECT: file GONE) → idempotent re-wipe (`removed:false`) →
401 unauthenticated. Full suite green (`go build && go vet && go test ./...`).
## 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.
## Live validation
The endpoint was exercised for the one-off cleanup: the lingering
`/var/lib/felhom-agent/escrow-stage/restic_repo_password` (left by the e2e) was wiped through the
controller container over the pinned local-API channel → `{"removed":true}`, file verified GONE on
felhom-pve; an immediate re-wipe returned `{"removed":false}` (idempotency proven live). No secret value
was ever printed or logged.
## 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.
## Deploy
Standard flow: built on 180 (`-X main.version=0.78.0`), scp'd via local → felhom-pve, `.bak-0.77.0` kept,
`install -m0755` + restart. `configs/` unchanged → no sudoers/wrapper shipping needed. NOT published to
Gitea (no Day-0 vouch change; the Day-0 manifest still vouches 0.76.0).