Files
felhom-agent/REPORT.md
T
admin 3c174bc6f2 agent v0.87.0: SystemDisks device-mapper walk — legacy-boot hosts get a working drive wizard (IA finding 2, MEDIUM)
Operator ruling 2026-07-13: walk the root's backing device through /sys/block/<dev>/slaves
recursively down to physical disks (dm AND md; topology, never VG names); those + any mounted-ESP
holder are system; the all-system fail-safe returns to being the WALK-FAILURE error case only.
SAFETY DIRECTION: a root-backing disk classified candidate is made impossible — per-branch
conservatism (any unresolvable slave fails the WHOLE walk -> ok=false -> the unchanged all-system
path).

- physicalDisksOf/walkSlaves in role.go (symlink canon -> wholeDiskOf fast path -> recursive
  slaves walk; cycle/depth guard; non-/dev sources unwalkable)
- HostReader.BlockSlaves(name) — the ONE new seam method; ProcHostReader reads
  /sys/block/<name>/slaves; all four test fakes mirror it
- role_walk_test.go: signature table (root-backing disk ALWAYS system across legacy-LVM /
  md-raid / EFI+raw / EFI+LVM / nested dm-on-md — NEVER weaken) + dead-wizard-lives +
  dangling-slave fail-safe (real sysKnown=false path) + cycle + empty-slaves; red-proofs A/B/D
  run->fail->revert (recorded in REPORT)
- §3 spike transcripts (drill legacy: dm-1->sda3->sda; felhom-pve: ESP+walk agree on sda ->
  byte-identical regression); caller audit: none relied on all-system as a feature
- format/mkfs paths, data-bearing guards, wizard UI untouched
2026-07-13 13:15:03 +02:00

