diff --git a/REPORT.md b/REPORT.md index fbba336..1d47363 100644 --- a/REPORT.md +++ b/REPORT.md @@ -4,93 +4,55 @@ --- -# REPORT — 3b-fix: `Datastore.Audit` box-wide (restore drive visibility) (host-install v1.7.0) +# REPORT — Impl-1 Part B: install the guarded-mkfs wrapper (host-install v1.8.0) -**Date:** 2026-07-01 · **Repo:** `felhom.eu` (`scripts/` only) · **Class:** Risky/supervised (low risk — -additive-first ACL change, no agent change, no agent stop). +**Date:** 2026-07-01 · **Repo:** `felhom.eu` (`scripts/` only) · **Class:** Risky/supervised (paired with +the destructive-path change in felhom-agent v0.54.0). -Fixes a regression the v1.6.0 pool-scoped ACL introduced. Script-only; agent v0.53.0 unchanged. +Companion to felhom-agent v0.54.0 (the format-safety foundation). Script-only change: host-install now +installs the guarded-mkfs wrapper during agent install so every fresh box gets the safe format path. ## 1. Baseline → target -script `v1.6.0` @ `1be1e0d` → **v1.7.0**. Agent **v0.53.0 unchanged** (its observer was always correct). +script `v1.7.0` @ `9e5bbc1` → **v1.8.0**. Paired with agent v0.54.0 (separate repo, `5209830`). -## 2. Root cause +## 2. What changed -The agent enumerates storage via `ListStorage`/`NodeStorage`, both gated by **`Datastore.Audit`** -(`felhom-agent/internal/storage/observe.go`). v1.6.0 put `Datastore.Audit` in the **Store** role, -granted only per-storage on `local`/`local-lvm`/`felhom-pbs` — **excluding the enrolled removable drives -`felhom-usb`/`felhom-flash`**. So `ListStorage` returned a filtered list missing the drives → the -observer reported them detached (the "Meghajtó leválasztva" alerts) and the agent-view dropped them. -**Confirmed at source that the fix is Audit-only:** the agent **creates no PVE storage** (no -`POST /storage` / `pvesm add` / `CreateStorage` — the only `/storage` code is host-side NAS mounting); -drives are dir-storages it *observes* (`Datastore.Audit`) + *mounts via host ops* + *binds into the -guest* (`VM.Config.Disk`), never *allocates VM disks onto*. So drives need only `Datastore.Audit` -(read-only), never `Datastore.Allocate`. The v1.6.0 swap's "felhom-usb → 403" was a **regression**, not -blast-radius containment (felhom-usb is Felhom's own customer drive). +- `scripts/felhom-host-install.sh` `step_agent_install`: new step (before the sudoers install) that + `fetch_raw`s `configs/felhom-mkfs-guarded.sh` from Gitea, `bash -n`-validates it, and + `install -m0755 -o root -g root` → `/usr/local/sbin/felhom-mkfs-guarded`. Wrapper-before-sudoers so + the sudoers (which allowlists only the wrapper) is never installed ahead of the file it names. +- The agent v0.54.0 sudoers (fetched by the same step) drops raw `mkfs.*` (allowlists only the wrapper) + and adds read-only `pvs`/`zpool status -P` for the agent's unclaimed-disk guard. +- `scripts/CHANGELOG.md`, version banner. Commit **`7ea36bc`** on `main`. +- `bash -n` + `shellcheck` clean (0 new warnings; the 2 pre-existing SC2015 in `step_verify` unchanged). -## 3. Files changed + commit +## 3. Served-copy version -- `scripts/felhom-host-install.sh`: `PVE_PRIVS_BASE` += `Datastore.Audit`; `PVE_PRIVS_STORE` −= - `Datastore.Audit`; `apply_scoped_acl` reordered Base-before-Store (gap-free re-apply). v1.6.0→**v1.7.0**. -- `scripts/CHANGELOG.md`, `REPORT.md`. Commit **`457a5cd`** on `main` (parent `1be1e0d`). -- `bash -n` OK; `shellcheck` clean (0 new; the 2 pre-existing SC2015 in `step_verify` unchanged). +`curl -fsSL https://felhom.eu/scripts/felhom-host-install.sh | grep SCRIPT_VERSION` → **`1.8.0`**. -## 4. Part 0 diagnosis (live, felhom-pve) +## 4. Live validation (felhom-pve, agent v0.54.0 deploy) -- Regression confirmed: scoped-token `--selftest=read` showed **3 storages** (drives missing). -- Applied `pveum role modify FelhomAgentBase -privs "Sys.Audit SDN.Use Datastore.Audit"` (additive) → - `--selftest=read` immediately showed **5 storages** incl. `felhom-usb`/`felhom-flash`. Mechanism proven. -- Write-scope residual gate (S2): settled at source (no `Datastore.Allocate` in the drive - enroll/format/mount path). A physical brand-new-drive UI enrollment (needs a spare USB) was NOT run — - flagged as operator-confirmable; the path is host-ops/Audit-only and unchanged from pre-3b. +The two-layer format guard (agent unclaimed-filter + this wrapper) validated on the demo — details in +`felhom-agent/REPORT.md` §5: +- wrapper REFUSES the OS disk `/dev/sda` and the LVM-PV partition `/dev/sda3`; +- raw `sudo mkfs.ext4 /dev/sda` is DENIED (Part B — wildcard removed); +- an unclaimed throwaway `/dev/sdd` FORMATS (the only real format); +- the agent guard's sudo reads (`pvs`/`lsblk`/`zpool`) all work as the felhom-agent user. -## 5. Live role privs after Part 2 (felhom-pve) +**Deploy note:** installing the sudoers via a manual scp of the Windows working-copy failed `visudo` +(CRLF line endings); fixed live by CR-stripping. The committed repo file is LF, and the host-install +`fetch_raw`-from-Gitea path serves LF — so the shipped path is unaffected. (Lesson recorded.) -``` -FelhomAgentBase = Datastore.Audit, SDN.Use, Sys.Audit -FelhomAgentStore = Datastore.Allocate, Datastore.AllocateSpace (Audit removed) -FelhomAgentGuest = Pool.Allocate, VM.Allocate, VM.Audit, VM.Config.*, VM.PowerMgmt, VM.Snapshot(.Rollback), VM.Backup -``` -Applied Base-first then Store (gap-free); no agent restart. Drives remained visible after Store lost -Audit (box-wide Base covers them). +## 5. NOT yet live-validated / deferred -## 6. Storage re-test (S1–S8) +- A **fresh install** exercising the new `step_agent_install` wrapper-install step end-to-end (the demo + was repaired in place; a clean box will exercise the fetch+install path — the code is dry-run-safe and + mirrors the existing sudoers/unit install). +- **Impl-2** (raw-device discovery + registry enrollment + wizard rewiring) and **Impl-3** (shared-box + operator gate for self-serve format) are the separate follow-up specs. -| # | Check | Result | -|---|-------|--------| -| S1 | drive observation | ✅ agent-view 3→**5** storages; `felhom-usb`/`felhom-flash` back; detach alerts clear | -| S1b | drive readable under scoped token | ✅ `GET /storage/felhom-usb/content` → **200** (was 403 under v1.6.0) | -| S2 | new-drive enrollment (physical) | ⏸ source-confirmed no `Datastore.Allocate` needed; physical USB test = operator (see §4) | -| S3 | drive format + mount | ⏸ host-ops (mkfs/mount via `SudoHostOps`) — ACL-independent; source-covered | -| S4 | detach + re-attach | ⏸ host-ops + observe — ACL-independent; not run on the live demo's data drives | -| S5 | NAS / netstorage add | ⏸ host-side mount (`localapi/netstorage.go`), no PVE Datastore priv — ACL-independent | -| S6 | offsite backup → felhom-pbs + restore | ✅ Store grant on `/storage/felhom-pbs` unchanged by this fix (3b-proven; re-confirmed intact) | -| S7 | write-containment | ✅ vzdump→`felhom-usb` → **403** (`Datastore.AllocateSpace` still per-storage); out-of-pool guest 9001 → **403** | -| S8 | in-guest features | ✅ 9201 controller Up (healthy) — bind mounts, no PVE perm; unaffected | +## 6. Observations -Live-proven: S1, S1b, S6, S7, S8. Source-confirmed (host-ops/Audit-only, no write priv needed): S2–S5. - -## 7. Served script version - -`curl -fsSL https://felhom.eu/scripts/felhom-host-install.sh | grep SCRIPT_VERSION` → **`1.7.0`**. - -## 8. 3b regression note (for CONTEXT) - -The v1.6.0/3b swap validation logged "felhom-usb → 403" as blast-radius success. That was WRONG — it was -the drive-visibility regression fixed here. Corrected understanding: the scoped token SHOULD be able to -*audit* (read) every storage incl. Felhom's drives (via box-wide `Datastore.Audit`); containment is on -*write* (`Allocate`/`AllocateSpace` per-storage) and on *guests* (VM.* at `/pool/felhom`). Both re-confirmed. - -## 9. NOT yet live-validated — awaiting supervised run - -- A physical **brand-new-drive enrollment** on the corrected layout (needs a spare USB on felhom-pve). -- The **colleague's-box install** (uses the corrected v1.7.0 layout from the start). - -## 10. Observations - -- Fresh installs get the corrected layout directly (Part 1). Existing installs: `--rescope-acl` now - produces it too (inherits the priv sets); the live demo was repaired with two `role modify` commands - (cheaper than a full re-rescope, which would needlessly recreate grants). -- The hub artifact-manifest bump to agent **0.53.0** (from the 3b REPORT) is still an OPEN operator - follow-up for fresh installs — unaffected by this fix. +- The guarded-mkfs wrapper is `configs/felhom-mkfs-guarded.sh` in the **felhom-agent** repo (co-located + with the sudoers it pairs with); host-install fetches it the same way it fetches the unit/sudoers. diff --git a/documentation/audits/SPIKE-drive-enrollment-2026-07-01.md b/documentation/audits/SPIKE-drive-enrollment-2026-07-01.md index 47cc0ae..4ec94d3 100644 --- a/documentation/audits/SPIKE-drive-enrollment-2026-07-01.md +++ b/documentation/audits/SPIKE-drive-enrollment-2026-07-01.md @@ -1,5 +1,13 @@ # SPIKE — safe visibility + enrollment of non-OS (customer data) drives (2026-07-01) +> **STATUS:** SQ3 (format-safety) IMPLEMENTED as **Impl-1** — felhom-agent **v0.54.0** (unclaimed-disk +> `Format` guard `internal/storage/claim.go` + guarded-mkfs wrapper `configs/felhom-mkfs-guarded.sh` + +> sudoers swap) + host-install **v1.8.0** (installs the wrapper). Live-validated on felhom-pve +> (refuses OS disk / LVM PV, raw mkfs denied, throwaway sdd formats). SQ1/SQ4/SQ5 (PVE-storage-free +> registry enrollment + raw-scan candidate endpoint + wizard rewiring) = **Impl-2** (pending). SQ3's +> shared-box operator gate for self-serve format = **Impl-3** (pending). See the felhom-agent + felhom.eu +> REPORTs + `RUNBOOK-usb-enrollment-3bfix-2026-07-01.md`. + **Class:** SPIKE (read-only investigation + design; no product code, no version bump). **Repos read:** felhom-agent v0.53.0 @ `7639ab5` (read-only). **Test bed:** felhom-pve — 1 OS SSD (`sda`), 2 enrolled drives (`sdb`=felhom-flash, `sdc`=felhom-usb), 1 free raw device (`sdd`, 59.5G, ntfs, unmounted).