Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
6.2 KiB
REPORT — 2026-09-29 evening: sign-up locked twice; "close sign-up now"; wanderer closable; three more probes
Architecture read first: 09 §3 decisions 45–49, 01-topology-and-trust.md §5, audits/gate-rollout-2026-09-29/,
rows R-714, R-715, R-716. Controller v0.282.0 (one release), floor 0.282.0, both demo boxes on it. Catalog
6446197. Evidence: documentation/audits/signup-lock-2026-09-29/ (A own switch, B tricks, C demo boxes, D wanderer,
E probes, redproofs).
The Parts
| Part | Step | State | Note |
|---|---|---|---|
| — | decisions 48, 49 recorded first | done | 09 §3 |
| A1 | own switch per app (spike) | done | 9 of 11 have an env switch (below); opengist, wishlist only in their database (R-717) |
| A1 | "can be set only after the first admin" | measured | 6 of 9 refuse the household's own first account while on; 3 (calcom, gitea, gramps-web) do not |
| A2 | after_setup: (controller) |
done | env merged + one compose up -d when the gate opens; command form with after_install's argv rules; an old compose reported, not faked; retries every 30 min at most |
| A2 | live | done | all 9 apps: record ok, running container carries the switch, a stranger straight at the app refused |
| A3 | the window with an own switch | done — lift and restore | homebox: the window turned the switch off (one restart), a family member joined; after 15 min both locks back, a stranger refused through the web and straight at the app |
| B | trick table | done, changed | termix's router ignores case: /users/CREATE got past the old prefix block (its own switch refused it). All blocks now PathRegexp((?i)…), slash-tolerant. Final: 113 tries on 11 apps, 0 got in, 106 refused by the block, 7 were vikunja's plain HTML page (its API blocked) |
| B | login / reset / sharing | done | household sign-in on 7 apps; password reset and share routes reach the apps, not the block |
| C | "close sign-up now" (controller) | done | lock record opened_by: close-signup, block, own switch; offered once; never a gate |
| C3 | demo boxes | done, changed | pressed on demo-hp adventurelog + opengist, demo-felhom opengist. "Before" proven WITHOUT making an account (the app answered an invalid sign-up with its own validation) — the apps' admin passwords are the operator's, so a test account could not be deleted through their admin pages. After: refused; login pages answer. adventurelog's backend restarted once (~30 s) for its own switch, same images (R-718: the card does not say so) |
| D | wanderer | done, changed | no gate: one DB URL for server and browser (measured), and no first-admin screen for a stranger (PocketBase's installer needs the log link). Closed by "close sign-up now": two holes found and closed (collection id _pb_users_auth_, collection name in capitals); proven on 9202 |
| E1 | probe reads lists / a done status | done | RP29, RP30 |
| E2 | ghost, home-assistant, gramps-web | done | before/after measured on fresh installs; each gate opened by itself within seconds of the setup; a press before the setup refused on all three |
| E3 | catalog gate probe-measured |
done | 5 decoys seen failing; it caught immich/n8n/audiobookshelf (their note sat one block too high) |
Part A / B — one row per app
| app | own switch | blocks the household's first account? | own switch live after the gate | tricks (8 shapes per route) |
|---|---|---|---|---|
| adventurelog | DISABLE_REGISTRATION |
yes | on; is_disabled: true |
0 in |
| calcom | NEXT_PUBLIC_DISABLE_SIGNUP |
no | on; "Signup is disabled" | 0 in |
| gitea | GITEA__service__DISABLE_REGISTRATION |
no | on; "Registration is disabled" | 0 in |
| gramps-web | GRAMPSWEB_REGISTRATION_DISABLED |
no | on; 405 "Registration is disabled" | 0 in |
| homebox | HBOX_OPTIONS_ALLOW_REGISTRATION |
yes | on; "user registration disabled" | 0 in |
| papra | AUTH_IS_REGISTRATION_ENABLED |
yes | on | 0 in |
| sparkyfitness | SPARKY_FITNESS_DISABLE_SIGNUP |
yes | on | 0 in |
| termix | ALLOW_REGISTRATION |
yes | on — and it caught the case hole | 0 in |
| vikunja | VIKUNJA_SERVICE_ENABLEREGISTRATION |
yes | on | 0 in |
| opengist | none reachable (DB) | — | block only | 0 in |
| wishlist | none reachable (DB) | — | block only | 0 in |
| wanderer | PUBLIC_DISABLE_SIGNUP (web only) |
— | on after the press | 0 in after the fix (2 holes before) |
Claims in the brief that turned out wrong (or right), named
- The three env names given from memory — right: gitea
GITEA__service__DISABLE_REGISTRATION(through its env-to-ini), homeboxHBOX_OPTIONS_ALLOW_REGISTRATION, papraAUTH_IS_REGISTRATION_ENABLED— each measured working. - "A native setting can be set only after the first admin exists" — true for 6 of 9, wrong for 3 (calcom, gitea, gramps-web make their first admin by another route).
- "The address block can be passed by case or encoding tricks" — right for case, wrong for encoding: termix (router ignores case) and PocketBase (collection name in any case, and by id) got past the old blocks; percent-encoding, double slashes, trailing slashes and query strings never did (traefik decodes and cleans before matching).
- "wanderer separates its internal and public database URL" — wrong: one
PUBLIC_POCKETBASE_URLfor both. - "gramps-web answers 405 only after its setup" — right: 200 with an owner token before, 405 after.
Also found
- The scratch box's Docker disk was full of old images (1 GB free) — the install check refused correctly; 44 unused images removed by name (no prune).
test_gate_decoys.pyhad stopped running any case after docmost moved to PostgreSQL 18 (a typed "16"); fixed to read it.- My own slip: I restarted the scratch box's controller while a removal job was running; one removal was cut off (502). Re-run; nothing left behind.
Rows
Closed: R-714, R-715, R-716. Opened: R-717 (opengist/wishlist own switch in their DB), R-718 (the close card should say the app restarts). Register 353 → 355 rows.
Teardown
Machines: 9202 — every test app removed through the product; no gate or block file left; back on the live catalog; the drill catalog reset. Demo boxes — the floor, and the three "close sign-up now" presses (ruled). Host: nothing. Hub: floor 0.282.0. ep0: untouched.