d124c77e17
gates / gates (push) Successful in 21s
The tier-3 pause is the zero-knowledge escrow design and is untouched. What was missing was the ASK, while the backup page promised the copy that had never run. - VOLUNTEER-first-hour.md: a new step 6, right after the dashboard password and before the first app - what the code is, where, write it on PAPER, and that Felhom cannot get it back for them. Sections 6..12 renumbered to 7..13. - day0-install.md A.2b: the operator step for a REBUILT box, which was missing. Acknowledged delete -> the hub re-issues by itself; otherwise ONE press of "Re-issue PBS credentials" (F-14 ruling 2026-07-13, hub/internal/web/pbsdr.go). This is the correction to last night's "zero presses" note. - 07-backup-architecture.md: 6.1 records tier-3's paused state as a DESIGN, and 2 records that the household is asked from first login. - capability map: the first-hour row's last gap closed, with what it still does not claim (no volunteer has walked the ask from the written guide). - register: R-543 CLOSED with the live measurements; R-545 filed (nothing un-configures an off-site target). R-511 was already closed yesterday. - STATUS: the answered publish question removed (1.28.0 is live), readiness yes. - evidence: red-proofs, the two-box live validation, teardown on three layers, and both of my own mistakes in this session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
131 lines
8.7 KiB
Plaintext
131 lines
8.7 KiB
Plaintext
## R-543 live validation — controller v0.245.0, 2026-09-16, demo-hp
|
|
## Method: endpoint-level. Every request below is the exact request the browser makes (same handler,
|
|
## same session cookie, same CSRF); only rendering is skipped. claude-in-chrome is not available here.
|
|
## Reachability note: neither guest answers on its LXC address from DooPlex, and the controller does
|
|
## not listen on the guest's 127.0.0.1 — it answers on the container address 172.17.0.2:8080 with the
|
|
## mandatory Host header. All requests therefore run INSIDE the guest via `pct exec`.
|
|
## Secrets: the dashboard password was read with scripts/read_credential.py (value never printed,
|
|
## file->file, 0600) and passed to curl as --data-urlencode password@<file>.
|
|
|
|
### THE SEAM, STATED
|
|
The two halves of this proof are on two boxes, not one box before and after a ceremony:
|
|
* PAUSED half — guest 9202 (scratch), off-site configured and escrow NOT complete.
|
|
* ESCROWED half — guest 9201 (demo), off-site configured, escrowed, running.
|
|
Running a real escrow ceremony on a fresh target would provision off-site storage, and this task's
|
|
fences put ep0 out of bounds. So the escrowed side is OBSERVED on a box that is already escrowed
|
|
rather than produced here. What is NOT weakened by the seam: both boxes run the same binary
|
|
(0.245.0), and the paused box's state was produced through the product's own configuration endpoint.
|
|
|
|
## ── 1. ESCROWED + ACTIVE — guest 9201 (0.245.0) ────────────────────────────────────────────────
|
|
login OK
|
|
GET /dashboard -> 200 bytes=60816 escrow-bar-hits=0
|
|
GET /launcher -> 200 bytes=44462 escrow-bar-hits=0
|
|
GET /backups/apps -> 200 bytes=106304 escrow-bar-hits=0
|
|
tier-1 file sentence, as rendered (2 class-A apps):
|
|
"Az alkalmazás fájljait a távoli másolat (és a második meghajtó) védi — ez a helyi mentés a
|
|
beállításokat és az adatbázist tartalmazza."
|
|
word counts on /backups/apps: Kulcslet=0 szünetel=0 védi=2 védené=0
|
|
=> a box whose recovery code exists is NOT nagged, and the promise it prints is a true one.
|
|
|
|
## ── 2. PAUSED — guest 9202 (0.245.0) ───────────────────────────────────────────────────────────
|
|
The state was produced through the product's own endpoint, POST /backup/offbox/config, with a
|
|
throwaway ed25519 key and a pinned known_hosts line. 9202 has no agent local API, so the escrow
|
|
STAGE could not run — the handler said so and saved the target anyway:
|
|
|
|
POST /backup/offbox/config -> 302
|
|
flash: "A távoli mentési cél elmentve. — a kulcs letéti előkészítése nem sikerült
|
|
(az ügynök nem elérhető); próbáld újra."
|
|
|
|
Persisted state afterwards (read from the guest's own settings.json):
|
|
enabled=True host=192.168.0.162 repo_path=/mnt/nvme-1tb/r543-paused-proof
|
|
escrow_state=pending last_run=None last_status=None snapshot_count=None
|
|
data/offbox/: known_hosts 95 B (0644) | repo_password 64 B (0600) | ssh_key 411 B (0600)
|
|
=> OffboxConfigured() is genuinely true (valid target + both secret files), and the escrow is NOT
|
|
complete. This is the state a fresh box lands in on day one.
|
|
|
|
### 2a. The bar is on EVERY page, not on the three someone remembered
|
|
GET /dashboard -> 200 escrow-bar-hits=1
|
|
GET /launcher -> 200 escrow-bar-hits=1
|
|
GET /backups/apps -> 200 escrow-bar-hits=1
|
|
GET /settings -> 200 escrow-bar-hits=1
|
|
GET /apps -> 404 escrow-bar-hits=0 (no such route; a 404 carries no bar)
|
|
|
|
Quoted from /dashboard:
|
|
"A távoli mentés szünetel, amíg nem hozod létre a helyreállítási kódot."
|
|
<a href="/backup/escrow"> (the route out, on the bar itself)
|
|
|
|
### 2b. A manual off-site run, while paused — refused, FOR THE RIGHT REASON
|
|
POST /backup/offbox/run -> 302
|
|
flash: "A távoli mentés a kulcs letétbe helyezésére vár."
|
|
after the attempt: last_run=None last_status=None snapshot_count=None
|
|
=> No snapshot, and the refusal came from the fork-4 escrow gate (offbox_handlers.go:224
|
|
OffboxRunnable), NOT from an unreachable target — the target was never contacted. This matters:
|
|
a run that failed to connect would have proven nothing about the pause.
|
|
|
|
### 2c. „Most nem" is for the visit only
|
|
POST /backup/escrow/banner/dismiss -> 302
|
|
Set-Cookie: felhom_escrow_banner=1; Path=/; HttpOnly; SameSite=Lax
|
|
^ no Max-Age and no Expires => a browser SESSION cookie, exactly as R-241 does it
|
|
same visit, cookie sent -> escrow-bar-hits=0
|
|
next visit, no cookie -> escrow-bar-hits=1
|
|
=> the off-site tier is still paused tomorrow, so the question is still asked tomorrow.
|
|
|
|
### 2d. The tier-1 FILE sentence, live, with the tier paused
|
|
The first pass of this phase could not show it: 9202 had no class-A app, so the sentence had nothing
|
|
to render („védi"=0 AND „védené"=0 — the „szünetel"=1 on that page was the BAR in the layout, not the
|
|
sentence). Recorded because it was briefly written down as a limit and it was not one. A throwaway
|
|
class-A app was then deployed on the box's own drive and the off-site copy turned on for it:
|
|
|
|
POST /api/stacks/calibre-web/deploy -> 202 {"ok":true,"message":"Telepítés elindítva ..."}
|
|
(HDD_PATH=/mnt/felhom-drives/scratch_hdd — the guest's own registered data drive, 938 G)
|
|
POST /backup/offbox/toggle app=calibre-web enabled=true -> 302
|
|
|
|
Rendered on /backups/apps, with the tier configured and PAUSED:
|
|
|
|
"Az alkalmazás fájljait a távoli másolat védené — a távoli mentés a helyreállítási kód
|
|
létrehozásáig szünetel."
|
|
...followed by the route: "Helyreállítási kód létrehozása →"
|
|
|
|
word counts on /backups/apps: Kulcslet=1 szünetel=3 védi=0 védené=1
|
|
Kulcslet=1 is the tier-3 row's own state („Kulcsletétre vár").
|
|
szünetel=3 is the bar + the sentence + the tier row.
|
|
védi=0 is the point: the page no longer claims a protection that has never run.
|
|
|
|
=> Both wordings are now observed LIVE on real boxes running 0.245.0: „védi" on the escrowed box
|
|
(9201, §1) and „védené … szünetel" on the paused box (9202, here).
|
|
|
|
## ── 3. TEARDOWN, three layers ──────────────────────────────────────────────────────────────────
|
|
Recorded after the evidence above was already written to DooPlex (R-320: evidence leaves the machine
|
|
at the END OF THE PHASE, before any revert — not at the end of the session).
|
|
|
|
MACHINE (guest 9202, scratch):
|
|
* the throwaway class-A app removed WITH its data and its backups:
|
|
POST /api/stacks/calibre-web/stop -> 200
|
|
POST /api/stacks/calibre-web/remove -> 200 {"removed":"calibre-web",
|
|
"volumes_removed":["calibre-web_calibre_web_config"],"hdd_paths_removed":[],
|
|
"hdd_note":"Az alkalmazás nem tárolt saját adatot…"}
|
|
verified after: containers named calibre = 0, drive folders = 0
|
|
* the off-site target this proof created is GONE:
|
|
before: offbox present=True, data/offbox/ held ssh_key, repo_password, known_hosts
|
|
after : offbox present=False, data/offbox/ ABSENT, all three files `shred -u`'d
|
|
MY OWN MISTAKE, recorded: the first teardown pass used the CONTAINER's view of the data path
|
|
(/opt/docker/felhom-controller/data) from a shell running in the GUEST, where that path does
|
|
not exist. It printed „offbox dir now: ABSENT" — which was TRUE of a path that never existed
|
|
and FALSE of the thing being claimed. The target was still fully configured. The same wrong
|
|
path had already produced three FileNotFoundError tracebacks earlier in this phase; I read
|
|
those as noise instead of as the instrument telling me it was pointed at nothing. The re-run
|
|
stops the controller first, edits the real file, shreds the secrets, restarts, and RE-READS
|
|
the state to confirm — a teardown asserted is not a teardown observed.
|
|
* controller restarted and healthy: felhom-controller:0.245.0 Up (healthy)
|
|
* temp files: none left (`ls /tmp/.r543*` empty in the guest)
|
|
* NOT touched: filebrowser, traefik, the box's registered data drive, its password, its claim state.
|
|
|
|
HOST (demo-hp): /tmp/.r543pw and /tmp/.r543key shredded; .r543kh, the scripts and one stray
|
|
/tmp/.r543out removed. Verified: 0 files matching /tmp/.r543* remain.
|
|
|
|
HUB: provisioned nothing. Guest 9202 has hub reporting OFF and no tunnel, so no customer, no host
|
|
record, no escrow row and no event was created by any of this. Nothing to tear down.
|
|
|
|
NOT torn down, deliberately: guest 9201 now runs controller 0.245.0. That is the release being
|
|
shipped, not a drill artifact, and its own off-site tier was never touched (still escrowed, active).
|