host-install 1.21.0: F-LEAK — grant FelhomAgentGuest on the scratch VMID band

A failed restore-test's scratch guest never joins the felhom pool, so the pool-scoped
grant cannot reach it and teardown 403s. Ten path-scoped /vms/<id> grants reach exactly
the scratch band and nothing else. Removal path + verify step extended.
This commit is contained in:
2026-07-28 11:05:44 +02:00
parent e168600148
commit b4c528801a
2 changed files with 66 additions and 2 deletions
+33
View File
@@ -1,3 +1,36 @@
## felhom-host-install 1.21.0 — F-LEAK: the restore-test scratch band gets its own path-scoped grant (2026-07-28)
Campaign 8's F-LEAK: a restore-test whose restore **fails** leaves a scratch guest the agent cannot
destroy — `403 missing privilege VM.Allocate` — so a half-restored guest holds its disks until a human
removes it. The cause is structural, not a missing privilege in the role: `FelhomAgentGuest` is granted
at `/pool/felhom`, and **a guest only joins that pool when its restore completes**. A failed restore
therefore produces a guest that exists, is in no pool, and is out of the token's reach.
`apply_scoped_acl` now also grants `FelhomAgentGuest` at each `/vms/<id>` in
`PVE_SCRATCH_VMID_MIN..PVE_SCRATCH_VMID_MAX` (990000990009, the band the restore-test already picks
from), to **both** the user and the token — the privsep intersection rule applies here as everywhere.
**This is not a widening.** PVE ACLs are path-scoped: ten explicit `/vms/<id>` grants authorise the
agent on exactly those ten IDs. Granting at `/vms` was rejected — that would authorise destroying every
guest on the box, including a co-tenant's. Verified live:
| path | `VM.Allocate` |
|---|---|
| `/vms/990000` (scratch band) | **yes** — 13 privs |
| `/vms/100`, `/vms/9999` | no — 3 privs (base only) |
| `/vms/990010` (one past the band) | no — 3 privs |
Two supporting changes, both load-bearing:
- `remove_scoped_acl` deletes the band grants **before** the role delete. PVE refuses to delete a role
still referenced by any ACL, so omitting this would have broken the uninstall.
- `step_verify` asserts the band grants. A missing one is otherwise invisible until a restore-test
*fails*, which is precisely the case that leaked a guest.
**The alternative that does not work, recorded so it is not retried:** adopting the stranded guest into
the pool first. It was implemented (agent v0.107.0), shipped, and refuted live on 2026-07-28 —
`PUT /pools/felhom` with `vms=<id>` **also** requires `VM.Allocate` on `/vms/<id>`, so `Pool.Allocate`
cannot bootstrap its own membership. That code was removed in agent v0.108.0.
## felhom-host-install 1.20.0 — R-82: a fresh box defaults to local-daily + offsite-weekly (2026-07-26)
The `backup` defaults gain `backup_targets: [{target_id: "felhom-pbs", cadence_seconds: 604800,