diff --git a/REPORT.md b/REPORT.md index 4695bf8..7ddc63b 100644 --- a/REPORT.md +++ b/REPORT.md @@ -4,25 +4,18 @@ --- -# REPORT — "no-mercy" campaign: full effects of the `felhom` pool + scoped-token migration +# REPORT — F3 doc: operator vmid selection runbook (companion to agent v0.60.0 F1/F2 fix) -**Date:** 2026-07-02 · **Class:** Runbook-style validation (aggressive, throwaway env) · **No code change, no version bump.** -**Findings doc:** [`documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md`](documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md) +**Date:** 2026-07-02 · **Repo:** `felhom.eu` (`documentation/` only, no version bump) · **Class:** doc +companion to the Risky/supervised fix in felhom-agent v0.60.0 (see that repo's REPORT.md for the full +F1/F2 deliverables). -Executed the full pool-effects campaign on felhom-pve (agent v0.59.0 live, host-install v1.7.0 scoped ACL): source-traced every `ListLXC` consumer in felhom-agent (read-only), then ran the complete agent→PVE operation matrix under the scoped token on scratch pool guests 9310/9311, adversarial pool-blindness probes with non-pool decoys, blast-radius regression re-confirms, and pool-membership side-effect checks. - -## Headline results - -1. **Track A — 16/16 ops PASS, zero surprise 403s.** The scoped token is functionally complete for the agent's real operation surface (incl. the previously untested Destroy+disk-reap, Snapshot/Rollback/Delete, SetConfig Network/CPU/Options, Resize, ListRunningTasks, TaskLogTail, and the full restore-test cycle). -2. **B1 (the campaign's most important result):** the provision vmid is **always externally supplied** (no `nextid` scan in agent OR hub — collision-avoidance is operator-side). Adversarially provisioning onto an existing **non-pool** vmid: the pool-blind duplicate guard misses it, PVE refuses the restore (no clobber), **but the compensating rollback then attempts to DESTROY the innocent guest** — stopped only by the pool ACL (403). Same shape live-proven for the restore-test scratch band (a squatter at 990000 additionally makes the restore-test **permanently FAIL** with false "backup unrestorable" alerts). Safe-but-noisy under the scoped ACL; a genuine destroy-risk under any broad token. -3. **Containment intact (Track C):** non-pool guest ops 403, non-granted-storage writes 403, drive audit readable (3b-fix holds). -4. **Hub inventory is pool-only (B3, by design — now recorded as a decision):** operators must pick vmids from the host's real guest list, never the hub view. No pool-name leak into any customer/controller-facing field (Track D); `--adopt-pool` idempotent; uninstall never deletes a non-empty pool. - -## Fix list (full detail + severities in the findings doc) - -- **F1 (HIGH, blocks shared-box trial):** arm the bring-up/restore-test compensating destroy only after `RestoreLXC` returns a UPID — never destroy what the job didn't create. -- **F2 (MED, blocks trial):** restore-test should advance past an "already exists" band vmid (or pre-verify via fenced root CLI); document 990000–990009 as reserved fleet-wide. -- **F3 (MED, doc-only, blocks trial):** provisioning runbook must say vmid selection uses the host's full guest list, not the hub inventory. -- F4/F5/F6 (LOW/INFO): non-pool source-config read in restore-test, pool-blind eject dependent-scan, latent reconcile desired-state rule. - -Demo left exactly as found: pool `felhom` = {9201}, all scratch/decoy guests and campaign artifacts removed, agent active, controller healthy. +- **NEW `documentation/runbooks/provisioning.md`** — the F3 note from + `documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md`: operators MUST pick a provision `-vmid` + from the host's full guest list (`pct list` + `qm list` on the node), never from the pool-only hub + inventory; documents the reserved bands (9999, 990000–990009 fleet-wide) and the safe collision + behavior under agent >= v0.60.0. +- **`documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md`** — resolution banner added: F1 fixed at + root (proof-of-launch destroy gating, all three destroy paths), F2 fixed (band-advance + skip), F3 + documented; F4/F5/F6 remain open; operator follow-up = hub Day-0 artifact manifest bump to agent + 0.60.0 (binary published to Gitea). diff --git a/documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md b/documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md index 0280b81..28f2c3f 100644 --- a/documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md +++ b/documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md @@ -1,5 +1,17 @@ # CAMPAIGN — full effects of the `felhom` pool + scoped-token migration +> **Resolution update (2026-07-02, agent v0.60.0):** **F1 FIXED at root** — proof-of-launch gating: a +> compensating destroy (bring-up rollback, restore-test teardown, AND Recover) fires only when +> `RestoreLXC` returned a UPID; no UPID ⇒ the transaction created nothing ⇒ never destroy. Recover is +> now safe by DESIGN (a no-UPID Scratch/Rollback entry is abandoned fail-safe), no longer by the +> pool-blind "already gone" accident (§2 B1.4). **F2 FIXED** — the restore-test advances past an +> "already exists" band vmid (bounded by the band width); a fully-occupied band → Skipped, no false +> alert. **F3 DOCUMENTED** — `documentation/runbooks/provisioning.md`. Red-proof-tested + live-proven +> on felhom-pve (provision onto existing 9001 → no destroy armed; restore-test advanced past a 990000 +> decoy and passed at 990001). F4/F5/F6 remain open as recorded. Operator follow-up: bump the hub +> Day-0 artifact manifest to agent **0.60.0** (binary published to Gitea, sha256 +> `45d19b87…51725831`). + **Date run:** 2026-07-02 (runbook authored 2026-07-01) · **Host:** felhom-pve (`demo-felhom`, PVE 9.2.2) **Agent live:** v0.59.0 (runbook table said v0.55.0 — v0.56–0.59 shipped between authoring and execution; the ListLXC/priv surface is unchanged) **ACL:** host-install v1.7.0 3-role scoped layout, verified live: `FelhomAgentGuest` @`/pool/felhom` (12 privs incl. `Pool.Allocate`), `FelhomAgentStore` (`Datastore.Allocate,AllocateSpace`) @`local`/`local-lvm`/`felhom-pbs`, `FelhomAgentBase` (`Sys.Audit,SDN.Use,Datastore.Audit`) @`/`. diff --git a/documentation/runbooks/provisioning.md b/documentation/runbooks/provisioning.md new file mode 100644 index 0000000..d1556ae --- /dev/null +++ b/documentation/runbooks/provisioning.md @@ -0,0 +1,40 @@ +# Runbook — provisioning a customer guest (operator notes) + +> Operational guardrails for `--selftest=provision` / bring-up on a Felhom host. The mechanics live in +> `felhom-agent` (RUNBOOK-provisioning-storage.md + the selftest flags); this runbook records the +> operator-side decisions those mechanics assume. + +## Picking the provision `-vmid` (F3 — campaign pool-effects) + +**Pick the vmid from the host's FULL guest list, never from the hub inventory.** + +On the node, as root: + +``` +pct list; qm list +``` + +Why this is load-bearing (CAMPAIGN-pool-effects-2026-07-01, F3): the agent's token is pool-scoped, so +the hub's per-host guest inventory contains ONLY the Felhom-pool guests. On a shared box (the +colleague's-box model), other guests — another customer's, spike/golden/scratch guests — are invisible +in the hub view, and there is deliberately NO automatic vmid assignment anywhere (agent or hub): the +operator-supplied `-vmid` is the only source. A vmid picked from the hub view can therefore collide +with an existing, hub-invisible guest. + +What happens on a collision (belt-and-suspenders, agent >= v0.60.0): PVE refuses the restore +("CT already exists"), the agent arms NO destroy (proof-of-launch gating — it never destroys a +guest the transaction didn't create), and the provision fails cleanly. So a collision is safe — but it +is still a failed provision and an ERROR in the logs; pick from `pct list` + `qm list` and it never +happens. + +Reserved — never provision on these (the agent refuses them): +- `9999` — standing selftest scratch +- `990000–990009` — restore-test scratch band, **reserved fleet-wide on every Felhom host**: a foreign + guest parked in this band forces the self-restore-test to advance around it (agent >= v0.60.0) and, + if the band fills, to skip entirely. + +## Related + +- Storage/sizing flags: `felhom-agent/RUNBOOK-provisioning-storage.md` +- Pool + scoped-ACL model: `documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md` +- Collision/pool-blindness analysis: `documentation/audits/CAMPAIGN-pool-effects-2026-07-01.md`