From 27f4e7d9767c6a8f9d2745b2eb30d5c57d39c37e Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 1 Oct 2026 22:19:50 +0200 Subject: [PATCH] Session close: REPORT-visitors-2026-10-01, STATUS (go/no-go: the family gate; SparkyFitness licence), CONTEXT, capability map rows, R-783..R-787 (register 422) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- CONTEXT.md | 10 ++ REPORT-visitors-2026-10-01.md | 139 ++++++++++++++++++ STATUS.md | 88 ++++++----- .../architecture/00-capability-map.md | 2 + documentation/backlog/OPEN-ITEMS.md | 5 + 5 files changed, 197 insertions(+), 47 deletions(-) create mode 100644 REPORT-visitors-2026-10-01.md diff --git a/CONTEXT.md b/CONTEXT.md index 4b41ad0a..dfeb09af 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -16,6 +16,16 @@ > and holds nothing of its own; this file does hold its own content, namely the standing rulings below. +> **2026-10-01 (late night) — the box tells visitors apart (R-753 CLOSED), controller v0.286.1 floored, golden 0.286.1 +> vouched.** cloudflared alone on `felhom-tunnel` at `172.16.253.2` (traefik `.3`; allocation confined to `.4/30`); traefik +> trusts forwarded headers from that address only and strips client-writable host/path/address headers +> (`felhom-forwarded@file`); the controller reads the hop traefik saw (`clientaddr.go`). **Readers take the visitor from the +> RIGHT** — 19 catalog apps that read the leftmost carry `-xff`; BookStack `APP_PROXIES`; checklist 3.10. R-772 +> (not-checked probe) and R-773 (lock after a restore) closed. Permanent family gate SPIKED and PASSED, not built (R-780, +> operator go/no-go, 2 sessions). SparkyFitness record added; its licence is non-commercial only (R-784, operator); a catalog +> licence sweep is owed (R-787). `01` §7 corrected: cloudflared runs in the guest (R-754). Report: +> `REPORT-visitors-2026-10-01.md`. + > **Ruling 2026-10-01 (evening, operator) — `09` §3 decision 63, recorded before the work.** Login problems are solved by > EXTENDING THE BOX'S OWN GATE (option A), not by an identity app on every box (option B, Authentik/Authelia — a possible > later step behind the same traefik `forwardAuth` hook). Order: the box tells visitors apart (R-753) → a SPIKE of a diff --git a/REPORT-visitors-2026-10-01.md b/REPORT-visitors-2026-10-01.md new file mode 100644 index 00000000..e0788410 --- /dev/null +++ b/REPORT-visitors-2026-10-01.md @@ -0,0 +1,139 @@ +# REPORT — the box tells visitors apart; the permanent-gate spike; SparkyFitness; R-772/R-773; release + golden (2026-10-01 night) + +## The Part table + +| Part | Result | Notes | +|---|---|---| +| **A** — visitors apart (build) | **DONE, with one change to the brief's sketch and one leg unmeasured** | The sketch plus 2 costs paid in the same rollout: a header clean-up at traefik, and 19 catalog router resets for the apps that read the LEFTMOST address. The brief named neither. ep0's one request was refused by Cloudflare before the box (R-779). | +| **B** — permanent family gate (spike) | **DONE — PASS** on exit items 1–5; costs measured | Exit test committed before the run. Build plan: 2 sessions. Waits for the operator (R-780). | +| **C** — SparkyFitness record | **DONE, with 7 rows open** | Bench (9401 rebuilt and destroyed) and 9202 measured. **Its licence forbids commercial use** (R-784, operator). | +| **D** — R-772, R-773 | **DONE** | Both red-proven and live on 9202. R-772 needed a second fix found live (0.286.0 → 0.286.1). | +| **E** — release, floor, golden | **DONE** | Controller 0.286.1 floored (min_agent 0.131.0); both demo boxes took it and reconciled traefik/cloudflared by themselves. Golden 0.286.1 baked, round-tripped and vouched; the currency gate is OK, not waived. | + +Baselines (re-verified): controller `c1b123c64955`, agent `d766666ff8cf`, felhom.eu `bc9c7b49346b`, catalog `94477cba435a`. +Ends at: controller `a4a753b` (v0.286.1), catalog `de0a9bd`, felhom.eu (this commit). Agent untouched. +Architecture read: `01-topology-and-trust.md` §5 and §7 (both corrected), `09` §3 decisions 45–49, 57–62; decision 63 added +first (operator ruling). + +## Claims in the brief that turned out wrong (or right), named + +- *`clientIP` takes the leftmost hop.* **Right** (`claim.go:232`, pre-0.286). +- *A stranger can lock the household out of the dashboard.* **Right, through the tunnel only.** Every tunnel visitor shared + cloudflared's address as the key; a LAN visitor always had its own key. +- *Cloudflare appends to a client-sent `X-Forwarded-For`.* **Right, measured:** `6.6.6.6,37.191.56.193` (M2). Also + measured, not in the brief: + - Cloudflare passes a client's `X-Forwarded-Host` and `X-Forwarded-Port` unchanged. + - It strips a client's `X-Real-IP`. + - It refuses a client-sent `CF-Connecting-IP` at the edge (403). +- *cloudflared's address is docker-assigned.* **Right** (`172.18.0.5`, no `ipv4_address`). +- *The setup gate's token is minted only from a dashboard session.* **Right** (`ServeGateStart`, one caller). But **"the + setup gate uses [the visitor address]" was wrong:** the gate read no client address at all, so there was nothing to + switch over. It now logs the visitor. +- *"Any reader takes the address at a fixed distance from the RIGHT."* **Half wrong.** The distance differs by path: + second from the right through the tunnel, first on the LAN. So a fixed count is wrong for one of the two paths, and + readers must skip trusted proxies from the right. Count readers (calibre-web, tandoor, wger) were left alone for that + reason. +- *The sketch (traefik trusts cloudflared) is enough.* **Not on its own.** Trusting cloudflared makes the leftmost entry + — written by a stranger — reach every app. 19 apps read exactly that one (several for rate limits: audiobookshelf and + docmost by address only, papra skips its limit on a junk value). It also lets a stranger's `X-Forwarded-Host` through. + Both were closed in the same rollout. +- *calibre-web `TRUSTED_PROXY_COUNT`, wger `AXES_*` proxy count.* **Left as they are.** Both are count readers, and both + lock per NAME (decisions 58, 61). A count of 2 would break the LAN path, and for calibre-web also its proto/host. +- *Grimmory improves.* **Right as read in source; not measured in this session** (R-775 updated). + +## Part A — the box tells visitors apart + +- **Paths**: `audits/visitors-2026-10-01/A/` — M1–M4 before, M5 after, DESIGN.md (the path table, the options, the choice, + the docs quoted). +- **Built** (controller v0.286.0/.1): + - A `felhom-tunnel` network `172.16.253.0/29` with docker's allocation confined to `.4/30`. The hand prototype found + traefik grabbing `.2`, so cloudflared now sits at a fixed `.2` and traefik at a fixed `.3`. + - traefik trusts `172.16.253.2/32` only, and runs `felhom-forwarded@file`. + - `EnsureBaseStack` reconciles a running traefik or cloudflared. + - `clientaddr.go`, plus IPv6 counted per /64. + - The dashboard login messages are informal, in both languages. +- **Red-proofs**: RP-A1, RP-A2 and RP-A3 each fail on their mutant. +- **Live**: + - **9202, simulated tunnel:** a stranger rotating a forged leftmost address was locked after 5 tries; the household + from another address got in at once; LAN and impostor forgeries were counted as themselves (L1). + - **demo-hp, real tunnel:** an app sees `6.6.6.6,37.191.56.193, 172.16.253.2`. The dashboard counter was keyed on + `37.191.56.193` and locked after 5. Every app answered (L2, M5, E/). + - **ep0's one request:** refused 403 by Cloudflare's edge, with no line in the box's log, so the second outside + address is unmeasured on the real tunnel → **R-779**. +- **Apps** (sweep of all 56 apps plus Grimmory and MeTube, read in source: `A/sweep/`): + - **19 router resets**, one commit each, shipped before the release. docmost on the real tunnel still throttles a + rotating forger. + - **BookStack `APP_PROXIES`**, with 3.6 re-measured before and after: the household is no longer throttled by the + stranger. + - **Gains with no change:** Home Assistant (it treated every internet visitor as "local"), actualbudget, immich, + dawarich, claper, termix, Grimmory. + - **Open:** kimai, zipline, vikunja, nextcloud (R-776); Emby and Jellyfin LAN rights (R-777). + - **Checklist 3.10** added. + +## Part B — the permanent gate (spike) + +`audits/permanent-gate-2026-10-01/VERDICT.md`. **PASS** on items 1–5. +- 36 stranger requests, 0 reached an app. +- Family members got their own 30-day logins, websockets worked, and logout worked. +- A stranger's guesses locked only him. +- OPDS, Kobo and KOReader worked through anchored exceptions, with the app's own login still in force. +- The family login never opened the dashboard. + +Costs: +0.4 ms per request; with the gate down, apps answer 500 (closed); the build is 2 sessions. One build +requirement: anchor every exception (`/api/v1/opdsx` slipped past an unanchored prefix; Grimmory's own login still +refused it). Fully torn down. + +## Part C — SparkyFitness + +`app-catalog-felhom.eu/onboarding/sparkyfitness.md`. +- **Bench:** 5.1 server 33 %; 5.2 server 38 % and db 53 % under a heavy burst, 0 kills; 1.4 v0.17.2 → v0.17.3 proven; + 2.1 CLEAN; 9.1 green. +- **9202:** + - A stranger got nothing during install. + - Sign-up was blocked in 3 spellings, and blocked again after remove + restore. + - Sign-in limit (3.6): ~10 s for everyone (R-783). + - 4.4: the state read degraded within 10 s. + - Backup → remove → restore read the data back. +- **Open:** 0.1 licence (**R-784 — non-commercial only**), 0.5, 0.7, 1.6, 1.7, 5.4, 8.3 (R-786). The pin is 11 releases + and a major behind (R-785). A licence sweep of the whole catalog is owed (R-787). + +## Part D — R-772, R-773 + +- **R-772:** not-run → `healthy:false, not_checked:true`, plus a line on the app page. 0.286.0 still waited for the + last healthy record's 5-minute interval; 0.286.1 sees it on the next tick. **Live:** not_checked 14 s after the stop, + healthy 42 s after the start. Red-proofs RP-D1 and RP-D1b. Readers of `health_probe`: the state override and the + API/page only; the hub never sees it. +- **R-773:** a restore of a removed app writes the lock record (`opened_by: restore`) and the block before the start. + **Live** on Karakeep and SparkyFitness: a stranger got 403 after remove + restore. Red-proof RP-D2. + +## Part E — release, floor, golden + +- **Release:** controller 0.286.1. Full suite rc 0, gates green. 0.286.0 ran on 9202 only. +- **Floor:** `0.286.1` + `min_agent 0.131.0` → demo-hp and demo-felhom on 0.286.1 within ~60 s. Each created the + network, recreated traefik and moved cloudflared by itself (`E/rollout-*.txt`). +- **Golden 0.286.1** (`documentation/tests/golden-0.286.1-2026-10-01/`): + - sha `1dec051d…a89`; the round trip is equal; token leaks 0, with the positive control at 1. + - Vouched: golden 0.286.1 / agent 0.138.0 / min_agent 0.131.0. The hub then refused golden 0.285.0. + - `golden_currency_gate`: OK (not waived). The waiver was not renewed — the bake ran. + +## Rows + +- **Closed:** R-753, R-754, R-772, R-773. +- **Narrowed:** R-775. +- **Opened:** R-776..R-787 (12). +- **Register:** 410 → 422. +- **Capability map:** two rows added (PARTIAL: visitors apart; MISSING/spiked: the family gate). +- **`unproven.py`:** unchanged — 35 of 55 not walked. + +## Teardown (three layers) + +- **Machine:** + - 9202: karakeep, bookstack and sparkyfitness removed with their data and backups through the product; the echo + containers, the spike (gate, Grimmory, MariaDB, MeTube, volumes, network, dynamic file), test images and helper + files removed. 9202 keeps controller 0.286.1, its new traefik config and `felhom-tunnel` — the product's own. + - demo-hp 9201: `a1-echo` and its image removed; its traefik config was restored after the M2 minute, and is now the + release's. +- **Host:** the bench 9401 was rebuilt and destroyed (`pvesm` before/after in `C/bench/C0`, `C9`). The drill VM is + powered off and reverted to `virgin`; CT 9100 destroyed. +- **Hub:** the floor and the artifact manifest changed on purpose (above); no customer or appliance records created. +- **ep0:** one HTTP request, nothing else. diff --git a/STATUS.md b/STATUS.md index 847b72b6..3e066fe7 100644 --- a/STATUS.md +++ b/STATUS.md @@ -2,67 +2,61 @@ **Ready for the first real tester (Tester-2): yes. You confirmed the tunnel route and the connect mails (2026-09-30).** -**Updated 2026-10-01 (night). Both demo boxes run controller 0.285.0 and host agent 0.138.0. Hub 0.126.0. New installs get golden 0.285.0 with agent 0.138.0.** +**Updated 2026-10-01 (late night). Both demo boxes run controller 0.286.1 and host agent 0.138.0. Hub 0.126.0. New +installs get golden 0.286.1 with agent 0.138.0.** **Tester-2 — read only, from the hub.** The customer record exists. Tester-2's box has not registered yet. -## Tonight: the first new apps through the checklist +## Tonight: the box tells visitors apart -- **wger is hidden** from new installs until its two problems are fixed. No box has wger. -- **Three new apps are in the catalog, each fully tested:** Radicale (calendar and contacts), Karakeep (bookmarks), - Dawarich (location history). Each passed all 60 checks, with a tested update and a tested restore. -- **Their logos and screenshots reach the boxes only with the next hub release.** Until then the cards have no picture. -- **Grimmory (e-book library) is ready but NOT published.** A stranger who guesses wrong 5 times locks everyone out of - its login for 15 minutes. You decide (below). -- **Not built, on the fit check:** Grimoire (its makers say: never put it on the internet), MeTube (it has no login at - all), Pinchflat (its makers stopped working on it). -- **Fit check only, as you asked:** Invidious and moonlight-web. My advice: build neither (below). +- **Before:** through the internet every visitor looked like the same address. A stranger's 5 wrong passwords locked the + whole family out of the box's own dashboard for a minute, and out of some apps. +- **Now:** the box sees each visitor's real address, and a stranger cannot fake it. Measured on demo-hp through the real + internet path: a stranger's wrong passwords locked only that stranger. +- **Apps:** 19 apps would have believed a faked address. They are protected, in the same update. BookStack now locks + only the stranger, measured. Home Assistant no longer treats every internet visitor as "at home". +- **Not measured:** a second outside address on the real internet path. The test machine abroad was refused by + Cloudflare before it reached the box. A 2-minute test from your phone would close it. -## The fit table, one line each +## The permanent family gate: tested, NOT built -- **Radicale** — build. Done. -- **Karakeep** — build with a note (it visits every page you save; AI is off unless you give it a key). Done. -- **Dawarich** — build with a note (a known login at first, replaced at install; map pictures come from its makers' server). Done. -- **Grimmory** — build with a note. Built, waiting for your word. -- **Grimoire** — stop. Its makers say it must not be on the internet, and there is no ready image. -- **MeTube** — stop for now. No login at all: anyone who finds it downloads through your home connection. -- **Pinchflat** — stop. No new version since September 2025. -- **Invidious** — stop (my advice). It breaks when YouTube changes, and YouTube can block the household's home address. -- **moonlight-web** — stop. It needs a gaming PC and network paths our tunnel does not carry. +- A gate with a login for each family member, in front of Grimmory and MeTube, passed every test on the scratch box. +- **Strangers:** they reached nothing, and their wrong guesses locked only themselves. +- **Family:** members stayed signed in for 30 days, logout worked, and the family login does not open the dashboard. +- **E-readers:** Kobo, KOReader and OPDS readers kept working with Grimmory's own login. +- **Cost:** under 1 ms per page. If the box's controller is down, the gated apps refuse — they never open. -## Earlier today +## Also tonight -- **The new-app checklist is built** (60 checks; a new app cannot reach the catalog without its filled-in copy). The test - on wger found its 4 known problems and 3 more (no styling or photos, strangers can sign up, no e-mail). -- Your afternoon decisions are built: calibre-web's secret login name; the registry clean-up rule (it deleted nothing). +- **SparkyFitness passed most of the checklist.** One problem: its **licence forbids commercial use** without the + author's written permission (below). +- **Two box fixes:** + - The health check now says "not checked" instead of "healthy" when it could not look. + - A removed and restored app keeps its sign-up lock. +- **A new golden.** Fresh installs get today's version. -## What broke tonight, and what I did - -- **Radicale's first version lost your login after a restore.** Found in testing, fixed before it went out. -- **After "remove the app, keep backups" and a restore, one of the two sign-up locks is gone** (the app's own lock - still holds). Written down for the box. -- **The box's health check writes "healthy" when it could not check at all.** The app's state still showed the problem. - Written down. -- Karakeep needed more memory than first planned. It now has room for saving many heavy pages at once. - -**Rows.** Tonight: 11 opened, one of them already closed (the Radicale restore problem). The list went from 399 to 410 rows. +**Rows.** 4 closed, 12 opened. The list went from 410 to 422 rows. ## What needs you -1. **Grimmory: publish it now, or wait?** - - **A — publish now** with a sentence on its page: "if someone guesses your password wrong 5 times, the login waits - 15 minutes." E-reader apps keep working during the wait (measured). - - **B — wait** until the box can tell visitors apart (the bigger build you have not decided yet). Nobody gets Grimmory - until then. - - I would choose **A**: the lock is short, it is the web page only, and e-readers are not touched. It is like mealie's lock, which you kept. -2. **Invidious and moonlight-web: build or not?** I advise **no** for both. If you do nothing, neither is built. -3. **MeTube and Pinchflat (video downloaders):** stopped for other reasons (no login; makers stopped). The YouTube - sentence („Csak saját használatra…") waits until one of them is built. -4. Older, nothing urgent: should apps see each visitor's real address; is the design document or the build right about - where the tunnel runs. +1. **The permanent family gate: build it or not?** + - **Go:** 2 work sessions — the box first, then Grimmory and MeTube published behind it. + - **No-go:** Grimmory stays unpublished, and MeTube is not built. + - **If you say nothing:** nothing is built, and the next sessions do other work. + - I would choose **go**. It also answers Grimmory and MeTube. +2. **SparkyFitness's licence** says "non-commercial use only". + - **A:** hide it from new installs and ask the author for permission. + - **B:** keep it offered while asking. + - I would choose **A**. + - **If you say nothing:** it stays offered. +3. **Grimmory:** publish behind the family gate (if go), or as it is now. Its lock is per visitor since tonight; read in + its code, not yet measured. +4. **One phone test (2 minutes):** sign in to demo-hp's dashboard from your phone off wifi, while I lock out my own + address. If you skip it, the second-address proof stays the simulated one. +5. Still open from before: Invidious and moonlight-web — I advise no to both. MeTube and Pinchflat are stopped. ## Standing steps - **Monthly security re-test: last run 2026-10-01, next due ~2026-11-01.** (You start it with the standing brief.) -- **Weekly:** the golden bake (around 8 October). +- **Weekly:** the golden bake (around 8 October; tonight's bake was 0.286.1). - **Registry clean-up:** only when the registry disk fills; "show me" mode first, then a person decides. diff --git a/documentation/architecture/00-capability-map.md b/documentation/architecture/00-capability-map.md index 7602eb13..a5064291 100644 --- a/documentation/architecture/00-capability-map.md +++ b/documentation/architecture/00-capability-map.md @@ -191,6 +191,8 @@ likewise silent. Evidence: `audits/DRILL-r361-2026-08-22/evidence/06-part3-decis | **Indítópult megosztás (vendég link)** — capability URL `/s/` serves a standalone read-only guest launcher (no account, no admin session); optional per-share password; QR | controller v0.165.0 | **IMPLEMENTED** | 160-bit `crypto/rand` token, constant-time match (empty stored = disabled = byte-identical to the mux default 404); guest headers `noindex`/`no-referrer`/`no-store`; optional SEPARATE bcrypt share password + its own per-IP attempt map; signed cookie `HMAC(token`\|`passwordHash)` keyed with `session_secret` (rotate-token OR change-password invalidates all cookies); token redacted in logs (`/s/`). Groups A–G (14 tests) + 3 red-proofs; **§13 endpoint-level live validation on 9201 all-pass** (`felhom-controller/REPORT.md` 2026-07-24). **Design ruling: member accounts SUPERSEDED by this capability-URL model; per-member tile visibility parked under the SSO arc (R-15).** | Full operator browser click-through + a validation doc pending → then PROVEN-LIVE. Accepted residuals: link-preview crawlers fetch once (noindex prevents indexing); reverse-proxy/CF access logs hold the path (ops-tier); the modal link carries the request Host (LAN-IP admin ⇒ LAN-IP link) | | Forgot dashboard password → instant reset code | controller v0.123, hub | **PROVEN-LIVE** | `DRILL-day0-take2-2026-07-12` F-15 (live re-run of the exact failure path: hash applied 1s after request, code accepted first try) | | | **The dashboard in English** — the household picks its language; Hungarian unchanged | controller v0.247.0 (spike) → v0.250.0 (slice 1, R-556 CLOSED) | **PARTIAL — PROVEN-LIVE for every dashboard template** (all 36 templates carry their copy in the bundles; the switch is on every dashboard page) | `audits/i18n-slice1-2026-09-17/C/live/` (and `A/`, `B/`, `audits/i18n-2026-09-17/live/`) — on demo-hp 0.250.0 each Hungarian page equals its 0.249.0 fetch once the new switch form is removed (live numbers aside; login, claim, catch-all byte-identical); `POST /settings/language` made every page English and back; the hub stored `hu`, `en`, `hu` (16:45:10Z, 16:46:06Z, 16:46:43Z). Unit: `TestI18nParity` (106 states vs fixtures from unconverted templates), `TestI18nParityCoversEveryMarker`, `TestI18nEnglishPages`, `TestDirectRenderHandlersFollowLanguage`, all red-proofed. Design `architecture/10-localisation.md` | Go-side messages and three app-name page titles (R-557 after R-553, R-566), hub e-mails (R-558), console/download page (R-559), catalog copy (R-560), guide + English stranger drill (R-561); ASCII-only Hungarian invisible to the English page test (R-565). **Hungarian households see the switch only once the fleet floor reaches 0.250.0** | +| **The box tells visitors apart — a stranger's wrong passwords lock only the stranger** (dashboard, setup gate, apps that read the visitor from the right) | controller v0.286.1 (`felhom-tunnel`, traefik trust of cloudflared only, `clientaddr.go`), catalog router resets | **PARTIAL** | `audits/visitors-2026-10-01/A/L2-demo-hp-real-tunnel.txt` (real tunnel: the dashboard counter keyed on the visitor `37.191.56.193`, locked after 5 while forging a new X-Forwarded-For each try); `A/L1-9202-live.txt` (simulated tunnel: the household from another address in at once); `A/bookstack-3.6.txt` | The second OUTSIDE address on the real tunnel was refused by Cloudflare before the box → R-779; right-walking app settings → R-776; Emby/Jellyfin LAN rights → R-777 | +| A permanent household gate with family accounts in front of an app (Grimmory, MeTube) | spike only | **MISSING** (spiked, passed) | `audits/permanent-gate-2026-10-01/VERDICT.md` | → R-780 (operator go/no-go) | | Multiple household users / per-person accounts | — | **MISSING** | — | Single dashboard password; acceptable for alpha → R-15 | | WireGuard base infra always-on; OOB operator access (felhom-sshd, /32 peer) | agent v0.72, hub v0.35 | **IMPLEMENTED** | `SPIKE-oob-wg-operator-peer-2026-07-05`, `SPIKE-felhom-sshd-2026-07-05` | Mutual-repair desired-state arc not built → R-13. **CHECKED 2026-08-08 (R-260) and this row was NOT claiming something untrue** — it claims the capability is implemented, never that it is monitored, so no correction was owed. What WAS untrue is narrower and sat one layer down: **the hub's own OOB health check could not see whether the operator's key was installed.** `HostOOBRow` mirrored five of the agent's eight OOB fields, so `operator_key_configured` — emitted every heartbeat since agent v0.72.0, i.e. from this row's own vintage — was discarded by `encoding/json` on arrival, and `oobDegraded` returned `ok` for a box with felhom-sshd active, reachable, a valid config, a configured peer and **no operator key at all**. `operator_peer_configured`, which it did read, only says the peer IP is in desired-state — that OOB is MEANT to work, not that entry is possible. Fixed hub v0.99.0; the missing key now degrades and the alert NAMES it; a stanza too old to carry the field is reported distinctly and is never a silent ok. Pinned end-to-end from raw report JSON by `TestHostOOB_MissingOperatorKey_EndToEnd` and `TestHostOOB_NoKeyField_IsNotSilentlyOK_EndToEnd` | | The operator can see WHERE a managed host is — its LAN address and its WireGuard address, on the host page | agent **v0.119.0**, hub **v0.85.0** | **PROVEN-LIVE** (2026-07-31) | `audits/host-addresses-visible-2026-07-31.md` | Before this the LAN IP was **not reportable at all** — `HostMetrics` carried no address of any kind — and the WG IP existed only in `/offsite`'s peer table keyed by pubkey (peer→host, never host→peer). New wire field `addresses[]`, one row per (interface, address); `IsGlobalUnicast()` is the whole filter, chosen by MEASURING both demo boxes, and it needs no veth/fwbr denylist because that plumbing carries no IP. Rendered live on both 0.119.0 hosts matching their `ip addr` ground truth exactly. **Two honesty properties carry the risk and are both red-proofed:** WireGuard shows the hub ALLOCATION and whether the box CONFIRMS holding it (allocation alone cannot tell a live tunnel from a peer never applied), and an agent below 0.119.0 renders **UNKNOWN, never "no addresses"** — proven live on `drill-r50-0a4f9a` (0.113.0). **Not covered:** a two-LAN-bridge box and a real WG drift, neither of which exists to observe | diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index 2e16b2aa..b02c0725 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -894,6 +894,11 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server` | **R-780** | **[P2-MEDIUM] A permanent household gate with family accounts — the spike PASSED; the build waits for the operator's go (`09` §3 decision 63).** Measured on 9202 2026-10-01 (`audits/permanent-gate-2026-10-01/VERDICT.md`, exit test committed before): a stranger reached nothing of Grimmory or MeTube (36 requests incl. websockets); family members with their own logins got in for 30 days, logout worked; a stranger's guesses locked only the stranger; Grimmory's OPDS/Kobo/KOReader worked through anchored path exceptions with the app's own login; the family login never opened the dashboard; +0.4 ms per request; the gate down → apps refuse (500). **Build requirement F1:** exceptions must be anchored (`PathPrefix(/api/v1/opds)` also matched `/api/v1/opdsx`). **Cost:** 2 sessions (controller release; catalog — Grimmory and MeTube published behind it). If nothing is decided: Grimmory stays held (R-775) and MeTube unpublished (R-767). | **WAITING-ON-OPERATOR — rank P2-MEDIUM; owner: operator (go/no-go), CC builds** | | **R-781** | **[P3-LOW] The catalog's `scripts/test_gate_decoys.py` fails 4 of its own "genuine" onboarding cases — on the untouched tree.** Measured 2026-10-01 (same 4 FAIL lines before and after this session's checklist edit): the harness copies the catalog into a temp tree with a fake sibling `felhom.eu`, and the REAL published records (radicale, karakeep, dawarich) name evidence that the fake sibling lacks, so a complete record reads incomplete. The gate itself (`onboarding`) is green on the real tree. **Needs:** the genuine cases build their own records, or the fake sibling mirrors the cited evidence. | **READY — rank P3-LOW; owner: CC (catalog)** | | **R-782** | **[P3-LOW] Two side observations of the R-753 sweep, inferred, not measured:** glance's seeded `glance.yml` has no `auth:` block (the dashboard is public to anyone with the address), and homepage's `/api/*` refuses a Host not in `HOMEPAGE_ALLOWED_HOSTS`, which the template does not set (widgets may 400). **Needs:** measure both on 9202; glance: decide whether a public link dashboard is intended (the setup gate does not cover it after setup). | **READY — rank P3-LOW; owner: CC (catalog)** | +| **R-783** | **[P3-LOW] SparkyFitness: three wrong sign-ins by anyone shut EVERY visitor out of sign-in for ~10 s — a stranger retrying every 10 s keeps the household out.** MEASURED 2026-10-01 on 9202 through the simulated tunnel (`audits/visitors-2026-10-01/C/box/sparky-box.txt`): better-auth's sign-in limit (3 per 10 s) is keyed on one address — it reads the LEFTMOST X-Forwarded-For, whose chain the R-753 router reset removes, so its frontend nginx hands it traefik's address; the household from another address got 429 at 3 s and 10 s, in at 16 s. Not forgeable (a rotating forged address did not escape). better-auth's header setting is not exposed as an env by SparkyFitness. **Needs:** accept (10 s), or an upstream setting for better-auth's `ipAddressHeaders` + a right-walking reader. | **OPEN — rank P3-LOW; owner: CC** | +| **R-784** | **[P2-MEDIUM] SparkyFitness's licence forbids commercial use: "may not be used, directly or indirectly, in any product, service … intended for … commercial advantage … without prior written permission from the author" — and Felhom is a paid service that offers it in its catalog.** READ 2026-10-01 (`audits/visitors-2026-10-01/C/C0-license.txt`): a custom licence (GitHub: NOASSERTION), the same at the pinned tag v0.17.3 and at `main`; termination clause 7 ("cease all use"). SparkyFitness was named as wger's replacement for fitness. **Needs (operator):** (A) hide it from new installs (`lifecycle: hidden`) until the author gives written permission, and ask; (B) ask first and keep it offered meanwhile; (C) keep it. Recommended A. If nothing is decided it stays offered. | **WAITING-ON-OPERATOR — rank P2-MEDIUM; owner: operator** | +| **R-785** | **[P3-LOW] SparkyFitness is pinned 11 releases and a major behind upstream (v0.17.3; upstream v1.7.3, v1.6.0 dated 2026-07-24).** READ 2026-10-01 (`audits/visitors-2026-10-01/C/bench/C1-previous-tag.txt`). **Needs:** an update walk 0.17 → 1.x through the ladder (bench + box), after R-784 is decided. | **OPEN — rank P3-LOW; owner: CC (after R-784)** | +| **R-786** | **[P3-LOW] SparkyFitness's onboarding record has six open rows** (`app-catalog-felhom.eu/onboarding/sparkyfitness.md`): 0.5 runtime internet (food search providers), 0.7 the phone app's sign-in route through traefik, 1.6 the env names the server reads, 1.7 the entrypoint read, 5.4 a second memory watch at another limit, 8.3 no logo/screenshots on felhom.eu (404). Everything else measured this session (bench + 9202). **Needs:** each row measured, or n/a with a reason. | **READY — rank P3-LOW; owner: CC (catalog)** | +| **R-787** | **[P2-MEDIUM] No catalog app's LICENCE has been checked against Felhom being a paid service; the first look (SparkyFitness, R-784) found a non-commercial-only licence.** The new-app checklist row 0.1 binds apps opened from 2026-10-01; the 53 exempt apps were never read. **Needs:** a read of every template's licence at its pinned tag (SPDX + any custom terms), one table, and the non-open ones to the operator. | **READY — rank P2-MEDIUM; owner: CC (read), operator (decisions)** |