REPORT + CONTEXT: F-LEAK closed via the fenced destroy (v0.110.0), all three attempts recorded

This commit is contained in:
2026-07-28 11:34:48 +02:00
parent 50751b8901
commit d5c769173b
2 changed files with 92 additions and 26 deletions
+16 -12
View File
@@ -18,18 +18,22 @@
Live on demo-hp: **120 s unattended** recovery vs the incident's **587 s** with a human; Scenario B
proven (an `onboot:0` guest left stopped throughout). Detail: `REPORT.md`.
- **2026-07-28 — v0.108.0: the F-LEAK pool-adoption fix was WRONG and was removed.** v0.107.0 also
shipped a teardown fallback that adopted a stranded scratch guest into the `felhom` pool and retried
the destroy. Its own live replay refuted it: `PUT /pools/felhom -> HTTP 500: permission denied at
/vms/990000 (missing privilege ...)`. **`PUT /pools/{pool}` also requires `VM.Allocate` on the VM
being added, so pool membership cannot bootstrap its own authority.** Removed rather than left in —
a path that provably cannot work looks like a fix. **The real fix is `felhom-host-install.sh`
v1.21.0** granting `FelhomAgentGuest` at each `/vms/990000..990009`; the cause was structural (the
role is granted at `/pool/felhom`, and a guest joins the pool only when its restore *completes*, so
a *failed* restore-test leaves a pool-less guest out of reach). Applied on **both** boxes. Proven by
live A/B on the same guest: grant removed → `403 (/vms/990000, VM.Allocate)`; granted → `200
UPID:...vzdestroy`. Still refused at `/vms/100` and `/vms/990010` — and since PVE checks
**permission before existence**, those 403s are real refusals, not artifacts.
- **2026-07-28 — F-LEAK took THREE attempts; v0.108.0 and v0.110.0 are the corrections.** The cause is
structural: `FelhomAgentGuest` is granted at `/pool/felhom` and a guest joins that pool only when its
restore **completes**, so a *failed* restore-test leaves a pool-less guest out of reach (403).
**(1) v0.107.0 pool adoption — REFUTED LIVE:** `PUT /pools/{pool}` also requires `VM.Allocate` on the
VM being added, so membership cannot bootstrap its own authority; removed in **v0.108.0**.
**(2) host-install v1.21.0 per-path `/vms/990000..990009` ACLs — works, but exactly ONCE per slot:**
PVE's destroy calls `AccessControl::remove_vm_access` (`API2/LXC.pm:906`) which deletes every ACL at
`/vms/<vmid>` (`AccessControl.pm:1898`) — **the grant is consumed by the op it authorises**. Caught by
counting ACL rows after the fix, not by reasoning. **(3) v0.110.0 SHIPPED —
`Privileged.DestroyScratchLXC`, the FOURTH root-fenced exception** (was exactly three: keyctl
`pct create`, USB mount/fstab, SMART/sensors). Band enforced in **sudoers literally**
(`pct destroy 99000[0-9] --purge`) + re-checked in code + journal provenance at the caller; none is
consumed by use. API destroy still tried FIRST; band ACLs stay provisioned so the common case needs no
privileged call. **Ships with a sudoers change — deploy `configs/felhom-agent.sudoers` WITH the
binary.** Live: token 403 on a stranded scratch → fenced path removed the guest and all 3 LVs; sudo
PERMITS the band and REFUSES `9201`/`9100`/`9999`/`990010`/`1`, and refuses `pct start 990000` too.
- **2026-07-28 — v0.109.0: the guest-power watchdog got the observable it shipped without.** A
self-correction: v0.107.0's watchdog logged only at startup and when it *acted*, so on a healthy box