v0.207.0 — R-249: the retrieval passphrase leaves the page body; R-252/R-253: two refusals learn to say what to do
gates / gates (push) Successful in 18s

R-249. settings_security.html rendered the passphrase into a display:none
span behind a Megjelenit button. That toggle stops a browser DRAWING the value
and nothing else — the plaintext was in the response body of every render, so a
curl of the page returned it. Found by exactly that: it landed in a session
transcript while driving the documented rebuild path.

The codebase already stated this rule for the recovery code and this page did not
follow it (escrow_handlers.go: 'reveal (claim XHR only — R is NEVER templated
server-side into HTML)'). The page now carries only HasRetrievalPassword; the
value comes from POST /settings/retrieval-password/reveal — CSRF-covered because
POST, no-store, and LOGGED as an act, which reading it off the markup never was.

The tests assert the RAW RESPONSE BODY. Every test that asked what the customer
sees passed while the bytes carried the secret; that is why this survived.

Census: the render-then-hide pattern appears twice more — app_info.html (a real
per-install app password in a hidden span) and deploy.html. Filed as R-254, NOT
fixed here.

R-252. A rebuilt box keeps its drives but loses their REGISTRATION. The restore
page now states that before the customer presses anything, says the backups and
drives are both still there, and links to Tarhely > Meghajtok. Page and resolver
ask ONE question — HasRestoreDestination() reads the same
GetSchedulableStoragePaths() the scratch resolver reads.

R-253. The list promised 'a visszaallitas elobb ujratelepiti' three lines above a
refusal that fired BECAUSE the app was not installed. The promise was the wrong
half: reconstitution writes to the app's own GetStackHDDPath, which exists only
once the CUSTOMER has chosen a drive at deploy time. Auto-reinstalling would mean
the product making that choice for them. Copy now says to install first and routes
to /stacks/<app>/deploy.

Both notices are conditional — a healthy box renders as before, pinned by a test
that fails if either becomes unconditional.
This commit is contained in:
2026-08-07 18:04:26 +02:00
parent 3d3b4496f3
commit 8dbbc98ff2
14 changed files with 554 additions and 15 deletions
+11
View File
@@ -160,6 +160,15 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated
snapshots sat in the repository. Installed-ness is a property OF a row (it changes what restoring
implies), never a filter on it; an unreadable store renders as UNKNOWN and keeps the action; the
`felhom-offbox` and `_shares` marker tags are never offered as apps.
**Its two preconditions now name a reason AND a route (v0.207.0, R-252/R-253):** a rebuilt box keeps
its drives but loses their REGISTRATION, so the page renders a notice — *„Előbb csatold vissza az
adatmeghajtót"*, linking to `/storage` — whenever `HasRestoreDestination()` is false, asked through
the backup manager's own predicate so page and resolver read the same `GetSchedulableStoragePaths()`.
And the not-installed row no longer promises *„a visszaállítás előbb újratelepíti"*: reconstitution
writes to the app's own `GetStackHDDPath`, which exists only after the customer picks a drive at
deploy time, so the copy says to install it first and links to `/stacks/<app>/deploy`. **Both notices
are conditional** — a healthy box renders exactly as before, pinned by a test that fails if either
becomes unconditional.
**A run that skipped a selected app is `incomplete` (v0.205.0, R-234):** the off-site verdict now
counts `missingUnprotected` beside `mandatoryGaps` — an app the customer selected that is DEPLOYED
but has no recovery unit is not protected, so the run is not `ok`. A selected-but-UNDEPLOYED app is
@@ -2537,6 +2546,8 @@ During setup wizard drive scan, both current and historical backups are discover
Generates `recovery-info.txt` on the system data partition with customer ID, Hub URL, retrieval password, and recovery instructions in Hungarian. Updated on startup and after config changes. Also displayed on the Settings page in a "Vészhelyzeti információk" section.
**The retrieval passphrase is NOT rendered into that page (v0.207.0, R-249).** `securityPageData` passes only `HasRetrievalPassword` (a boolean), and the value is fetched by an explicit act: **`POST /settings/retrieval-password/reveal`** → `{"ok":true,"data":{"password":"…"}}`, behind RequireAuth + CsrfProtect like every other POST, `Cache-Control: no-store`, and logged (`retrieval passphrase revealed via the security page from <ip>` — the value is never logged). Until v0.207.0 the page rendered the plaintext into a `display:none` span, so any fetch of the page returned it; the toggle was cosmetic. This follows the rule `escrow_handlers.go` already states for the recovery code: a secret is revealed by an XHR, never templated server-side into HTML.
### 11. Disaster Recovery
When a system drive fails and is replaced, the recovery flow uses the setup wizard: