agent v0.24.0: role-gate the eject path (system/backup mounts unmount-protected at the agent)

handleDiskEject now resolves the authoritative role of the storage at `where`
and refuses 403 (no Unmount) unless it is user-data. Fails safe to protected on
ambiguity. Adds roleForMountPath + an injectable HostReader seam for testability.
TestEject_RoleGated asserts protected mounts are refused with no Unmount.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 09:29:09 +02:00
parent 832b73e6e8
commit 7ae82e1d5d
5 changed files with 153 additions and 9 deletions
+21
View File
@@ -3,6 +3,27 @@
All notable changes to **felhom-agent** are recorded here. Update on every code
change that gets pushed.
## v0.24.0 — role-gate the eject path (system/backup mounts are unmount-protected at the agent) (2026-06-12)
Closes the eject gap in the storage-authorization redesign: `POST /disks/eject` now **refuses to
unmount a system or backup storage**, enforced at the agent — not just hidden in the controller UI.
A direct API call (or a compromised controller) trying to `eject {where:"/var/lib/vz"}` or the PBS
mount is refused 403; only `user-data` mounts are ejectable.
- **`handleDiskEject` (`internal/localapi/disks.go`)** — before `Unmount`, resolves the AUTHORITATIVE
protection role of the storage mounted at `where` (the agent's own storage-view + host-topology
classification, never the caller's claim) via the new `roleForMountPath`. Refuses (403, no
`Unmount`) unless the role is `user-data`. **Fails SAFE**: an unresolvable mount (view error or no
storage target at that path) → treated as protected → refused (the same most-protected-on-ambiguity
default the wipe gate uses). Mirrors the wipe path's "protected — eject refused by role" logging.
- **`roleForMountPath` + `hostReader` seam** — `roleForMountPath` keys `RoleForStorage` on the mount
path (the eject input), mirroring `deviceRole`. `Options.HostReader` (optional; defaults to the
production `*storage.ProcHostReader`) injects the root-free topology reader so the role-gate is unit-
testable. `handleDisks`/`deviceRole` now share the same seam.
- **Tests** — `TestEject_RoleGated` asserts a `system` and a `backup` mount are refused with **no
`Unmount`**, a `user-data` mount ejects, and an unresolvable mount fails safe to refused (the same
non-hollowness the wipe tests use). `TestEject_UnmountAndDependents` updated to a user-data target.
## v0.23.0 — device-ROLE classification + tiered storage-wipe gate (system/backup operator-only, user-data customer-confirmable) (2026-06-11)
The storage-authorization redesign (agent half). The gate's destructive-wipe path is now **tiered by