88 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# REPORT — v0.87.0: SystemDisks device-mapper walk (IA finding 2, MEDIUM)
**Date:** 2026-07-13 · **Version:** felhom-agent v0.87.0 (from v0.86.0, baseline `c20814e` confirmed) · Agent-only classification fix; MinAgent/controller coupling: none. **Safety direction:** the outcome made impossible is a root-backing disk classified candidate; the fixed failure is the opposite over-protection (legacy-boot → everything system → dead wizard).
## §3 spike (live, BEFORE code — both transcripts)
- **Drill host** (root@192.168.0.152, the exact IA-failure shape): legacy boot — `/` from
`/dev/mapper/pve-root``readlink -f`**/dev/dm-1** → `/sys/block/dm-1/slaves` = **sda3**
`/sys/class/block/sda3/partition` exists → parent **sda**. NO /boot/efi mount (sda2 vfat
exists, unmounted — classic legacy shape). Bonus fact baked into the design: a PHYSICAL disk's
`slaves/` dir EXISTS and is EMPTY (`ls /sys/block/sda/slaves | wc -l` = 0) — so `hasDir` alone
is not resolution; the walk requires non-empty slaves to ground a virtual device.
- **felhom-pve** (regression baseline): `/` → dm-1 → slaves sda3 → sda AND `/boot/efi`
/dev/sda2 → sda — ESP and walk agree on the same disk ⇒ post-fix output must be identical.
Pre-upgrade API captures saved (scratchpad `pve-disks-pre-0870.json`, `pve-cands-pre-0870.json`,
`drill-pre-0870.txt`): felhom-pve roles (felhom-usb/felhom-flash/raw-sdb user-data, local/lvm
system, pbs/offsite backup), candidates EMPTY on both hosts pre-fix.
No surprises → proceeded.
## Implementation (commit on main)
- `internal/storage/role.go`: `SystemDisks` now grounds every system mountpoint via
**`physicalDisksOf`** — symlink canonicalization → `wholeDiskOf` fast path (raw disks/
partitions, unchanged) → **`walkSlaves`**: recursive `/sys/block/<name>/slaves` resolution for
virtual devices (dm-*, md*), partitions resolved by the existing regexes (`sda3 → /dev/sda`),
cycle/depth guard (visited set, cap 32). Per-branch conservatism (operator ruling): ANY
unresolvable slave — dangling entry, unrecognizable name (e.g. `md0p1`), virtual with empty
slaves — fails the WHOLE walk → `ok=false` → the UNCHANGED all-system fail-safe. Non-`/dev`
sources (ZFS dataset, NFS, overlay) are unwalkable → fail-safe (same as pre-fix).
- `internal/storage/hostread.go`: **`HostReader.BlockSlaves(name) ([]string, bool)`** — the one
new seam method (root-free; sysfs world-readable); `ProcHostReader` reads
`<sysBlockDir>/<name>/slaves`; all four test fakes mirror it (storage `fakeHostReader` gains a
`slaves` map; localapi `fakeHostReader`/`uuidHostReader`/`f2HostReader` return nil,false).
- **Caller audit:** `handleDisks`, `roleForMountPath`, `deviceRole` (localapi/disks.go) and
`gatherClaimFacts` (storage/claim.go) — all consume `SystemDisks` through
`isSystemBacked`/`classifyClaim` fail-safes; NONE relies on all-system as a feature (finding:
none needed changes). Format/mkfs paths, data-bearing guards, wizard UI untouched.
- **Behavior deltas:** legacy-boot LVM → resolves, wizard lives; EFI(+LVM) → byte-identical;
md-raid root → BOTH members system. New PROTECTIVE delta: an ESP-resolving host whose root
topology cannot be grounded is now all-system (pre-fix trusted the ESP alone) — per the
ruling's conservatism; direction-safe.
## Tests + red-proofs (fake sysfs via the HostReader seam)
`role_walk_test.go` — fixtures mirror the §3 transcripts: legacy-LVM (dm→part→disk), md-raid
(md→2 disks, BOTH asserted system), EFI+raw, EFI+LVM (felhom-pve), nested dm-on-md;
dangling-slave (with a load-bearing RESOLVABLE sibling branch so a skip-mutation yields a
plausible partial set); cycle; virtual-with-empty-slaves. **Signature test
`TestSystemDisks_WalkTopologies`** asserts the root-backing physical disk(s) are ALWAYS in the
system set + the scratch disk never is + role-level consequences — never weaken.
Red-proofs (mutate → fail → revert, verbatim):
- **A (pre-fix resolver, no walk):** `TestSystemDisks_LegacyBoot_WizardLives` FAILS —
"legacy-boot topology must resolve (the all-system fail-safe is the ERROR case…)" — the exact
dead-wizard live shape; the signature table fails on legacy/md/nested too.
- **B (walk returns the dm node):** `SIGNATURE VIOLATION: root-backing disk /dev/sda missing
from system set map[/dev/mapper/pve-root:true]` (+ md0 / nested variants naming both disks).
- **D (per-branch conservatism removed):** `TestSystemDisks_DanglingSlave_FailSafe` FAILS —
scratch classified candidate while the walk is incomplete (asserted through the REAL
`sysKnown=false` → `isSystemBacked`/`RoleForRawDevice` path, not a lookalike).
Full suite: `go test ./...` green (all packages; recovery-code flake did not fire).
## §13 deploy + regression
- (Filled at deploy — build 0.87.0 on 180 → drill host first with `.bak-0.86.0` backup +
restart + clean journal, then felhom-pve; 13.3 = post-upgrade `/disks` + `/disks/candidates`
diffed against the §3 pre-captures.)
## STOPPED for Viktor (per the task's STOP)
1. **13.2 wizard live leg** — hot-add the 5 GB scsi scratch disk to the drill PVE VM (qm 300 on
felhom-pve), then through YOUR logged-in dashboard session (no gate-lift): wizard OFFERS the
disk → enroll + format (GO required before format) → unenroll/detach, leave as found.
2. **Day-0 manifest bump** to agent 0.87.0 (hub operator UI, password-gated) + the IA audit doc
finding-2 disposition line (felhom.eu).
## Observations
- No `SystemDisks` caller relied on the all-system behavior as a feature (audited: disks.go ×3,
claim.go ×1) — the fix is purely widening resolution.
- md-raid fixture lesson: partitions of an md array (`md0p1`) are NOT covered by the partition
regexes — such a slave fails the walk → all-system (documented in code; acceptable, exotic).
- A physical disk's `slaves/` dir exists and is empty (live-probed) — any future sysfs-walking
code must treat "dir present" ≠ "virtual device".
- Pre-existing `gofmt -l` hits (capability/probe.go, escrow/*.go) — not touched, not mine.