Files
felhom-agent/REPORT.md
T

6.0 KiB

REPORT — v0.63.0: B3 + B2 fresh-install fixes (token reload-on-miss + guesthook dir)

Date: 2026-07-03 · Class: implementation, correctness+security discipline (agent v0.62.0 → v0.63.0, live on felhom-pve) · Source findings: felhom.eu/documentation/audits/DRILL-day0-cleanroom-2026-07-03.md B3/B2.

Baselines & commits

What Value
Base 84f3f7d (v0.62.0, as spec'd)
Fix commit f31a76f — v0.63.0: B3+B2 (tokenstore.go, guesthook/install.go, sudoers, tests, CHANGELOG, REUSE)
Docs commit (this one — REPORT/CONTEXT)

What changed

  • B3 — TokenStore.Lookup reload-on-miss (internal/localapi/tokenstore.go): the one-shot provisioner Mints into the shared append-only JSONL while the daemon serves Lookup from an index built once at open — the daemon 401'd any token minted after it started (the drill's /controller/swap: HTTP 401 until a manual restart). Lookup now re-reads the file once on a miss (reloadLocked(), factored from load(); idempotent under apply's last-write-wins) and re-checks with the same constant-time compare, all under the existing single mutex. Append-only size short-circuit: an unknown token against an unchanged file costs one stat, no re-read (loadedSize kept accurate by in-process Mint). Fail-closed on an unreadable store; missing file = empty. Entirely behind the TokenAuthority seam — server.go untouched. No token/hash material logged (nothing new is logged at all).
  • B2 — guesthook.InstallSnippet ensures the snippets dir (internal/guesthook/install.go): fenced mkdir -p /var/lib/vz/snippets before the install op (fresh PVE lacks the dir; install without -D fails ENOENT — the drill's silent no-hook finding). configs/felhom-agent.sudoers FELHOM_GUESTHOOK gains exactly the one grant /usr/bin/mkdir -p /var/lib/vz/snippets (comment ties it to B2). Kept the separate-mkdir shape — install -D would have changed the allowlisted install argv.

Tests & red-proofs (both run, shown failing, restored; git diff clean)

Test Asserts Result
TestTokenStore_ReloadOnMiss_CrossProcessMint (Scenario A) token minted by a SECOND store handle after the daemon handle opened resolves to (120,true) PASS. Red-proof: pre-fix Lookup shape (plain miss, no reload) → FAIL with got (0,false), want (120,true) — the exact drill 401
TestTokenStore_ReloadOnMiss_BoundedReloads (Scenario B) unknown token → (0,false); exactly 1 reload after an external append; 0 further reloads on an unchanged file (size short-circuit) — no loop, no per-candidate re-read PASS
TestTokenStore_ReloadOnMiss_RemintCoherence (Scenario C) cross-process rotation: new hash → (120,true), rotated-out hash 401s, byHash/byVMID coherent after full reload PASS
TestTokenStore_ReloadOnMiss_MissingFile (§8 edge) store deleted → fail closed, no crash PASS on linux (felhom-pve run); skipped on Windows (can't unlink an open handle)
TestInstallSnippet_EnsuresSnippetsDirFirst (Scenario D) a mkdir -p /var/lib/vz/snippets op with exactly the sudoers-fenced argv PRECEDES the install op PASS. Red-proof: mkdir call removed → FAIL with no mkdir -p /var/lib/vz/snippets op issued … calls: [[install …]]
Pre-existing suites tokenstore_test.go originals, TestInstallSnippet_RandomTempName (only adapted to filter install calls from the recorded vector — assertions unchanged), full repo all PASS; green gate go build && go vet && go test ./... exit 0

Deploy verification (felhom-pve)

  • Built on 180 from f31a76f; binary backed up as felhom-agent.bak-0.62.0; sudoers shipped WITH the binary (CRLF-stripped, visudo -cf on the file AND the live /etc/sudoers context: parsed OK; the new mkdir grant present).
  • Service active; --selftest OK (incl. pool read pool "felhom", 1 member); daemon hub report: agent 0.63.0, 47/47 capabilities ok, pve:pool-read ok (host_reports id 2412). No reassert/rebind or error lines in the journal after restart.
  • Published to Gitea: felhom-agent/0.63.0, HTTP 201, sha256 b4a89c81c33d51ea…. OPERATOR FOLLOW-UP: bump the hub Day-0 artifact manifest to agent 0.63.0 (password-gated UI — CC cannot). Until then, fresh installs fetch 0.62.0 and still need the D.1b restart.

Scenario E method + result (stated per §7-E; live store NOT polluted)

felhom-pve's guest 9201 already has its token in the daemon index, so a live swap cannot reproduce the fresh-install miss, and minting into the production store is forbidden. Method used (the spec's sanctioned alternative): (1) compiled the localapi test binary on 180 and ran the full TokenStore suite ON felhom-pve — all 4 reload-on-miss tests PASS on the real platform, including the linux-only deleted-file case; (2) live hit-path/no-regression: the in-guest controller's agent-channel-health scheduler job completed cleanly every minute after the restart (no 401, no channel event) — the deployed daemon authorizes the existing token exactly as before.

Guide follow-through (felhom.eu)

D.1b's unconditional "restart the agent first" step was narrowed, not dropped: the fix is deployed and platform-proven, but the Day-0 manifest still vouches agent 0.62.0, so a box installed today still gets a pre-fix agent. The guide now says: restart first only when the installed agent is < v0.63.0; the troubleshooting row records the fix version. Drill ledger B2/B3 marked FIXED v0.63.0. (The step drops entirely once the manifest vouches ≥ 0.63.0.)

Observations (not acted on)

  • The one-shot --selftest=hub report carries an EMPTY capabilities list (the probe is composed only into the daemon loop) — a hub-side capability checker reading the newest report could transiently see 0 capabilities after an operator runs the one-shot. Cosmetic today; worth a look when touching the capability checker.
  • OpenTokenStore calls load() before MkdirAll(dir) — harmless (read tolerates ENOENT) but the ordering reads oddly; left as-is (out of scope).