hub v0.15.0: Phase 2 managed updates — per-customer controller-version floor
Operator sets a minimum controller version (FLOOR), per-customer defaulting to a
global floor; the report ACK returns the effective floor + latest_version so the
controller auto-updates to the floor when below it (latest stays the opt-in button).
- store: min_controller_version column + hub_settings global floor + Effective/
Get/SetGlobal/SetMin resolution + config/env DEFAULT_MIN_CONTROLLER_VERSION
- handler: report ACK {min_controller_version, latest_version}; LatestVersionProvider
- web: global floor editor + per-customer override form + Floor column (English)
- tests: floor resolution + ACK + render; override-precedence red-proof verified
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FSZmmSFVzGwEzhYmxbkgBK
This commit is contained in:
@@ -1,5 +1,35 @@
|
||||
# Felhom Hub — Changelog
|
||||
|
||||
## v0.15.0 — Phase 2 managed updates: per-customer controller-version floor (2026-06-27)
|
||||
|
||||
The operator can now set a **minimum controller version** (FLOOR) — per-customer, defaulting to a
|
||||
**global** floor — and any box below it **auto-updates** to the floor on its next report (no customer
|
||||
action). The customer "update to latest" button is unchanged (latest, opt-in); the floor is the
|
||||
operator's enforced minimum and the **auto-target** (controlled rollout: the operator raises the floor).
|
||||
|
||||
- **`store.go`:**
|
||||
- `customer_configs` gains `min_controller_version TEXT NOT NULL DEFAULT ''` (per-customer override).
|
||||
- New `hub_settings(key,value)` table holds the operator-set **global** floor (survives restarts).
|
||||
- Global default fallback `SetDefaultMinControllerVersion` (config/env `DEFAULT_MIN_CONTROLLER_VERSION`).
|
||||
- `EffectiveMinControllerVersion(customerID)` = per-customer override if non-empty, else global
|
||||
(hub_settings → config default), else "". Plus `Set/GetGlobalMinControllerVersion`,
|
||||
`SetMinControllerVersion`.
|
||||
- **`handler.go` (`handleReport`):** the controller report ACK (previously just `{status, customer_blocked}`)
|
||||
now also returns `{min_controller_version: <effective floor>, latest_version: <registry latest>}`. Both
|
||||
omitted when empty, so old controllers / unconfigured hubs behave exactly as before. New
|
||||
`SetLatestVersionProvider` wires the registry `VersionChecker` (nil-safe).
|
||||
- **`configs.go` + templates (operator UI, English):** the Customers list shows a **Floor** column
|
||||
(effective floor, "override" tag, below-floor ● marker) + a **global floor** editor; each customer page
|
||||
shows the effective/global floor, below-floor status, and a **per-customer override** form. Routes
|
||||
`POST /configs/global-floor` and `POST /customers/{id}/floor` (CSRF-protected; X.Y.Z or blank-to-clear).
|
||||
- **`main.go`:** seeds the default floor from config/env; wires the latest-version provider.
|
||||
- **Tests:** effective-floor resolution (override beats global; empty when unset; DB-beats-default;
|
||||
preserved across save); report ACK carries effective floor + latest + omits when unset; template render
|
||||
smoke. **Companion red-proof:** breaking `EffectiveMinControllerVersion` to return the global when an
|
||||
override is set makes the override-precedence store test AND the ACK test FAIL (verified, then restored).
|
||||
- Reuse: rides the existing report cycle (no new endpoint); the swap itself is the controller's Phase 1
|
||||
flow + the agent — untouched here.
|
||||
|
||||
## v0.14.0 — Passphrase-authed host enrollment (Day-0 option C) (2026-06-26)
|
||||
|
||||
Adds the single-secret Day-0 host-enrollment path proven in
|
||||
|
||||
Reference in New Issue
Block a user