v0.44.0: role-aware drive management — protected lockout + customer type-to-confirm wipe + drive-list restyle

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 21:44:50 +02:00
parent 2c32c821fe
commit 12064dcd88
13 changed files with 696 additions and 182 deletions
+26 -13
View File
@@ -514,23 +514,36 @@ not just those with HDD data. Non-HDD apps can configure destination, method, an
### 4. Storage Management
> **⚠️ Rebuilt on the agent-delegated disk model (v0.43.0).** After the 8C de-privileging, the controller
> holds **no Proxmox/disk credentials and no destructive authority** — disk execution + the data-bearing
> signature gate live entirely in the **host agent**. The controller is now a thin presenter/orchestrator:
> - **Overview** (`settings.html` ← `GET /api/disks`): the agent's live disk view (name/type/state/device/
> mount/class) + the **`data_bearing`** badge + "registered?" cross-reference.
> **⚠️ Rebuilt on the agent-delegated disk model (v0.43.0), made ROLE-AWARE in v0.44.0.** After the 8C
> de-privileging, the controller holds **no Proxmox/disk credentials and no destructive authority** — disk
> execution + the gate live entirely in the **host agent**. The drive UI is driven by the agent's
> authoritative **role** (`system` | `backup` | `user-data`, from `GET /api/disks`): the appliance's own
> system storage and the backup safety-net are visibly **protected** (lock badge, NO destructive controls);
> the customer manages their own **user-data** drives with informed consent. The agent re-enforces role at
> wipe time — the UI lockout is defense-in-depth, not the gate.
> - **Overview** (`settings.html` ← `GET /api/disks`): styled **cards** (not a table) — name, mono
> device/mount, badges for class (gyors/lassú), data (`Adatot tartalmaz`), **role** (🔒 Rendszer / 🔒
> Biztonsági mentés — védett / Felhasználói adat) and registered state, plus a **capacity bar** (the
> monitoring `system-bar`, from the agent's `total_bytes`/`used_bytes`). Eject/Wipe render **only** for
> user-data drives mounted under `/mnt`.
> - **Customer wipe/eject** — a **type-to-confirm** modal that names the deployed apps that break
> (`GET /api/storage/impact` → `appsUsingPath`) and disables the destructive button until the **mount
> name is typed exactly**. Wipe (`POST /api/storage/wipe`): eject (unmount + deregister) → server-side
> two-step customer-confirmed format (learn the agent's durable id, then re-submit `confirmed:true` bound
> to it). The agent refuses a protected device regardless of what the controller sends.
> - **Guided init** (`/settings/storage/init`, `POST /api/storage/init`, `web/storage_handlers.go`): format
> → resolve the new fs UUID from the re-listed disks (`durable_id`, `uuid:`-stripped) → `assign` (mount)
> → register a `StoragePath`. **A data-bearing device is REFUSED by the agent** (`pending_op`); the UI
> surfaces the exact `felhom-opsign -op storage_wipe -host … -durable-id …` command and stops — **there
> is no force-format**. The agent's `data_bearing` verdict (it inspects the device) is ground truth.
> → resolve the new fs UUID → `assign` → register. The selector lists **only user-data** targets. A
> data-bearing user-data device now uses the **customer-confirmation** flow (type-to-confirm → re-submit
> `confirmed:true` + durable id), NOT the `felhom-opsign` command. The opsign surface remains a fallback
> only if a protected device somehow reaches init.
> - **Guided attach** (`/settings/storage/attach`, `POST /api/storage/attach`): non-destructive — resolve
> the existing fs UUID → `assign` → register.
> the existing fs UUID → `assign` → register. Selector restyled to cards (user-data only).
> - **Eject** (`POST /api/storage/eject`): benign unmount + deregister, with the agent's dependent-guest warning.
> - **`agentapi`** (`internal/agentapi`) is the pinned client to the agent local API: `Disks`/`AssignDisk`/
> `EjectDisk`/`FormatDisk`; `DiskInfo.FSUUID()` + `FormatResult.PendingOp.OpsignCommand()`.
> - The **`StoragePath` registry** (`settings.go`: `AddStoragePath`/default/schedulable/label) is unchanged —
> init/attach register into it; the existing per-path management handlers stay.
> `EjectDisk`/`FormatDisk(…, confirmed, durableID)`; `DiskInfo.role`+capacity;
> `FormatResult.{role,needs_confirmation,durable_id}`; `ErrNeedsConfirmation` (user-data) vs
> `ErrFormatRefused` (system/backup). `FormatResult.PendingOp.OpsignCommand()` for the operator path.
> - The **`StoragePath` registry** (`settings.go`: `AddStoragePath`/default/schedulable/label) is unchanged.
> - **Migration** (drive + per-stack) is **deferred** to its own slice (buttons disabled "Hamarosan").
>
> The privileged controller-side disk subsections **below are historical** (the `internal/storage/*` scan/