e04b75e1f8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
44 lines
3.1 KiB
Markdown
44 lines
3.1 KiB
Markdown
# 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-`/dev` source (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`, `ReassertGuestBinds` untouched; the
|
|
`deviceRole`/`roleForMountPath` unification 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.
|