app guides night: R-1089..R-1092 (found writing the guides), R-1088 extended; read_credential.py refuses to overwrite the credentials file (red-proved); STATUS; batch evidence
gates / gates (push) Successful in 6m57s

Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-15 23:25:53 +02:00
parent 3eca98f135
commit 08cf15d8cd
129 changed files with 9032 additions and 2 deletions
+6 -2
View File
@@ -124,11 +124,15 @@ stopping line that lies.
| **R-494** | Install & onboarding | P4 | **NARROWED 2026-09-14 by operator ruling → [P3-LOW] the hub COULD create the tunnel at customer creation, for a domain already on Cloudflare. Not blocking: every customer has their own domain and the operator creates the tunnel per day-0 A.1 (`architecture/01-topology-and-trust.md`).** *Original finding, kept:* **[P1-HIGH] A new customer's dashboard has NO reachable address unless the operator hand-makes a Cloudflare tunnel — the link in the setup-code mail is dead.** MEASURED 2026-09-14 on a fresh install from the public ISO (drill intervention **I1**): the claim mail points at `https://felhom.drill0242.felhom.eu`; that name has **no A and no AAAA** record (`dig @1.1.1.1`, control `felhom.enkisfelhom.hu` resolves); the hub has **no tunnel- or DNS-creation code** (`hub/internal/cloudflare/` holds only geo-rule removal; `cf_tunnel_token` is a pasted, optional form field, `configs.go:1478`) — day-0 runbook A.1 makes it a manual Cloudflare-dashboard step that nothing on the customer-create page asks for; the box's own split-horizon resolver on the appliance LAN IP answered `google.com` but not the dashboard name at 13:27:39Z; the agent applied the record at **13:27:44Z** (`lanresolver: applied split-horizon record … ip=192.168.0.158`, 3 m 46 s after the controller started), so the box CAN answer the name — **but only to a device that uses the box as its DNS server, and no document, screen or mail tells a household to do that**; the router and the installer-offered DNS answer nothing. The page was reachable only at the guest's LAN address with the name forced (`curl --resolve …:443:192.168.0.158`). **A volunteer could not have done that.** **What it needs:** an operator ruling — the hub creates the tunnel and DNS at customer creation, or the product gives a household a LAN address that works with no DNS change. | **READY — rank P3-LOW; owner: CC** **Re-ranked 2026-10-03: P3→P4: operator-side automation; the operator creates the tunnel by hand per the day-0 runbook.** | — | — | CC |
| **R-504** | Install & onboarding | P4 | **[P3-LOW] `iso.felhom.eu` cannot show an index page on its own — its root returns 404, and the download page lives on the website instead.** MEASURED 2026-09-14: `https://iso.felhom.eu/` and `/index.html` → 404; only named objects answer. The host is an R2 bucket behind a custom domain; whether R2 would serve an uploaded `index.html` at `/` was **not measured** (uploading anything to the public bucket is a publication). The ISO v1.27.0 task puts the Hungarian download page at `felhom.eu/letoltes` (published with the ISO, after the operator's yes). **Remaining:** a redirect from `iso.felhom.eu/` to that page needs a Cloudflare rule the session has no credential for. | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator (Cloudflare rule)** **Re-ranked 2026-10-03: P3→P4: households are sent to the website's download page; the bare address is cosmetic.** | — | — | operator |
## Apps & catalog — 17 rows (P2 2, P3 9, P4 6)
## Apps & catalog — 21 rows (P2 3, P3 11, P4 7)
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
| **R-1086** | Apps & catalog | P2 | **qBittorrent's first steps tell the household to set their own password — and the box's media wiring logs in with the INSTALL password, so after that change Sonarr and Radarr stop getting their downloads handed over and a safe drive removal cannot pause its torrents.** FOUND 2026-10-15 night writing the qBittorrent guide; static, not yet reproduced. `templates/qbittorrent/.felhom.yml` first_steps[1] (set your own password on the Web UI settings page); felhom-controller `internal/mediawire/mediawire.go:124` (the wiring), `:437` (the Sonarr/Radarr client entry), `:757` and `:828` (pause/resume on safe removal) all read `QBT_ADMIN_PASSWORD` from the container env, and the template seeds no login bypass for the Docker network. Transmission has the same shape (`trPW`). Second fault in the same sentence: the qBittorrent Web UI starts in ENGLISH (the image sets no language — its env holds only PATH, read 2026-10-15), so the labels are „Options” and „WebUI”, not the Hungarian words the step quotes. The guide written tonight says nothing about the password. | OPEN — filed 2026-10-15 | Operator: (a) the copy stops advising a password change — the generated one is long, random and shown on the dashboard; or (b) the box asks for the changed password (an after-start field) | Reproduce on 9202 (change it, press „Bekötés most”, read Sonarr's client test), then (a) or (b) | CC |
| **R-1089** | Apps & catalog | P2 | **RomM may never find the household's games: the first steps put them where the scan probably does not look.** FOUND 2026-10-15 night writing the RomM guide, from RomM 5.3.1's source — NOT measured. RomM's default layout is `library/roms/<platform>/<game>`; the compose mounts the drive's `userdata/roms` as `/romm/library`, so the first steps' `roms/gba/`, `roms/snes/` land at `library/gba`, outside the scan's `library/roms`. The same first steps send the household to a „Settings" menu and a left-hand „Scan" the new default UI (5.3.1) no longer has (both are in the profile menu now), and the compose comment's default login `admin / admin` is stale (the first run asks for a password). The guide written tonight gives no folder path. Draft and source note: `audits/app-guides-2026-10-15/B/romm-labels.txt`. | OPEN — filed 2026-10-15 | — | On 9202: install RomM, put one legal ROM where the first steps say, scan, read the library; then fix the path (copy or compose) and the two labels | CC |
| **R-1090** | Apps & catalog | P3 | **Ghost may lock a household out of its own blog on a second device: new-device sign-in asks for a code by e-mail, and the box wires no e-mail for Ghost.** FOUND 2026-10-15 night from Ghost 6.67.0's source (`ghost/core` defaults: `security.staffDeviceVerification: true`) — NOT measured. The same missing mail makes staff invitations and newsletters impossible; the guide leaves those out and says so. Related: the first-admin audit already marks Rallly and Outline sign-in as needing e-mail (`app-catalog-felhom.eu/FIRST-ADMIN.md`). | OPEN — filed 2026-10-15 | — | On 9202: set Ghost up, sign in from a second browser, see whether a code is asked; if so, switch the app's e-mail on or set the flag off in the template | CC |
| **R-1091** | Apps & catalog | P3 | **Catalog copy that is wrong or stale at the pinned tag, found writing the guides — each needs an operator word or a live check, so none was changed tonight.** From source at each app's tag (evidence per app in `audits/app-guides-2026-10-15/B/`): (1) **calcom** use_case and first_steps promise Google Calendar / Outlook sync — the compose sets neither app's keys, so only Apple Calendar and CalDav are offered (a promise, so the operator's); (2) **bentopdf** tagline and use_case say files are processed „on the server" — they are processed in the browser, and some tools load code from a public CDN (a privacy promise, so the operator's); (3) **sabnzbd**, **nzbget** use_cases say Radarr/Sonarr/Jellyseerr hand them jobs — the box wires only qBittorrent and Transmission (`mediawire.go`), and a hand link needs a path mapping; (4) **onlyoffice** first_steps 3–4 tell the household to wire Nextcloud by hand — the integration toggle does it (`internal/integrations/onlyoffice_nextcloud.go`); (5) **glance**, **homepage** first_steps send the household into config files in a Docker volume no household tool reaches; (6) **lubelogger** starts with only the „Dashboard" tab and in miles (shipped `appsettings.json`), so first step 3 cannot be done as written; (7) **home-assistant** first_steps promise auto-discovered devices — the app runs on a Docker bridge, where mDNS/SSDP were measured deaf (spike R-6); (8) **homebox** and **gitea** `add_people` name menus that moved or read differently at the tag; **bookstack** `default_creds` still says `admin@admin.com / password`, which after_install replaces; **dawarich** names the API key's page „Settings" (source suggests the account page); **code-server** says „install your tools" with no sudo; **komga** names the discontinued Tachiyomi; **seerr** `docs_url` points at Overseerr; **wanderer**'s comment still says it cannot close sign-up (R-714 is fixed in the same file); (9) **nzbget** and **grafana** deploy-field descriptions say the password can be changed later — nzbget re-applies its env password at every start and grafana ignores the field after first start (R-1086 is the qBittorrent/Transmission side). | OPEN — filed 2026-10-15 | Operator: (1) and (2) are promises — reword to what is true? | Live-check (5)–(7) and (9) on 9202; fix (3), (4), (8) as copy with the freeze re-admitted; re-run the guide label check for any app whose copy moves | CC |
| **R-1092** | Apps & catalog | P4 | **Three apps show no guide: plant-it and home-assistant carry one HIDDEN (`checked_version: ""`), emby has none.** plant-it: `lifecycle: abandoned`, and its pinned image does not exist upstream, so there is no screen to check labels against. home-assistant: its frontend follows the browser language and the Hungarian strings are fetched at build time, not kept in git, so the Hungarian labels cannot be checked against source (the draft is written; the shipped frontend in the image could check them). emby: its server's web UI is in no public source at 4.11.0.4. Evidence: `audits/app-guides-2026-10-15/B/`. The other 62 templates show a checked guide (controller ≥ 0.315.0). | OPEN — filed 2026-10-15 | — | home-assistant: check the Hungarian labels against the frontend files in the pinned image (read-only, on a box running it), then set checked_version; emby: label-check against the image's own web files the same way; plant-it: nothing while abandoned | CC |
| **R-981** | Apps & catalog | P3 | **The homepage app gets the Docker socket (that is root in the guest) and has no login, no setup gate and no family gate.** Fix: remove the socket mount, or put homepage behind the family gate. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN | — | Change the catalog template; prove on 9202 | CC |
| **R-971** | Apps & catalog | P2 | **A change pushed to the catalog's `main` reaches the installed apps on every box within about 15 minutes, and nothing on the box refuses dangerous container settings (privileged mode, the Docker socket, host mounts, host namespaces); so whoever can push to the catalog repository can take every guest.** Design-shaped: installed apps take catalog fixes on purpose. Decision for the operator in `STATUS.md`. Fix options: a privilege allow-list check on the box before any compose is written (and in catalog CI), and later signed catalog releases. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | WAITING-ON-OPERATOR — confirmed by a second reader | operator decision | Decide; then build the box-side check | operator |
| **R-676** | Apps & catalog | P3 | **[P3-LOW] Watch: immich's first start restarted 12 times — decision 28's crash-loop stop (6 in 10 min) would stop it.** From the 2026-09-17 chaos night (DB connection dropped during the first-start geocoding import on a 6 GB guest; it did not recover that night). No healthy app in any drill evidence restarts on a first start (1831 samples, 40 live containers), so the threshold stands; this row exists so the first immich install under v0.269.x is watched. `audits/night-2026-09-24/A3/40-first-start-restarts.txt` **2026-09-25 night (read from source, v0.271.0): a DEPLOY's first start is NOT covered by decision 28's suppression** — `Deploying` clears when `compose up -d` returns (`deploy.go` "Clear deploying flag"), and `ObserveUnhealthy` then samples the app; an automatic update's step, verify and undo ARE covered (`Updating`, pinned by `TestD28_NoCrashLoopStopDuringAnAutomaticStep`). So a first start that restarts ≥ 6 times in 10 min is stopped — which R-676 already accepts for a broken first start; a healthy slow first start would be stopped too. **-- 2026-09-30: the first-start restarts are explained.** immich's first-start geodata import OOM-kills its database at 512M on a guest with no swap (R-732, measured: 61–104 kills); the 2026-09-17 chaos-night case (DB connection dropped during the import on a 6 GB guest) fits it. Fixed in the catalog (`56c4888`, 768M). The watch itself (decision 28 on a DEPLOY's first start) is unchanged. | **OPEN — P3; owner: CC (watch)** | — | — | CC |
@@ -216,7 +220,7 @@ stopping line that lies.
| ID | Category | Sev | What | State | Blocked on | Next action | Owner |
|---|---|---|---|---|---|---|---|
| **R-1033** | Security & access | P1 | **Every box answers its public names over plain `http://` — login pages included.** MEASURED 2026-10-14 from DooPlex over the public path (Cloudflare `Server: cloudflare`, `CF-RAY`): `http://felhom.enkicsifelhom.hu/login` → 200, `http://felhom.enkisfelhom.hu/login` (demo-hp) → 200, `http://torrent.enkicsifelhom.hu/` → 200; no redirect to https and no `Strict-Transport-Security`. Sonarr, Radarr and Prowlarr make it worse: their sign-in redirect is ABSOLUTE `http://<name>/login`, so a household that opened the https address lands on the plain page and sends its password unencrypted between the browser and Cloudflare (`audits/media-all-drives-2026-10-14/H-indexer-sync-ncore.txt`). On an untrusted network (café Wi-Fi) that password can be read. The operator may raise this to P1. | **NARROWED** — filed 2026-10-14; **P1 by the operator 2026-10-14 22:13 (`09` §3 decision 244)**. FIXED in controller v0.312.0 (traefik sends every `http://` to `https://`, 301, path and query kept; HSTS one day; decision 246) and PROVEN on Tester 1, demo-hp and demo-felhom (29 public names, `scripts/https_only_check.py`; https answers unchanged), delivered by hand. Open: the fleet delivery — vouch 0.312.0 and the floor (morning); Tester 2 (`sajatfelhom.hu`, 0.292.0, off) gets it with the floor | the operator's vouch + floor | Vouch controller 0.312.0, raise the floor; then run `scripts/https_only_check.py` on every box and close | CC |
| **R-1088** | Security & access | P2 | **CC's credentials file was overwritten with one token, and that token was printed once into a session transcript.** 2026-10-15 22:03 (local): a CC session called `scripts/read_credential.py HUB_TOKEN ~/.config/credentials` — the second argument is the OUTPUT file, so the reader wrote the hub token over the whole file; every other key (dashboard passwords, the box passwords) is gone from DooPlex. At 20:43 UTC the storage-identity build B session listed the file's „key names" with `sed 's/=.*//'`; the file had no `=`, so the token itself was printed into that session's transcript. The token is CC's scoped hub token (floor only; no secrets, no deletes). | OPEN | Operator: rotate CC's hub token; restore `~/.config/credentials` from the password manager. | Rotate the hub token (`05` §17); restore the file; make `read_credential.py` refuse an output path equal to its credentials file (a red-proved test in `scripts/test_read_credential.py`). | Operator |
| **R-1088** | Security & access | P2 | **CC's credentials file was overwritten with one token, and that token was printed once into a session transcript.** 2026-10-15 22:03 (local): a CC session called `scripts/read_credential.py HUB_TOKEN ~/.config/credentials` — the second argument is the OUTPUT file, so the reader wrote the hub token over the whole file; every other key (dashboard passwords, the box passwords) is gone from DooPlex. At 20:43 UTC the storage-identity build B session listed the file's „key names" with `sed 's/=.*//'`; the file had no `=`, so the token itself was printed into that session's transcript. The token is CC's scoped hub token (floor only; no secrets, no deletes). **The session that did it was the app-guides night** (it stopped at once, touched the file no more, and told the operator in the terminal). **The guard is built (same night, felhom.eu):** `read_credential.py` refuses an OUTFILE that is the credentials file by path, symlink or hard link, before reading or writing; pinned by `test_the_outfile_can_never_be_the_credentials_file`, red-proved (`audits/app-guides-2026-10-15/credential-guard-redproof.txt`). Until the restore, the demo-hp rendering check of the night's guides is owed (it needs the dashboard password). | OPEN | Operator: rotate CC's hub token; restore `~/.config/credentials` from the password manager. | Rotate the hub token (`05` §17); restore the file; then CC re-runs the demo-hp rendering check of the Plex and Sonarr guides. | Operator |
| **R-985** | Security & access | P3 | **Our zero-knowledge wording is stronger than the product: on a live box the operator can reach the off-site backup key (through the vaulted root credential and the operator tunnel) without the customer's recovery code.** Design-shaped; decision for the operator in `STATUS.md`. Fix options: change the wording, or remove operator root reach to the key. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | WAITING-ON-OPERATOR — design-proposal | operator decision | Decide the wording or the change | operator |
| **R-983** | Security & access | P3 | **Seven small dashboard weaknesses: after sign-in the browser can be sent to another site; the server-reboot route acts on a GET, so a link can reboot the guest (**FIXED 2026-10-13 in controller v0.310.0, R-998 session: POST only, `TestServerReboot_PostOnly` — six remain**); no anti-framing headers; parallel sign-in attempts get past the limiter; the settings page allows 8-character passwords; reset-code requests have no limit on the box; logout can be triggered from another site.** Fix each with a test, in one controller release. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN | — | One hardening release | CC |
| **R-977** | Security & access | P3 | **FileBrowser's default password can come back if its data volume is ever re-created, because the box checks it only once; and the tunnel can start before the box is claimed.** Static; needs a live check on 9202. Fix: check at every start, and do not start the tunnel before the claim. Security review 2026-10-12 (`audits/security-review-2026-10-12/`); detail held off-git for the operator (`/mnt/5_hdd/felhom.eu/evidence/security-review-2026-10-12-PRIVATE/`). | OPEN | — | Measure on 9202; then fix | CC |