docs: v0.123.0 polish batch — CHANGELOG + REPORT + CONTEXT + REUSE (felhomConfirm pattern, new gates)

Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
This commit is contained in:
2026-07-13 08:47:58 +02:00
parent b482860c03
commit df7ad378f4
4 changed files with 106 additions and 43 deletions
+35
View File
@@ -1,5 +1,40 @@
## Changelog
### v0.123.0 — polish batch: F-15 instant reset codes, F-11 inline confirms, Tier-3 "Távoli mentés" rename, zero-toggle honesty (2026-07-13) — MinAgent: 0.81.0
Four independent fixes from the take-two drill + operator review. Live-validated on the drill box
(qm 300 guest 9201) and demo 9201; hub v0.52.0 is the F-15 counterpart (an old hub's bare
reset-request response is a clean no-op — no coupling gate needed).
- **F-15 instant reset codes** (`internal/web/claim.go`): `requestHubResetCode` now parses the
hub's reset-request RESPONSE (`{claim: {code_hash, generation, issued_at}}`, hub ≥0.52.0) and
applies it through the SAME generation-guarded consumer as the report ACK
(`report.ClaimSync.Reconcile`) — the emailed code works the moment it lands instead of after
the next ACK (~15 min; the take-two "Hibás vagy lejárt kód" failure). Replay/older-generation
responses can never downgrade the active hash (guard reused, not reimplemented). Live re-run of
the exact failure path: code applied 1 s after the request, accepted on first try.
- **F-11 inline confirms** (`layout.html` + templates): every native `confirm()` (an OS-modal
that freezes browser automation) replaced by the LIGHT inline two-step — `felhomConfirm(el, q,
onYes)` swaps the trigger in place to "kérdés + Igen/Mégse"; form buttons opt in via
`data-confirm="…"` (submitted with `requestSubmit`, so formaction/name-value survive).
Converted: offbox restore-to-verify, tier2 restore, whole-guest backup, app data migrate,
debug simulate-disconnect + DR trigger, deploy stale-data delete (keeps its DOUBLE
acknowledgement, chained inline). New gate `scripts/native_confirm_gate.py` (zero native
confirm/prompt in templates; red-proven).
- **Tier-3 rename** (`backups.html`, `offbox_handlers.go`, `backup/offbox.go`): customer-facing
"NAS-mentés" branding → **"Távoli mentés"** (the productized target is the Storage Box; the
tier concept is offsite). Manual-target form generalized to any SFTP target ("Cél címe (IP
vagy hosztnév — NAS vagy SFTP-kiszolgáló)", "Tároló útvonala a célgépen"). The "Hálózati
tárhely" NAS network-storage feature keeps its device-truthful wording (different feature).
Python sweep (multibyte rule) + committed gate `scripts/offbox_rename_gate.py` (red-proven).
- **Zero-toggle honesty** (`backup/offbox.go`, `handlers.go`, `backups.html`): a configured +
escrowed offbox with ZERO toggled apps shows "Nincs távoli mentésre jelölt alkalmazás — jelölj
ki legalább egyet." on the toggle list, and a run in that state reports "Sikeres — nincs
mentésre jelölt alkalmazás" via LastWarning instead of bare success (red-proven unit test).
- **Dev-box fix**: `atomicPromoteTar` fsyncs via an O_RDWR handle — read-only fsync is refused on
Windows, which kept the two F7 atomic-dump tests permanently red on the dev box (Linux
behavior unchanged).
### v0.122.0 — customer-claim password gate (closes DRILL-day0-vm F-4/F-5) (2026-07-12) — MinAgent: 0.81.0
The customer sets + OWNS the dashboard password; the old "no password → open dashboard" is gone.
+13 -1
View File
@@ -7,7 +7,19 @@
>
> Ask Claude Code: "Please update CONTEXT.md with what we did today"
Last updated: 2026-07-12 (v0.122.0 — customer-claim password gate)
Last updated: 2026-07-13 (v0.123.0 — polish batch)
> **2026-07-13 — v0.123.0: POLISH BATCH (take-two F-15/F-11 + rename + zero-toggle). MinAgent
> 0.81.0 unchanged; floor 0.122 unchanged. Requires hub v0.52.0 for F-15 (old hub = clean no-op).**
> (1) F-15: the reset-request RESPONSE carries the rotated code hash, applied via the ACK's
> generation-guarded ClaimSync — emailed codes work immediately (live: 1 s, first-try accept).
> (2) F-11: zero native `confirm()` — `felhomConfirm`/`data-confirm` inline Igen/Mégse (layout.html);
> gate `scripts/native_confirm_gate.py`. (3) Tier-3 customer branding is **"Távoli mentés"**
> (NAS-mentés gone; manual form generalized to any SFTP target; gate
> `scripts/offbox_rename_gate.py`; "Hálózati tárhely" feature untouched). (4) Zero-toggle honesty:
> hint + "Sikeres — nincs mentésre jelölt alkalmazás" run copy. Also: `atomicPromoteTar` O_RDWR
> fsync (Windows dev-box green gate was permanently red). Deployed drill qm300 + demo 9201.
> NOT started (separate queued task, operator fork pending): offbox `managed_by` coexistence.
> **2026-07-12 — v0.122.0: CUSTOMER-CLAIM PASSWORD GATE (closes DRILL-day0-vm F-4/F-5). MinAgent
> 0.81.0 unchanged. Requires hub v0.50.0.** The dashboard password is CUSTOMER-OWNED via a one-time
+56 -41
View File
@@ -1,49 +1,64 @@
# REPORT — v0.122.0: customer-claim password gate (closes DRILL-day0-vm F-4/F-5)
# REPORT — v0.123.0: polish batch (F-15 instant reset codes, F-11 inline confirms, "Távoli mentés" rename, zero-toggle honesty)
**Date:** 2026-07-12 · **Version:** controller v0.122.0 (from v0.121.0) · **MinAgent:** 0.81.0 (UNCHANGED) · **Requires:** hub v0.50.0
**Date:** 2026-07-13 · **Version:** controller v0.123.0 (from v0.122.0) · **MinAgent:** 0.81.0 (UNCHANGED) · **Companion:** hub v0.52.0 (F-15 response; old hub = clean no-op) · **Floor:** 0.122 UNCHANGED (no raise in this task)
## What shipped
## What shipped (commits `b4e0a19`, `40b5304`, `8987ce0`, `a00afcc`, `b482860`)
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).
1. **F-15 — reset code works the moment the email lands** (`internal/web/claim.go`). The
reset-request POST now reads the hub's response (`claim {code_hash, generation, issued_at}`,
hub ≥0.52.0) and applies it through the SAME generation-guarded consumer as the report ACK
(`report.ClaimSync.Reconcile` — one consumer, two feeds). Replayed/older generations can never
downgrade the active hash; a legacy hub's bare `{"status":"ok"}` is a no-op.
2. **F-11 — inline confirms** (`layout.html` helper + 7 call sites). `felhomConfirm(el, q, onYes)`
swaps the trigger IN PLACE to "kérdés + Igen/Mégse"; form buttons opt in with `data-confirm`
(delegated listener + `requestSubmit`). Zero native `confirm()`/`prompt()` remain —
enforced by the new committed gate `controller/scripts/native_confirm_gate.py`. The deploy
stale-data delete keeps its double acknowledgement (two chained inline steps).
3. **Tier-3 rename** — customer-facing "NAS-mentés" → **"Távoli mentés"** across `backups.html`,
`offbox_handlers.go` flashes, and the `backup/offbox.go` quota copy; the manual-target form is
generalized to any SFTP target. Executed as a count-guarded python sweep (multibyte rule);
enforced by `controller/scripts/offbox_rename_gate.py`. "Hálózati tárhely" (NAS network
storage) is a different feature and was deliberately untouched.
4. **Zero-toggle honesty** — configured+escrowed offbox with no app selected: muted hint
"Nincs távoli mentésre jelölt alkalmazás — jelölj ki legalább egyet." + the run reports
"Sikeres — nincs mentésre jelölt alkalmazás" (LastWarning; status stays ok).
5. **Dev-box green-gate fix** (`backup.go` `atomicPromoteTar`): fsync via O_RDWR — read-only
fsync is refused on Windows; the two F7 atomic-dump tests were permanently red on the dev box
since CAMPAIGN-3 (Linux unchanged).
- **`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 (all run → FAIL → restored)
## Tests + red-proofs
- `TestResetRequest_ResponseHashAppliedImmediately` (+ generation-guard + legacy-hub no-op
tests). **Red-proof:** response handling disabled → FAIL `gen=1 hash-is-new=false`.
- `native_confirm_gate.py` **red-proof:** one `onsubmit="return confirm('redproof')"`
reintroduced → exit 1; restored → 0.
- `offbox_rename_gate.py` **red-proof:** one 'A NAS-mentés…' flash reintroduced → exit 1.
- `TestOffbox_ZeroToggledRunReportsEmptiness` (+ covered-run negative). **Red-proof:** emptiness
branch disabled → FAIL `LastWarning = ""`.
- Full green gate (build+vet+test, all packages) + template_id/emoji/native_confirm/offbox_rename
gates green before every commit.
- 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 box qm300/guest 9201 + demo 9201, controller 0.123.0 both, healthy)
## Live validation (drill guest 9201 on qm 300, controller 0.122.0, pre-floor)
- **F-15 exact-failure-path re-run:** "Visszaállító kód kérése" on felhom.enkisfelhom.hu/claim →
controller log `claim-sync: hub claim code cached (generation 3)` **1 second** after the POST →
Viktor entered the emailed code: **accepted immediately, first try** (take-two failure closed).
- **F-11 automation-completes proof:** offbox restore-to-verify driven END-TO-END by browser
automation — inline strip rendered, Igen → restore ran ("A távoli visszaállítás elindult…",
banner "Távoli visszaállítás folyamatban: actualbudget…"), zero freezing.
- **Rename:** /backups renders with ZERO 'NAS-mentés' strings (screenshots in session record);
only the allowlisted "saját NAS vagy Felhom offsite tárhely" intro mention remains.
- **Zero-toggle:** untoggled ActualBudget → hint appeared → run → "Sikeres — nincs mentésre
jelölt alkalmazás" + status Rendben → re-toggled (box left as found).
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.
## Observations
- The queued **customer-target coexistence** task (`managed_by` on OffboxTarget) remains a
SEPARATE task with a pending operator fork — not started, per spec.
- NAS-string inventory beyond backups.html: the two customer-facing quota strings in
`internal/backup/offbox.go` (renamed here); everything else is the distinct "Hálózati tárhely"
feature or English comments/tests (untouched by design).
- Windows-only pre-existing failure found+fixed: read-only-handle fsync in `atomicPromoteTar`
(the F7 tests were red on the dev box, green on Linux — a silent hole in the local green gate).
- Browser-automation note: `find`-ref clicks on plain submit buttons focused but did not submit
(coordinate clicks did); the data-confirm buttons worked via refs. Cosmetic, tooling-side.
+2 -1
View File
@@ -207,7 +207,8 @@ Cross-repo edges:
- **New REST endpoint**: path dispatch in `Router.ServeHTTP` (controller/internal/api/router.go); use `writeJSON` + `limitBody`.
- **New background job**: `sched.Every`/`sched.Daily` registration block in controller/cmd/controller/main.go.
- **New template function**: `Server.templateFuncMap` (controller/internal/web/funcmap.go) — obey v2 state-suffix vocabulary.
- **New page/nav item**: `baseData` + sidebar in controller/internal/web/templates/ (nested sub-links pattern `.nav-links-nested`); must pass `controller/scripts/template_id_gate.py` + `controller/scripts/emoji_gate.py`.
- **New page/nav item**: `baseData` + sidebar in controller/internal/web/templates/ (nested sub-links pattern `.nav-links-nested`); must pass `controller/scripts/template_id_gate.py` + `controller/scripts/emoji_gate.py` + `controller/scripts/native_confirm_gate.py` + `controller/scripts/offbox_rename_gate.py`.
- **Consequential-action confirm (LIGHT)**: `felhomConfirm(el, question, onYes)` in layout.html (v0.123.0) — the trigger swaps in place to "kérdés + Igen/Mégse"; form buttons opt in with `data-confirm="…"` (delegated listener, `requestSubmit` keeps formaction/name-value). NEVER native `confirm()`/`prompt()` (OS-modals freeze browser automation — drill F-11; `native_confirm_gate.py` enforces). Heavy destructive flows keep the `.confirm-overlay` `openDialog` pattern.
- **New hub event**: typed `Notify*` wrapper on Notifier + hub allowlist entry (cross-repo).
- **New app integration**: `integrations.Manager.RegisterHandler` with `IntegrationKey(provider, target)`.
- **New startup self-check**: append check fn in `selftest.Run` (controller/internal/selftest/selftest.go).