fix(localapi): F2 mount-role fallback — enrolled user-data drives ejectable again (v0.73.0)

roleForMountPath resolved role only from the PVE storage view; a bind-mounted
RAW enrolled user-data drive is not a PVE storage, so it fail-safe'd to system
and the eject/decommission gates 403'd EVERY user-data drive in the standard
topology (campaign F2, where=/mnt/teszt_enroll role=system). Add a mount-table
fallback mirroring durableIDForMount Impl-2b: device-keyed classification with a
whole-disk containment pass (new storage.SameWholeDisk) and the Observe-error
early return kept BEFORE the fallback (else a blind view -> permissive). Only
roleForMountPath touched. Tests A1/B1/B2/C1-C3 + 3 red-proofs; existing RoleGated
tests green unmodified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-06 20:07:45 +02:00
parent 26664d6d51
commit 7545af8a2c
4 changed files with 266 additions and 4 deletions
+23
View File
@@ -1,3 +1,26 @@
## v0.73.0 — F2 mount-role fallback: enrolled user-data drives are ejectable/decommissionable again (2026-07-06)
Closes campaign finding **F2** (`felhom.eu/documentation/audits/CAMPAIGN-nomercy-2026-07-06.md` +
RERUN addendum). `roleForMountPath` (`internal/localapi/disks.go`) resolved a mount's protection role
ONLY from the PVE storage view (`Observe`), but a **bind-mounted RAW enrolled user-data drive is not
a PVE storage** → no MountPath match → fail-safe `RoleSystem` → the eject/decommission role gates
403'd **every user-data drive in the standard topology** (journal: `where=/mnt/teszt_enroll
role=system`). Customers could not eject or decommission their own drives.
- **Fallback** mirrors `durableIDForMount`'s Impl-2b: after the MountPath loop misses (on a SUCCESSFUL
Observe), resolve the mount's backing device from the host mount table and classify **device-keyed**
— non-`/dev` source (NAS) → system; device on the same whole disk as a KNOWN target → THAT target's
role (containment, via new `storage.SameWholeDisk`, whole-disk granularity so a protected disk can't
be ejected through this path); else `RoleForRawDevice`. **Fail-safe preserved**: an Observe error
returns system BEFORE the fallback (a blind containment pass could label a backup drive user-data —
permissive), and a mount-table-read failure or an absent/NAS mount → system.
- Scope: **only** `roleForMountPath`; gates, `deviceRole`, `DecommissionExecutor`, `classify.go`,
`ReassertGuestBinds` untouched; the `deviceRole`/`roleForMountPath` unification is deferred.
- Tests (`f2_role_fallback_test.go`): A1 ejectable + decommission effects; B1 containment→403; B2
system-disk→403; C1/C2 fail-safe; C3 Observe-error skips the fallback. Three red-proofs demonstrated
(pre-fix→A1 FAIL, containment-skip→B1 FAIL, fallback-on-error→C3 FAIL). Existing RoleGated/
Decommission tests green unmodified.
## v0.72.0 — OOB operator access: rendered operator /32 + dedicated felhom-sshd + port-adaptive belt + oob health (TASK H1) (2026-07-05)
The agent half of the merged E1+H1 operator-SSH-access feature (hub half = felhom-hub v0.35.0).