diff --git a/REPORT.md b/REPORT.md index 0b1e9bc..9bb400a 100644 --- a/REPORT.md +++ b/REPORT.md @@ -4,43 +4,31 @@ --- -## SPIKE — A1 pool-membership read for the stale-lock reaper (2026-07-03) +## felhom-host-install.sh v1.9.0 — Pool.Audit for the stale-lock reaper (A1) (2026-07-03) -**Class:** SPIKE (docs-only; no production code, no felhom-agent commit, no live ACL/agent change). -**Deliverable:** `documentation/audits/SPIKE-a1-pool-membership-read-2026-07-03.md`. +**Class:** implementation (this repo's share of the A1 fix; agent side = felhom-agent **v0.62.0**, +see that repo's REPORT for the full evidence). Spec basis: +`documentation/audits/SPIKE-a1-pool-membership-read-2026-07-03.md`. Commit **`639a57e`** +(baseline `5e3dfcb`). -Empirically answered the three open A1 mechanism questions on live felhom-pve, probing under the -**production** scoped token `felhom-agent@pve!agent` (secret read on-host, length-only recorded) -vs root as oracle: +**Change:** `PVE_PRIVS_GUEST` gains **`Pool.Audit`** (12 → 13 privs; comment cites the spike and +why `Pool.Allocate` does not satisfy the read), `SCRIPT_VERSION` 1.8.0 → **1.9.0**. No structural +change — `_ensure_role` already `role modify`s to the exact set, so `--rescope-acl` is the +idempotent upgrade path; `remove_scoped_acl` deletes by role name and needed nothing. Gates: +`bash -n` OK, `reuse_refs_check.py` OK (31 paths). -- **T1 (crux):** `GET /nodes/demo-felhom/lxc` under the scoped token returns **[9201] only**; root - sees [9001, 9100, 9201, 9999]. LXC enumeration IS pool-filtered — the reaper's scan is already - ownership-scoped *as deployed*, so A1 is latent, re-armed only by a broad-token redeploy. -- **T2:** `GET /pools/felhom` under the token → **403 "Permission check failed (/pool/felhom, - Pool.Audit)"**. `GET /pools` → 200 `[]` (silently filtered, not an error). -- **T3:** throwaway `felhom-probe@pve!probe` with ONLY `Pool.Audit`@`/pool/felhom` → **200 with - members** — minimal priv delta proven. Bonus (T3b): a token with no VM.Audit gets **200 + empty - list** from the LXC index (mis-scope is silent, not an error). Full teardown verified (0 residue). -- **T4:** root `pvesh get /pools/felhom` works but would be a 4th `proxmox.Privileged` fence - exception — rejected. -- **T5:** local ownership records (guest-binds.json, reconcile journal, guests/ dir, installer - state.json) are all **partial** — journal's newest vmid (9310) no longer exists; adopted or - drive-less guests are absent — rejected as reaper gate. -- **T6:** live foreign-guest reap deliberately NOT run (needs broad-token redeploy); deferred to - the named unit test. **T7 (extra):** `/cluster/resources` withholds the `pool` field without - `Pool.Audit` — no zero-ACL-change API path exists. +**Live run (felhom-pve, the PUSHED script fetched from Gitea raw):** +`--rescope-acl --vmid 9201` → roles re-ensured; after: `FelhomAgentGuest` = +`Pool.Allocate,Pool.Audit,VM.*…` — Base/Store unchanged. Production-token `GET /pools/felhom` +went 403 → **200 (members [9201])**. Running v0.61.0 agent unaffected; agent v0.62.0 deployed +AFTER the rescope (order per spec) — startup shows +`stale-lock: scanning pool guests pool=felhom listed=1 scanned=1` and 47/47 capabilities incl. +`pve:pool-read` ok (also verified in the hub's stored host report). -**Recommendation (for the now-unblocked A1 impl spec):** add `Pool.Audit` to `PVE_PRIVS_GUEST` -(`scripts/felhom-host-install.sh` L183, granted at `/pool/felhom`) + intersect `ListLXC` with -`GET /pools/felhom` members inside `staleLockController.Guests()`; a pool-read failure propagates -to the existing "guest list unavailable — skipping recovery" fail-safe. Ship agent + `--rescope-acl` -together; optionally surface pool-read in the capability probe. Named tests: -`TestStaleLock_ForeignGuestNotReaped`, `TestStaleLock_PoolGuestStillReaped`, -`TestStaleLock_PoolReadFails_SkipsAll`. +**Also in this commit:** REUSE.md §2 errata — the secret-handling row claimed `gitea-creds` is +out-of-band; it is in fact COMMITTED in `manifests/felhom.secret.yaml` AND live-consumed by +hub.yaml. §3 trap row now lists it too. Rotation + de-git of the 3 committed secrets remains a +pending operator task (spike appendix). -**Appendix folded in:** committed-secrets rotation micro-runbook for the 3 live `stringData` blocks -in `manifests/felhom.secret.yaml` (healthchecks-config / umami-config / gitea-creds) — rotate -upstream first, out-of-band `kubectl create secret`, then de-git; operator follow-up, no execution. - -**Cleanup:** probe user/token/role removed and verified absent; no throwaway guest needed (three -real non-pool guests existed); production roles/token/agent untouched; secrets never persisted. +**Operator follow-ups:** hub Day-0 artifact manifest → vouch agent **0.62.0** +(sha256 `ed1192c9ae8f355dee19128cf4b01984ba7398e860b4a16a8009655b84b32d81`); secrets rotation above.