v0.62.0 — A1: pool-membership ownership check for the stale-lock reaper

staleLockController.Guests() = ListLXC ∩ GET /pools/felhom members (ownership
PROVEN via the pool registry, never assumed from enumeration scope); pool-read
failure fail-safes the whole recovery through the existing guest-list guard.
New Client.Pool read (needs Pool.Audit — host-install v1.9.0; Pool.Allocate
does NOT satisfy it, spike T2). Composed pve:pool-read capability (non-critical)
+ --selftest pool-read line. Red-proofed negative tests drive the REAL
controller over a broad-token-shaped fake.

Per SPIKE-a1-pool-membership-read-2026-07-03.md; audit A1
(AUDIT-blast-radius-hostroot-localapi-2026-07-02).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-03 13:25:05 +02:00
parent 3e760a559a
commit 3f37c5fc23
8 changed files with 386 additions and 26 deletions
+15
View File
@@ -76,6 +76,21 @@ type Guest struct {
Uptime int64 `json:"uptime"`
}
// PoolInfo is GET /pools/{poolid} — the pool's identity + membership. The stale-lock recovery
// uses it as the ownership registry: only pool members are ever scanned (audit A1).
type PoolInfo struct {
PoolID string `json:"poolid"`
Members []PoolMember `json:"members"`
}
// PoolMember is one entry of PoolInfo.Members. A pool can hold guests AND storages; storage
// entries carry type "storage" and no vmid, so membership checks must filter on both (spike
// SPIKE-a1-pool-membership-read §8).
type PoolMember struct {
VMID int `json:"vmid"`
Type string `json:"type"` // "lxc" | "qemu" | "storage"
}
// GuestConfig is GET /nodes/{node}/lxc/{vmid}/config. The config surface is
// dynamic (net0..netN, mp0..mpN, unusedN), so known fields are typed and the full
// raw map is preserved in Extra for the dynamic ones.