Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
3.1 KiB
REPORT — v0.73.0: F2 mount-role fallback (enrolled user-data drives ejectable/decommissionable)
Date: 2026-07-06 · Class: risky/supervised (loosens a role gate; bounded by containment red-proofs).
Baseline: main @ 26664d6 (v0.72.0) → 7545af8. Part A of the pilot-blockers bundle (B = controller
v0.102.0, C = catalog healthcheck sweep). Provenance: campaign F2 + RERUN addendum.
The bug
roleForMountPath (internal/localapi/disks.go) resolved a mount's protection role ONLY from the PVE
storage view (Observe). A bind-mounted RAW enrolled user-data drive is not a PVE storage → no MountPath
match → fail-safe RoleSystem → the eject (disks.go:353) and decommission (disks.go:404) role gates 403'd
every user-data drive in the standard topology (campaign journal: where=/mnt/teszt_enroll role=system).
The fix (only roleForMountPath)
After the MountPath loop misses on a SUCCESSFUL Observe, resolve the mount's device from the host mount
table (mirroring durableIDForMount's Impl-2b) and classify device-keyed:
- non-
/devsource (NAS) → system; - device on the same whole disk as a KNOWN target → THAT target's role (containment, new
storage.SameWholeDisk, whole-disk granularity so a protected disk can't be ejected here); - else
RoleForRawDevice(system-disk membership). Fail-safe preserved: an Observe error returns system BEFORE the fallback (a blind containment pass could label a backup drive user-data — permissive); a mount-read failure or absent/NAS mount → system. Handlers,deviceRole,DecommissionExecutor,classify.go,ReassertGuestBindsuntouched; thedeviceRole/roleForMountPathunification is deferred.
Tests + red-proofs (f2_role_fallback_test.go)
A1 bind-mounted user-data ejectable + decommission effects; B1 containment (mount on a protected target's
disk → 403); B2 system-disk mount → 403; C1/C2 fail-safe (absent, NAS → 403); C3 Observe-error skips the
fallback (403 + Mounts() called once). Three red-proofs demonstrated: pre-fix body → A1 FAIL (exact
role: system 403); containment-skip mutation → B1 FAIL (protected disk becomes ejectable); Observe-error
fallback → C3 FAIL (permissive). Existing TestEject_RoleGated/TestDecommission_* green UNMODIFIED. Full
gate go build/vet/test ./... = PASS.
Deploy + live acceptance (on /mnt/teszt_enroll ONLY)
Built -X main.version=0.73.0 on 180, deployed to felhom-pve (.bak-0.72.0 kept). --version = 0.73.0,
systemctl is-active = active, capabilities 56/56 degraded=0. Full F2 lifecycle through the real controller
endpoints: eject → HTTP 200 (was 403), decommission-anyway → HTTP 200 (decommissioned:true, was
403), post-decommission bind detached, agent restart → drive stayed detached (no rebind), re-commission
(reconnect) → 200, end state == pre-state (bound on /dev/sdb, attached, durable uuid:f2236136-ced7…).
Not changed / observations
Only roleForMountPath + the new storage.SameWholeDisk helper. The pre-existing VM.Audit permission
ERROR in the agent log is unrelated (known A1 privilege gap). The deviceRole/roleForMountPath
unification refactor is deferred.