v0.32.0: self-serve decommission endpoint + intent-aware re-assert (B2a)
POST /disks/decommission mirrors eject (withGuest, user-data role gate) — no operator signature, non-destructive (never formats): sets IntentDecommissioned, prunes the GuestBindStore entry, unmounts. ReassertGuestBinds is now intent-aware (skip non-enrolled) so a decommissioned-but-present drive never auto-rebinds on agent restart — the load-bearing F9-reconnect fix. GuestBindStore.Remove added. Operator-signed DecommissionExecutor + classify untouched. Non-hollow tests incl. the intent-aware reassert companion (mutation-proven to fail on intent-blind code). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,33 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.32.0 — self-serve decommission + intent-aware re-assert (B2a) (2026-06-14)
|
||||
|
||||
Customer-self-serve storage decommission (no operator signature; non-destructive — never formats),
|
||||
plus the load-bearing fix that keeps a decommissioned drive from auto-rebinding into the guest.
|
||||
|
||||
- **`POST /disks/decommission`** (`internal/localapi/disks.go` `handleDiskDecommission`, route in
|
||||
`server.go`) — mirrors `handleDiskEject` exactly: `withGuest` self-scoping, `scopedFromBody`, and the
|
||||
same **user-data role gate** (`roleForMountPath` must be `RoleUserData`, else 403; fail-safe-to-
|
||||
protected on ambiguity) so a compromised controller can't decommission system/backup storage. It
|
||||
records a PERMANENT `IntentDecommissioned`, prunes the `GuestBindStore` entry (hygiene), and unmounts
|
||||
(so the drive is physically removable). It **NEVER** calls any format/mkfs path — the data stays on
|
||||
the drive. The operator-signed `DecommissionExecutor` + `reconcile.Classify` classification are
|
||||
untouched (the absent-drive/DR route).
|
||||
- **`ReassertGuestBinds` is now intent-aware** (THE correctness fix): the startup re-assert skips any
|
||||
durable-id whose intent is not `enrolled`, so a decommissioned- (or ejected-) but-still-present drive
|
||||
is never auto-rebound into the guest on agent restart. A nil intent store falls back to legacy
|
||||
bind-all (matching the watchdog's nil-intent rule). Covers both the self-serve and the operator-
|
||||
signed decommission paths (both land on `IntentDecommissioned`).
|
||||
- **`GuestBindStore.Remove(vmid, durableID)`** (`internal/localapi/guestbindstore.go`) — idempotent
|
||||
(absent = no-op), atomic tmp+rename like `Record`; drops the vmid key when its set empties. Re-enroll
|
||||
re-`Record`s via the existing `recordGuestBind` on guest-attach, so Remove doesn't break re-commission.
|
||||
- `IntentRecorder` extended with `SetDecommissioned` + `Get` (both already on `*storage.IntentStore`).
|
||||
- Non-hollow tests (`internal/localapi/decommission_test.go`): role-gate refuses system/backup (403,
|
||||
no unmount); decommission sets intent + removes the bind + unmounts + never formats; intent-aware
|
||||
re-assert does NOT rebind a decommissioned-but-present drive (companion: enrolled DOES rebind; the
|
||||
intent-blind pre-fix code fails this); re-commission re-records; `Remove` idempotency + persistence.
|
||||
|
||||
## v0.31.0 — live-drive F9 + F20-BUG2 + F20-BUG3 (disk bind/wipe) (2026-06-14)
|
||||
|
||||
The last live-drive findings, all disk/`localapi`-side, implemented + deployed on `felhom-pve` and
|
||||
|
||||
Reference in New Issue
Block a user