From 81e64c6fe81f5f469193ada6398d234e47bdd7d6 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Tue, 13 Oct 2026 20:36:42 +0200 Subject: [PATCH] =?UTF-8?q?Doc=2014:=20turning=20the=20machine=20off=20(R-?= =?UTF-8?q?998)=20=E2=80=94=20path,=20guards,=20the=20hub's=2014-day=20hol?= =?UTF-8?q?d,=20the=20threat;=20F11;=20R-1000=20filed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 03 §6 lists /guest/reboot and /host/poweroff; 13 counts 38 local-API routes and names the new power of attacker (e). Hub CHANGELOG corrected: os_ring0_stalled is NOT held (a fleet rollout alarm, on purpose). R-983: the GET reboot fixed (six remain). R-1000: the website FAQ line. --- .../architecture/00-capability-map.md | 1 + documentation/architecture/03-host-agent.md | 9 +- documentation/architecture/13-threat-model.md | 4 +- .../architecture/14-host-power-off.md | 88 +++++++++++++++++++ .../architecture/capability-map-detail/F.md | 19 ++++ documentation/backlog/OPEN-ITEMS.md | 5 +- hub/CHANGELOG.md | 2 +- 7 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 documentation/architecture/14-host-power-off.md diff --git a/documentation/architecture/00-capability-map.md b/documentation/architecture/00-capability-map.md index 64ad099a..51d98981 100644 --- a/documentation/architecture/00-capability-map.md +++ b/documentation/architecture/00-capability-map.md @@ -217,6 +217,7 @@ | [F7](capability-map-detail/F.md#f7) | Always-on debug rings + on-demand log-bundle pulls with TTL/custody | controller v0.116, agent v0.83, hub v0.46 | **PROVEN-LIVE** | — | `audits/CAMPAIGN-3-2026-07-11.md` (2026-07-11) | | [F8](capability-map-detail/F.md#f8) | Operator alerting (Healthchecks → monitoring@felhom.eu) | k3s, Resend | **IMPLEMENTED** | no corpus validation doc | operator infra; no evidence document | | [F9](capability-map-detail/F.md#f9) | Backup-deadline alerting (`expected_backup_missed`) is ANCHORED — absence of signal is UNKNOWN, not failure | hub v0.75.0 | **IMPLEMENTED** | — | `audits/DIAG-backup-missed-2026-07-26.md` (2026-07-26); R-82 | +| [F11](capability-map-detail/F.md#f11) | The household turns the whole machine off („A gép kikapcsolása"); the hub holds every silence alarm for 14 days and shows KIKAPCSOLVA | agent v0.155.0, hub v0.149.0, controller v0.310.0 | **PARTIAL** | built and tested; live proof on the N100 pending | `architecture/14-host-power-off.md`; `audits/poweroff-2026-10-13/`; R-998 | | [F10](capability-map-detail/F.md#f10) | A box that is not always on (off at its backup time) makes the missed night up once when it comes back; the household sees a banner; the operator gets the missed-backup alarm, down or not | controller v0.295.0, hub v0.134.0, agent v0.145.0 | **PARTIAL** | catch-up and banner live; R-872 alarm by tests; suspend not measured | `audits/catchup-2026-10-05/partA/` (2026-10-05); R-872 | ## G. Fleet & operator (hub) diff --git a/documentation/architecture/03-host-agent.md b/documentation/architecture/03-host-agent.md index c133e1d2..ad1c6e19 100644 --- a/documentation/architecture/03-host-agent.md +++ b/documentation/architecture/03-host-agent.md @@ -264,9 +264,14 @@ destructive → the §4 gate → refused **`pending_signature`** (the operator-s drive — the 8C analog of self-scoping. **Status: implemented** (agent v0.12.0 `internal/localapi` + `internal/storage`; controller v0.37.0 `internal/web/agent_disk_handlers.go`). + - **Guest restart:** `POST /guest/reboot` — `pct reboot` of *this* guest (the dashboard's „A Felhom újraindítása"). + - **Host power-off (R-998, agent v0.155.0):** `POST /host/poweroff` — the household's „A gép kikapcsolása": this guest + shut down, then the host powered off. Guarded (10 min after boot, one per boot, no other guest or VM running, no + backup/restore/update/drive job) — the whole design, its hub hold and its threat: `14-host-power-off.md`. + Note what is *absent*: nothing here lets a controller touch **another guest**, the **host** beyond -this narrow disk surface, or **restore-overwrite**; and within the disk surface, **data-destructive** -power stays operator-signed (§4). Destructive/cross-guest power stays operator-signed. +this narrow disk surface **and the guarded power-off above**, or **restore-overwrite**; and within the disk surface, +**data-destructive** power stays operator-signed (§4). Destructive/cross-guest power stays operator-signed. A controller can only `POST /rollback` (or snapshot/backup) **its own** guest — the agent maps token → guest and authorizes per guest, so a compromised controller's blast radius is diff --git a/documentation/architecture/13-threat-model.md b/documentation/architecture/13-threat-model.md index 7c07337e..81d9b470 100644 --- a/documentation/architecture/13-threat-model.md +++ b/documentation/architecture/13-threat-model.md @@ -47,7 +47,7 @@ scripts are held with the review's working notes. |---|---|---|---| | controller | 231 (+8 in setup mode) | 21, of which 7 change state, each behind its own password, code or token | port 8080 on the guest's Docker networks (not published); mail relay 2525/2465/2526 | | hub | 119 (1 health, 53 API, 65 web) | appliance register (rate-limited, by design), re-enroll (only while the operator has armed recovery mode), login, health | one ingress, path `/`, geo filter (HU, IE, LAN) | -| agent | 37 local-API routes | 0 | local API on the island bridge; WireGuard; poke (tunnel only); felhom-sshd (tunnel only, measured) | +| agent | 38 local-API routes (`POST /host/poweroff` added 2026-10-13, R-998) | 0 | local API on the island bridge; WireGuard; poke (tunnel only); felhom-sshd (tunnel only, measured) | **Outbound fetches that bring code or config onto a box:** the catalog (git, `main`), app images, the four infra images, the controller image (by tag), `controller.yaml` from the hub, the agent binary and config bundle (signed), @@ -59,7 +59,7 @@ OS packages (exact versions, apt-signed), the installer script (by tag, R-980). |---|---|---| | end-user ↔ apps | holds, with gaps | traefik routing and header stripping hold; homepage has the Docker socket and no gate (R-981) | | customer ↔ controller UI | partly | bcrypt and session hold; small gaps (R-983); family sessions survive a reset (R-976) | -| controller ↔ agent | partly | every route bound to the caller's guest; a compromised controller can still flush restore points (R-973) and void the recovery code (R-978) | +| controller ↔ agent | partly | every route bound to the caller's guest; a compromised controller can still flush restore points (R-973), void the recovery code (R-978), and — since agent v0.155.0 — switch the whole machine off once per power-on, holding the hub's silence alarms for up to 14 days (R-998; mitigations and residual risk: `14-host-power-off.md` §5) | | agent ↔ hub | holds for destructive ops | signed jobs verified in the documented order; unsigned spec has no size bounds (R-984) | | controller ↔ hub | **did not hold until 2026-10-12** | the global key was public (R-950, rotated) and three routes needed no key (R-951, fixed); per-box keys are bound to their box (R-955) | | box ↔ PBS | holds as written | ciphertext only; the zero-knowledge wording is stronger than a live box allows (R-985) | diff --git a/documentation/architecture/14-host-power-off.md b/documentation/architecture/14-host-power-off.md new file mode 100644 index 00000000..7a1daea3 --- /dev/null +++ b/documentation/architecture/14-host-power-off.md @@ -0,0 +1,88 @@ +# 14 — Turning the machine off: „A gép kikapcsolása" (R-998) + +> **What this is:** the household's way to switch the whole machine off — the path, the guards, what the hub does, and +> the threat it adds. Written 2026-10-13 with the build (agent v0.155.0, hub v0.149.0, controller v0.310.0). +> Spike: `documentation/audits/poweroff-2026-10-13/`. Marks as in `01`: **[DESIGN]** a decision; **[FACT]** read in a +> named file or measured. + +## 1. Why + +**[FACT]** Before this, nothing could turn a Felhom machine off: „Kiszolgáló újraindítása" restarted only the guest +(controller `HandleServerReboot` → agent `POST /guest/reboot` → `pct reboot`). A household moving house could only pull +the plug. **[FACT]** Measured on the N100 (spike Part A): a clean guest shutdown (12 s) and `systemctl poweroff` work; +the plug then reads 0.0 W; the hub stayed silent and „ONLINE" for 18 minutes, and by code alarms at 45 min +(`host_stale`), 90 min (`host_down`) and every 05:00 (`expected_*_missed`); the N100 did **not** start when the plug +came back (BIOS „last state", inferred), its power button did (dashboard in 42 s). + +## 2. The path + +| Step | Where | What | +|---|---|---| +| 1 | controller `settings_system.html` | card „A gép kikapcsolása"; the household types KIKAPCSOLÁS / TURN OFF | +| 2 | controller `POST /api/server/poweroff` (`internal/web/poweroff_handlers.go`) | dashboard login (`RequireAuth` + CSRF), POST only, the word again, the controller's own backup/restore/app-update check, the `host_poweroff` feature gate (MinAgent 0.155.0) | +| 3 | agent `POST /host/poweroff` (`internal/localapi/hostpoweroff.go`) | `withGuest` token scope; the guards (§3); the record (`internal/poweroff`) | +| 4 | agent → hub | a host report carrying `deliberate_off.requested_at`, waited for until the hub ACCEPTED it (≤ 60 s, `Loop.SetReportedHook`) | +| 5 | agent | `pct shutdown --timeout 120`, then `systemctl poweroff` (two exact sudoers vectors, `FELHOM_POWEROFF`) | +| 6 | hub (`store/deliberateoff.go`) | `hosts.deliberate_off_at`; silence alarms held 14 days (§4) | +| 7 | the household | presses the machine's power button; the first report of the new boot has no `deliberate_off` → the hub clears it | + +## 3. The guards (agent) — each refuses with a stable `reason`, each fails closed + +| Guard | Reason | Test (`hostpoweroff_test.go`) | +|---|---|---| +| first 10 min after boot | `too_soon_after_boot` | `TooSoonAfterBoot` | +| one accepted request per boot (file keyed by `/proc/stat` btime) | `already_requested_this_boot` | `SecondRequestSameBootRefused`, `poweroff/state_test.go` | +| any other guest or VM running (`/proc`: `lxc-start -n N`, `kvm -id N`) | `other_guests_running` | `RefusedWhileOtherGuestsRun`, `RunningGuestsFromProc` | +| heavy-operation gate held (backup, restore test, OS step, sweep, trim) | `backup_running` / `restore_test_running` / `os_update_running` / `host_busy` | `RefusedDuringBackup` | +| backup job, controller swap, drive format, NAS verify, escrow ceremony, Proxmox vzdump | `backup_running` / `controller_update_running` / `drive_operation_running` / `escrow_ceremony_running` | `RefusedDuringVzdump`, `FailsClosedWithoutTaskReader` | +| after acceptance: the heavy gate is TAKEN and kept; before each step the jobs and other guests are read again — a job waits ≤ 15 min, another guest cancels at once, a job still running cancels | (log) | `JobStartedAfterAcceptance`, `OtherGuestStartedAfterAcceptance` | + +**[DESIGN]** A cancelled power-off leaves the box on (gate released) — better a box that did not switch off than a +backup, update or format cut in the middle. **[DESIGN]** A failed guest shutdown does not stop the power-off: Proxmox's +own shutdown stops a still-running guest before the host goes down. + +## 4. The hub's hold — **[DESIGN]** 14 days (operator default, `store.DeliberateOffHold`) + +Held while the box is silent AND inside the hold — every alarm a switched-off box would raise, named from the code: + +| Alarm | Where | How it is held | +|---|---|---| +| `host_stale`, `host_down` | `monitor/host_staleness.go` | state `off` | +| `node_stale`, `node_down` | `monitor/staleness.go` | state `deliberately_off` | +| `expected_backup_missed`, `expected_dbdump_missed` | `monitor/deadline.go` | skipped (state, and the host row) | +| `offsite_stale`, `offsite_escrow_pending` | `monitor/offsite.go` | customer skipped | +| `restore_test_stale` | `monitor/restoretest.go` | customer skipped | +| `os_update_stale`, `agent_behind`, `os_config_bundle_behind`, `os_reboot_needed`, `os_not_covered` | `osupdates/service.go` | host filtered | +| the kernel „tonight your box restarts" mail | `osupdates/kernel.go` | host filtered | + +**Not held, on purpose:** `os_ring0_stalled` (`osupdates/service.go`, `ring0Hosts`) — it is about the FLEET's update +rollout, not about this box: a ring-0 box switched off stalls the rollout, and the operator should know. + +After the hold, still silent: `host_down` + `node_down` once, with a text naming the household power-off. Back on inside +the hold: no `*_recovered` mail. Pages: KIKAPCSOLVA and „Kikapcsolva a háztartás által, T". A customer is held only +when EVERY host of it is held; a future `requested_at` (the box's clock) is cut to the hub's now. Tests: +`monitor/deliberate_off_test.go` (each with a control that alarms), `api/deliberate_off_test.go`, +`web/deliberate_off_view_test.go`. + +## 5. The threat it adds — attacker (e), a compromised controller (`13-threat-model.md`) + +**[FACT]** `/host/poweroff` is the first local-API route whose effect reaches beyond the caller's own guest: a +compromised controller can now switch the whole machine off, and **nobody can switch it on remotely**. And it can +choose to: its power-off holds the hub's silence alarms for 14 days. + +| Mitigation | Bound | +|---|---| +| one request per boot, none in the first 10 min after boot | no power-off loop; one outage per physical power-on | +| refused while another guest or VM runs | cannot take down a neighbour's guest (demo-hp, multi-guest hosts) | +| refused during backup/restore/update/drive jobs; re-checked before each step | cannot cut a job in the middle | +| the hold ends at 14 days; one machine of two does not hold the customer | the silence is bounded | + +**Residual risk, named:** a compromised controller can switch a single-guest household box off once per power-on and +silence the hub for up to 14 days. The household sees a dark machine; the operator sees „Kikapcsolva a háztartás által" +— not an alarm. Accepted for a household product whose controller is already trusted with the household's data; the +alternative (an out-of-band confirmation) needs a second channel the box does not have. + +## 6. Not done here + +- The website FAQ line („to turn it off: Beállítások → Rendszer → A gép kikapcsolása") — a later website task (R-1000). +- The BIOS „after power loss" value of the N100 was not read (no monitor); the household text promises only the button. diff --git a/documentation/architecture/capability-map-detail/F.md b/documentation/architecture/capability-map-detail/F.md index 4cb90f29..741869e9 100644 --- a/documentation/architecture/capability-map-detail/F.md +++ b/documentation/architecture/capability-map-detail/F.md @@ -177,3 +177,22 @@ **Gap / roadmap (as written):** R-872 live; a suspend never measured --- + +## F11 — The household turns the whole machine off („A gép kikapcsolása"); the hub holds every silence alarm for 14 days + +*Map row: [F11](../00-capability-map.md#f11).* + +**Scenario:** a household moving house or going away presses „A gép kikapcsolása" (Beállítások → Rendszer), types +KIKAPCSOLÁS; the guest shuts down, then the host; the hub shows KIKAPCSOLVA and raises no outage alarm for 14 days; +the machine's power button brings it back, and the hub clears the state. + +**Components:** agent v0.155.0 (`POST /host/poweroff`), hub v0.149.0 (`hosts.deliberate_off_at`, the hold), controller +v0.310.0 (the card, `POST /api/server/poweroff`). + +**Status:** PARTIAL — built and tested (each guard red-proofed); live proof on the N100 pending. + +**Evidence:** design `14-host-power-off.md`; spike `audits/poweroff-2026-10-13/`. + +**Gap / roadmap:** the website FAQ line (R-1000). + +--- diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index 5a8d46e3..304cf8d4 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -112,10 +112,11 @@ match what the reader sees is how an instrument stops being believed (R-421). It **nothing was proven on the day this line was drawn** and a stopping line that moves a status is a stopping line that lies. -## Install & onboarding — 8 rows (P3 6, P4 2) +## Install & onboarding — 9 rows (P3 6, P4 3) | ID | Category | Sev | What | State | Blocked on | Next action | Owner | |---|---|---|---|---|---|---|---| +| **R-1000** | Install & onboarding | P4 | **The website does not say how to turn a Felhom machine off.** Since controller v0.310.0 (R-998) the dashboard has „A gép kikapcsolása" (Beállítások → Rendszer); the FAQ still has only the power-cut line. Text to add (HU/EN): turn it off there; switch it on again with the power button; the hub stays quiet for 14 days. The plug trick is not mentioned to households. | **READY** — filed 2026-10-13 | — | One website task: one FAQ entry per language, `site_gates.py` | CC | | **R-980** | Install & onboarding | P3 | **A person cannot check that the installer is ours: the ISO's first boot runs the install script from a movable tag with no hash or signature, and the ISO checksum sits on the same website as the download.** Fix: a signed manifest (or signature) checked by the ISO before it runs the script, and the public key printed in the guide. 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 — design-proposal | — | Design note, then build | CC | | **R-250** | Install & onboarding | P3 | **A customer create can fail fail-closed because the host-key scan ladder is shorter than the DNS/AAAA settle time.** Found 2026-08-07 creating the fifth walk's venue. `POST /configs/new` with off-site enabled provisions the Storage Box sub-account and then scans its SSH host key to pin it — **fail-closed by design** (`offsite.go:111-121`, *"don't serve a descriptor the controller can't verify"*), with `defaultScanBackoff` = 2+4+8+16+30 ≈ **60 s**, sized by its own comment to *"the observed DNS propagation lag"*. **Measured, both halves:** the first create exhausted the ladder — five `no such host`, then `dial tcp [2a01:4f8:bacc:2:200::d30]:23: connect: network is unreachable` (the name had just begun resolving, **AAAA-first, into a pod with no IPv6 route**) — and the hub logged `[ERROR] offsite provision for walk5`. An **identical second POST succeeded** ~70 s later on its own final rung (`shared already provisioned … (subaccount 285351)`). **Total settle ≈ 100 s against a 60 s budget.** The endpoint was never the problem: verified afterwards from both the node and the hub pod, by name, `SSH-2.0-OpenSSH_9.6p1`. **Two distinct things are wrong and should not be merged:** (1) the budget is sized against DNS *existence*, but what actually bit is the **AAAA-before-A** window, a different and longer phenomenon — lengthen the ladder and/or prefer the A record for the scan dial; (2) **the operator is told nothing actionable** — the create fails with a generic error, the remedy is "press it again", and nothing says so. The retry is genuinely safe (idempotent on the label; confirmed afterwards — `one_time_secrets` 1, one sub-account, no double-provision) **but that safety is invisible to the person deciding whether pressing again will double-charge them.** **Severity LOW-MEDIUM:** self-clearing, no data at risk — but it is the first thing a new customer's provisioning does and it fails looking like an outage. | **VERIFY** — **2026-10-12: hub 0.147.0 live** (S29, decision 224): the host-key scan dials IPv4 first, waits ~2 min (was ~1), and when it still runs out says the store was created and it is safe to press Save again (`TestScannerDialsIPv4First`, `TestScanOutOfRetriesSaysSafeToPressAgain`, red-proved). Known limit: the hub Ingress reads for 60 s, so a very slow first try can show a gateway timeout while provisioning finishes in the background (pressing again is safe). **READY** — operator ruling 2026-10-12 (S29, `09` §3 decision 224): yes — the scan prefers IPv4, waits longer, and the error says „safe to press again". **READY** — owner Viktor | — | The next real off-site setup (a new customer): read the hub log for the scan; success or the new message → close | CC | | **R-516** | Install & onboarding | P3 | **[P3-LOW] English a customer meets on a fresh box and its apps' first screens — enumerated by the big night.** MEASURED 2026-09-14 (BIGNIGHT, VM 333, ISO 1.27.1, controller 0.242.0). Felhom-owned: (1) the dashboard menu item **„Debug"**; (2) the dashboard CPU tile **„Load: 0.29 / 0.39 / 0.37"**; (3) the launcher tile **„Filebrowser"** opens a login in English with no Felhom text (R-513); (4) the storage page mixes formal „Adjon hozzá / Csatlakoztasson" with the product's „te". App first screens a household meets before any Felhom text helps: (5) **Uptime Kuma 2.4 opens on „Which database would you like to use?"** (SQLite / Embedded MariaDB, „Next") — the app card's „Első lépések" does not mention it; (6) PrivateBin, Gokapi, AdventureLog and FileBrowser UIs are English (the apps' own). Already rows: the Proxmox installer screens (R-495, answered by the guide), `wiki.DOMAIN` (R-498). **Fix shape:** rename „Debug"/„Load" (controller); add the Uptime Kuma database step to its card, or pre-seed `db-config.json` for SQLite in the template (catalog). **Added by F4 (20:04:54Z):** (7) the storage page prints the disconnect time as a raw ISO UTC string „Leválasztva: 2026-09-14T19:58:02Z"; (8) the „Meghajtó leválasztva" banner appears twice on every page; (9) „4 telepített alkalmazás nem fut — nézze meg a rendszermonitort" uses the formal form. **Added by F7 (20:50–21:00Z, system disk at 95 %):** (10) a banner on every page in English, „**SSD disk usage high: 90%**"; (11) the dashboard tile reads „Rendszer (/) 61.8 GB / 68.7 GB (**90%**)" while `df` reports **95 %** (reserved blocks ignored), and „(/)" labels the data volume `/mnt/sys_drive`; the deploy page says nothing about free disk. **Added by the i18n spike (2026-09-17, controller v0.247.0):** (12) **six formal („ön") forms in the converted dashboard copy** — „Olvassa be telefonnal" (launcher QR hint), „Biztosan kikapcsolja a megosztást?" (launcher), „Ha újratelepíti … importálnia kell" (the layout's remove-app modal), „Kérjük, vegye fel a kapcsolatot" (backups empty state). They were NOT fixed — a localisation release may not change Hungarian bytes — and are now COUNTED by `controller/scripts/i18n_missing_gate.py` (`HU_FORMAL_CEILING` = 6, a ratchet: a new one convicts, fixing one lowers it). The inventory (`audits/I18N-INVENTORY-2026-09-17.md`) is the list this row closes against in localisation slice 6 (R-561). **Extended 2026-09-17 by slice 1 (controller v0.248.0–v0.250.0):** the converted copy now counts **16** formal forms (`HU_FORMAL_CEILING` 6 → 10 → 12 → 16, each raise stated, Hungarian unchanged by rule) — and the count is an UNDER-count: the gate's stem list sees 4 on the release C pages (storage, drive wizards, debug), while a wider list („írja be”, „adja meg”, „adjon hozzá”, „válassza ki”, „biztosan eltávolítja”, „engedélyezze”, „hozzon létre”, „kattintson”) finds at least **22** keys there alone (login „Adja meg a jelszavát”, the NAS guide, the storage confirms). Widen the stems when this row is worked; the ceiling rises with them. **NARROWED 2026-09-20 by localisation slice 6's walk, item by item** (`audits/i18n-slice6-2026-09-20/R-516-item-by-item.md`): item 2 FIXED (slice 1), items 3 and 6 APP-OWNED (and for an English household item 6 is an advantage), item 11 is a wrong NUMBER rather than a language and needs its own row, item 1 is correct English for an English reader and still open for a Hungarian one. **Items 4, 7, 8, 9 and 10 are NOT DECIDABLE FROM AN ENGLISH WALK** - they are about Hungarian copy quality, a disconnected drive and a full disk, none of which this walk had. **What this row is now waiting for is a HUNGARIAN walk on a box with a second drive**, not another English one; saying it closed would be the kind of closure that makes a register stop meaning anything. **-- 2026-10-08:** the recovery screen's own answers are Go literals in Hungarian only — 14 `renderRecovery` messages in `controller/internal/web/recovery_handlers.go` (seen: the safe default „A művelet nem fejeződött be…" rendered on an English page in a red-proof run). Today's new R-304 sentence is a bundle key in both languages; the 14 old ones are not. | **NARROWED 2026-09-20 - rank P3-LOW; owner: CC; needs a Hungarian walk** **2026-10-05 (burn-down night): items 1 and 4 FIXED on controller `main`** (`d7efa7b`): the menu says „Hibakeresés” (English „Debug”); the storage pages use the te-form (formal-form ceiling 17 → 14; 116 parity fixtures changed by exactly those bytes). Item 2 was already fixed. **Left:** items 5–6 (apps' own screens) and the rest. **2026-10-06: items 1 and 4 DELIVERED** (controller v0.298.0). **2026-10-06 (burn-down night, later): items 7–10 and 12 FIXED on controller `main`** (`e4774e6`, `2e5ef7e`): the disconnect time in local time; one banner per unplugged drive; „nézd meg”; the disk/memory/CPU/temperature banners in the household's language (`health.*` keys; the wire text to the hub unchanged and pinned); the last eleven counted formal forms are te-form (ceiling 14 → 0; 119 parity fixtures changed by exactly those bytes). **Left:** items 5–6 (apps' own screens); about 20 formal forms the gate does not count yet („írja be”, „adja meg”, „hozzon létre”, …) on the debug, storage, network-storage and security pages. Item 11 moved to its own row **R-889**. **2026-10-06 02:40: the bundle has NO formal form left** (controller `4c3c203`, unreleased): 49 sentences in the te-form; the gate's stem list widened (it counted 61 on the previous bundle, 0 now) with decoys and one listed third-person exception. **Left (narrowed):** Felhom-owned formal forms in Go and template literals the gate cannot read yet — the network-storage attach errors, escrow and share handlers, the single-copy notice, a settings refusal, the SMART mail, a fill-watch „Kérjük”, and the setup wizard pages; each moves into the bundle in the te-form. Items 5–6 are the apps' own screens (not ours). **2026-10-06: items 7–10, 12 and the bundle's 49 formal forms DELIVERED** in controller v0.299.0. **2026-10-06 night: the Go-literal leftover moved** (controller main `3d6ba28`, unreleased): 22 Go-literal messages — escrow handler (6), share password page (2), export upload (1), network-storage uid/remove/attach failures (13) — are bundle keys (`api.escrow.*`, `api.share.*`, `api.export.*`, `api.netstorage.*`) in the te-form with English (14 were formal); a detached attach failure renders in the reader's language; the NAS refusal says „Válassz". `TestR516_GoLiteralFormalFormsAreGone` (source scan + positive control), `TestR516_NetAddFailureFollowsTheReader`; red-proofs `audits/night-burndown-2026-10-06/ctrl/R-516-red*.txt`. **Left:** the setup wizard and recovery-info.txt (R-554); the SMART and fill-watch texts (the hub event's message — wire text, needs the household-copy producer shape); items 5–6 (apps' own screens). | — | — | CC | @@ -192,7 +193,7 @@ stopping line that lies. | ID | Category | Sev | What | State | Blocked on | Next action | Owner | |---|---|---|---|---|---|---|---| | **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; 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-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 | | **R-976** | Security & access | P3 | **A family member's session can be copied out of a family-gated app, and a dashboard password reset does not end family or gate sessions; so a stolen session keeps working for up to 30 days.** Fix: give each app its own derived token instead of the session itself, and end every family and gate session on a reset. 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 | — | Fix with tests in a controller release | CC | | **R-970** | Security & access | P2 | **Whoever holds a box's own hub API key — the hub, or anyone with a copy of the hub database — can read the box's settings file with every secret in it and replace that file through the internet; the box does not check that such a change is signed.** This contradicts `01` §4 (the box exposes no control endpoint) and §10 (a hub compromise alone cannot forge commands). Nothing in the product calls this route any more. Fix: remove the route, or require an operator-signed op for it. 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 — confirmed by a second reader | — | Remove the route with a test that it is gone; release the controller | CC | diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md index 0e516951..a8ef341e 100644 --- a/hub/CHANGELOG.md +++ b/hub/CHANGELOG.md @@ -10,7 +10,7 @@ Needs **agent ≥ 0.155.0** to see anything: the agent's new `deliberate_off.req `host_stale`/`host_down` (state `off`), `node_stale`/`node_down` (state `deliberately_off`, also read by the 05:00 check), `expected_backup_missed`/`expected_dbdump_missed` (also skipped from the host row, so a box switched off at 04:50 is covered), `offsite_stale` and `offsite_escrow_pending`, `restore_test_stale`, the OS alarms - (`os_update_stale`, `agent_behind`, `os_config_bundle_behind`, `os_reboot_needed`, `os_not_covered`, `os_ring0_stalled`) + (`os_update_stale`, `agent_behind`, `os_config_bundle_behind`, `os_reboot_needed`, `os_not_covered`; NOT `os_ring0_stalled`, a fleet rollout alarm, on purpose) and the household's kernel notice mail. **After the hold**, still silent: the usual `host_down` + `node_down`, once, with a text naming the household power-off. Back on inside the hold: no `*_recovered` mail. - **Security review (same day):** the time is the BOX's clock, so a future `requested_at` is cut to the hub's now (it