3.5 KiB
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 viaSetPasswordHash→ mark claimed → consume generation → session), andPOST /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 allowlistedclaim_lockoutevent. Pre-auth CSRF = HMAC overweb.session_secret(fixes CTRL-007). Min password 12.- Gate wiring (
auth.go/csrf.go/server.go/cmd): gate atopRequireAuth; 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 ACKclaim {hash, generation}into settings.json idempotently by generation (one-way: newer advances; same/older/nil never rewrites; hub outage never clears). Report carriesclaimed(set-only). Hub bakesweb.claim_code_*for gate-from- first-boot.--print-reset-coderoot 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
RotateClaimCodebump 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-sensitiveinternal/backupvolume-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.