diff --git a/documentation/audits/SPIKE-agent-pin-mismatch-2026-06-29.md b/documentation/audits/SPIKE-agent-pin-mismatch-2026-06-29.md index 06e0544..3556c06 100644 --- a/documentation/audits/SPIKE-agent-pin-mismatch-2026-06-29.md +++ b/documentation/audits/SPIKE-agent-pin-mismatch-2026-06-29.md @@ -179,7 +179,37 @@ the old token store), or the symptom merely changes from `TLS pin mismatch` to ` **Token store (applies to R1/R2):** also re-seed guest 9201's bearer token into `/var/lib/felhom-agent/local-tokens.log` (re-provision token mint, or restore the old token store -from the same `aside-var-lib` set-aside if present), else expect a `401` after the pin is fixed. +from the same `aside-var-lib` set-aside), else expect a `401` after the pin is fixed. + +### Follow-up CONFIRMED (2026-06-29) — `aside-var-lib` holds the matching token store → R1 is one copy + +The set-aside **does** contain the pre-migration token store, and it matches guest 9201's +*current* controller token, so **R1 fixes the pin and the token blocker in a single restore**: + +``` +/root/agent-backup-bundle-test/aside-var-lib/local-tokens.log + 656 bytes, 8 records, mtime 2026-06-26 19:56 (pre-migration) + effective (last-write-wins) vmids: 9200, 9201 +vs live /var/lib/felhom-agent/local-tokens.log : 0 bytes, mtime 2026-06-28 08:56 (reset at migration) +``` + +Verified on-host (token plaintext/hashes never left the host; only the verdict was emitted): the +agent stores `{"v":,"h":hex(sha256(token))}` JSONL (`internal/localapi/tokenstore.go`, +last-write-wins per vmid). The SHA-256 of the controller's **current** `controller.yaml` +`local_api.token` (the line under `local_api:`, **not** the unrelated `git:`/`hub:` tokens in the +same file) is **present in the old store under vmid 9201**. So: + +- old leaf fp `60b5974d…` **==** `PIN_FP` (and `SEED_FP`) ✓ +- old store's effective 9201 token hash **==** controller's current `local_api.token` hash ✓ + +**Therefore the cleanest remedy is R1 extended to three files:** restore +`local-api.crt`, `local-api.key`, **and** `local-tokens.log` from `…/aside-var-lib/` → +`/var/lib/felhom-agent/`, `chown felhom-agent:felhom-agent` (crt `0644`, key/tokens `0600`), +restart the agent. The agent then *loads* (not regenerates) the old leaf and re-indexes the old +token store; the controller's existing pin **and** token both validate, **with zero in-guest +change**. (Caveat: this reinstates the pre-migration leaf `60b5974d…` rather than adopting the +new `ced34036…` — fine for restoring service; if the operator wants the new leaf to be canonical, +that's R2/R3 instead, both of which still need the token re-seed handled separately.) **Forward-looking:** the root→non-root migration runbook should **carry the existing `local-api.{crt,key}` and `local-tokens.log` into the new data dir** (or treat their loss as a @@ -196,8 +226,10 @@ incident. migration mtime is strong evidence; not *proven* live because the TLS pin fails before any token is evaluated, and probing it would require an authenticated call (out of scope for read-only). Operator should expect it and plan the token re-seed alongside whichever pin remedy is chosen. -- **Not assessed:** whether `…/aside-var-lib/` also holds the matching pre-migration - `local-tokens.log` (would make R1 + token restore a single copy). Cheap to check before choosing. +- **Resolved (was "not assessed"):** `…/aside-var-lib/` **does** hold the matching pre-migration + `local-tokens.log`, and its effective 9201 token hash equals the controller's current + `local_api.token` hash — so R1 restored as three files (crt+key+tokens) fixes pin **and** token in + one copy, zero in-guest change. See §7 follow-up. *No secrets recorded: the per-guest bearer token is referenced as "stored out-of-band"; the leaf fingerprint is not a secret.*