Files
felhom-controller/REPORT.md
T
2026-06-11 20:01:00 +02:00

4.7 KiB

REPORT — v0.43.0: rebuilt storage management (guided init/attach/eject on the agent disk model)

Repo: felhom-controller · Version: 0.43.0 · Date: 2026-06-11 Pushed commit: 29a9dcd · paired with felhom-agent v0.22.0 (4734d4a, exposes durable_id) + golden rebake.

What shipped

After the 8C de-privileging the storage UI's buttons pointed at deleted routes (all 404); only manual "add already-mounted path" survived. The agent already owns disk execution + the data-bearing signature gate, and the controller already had the agentapi client + /api/disks/* proxies + the StoragePath registry. This is a controller-only UI/orchestration layer over those — the controller holds no destructive authority.

  • Storage overview (settings.html, GET /api/disks): the agent's live disk view — name/type/state/ device/mount/class + the data_bearing badge + a "registered?" cross-reference.
  • Guided init (/settings/storage/init + POST /api/storage/init): format → resolve the new fs UUID from the re-listed disks → assign (mount) → register the StoragePath. A data-bearing device is REFUSED by the agent; the UI surfaces the exact felhom-opsign … command and stops — no force-format.
  • Guided attach (/settings/storage/attach + POST /api/storage/attach): non-destructive — resolve the existing fs UUID → assign → register.
  • Eject (POST /api/storage/eject): benign unmount + deregister, surfacing the agent's dependent-guest warning.
  • agentapi: DiskInfo.DurableID + FSUUID() (the assign key — strip uuid:); FormatResult.PendingOp
    • OpsignCommand(), now parsed from the agent's 403 body (the old client discarded it).
  • Honest buttons: init/attach wired; migrate (drive + per-stack, both places) disabled "Hamarosan" — no 404s.
  • Phase 3 (de-priv template debt): removed the dead CrossDrive* blocks in deploy.html (the "2. mentés" form + 3 JS fns) and backups.html (run buttons + 2 JS fns) — they referenced fields the de-privileged handlers no longer provide.

Security invariant — held, proven live

The UI never bypasses the agent's data-bearing gate; there is no force-format. A refusal surfaces the felhom-opsign command only. Unit-tested (runStorageInit on a data-bearing refusal performs zero assign/register) and proven live on 9201's real sdb: POST /api/storage/init {device:/dev/sdb1}HTTP 409, refused:true, registered:false, opsign: felhom-opsign -op storage_wipe -host demo-felhom-01 -durable-id byid:wwn-0x5000039ddb108568-part1. No format, no mount, no registration.

Live validation (guest 9201, real 1TB USB sdb = felhom-usb)

  • /api/disks now carries durable_id; felhom-usb/dev/sdb1, data_bearing:true ("device is mounted"), durable_id:uuid:277a2179-…. Overview badge maps correctly.
  • Init on sdb (data-bearing) → 409 + opsign, gate held (the spec's passing gate test — sdb holds data).
  • Pages render (no 404/500): /settings, /settings/storage/init, /settings/storage/attach, /stacks/<app>/deploy (deploy.html — CrossDrive removed), /stacks, /monitoring. No dead storage links.
  • Tests: refusal-surfaces-opsign-and-does-NOT-mount/register; success assigns with the resolved UUID + registers the expected StoragePath; UUID resolution; a template-parse test guards every page.

Deferred / flagged (NOT in this slice)

  • Phase 2 — migration (controller-side rsync): intentionally its own slice (the migrate buttons are disabled "Hamarosan", not dead). The controller still has /mnt:/mnt:rw, so it can rsync app-data between mounts + update app.yaml's HDD_PATH (stop→rsync→verify→start) — no agent endpoint needed.
  • /backups still 500s on PRE-EXISTING restic debt (NOT this change, NOT CrossDrive). The page references ~30 dead restic-tier fields (.Backup.RepoStats, .SnapshotHistory, .ResticSchedule, .Retention, .LastBackup, .NextBackup, .LastCheckOK, …) that 8C removed from the backend — the whole restic snapshot tier + repo stats + snapshot history + restic-password UI is dead. That's a backups-page de-priv rebuild (a design slice: what the page shows in the app-data-only model), well beyond the CrossDrive cleanup this spec scoped (the spec listed "backups.html (5)" = the CrossDrive refs, which I removed). /backups was already 500'ing before this task. Recommend it as the next slice.

Notes

  • No agent disk-subsystem or gate changes; the only agent change is the read-only durable_id exposure (v0.22.0) the user approved (without it the de-privileged controller can't learn the fs UUID assign needs). Golden rebaked with controller 0.43.0 so fresh provisions get the rebuilt UI.