Files
felhom.eu/documentation/audits/permanent-gate-2026-10-01/EXIT-TEST.md
T
2026-10-01 21:13:27 +02:00

3.9 KiB
Raw Blame History

Permanent household gate with family accounts — EXIT TEST (written before the spike ran)

Written 2026-10-01 ~19:30 UTC, before anything below was built or measured. Model: audits/login-gate-2026-09-29/B/B-VERDICT.md. Operator ruling 09 §3 decision 63: option A (extend the box's own gate), measured before any build; the build waits for the operator's go.

What is tested

A gate that stands IN FRONT OF an app permanently (not only until its first setup), letting in only members of the household's family list, each with their OWN login. Apps: Grimmory (e-book library; e-readers sync over OPDS / Kobo / KOReader) and MeTube (yt-dlp web UI with NO login of its own — its fit verdict R-767 was "stop: no login at all").

Venue and method (fences: the spike ships nothing)

  • Scratch guest 9202 only, through its traefik (https://192.168.0.114 + Host). Grimmory and MeTube are started BY HAND with docker compose from throwaway files in /root/spike/ on 9202 (Grimmory from the held template in audits/new-apps-2026-10-01/wip/grimmory/, MeTube from upstream's image) — never the live catalog, never a release.
  • The gate is a throwaway auth service on 9202 (a small Go program in a container on traefik-public) answering traefik forwardAuth, with a family list of two members, a sign-in page, a session cookie, logout, and a per-visitor lock that reads the visitor by the SAME rule as controller v0.286 (clientaddr.go). Its source is kept in this folder as evidence.
  • The tunnel hop is simulated as in Part A (a container at 172.16.253.2); one outside address on the real tunnel is not needed for the gate's logic, which is the same code.
  • Everything is removed afterwards (containers, files, traefik labels, images).

Exit items — each PASS or FAIL, measured

  1. A stranger reaches nothing of Grimmory or MeTube: every path tried (the front page, the API, static files, an unknown path, MeTube's socket.io websocket upgrade and its download/add API) answers the gate (302 to the sign-in for a browser GET, 401 otherwise) and never the app. Pass = 0 app answers.
  2. A family member with their OWN login (not the dashboard password) gets in; the session lasts days (cookie lifetime ≥ 7 days, survives a gate restart); logout works (the old cookie is refused afterwards).
  3. A stranger's wrong guesses lock only the stranger: after N wrong sign-ins from one visitor (through the simulated tunnel, rotating a forged leftmost address), that visitor is refused; a family member from another address signs in at once. Pass = both.
  4. Grimmory's e-reader paths (OPDS, Kobo sync, KOReader sync) work for a faithful curl of the client through a per-app PATH EXCEPTION — and on those paths the app's own authentication stays in force: a stranger there meets the app's own 401 (not the app's data). Pass = the client answers 200 with its own credentials, the stranger 401.
  5. The family login cannot reach the box dashboard: the gate cookie is host-only to the app host; the dashboard does not accept it; the family password does not work at the dashboard login.
  6. Cost, measured: the added time per gated request (ms, gated vs ungated, same request, median of ≥ 50); what happens while the gate's answerer is DOWN (stop it: the gated app must be refused — closed, not open); the build's cost in sessions (estimated from the spike's code size and what the controller already has).

Also answered (in the verdict)

Where family accounts live and who manages them; one sign-in for all gated apps on the domain or per app; how Radicale/Dawarich-style API clients are excepted; whether MeTube becomes publishable behind it.

Verdict rule

The spike PASSES only if items 1–5 all pass. Item 6 is a cost, reported, not a pass/fail. A failed item is reported as measured, with what a build would have to do about it.