tasks: tick P4-03/04 + sweep notes
Live Playwright + curl sweep on the smoke env exercised the full user-management lifecycle: admin add user → setup link generated → curl-as-new-user fetches /setup (200, username on page) → POSTs password → 303 to / with Set-Cookie → 200 on dashboard, 200 on /settings/account, **403 on /settings/users** (admin-only) → admin disables → next request is **401** + session row count drops to 0 → audit log reflects user.created + user.setup_completed. Three-role middleware enforces band gates; admin is fail-closed default. Setup tokens are sha256-hashed at rest with 1h expiry; expired tokens are swept on the alert engine's 60s tick. Last-admin guard rejects disable + demote of the only enabled admin. Self- service password change at /settings/account is reachable by every role.
This commit is contained in:
@@ -296,8 +296,20 @@ Sizes: **S** = under a day, **M** = 1–3 days, **L** = 3–7 days.
|
|||||||
|
|
||||||
- [ ] **P4-01** (M) Update delivery via OS package managers — host an apt repo (Linux) and Chocolatey package (Windows) on gitea releases. `restic-manager-agent update` is a thin wrapper over `apt-get install --only-upgrade restic-manager-agent` / `choco upgrade`. Trades flexibility for a much smaller security surface than bespoke signed binaries (see spec.md §4.2)
|
- [ ] **P4-01** (M) Update delivery via OS package managers — host an apt repo (Linux) and Chocolatey package (Windows) on gitea releases. `restic-manager-agent update` is a thin wrapper over `apt-get install --only-upgrade restic-manager-agent` / `choco upgrade`. Trades flexibility for a much smaller security surface than bespoke signed binaries (see spec.md §4.2)
|
||||||
- [ ] **P4-02** (M) Agent version reporting on dashboard: surface "agent N versions behind server"; "update all" admin action calls the package-manager wrapper on each host
|
- [ ] **P4-02** (M) Agent version reporting on dashboard: surface "agent N versions behind server"; "update all" admin action calls the package-manager wrapper on each host
|
||||||
- [ ] **P4-03** (M) RBAC enforcement at API layer (admin / operator / viewer)
|
- [x] **P4-03** (M) RBAC enforcement at API layer (admin / operator / viewer)
|
||||||
- [ ] **P4-04** (S) User management UI (create/edit/disable, role assignment, password reset)
|
- [x] **P4-04** (S) User management UI (create/edit/disable, role assignment, password reset)
|
||||||
|
|
||||||
|
> **As shipped (2026-05-05):** Three-role hierarchy (admin > operator > viewer) enforced via chi route-group middleware (`requireRole`). Admin is the fail-closed default; agent endpoints stay on the bearer-token chain. Sessions re-validate `disabled_at` on every authenticated request — admin-driven changes (disable, force-logout) land immediately.
|
||||||
|
>
|
||||||
|
> **Setup-token flow** replaces temp passwords. Admin clicks `+ Add user`, picks username + email + role, server returns a one-time setup link valid for 1 hour (sha256-hashed at rest, raw shown to admin once). User clicks the link → sets a password (≥12 chars) → drops a session → lands on `/`. `/settings/users/{id}/regenerate-setup` issues a new link, replacing the old via INSERT OR REPLACE. Expired tokens are swept on the alert engine's 60s tick.
|
||||||
|
>
|
||||||
|
> **Disable-only lifecycle** — soft delete via `disabled_at`. Last-admin guard rejects "disable last admin" and "demote last admin to non-admin" (both server-side and UI-hinted). Re-enable on disabled-username collision: admin trying to add a name that matches a disabled user is redirected to that user's edit page rather than 409'd.
|
||||||
|
>
|
||||||
|
> **Self-service password change** at `/settings/account` available to any role. Skips current-password check when `must_change_password` is set so admin-initiated resets work without surfacing a credential the user doesn't know.
|
||||||
|
>
|
||||||
|
> **Schema:** migration 0017 adds `email`, `disabled_at`, `must_change_password` plus a UNIQUE INDEX on LOWER(username) (lowercase normalisation in Go on every CreateUser); 0018 adds `user_setup_tokens`. Both column-level ALTERs per CLAUDE.md preference. Email is metadata only in v1 (no SMTP-the-link); the SMTP channel infrastructure from P3-06 makes that a one-page follow-up.
|
||||||
|
>
|
||||||
|
> **Sweep verified (smoke env):** admin adds operator → setup link generated → curl-as-new-user fetches /setup (200, page shows username) → POSTs password → 303 to / + Set-Cookie → operator authenticated → 200 on /, 200 on /settings/account, **403 on /settings/users** (admin-only) → admin disables user → operator's next request is **401** + session row count drops to 0 → audit log shows `user.created` + `user.setup_completed` for the cycle. All 26 implementation tasks landed; full `go test ./...` green.
|
||||||
- [ ] **P4-05** (L) OIDC login (generic provider config, group → role mapping)
|
- [ ] **P4-05** (L) OIDC login (generic provider config, group → role mapping)
|
||||||
- [ ] **P4-06** (M) Repo size trend graphs (sparkline on host card, full chart on repo page)
|
- [ ] **P4-06** (M) Repo size trend graphs (sparkline on host card, full chart on repo page)
|
||||||
- [ ] **P4-07** (S) Per-host tags + dashboard filtering by tag
|
- [ ] **P4-07** (S) Per-host tags + dashboard filtering by tag
|
||||||
|
|||||||
Reference in New Issue
Block a user