a1d045079f
hub v0.54.0: change operator login password from the Configuration UI Adds a "Login password" card on /configuration. The password was previously settable only via the hub-config ConfigMap (auth.password_hash) + redeploy. - store: hub_settings key operator_password_hash + Get/SetOperatorPasswordHash - server: passwordHash field -> configPasswordHash (seed); new effectivePasswordHash() (DB override wins, else seed) is now the single source for the CSRF gate, RequireAuth, and handleLogin - POST /configuration/password (handleChangePassword): requires current password, 8-72 byte new + confirm, bcrypt cost 10, persists DB override; existing sessions kept valid; ConfigMap stays the break-glass reset path - UI: current/new/confirm form + inline mismatch pre-check + 6 flashes - tests + red-proofs: override precedence, happy-path via handleLogin, wrong-current rejection, mismatch/too-short/no-op, template render - docs: CHANGELOG, README (auth+config), REUSE, REPORT Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LbMm4T7Ayzs1unB9pN6Uqd @
60 lines
3.3 KiB
Markdown
60 lines
3.3 KiB
Markdown
# felhom.eu — task reports
|
||
|
||
> **Overwrite** this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in [hub/CHANGELOG.md](hub/CHANGELOG.md); the scripts history lives in [scripts/CHANGELOG.md](scripts/CHANGELOG.md).
|
||
|
||
## Hub v0.54.0 — operator login password changeable from the UI — 2026-07-13
|
||
|
||
### What & why
|
||
|
||
The hub login password could previously be changed **only** by editing `auth.password_hash` in the
|
||
`hub-config` ConfigMap and redeploying — no in-app path existed (operator hit this wall). Added a
|
||
**Configuration → Login password** card that changes the password at runtime, persisted in the DB,
|
||
with the ConfigMap kept as the break-glass reset path.
|
||
|
||
### Design (matches the controller-version-floor precedence pattern)
|
||
|
||
- **Store** (`internal/store/store.go`): new `hub_settings` key `operator_password_hash` with
|
||
`GetOperatorPasswordHash()` / `SetOperatorPasswordHash()` (thin wrappers over the existing
|
||
`getSetting`/`setSetting`). No schema change.
|
||
- **Server** (`internal/web/server.go`): the static `Server.passwordHash` field is renamed
|
||
`configPasswordHash` (the hub.yaml SEED). New `effectivePasswordHash()` = **DB override wins, else
|
||
config seed** — and it is now the single source for every auth check (CSRF gate, `RequireAuth`
|
||
session + Basic-Auth paths, `handleLogin`).
|
||
- **Handler** `POST /configuration/password` (`handleChangePassword`): requires the current password
|
||
(verified against the effective hash), new password 8–72 bytes, matching confirmation, rejects a
|
||
no-op. On success bcrypts (cost 10) and persists the override. Existing sessions stay valid; CSRF
|
||
enforced by the central `ServeHTTP` gate; no secret logged.
|
||
- **UI** (`templates/configuration.html`): current/new/confirm fields, inline client-side mismatch
|
||
pre-check, six flash outcomes.
|
||
|
||
### Recovery posture (operator's explicit choices)
|
||
|
||
- Requires the **current** password to change it (blocks a walk-up attacker on an open session).
|
||
- ConfigMap `auth.password_hash` remains the **break-glass fallback** — blank the DB row (or edit the
|
||
manifest + redeploy) to reset a forgotten password.
|
||
|
||
### Tests & red-proofs (`internal/web/change_password_test.go`)
|
||
|
||
- `TestEffectivePasswordHash_DBOverrideWins` — override wins; clearing falls back to the seed.
|
||
- `TestChangePassword_HappyPath` — end-to-end through `handleLogin` (new works, old dead).
|
||
- `TestChangePassword_WrongCurrentRejected` — security anchor: no override written.
|
||
- `TestChangePassword_ValidationRejections` — mismatch / too-short / no-op refused, no override.
|
||
- `TestConfigurationPage_RendersPasswordCard` — form renders through the production template.
|
||
- Red-proofs verified: dropping the current-password check → WrongCurrentRejected fails; breaking the
|
||
override precedence → precedence + happy-path login assertions fail.
|
||
|
||
### Gates
|
||
|
||
- `go build ./... && go vet ./... && go test ./...` (hub): green.
|
||
- `python scripts/hub_confirm_gate.py`: green (no native confirm/prompt in templates).
|
||
|
||
### Docs
|
||
|
||
- `hub/CHANGELOG.md` (v0.54.0), `hub/README.md` (Authentication + Configuration sections),
|
||
`REUSE.md` (`effectivePasswordHash`, `Get/SetOperatorPasswordHash` rows).
|
||
|
||
### Deploy
|
||
|
||
Hub image built + pushed as `v0.54.0`; `manifests/hub.yaml` tag bumped; ArgoCD synced; verified live
|
||
on `hub.felhom.eu`.
|