50 lines
3.5 KiB
Markdown
50 lines
3.5 KiB
Markdown
# REPORT — v0.122.0: customer-claim password gate (closes DRILL-day0-vm F-4/F-5)
|
|
|
|
**Date:** 2026-07-12 · **Version:** controller v0.122.0 (from v0.121.0) · **MinAgent:** 0.81.0 (UNCHANGED) · **Requires:** hub v0.50.0
|
|
|
|
## What shipped
|
|
|
|
The dashboard password is now **customer-owned**, set through a one-time claim code the hub emails
|
|
to the registered address. The old "no password → open dashboard" default is gone: a fresh box
|
|
(claim-code hash delivered, no password) serves ONLY the claim page — every other route answers the
|
|
claim page (`302 → /claim`) or `401` (API). This closes the DRILL-day0-vm F-4 exposure (every Day-0
|
|
dashboard was open on the internet, with the full deploy API = RCE-equivalent) and F-5 (the
|
|
unauthenticated geo toggle is now behind the gate too).
|
|
|
|
- **`internal/web/claim.go`** — `claimGateActive()` / `effectiveClaimCode()` (ACK-cached settings
|
|
beats the config bake by generation), the claim page (`GET /claim`), submit (`POST /claim`:
|
|
verify code → set own password via `SetPasswordHash` → mark claimed → consume generation →
|
|
session), and `POST /claim/request-new-code` (forwards to the hub reset-request). Code checks:
|
|
bcrypt match AND generation-not-consumed (single-use) AND ≤ 72 h. Per-source + global limiter (5
|
|
→ 15-min lockout) raising the allowlisted `claim_lockout` event. Pre-auth CSRF = HMAC over
|
|
`web.session_secret` (fixes CTRL-007). Min password 12.
|
|
- **Gate wiring** (`auth.go`/`csrf.go`/`server.go`/`cmd`): gate atop `RequireAuth`; a SET password
|
|
disables it (auth wins — claimed boxes never regress). `/claim*` + `/static/*` reachable pre-auth.
|
|
Legacy-open (no password, no hash) → red transition banner (`layout.html`). Login "Elfelejtett
|
|
jelszó" link.
|
|
- **`internal/report/claim_sync.go`** — caches the ACK `claim {hash, generation}` into settings.json
|
|
idempotently by generation (one-way: newer advances; same/older/nil never rewrites; hub outage
|
|
never clears). Report carries `claimed` (set-only). Hub bakes `web.claim_code_*` for gate-from-
|
|
first-boot.
|
|
- **`--print-reset-code`** root escape hatch (one-time local code above cached/baked/consumed gen).
|
|
|
|
## Tests + red-proofs
|
|
|
|
- Gate-coverage signature test (`TestClaimGate_EveryRouteGated`): every route → claim page/401, a
|
|
deploy POST reaches no handler. Plus happy-path / reuse-refused / expired / lockout+window-reopen
|
|
(fake clock), legacy-open vs password-set, claim-sync idempotence.
|
|
- **Four §10 red-proofs proven** (mutate → FAIL → revert → green): (1) gate skip-line, (2) single-use
|
|
generation — hub `RotateClaimCode` bump AND controller consumed-generation check, (3) reset
|
|
non-DoS (clearing claimed → fail), (4) rate-limiter (both scopes disabled → fail).
|
|
- Green gate: `go build ./... && go vet ./...` clean; all touched packages pass. Pre-existing
|
|
env-sensitive `internal/backup` volume-dump failures are unrelated (fail identically on the clean
|
|
baseline — no tar/zstd toolchain on the dev box).
|
|
|
|
## Live validation (drill guest 9201 on qm 300, controller 0.122.0, pre-floor)
|
|
|
|
Deployed 0.122.0 → the ACK delivered the claim hash → gate flipped ON within a report cycle. Proven
|
|
via the REAL Cloudflare edge (`curl --resolve`): `/` → 302 → "A szerver beállítása" claim page;
|
|
`/claim` → 200; `/api/host-metrics` → 401. Controller log: `claim-sync: hub claim code cached
|
|
(generation 1)`. Hub log: claim code emailed to the registered address of demo-vm-felhom. The
|
|
customer-side claim + reset + the floor raise are the operator's supervised steps.
|