b7f0f7cef5
gates / gates (push) Failing after 14m4s
60 template directories, 58 offered. Records: onboarding/grocy.md and onboarding/lubelogger.md, all 61 checks answered, none open. Evidence: felhom.eu/documentation/audits/new-apps-2026-10-10/. Grocy 4.7.1 from lscr.io/linuxserver/grocy (grocy publishes no image of its own). SQLite in one volume, no HDD, ~30 MiB idle, amd64 + arm64, Hungarian UI 91.6 %. First admin class 3: it starts with its documented admin/admin and after_install replaces that password with a generated one. LubeLogger v1.7.3 from ghcr.io/hargata/lubelogger. LiteDB in one volume, no HDD, ~60 MiB idle, amd64 + arm64. First admin class 1 — and it has to be: the image ships EnableAuth=false, and with that the middleware mints a ticket with the IsRootUser role for every visitor. Measured on a default start: a stranger got 200 on /, on /api/vehicles and on /Home/Settings and CREATED A VEHICLE. The compose entrypoint exports EnableAuth=true and the SHA-256 of a generated name and password, so the app's own login is on before its first byte (at t+1 s nothing listening, at t+2 s /api/vehicles already 401). Two defects found by the walk and fixed before publishing: 1. An after_install command may not contain `$`. The controller runs every element through os.Expand and refuses one naming anything outside env:, so PHP cannot be inlined. On 9202 the first attempt came back `[pw argv dsn db i t e s n q h] not declared in env or has no value — not run` and the app sat behind its install hold with admin/admin in place. The code now lives in a file the compose entrypoint writes. Written into REUSE.md's after_install row as a trap. 2. Grocy's persisted config.php does not follow the image. The image copies config-dist.php only when that file is absent, so a volume written by 4.6.0 and started under 4.7.1 answered HTTP 500 on every page — AUTH_CLASS names a class 4.7 moved — while its log said migrations done. The entrypoint now deletes the file at every start. The 4.6.0 -> 4.7.1 edge failed before this and is proven after it, on both venues. Ladders, written by upgrade-test.py --write-ladder from both verdicts: grocy 4.6.0 -> 4.7.1 bench proven, box proven (guarded Update, 41 s) lubelogger v1.7.2 -> v1.7.3 bench proven, box proven (25.6 s) Checklist 6.3 came from a real failure, not a forced one: before the config.php fix the product undid the same step in 346 s with the data intact. REUSE.md: a fifth healthcheck family (bash /dev/tcp) for an image with no HTTP client at all, measured in both directions. Tool fixes made on the way: check-onboarding.py crashed on a Windows console while printing which ids were open; upgrade-test.py's read_text/write_text used the platform encoding and wrote a cp1250 em dash into a template full of Hungarian.
125 lines
29 KiB
Markdown
125 lines
29 KiB
Markdown
# FIRST-ADMIN — how each app gets its first admin account (the audit behind `09` §3 decision 45)
|
||
|
||
**The rule (operator, 2026-09-28): an app is never published with a login a stranger knows.** The box publishes every
|
||
app on the household's domain (`*.domain` through the tunnel). Where the box can set the first admin password, it
|
||
generates one at install and shows it on the app page. Where it cannot, the app stays in the catalog, and the install
|
||
dialog and the app page say what the default login is and to change it at once.
|
||
|
||
**Mechanisms (controller ≥ 0.279.0; the gate ≥ 0.280.0):**
|
||
- `after_install:` in `.felhom.yml` — one command in the app's own container after a FRESH install, with generated
|
||
deploy values filled in; `success:` marker required. Never after a restore or a kept-data load. (`internal/stacks/after_install.go`)
|
||
- The page's default-login rule — `app_info.default_creds` is shown, with the sentence „Ez az alkalmazás egy ismert,
|
||
közös jelszóval indul: %s. Telepítés után azonnal változtasd meg." / "This app starts with a known, shared password:
|
||
%s. Change it right after the install.", while that login is in effect; hidden once `after_install` replaced it.
|
||
(`internal/web/known_login.go`)
|
||
- The setup gate (`09` §3 decision 46, controller ≥ 0.280.0) — `setup_gate: true` (+ optional `setup_done_probe:`): a
|
||
fresh install of an open-first-run app is closed to everyone but the household until the app's own status says an
|
||
admin exists, or the household presses „Kész, beállítottam". Spike and verdict:
|
||
`felhom.eu/documentation/audits/login-gate-2026-09-29/B/B-VERDICT.md` (14 of 34 class-4 apps have a probe — 2
|
||
measured, 12 upstream; 20 need the button). **It does not close OPEN SIGN-UP after the setup** (R-711).
|
||
- „Megváltoztattam" / "I changed it" (controller ≥ 0.280.0, R-710) — the household's word under a known default login.
|
||
|
||
**Classes:** 1 generated by us at install · 2 set by the household in our dialog · 3 a hard-coded default · 4 an open
|
||
first-run screen (the first visitor creates the admin) · 5 no login by design · 6 unknown.
|
||
**Sources:** **M** = measured on a box (named) · **R** = read in this catalog · **U** = upstream, read or remembered,
|
||
NOT measured. Every U must be measured before a fix is built on it.
|
||
|
||
**Status 2026-09-29 (afternoon):** every class-3 app fixed (5); **32 of 34 class-4 apps gated** (controller ≥ 0.281.0) —
|
||
9 open by the app's own status (probe measured before and after on 9202), the rest by the household's press, which
|
||
asks the probe first where there is one. Open sign-up is closed by the box after the setup on 11 apps (decision 47);
|
||
11 more refuse a stranger by themselves. **Not gated:** wanderer (R-714, needs a design); plant-it is not installable.
|
||
**Not provable on 9202:** the opening of seerr (media server), outline and rallly (e-mail).
|
||
|
||
| app | class | how the first admin exists | fix route | status | source |
|
||
|---|---|---|---|---|---|
|
||
| **actualbudget** | 4 | first visitor sets the server password | **setup gate**, opened by probe `/account/needs-bootstrap` → `data.bootstrapped`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **adventurelog** | 4 | open sign-up | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup` + allauth signup | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **audiobookshelf** | 4 | first visitor creates root | **setup gate**, probe `GET /status` → `isInit` | **GATED** — catalog, 2026-09-29 | **M 9202**: as immich (the probe, read from upstream, measured: opened ~20 s after `POST /init`); its app's login 200 after |
|
||
| bentopdf | 5 | browser-only PDF tool, no accounts | – | fine | R |
|
||
| **bookstack** | 3 | `admin@admin.com / password` | (b) `artisan bookstack:create-admin --initial` | **FIXED** — catalog, decision 45 | **M 9202**: default fails, generated works; **M demo-hp**: default still works on the installed app (unchanged, page warns) |
|
||
| **calcom** | 4 | first visitor becomes admin (`/api/auth/setup`) | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup`, `/auth/signup`, `/api/auth/signup` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **calibre-web** | 3 | `admin / admin123` | (b) as `abc`: rename `admin` in `app.db` to the generated `ADMIN_USER` (`secret`, `hex:5`), then `cps.py -p /config/app.db -s <name>:<pw>`, then prove the hash and that no `admin` is left; `generate: password:24:special` (controller ≥ 0.280.0) | **FIXED** — catalog, 2026-09-29; **the name generated too** 2026-10-01 (`09` §3 decision 61, R-752: Calibre-Web locks a NAME for a day after 40 wrong tries) | **M 9202** (2026-10-01): fresh install — the generated name + password sign in (form and OPDS), `admin` refused, 40 wrong tries on `admin` and the household still in at once; **M demo-hp**: the installed app renamed by hand the same way, the name in the operator's credentials file |
|
||
| **claper** | 3 (+ open sign-up) | seeds `admin@claper.co / claper` | (b) `bin/claper rpc … update_user_password` | **FIXED** — catalog, decision 45 | **M 9202**: default fails, generated works, a restore keeps it |
|
||
| code-server | 1 | `PASSWORD` generated, applied every start | – | fine | R |
|
||
| crafty-controller | 1 | `CRAFTY_PASSWORD` → default.json | – | fine | R |
|
||
| **dawarich** | 3 | `rails db:seed` creates `demo@dawarich.app` / `safepassword` | (b) `bin/rails runner` sets the generated password (ARGV); the install hold keeps strangers out until it succeeds | **NEW 2026-10-01** — catalog, `onboarding/dawarich.md` | **M 9202** (drill catalog): the first public answer 2 s after the password was replaced; default refused, generated signs in (303), wrong refused; registration off (302/422); 10 wrong tries lock the public name for 1 h (Devise; per-minute throttles first) — the mealie precedent (decision 57), the first step tells the household to set its own e-mail; the phone API key keeps working (`felhom.eu/documentation/audits/new-apps-2026-10-01/box/dawarich/`) |
|
||
| **docmost** | 4 | first registered user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; no JSON status before/after → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **emby** | 4 | setup wizard | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **ghost** | 4 | `/ghost/` setup | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; its status exists but is a list (`setup[0].status`) — the box reads only objects → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **gitea** | 4 | web installer open (no `INSTALL_LOCK`) | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/user/sign_up`; `/api/v1/version` is not JSON before the install → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| glance | 5 | config-file dashboard, no users | – | fine | R |
|
||
| gokapi | 1 | `GOKAPI_PASSWORD` before first serve | – | fine | R |
|
||
| grafana | 1 | `GF_SECURITY_ADMIN_PASSWORD` — **falls back to `admin` if empty** (R-708) | – | fine while the field is set | R |
|
||
| **gramps-web** | 4 | first-run onboarding | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/users/<name>/register/`; its status answers HTTP 405 after the setup — the box reads only 200 answers (measured: the press was then refused, fail closed) → button; self-registration answered 500, blocked anyway | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **grimmory** | 4 | first visitor creates the admin (`POST /api/v1/setup`) | **setup gate**, probe `GET /api/v1/setup/status` → `data` (`false` → `true`), **and the family gate** for good (decision 64): strangers reach nothing but the e-reader exceptions, which keep Grimmory's own login | **NEW 2026-10-02** — catalog, `onboarding/grimmory.md` | **M 9202**: the household made the admin through both gates; a second setup 403; R-775's lock cannot be aimed from outside (`audits/family-gate-2026-10-02/A/items.txt`) |
|
||
| **grocy** | 3 | `admin` / `admin`, created by grocy's own first-request migration | (b) the box replaces the password at install: `after_install` runs a PHP helper the compose entrypoint writes, which hashes with grocy's OWN `password_hash(..., PASSWORD_ARGON2ID)` and PROVES the result with `password_verify` before saying so. The code cannot live in the command itself — the controller expands every `$name` in an after_install command — and grocy's image has no other interpreter | **NEW 2026-10-10** — catalog, `onboarding/grocy.md` | **M 9202** (drill catalog): the documented default POSTed once a second as a stranger from before the install press, 65 attempts, **0 signed in** (404, then 401 behind the install hold, then `invalid=true`); after the install the default is refused, the generated password signs in, a wrong one is refused; 25 wrong tries then the household in at once (no lock); a family member added through `POST /api/users` signs in (`felhom.eu/documentation/audits/new-apps-2026-10-10/box/grocy/`) |
|
||
| **home-assistant** | 4 | onboarding | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; its status is a list (`/api/onboarding`) → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **homebox** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/v1/users/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| homepage | 5 | static start page | – | fine | R |
|
||
| **immich** | 4 | first visitor admin sign-up | **setup gate**, probe `GET /api/server/config` → `isInitialized` | **GATED** — catalog, 2026-09-29 (decision 46) | **M 9202**: stranger 302→gate page / 401 during and after the install; household in 0.2 s; probe opened it 0–20 s after the sign-up; phone-app API (Bearer) 200 after (`felhom.eu/documentation/audits/login-gate-2026-09-29/C/`) |
|
||
| **jellyfin** | 4 | startup wizard | **setup gate**, opened by probe `/System/Info/Public` → `StartupWizardCompleted`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **karakeep** | 4 | the first account that signs up becomes the admin (`users.create`) | **setup gate**, opened by the household's press („Kész, beállítottam"); sign-up closed twice after the setup: `after_setup` → `DISABLE_SIGNUPS=true` (it also refuses the FIRST account, so never at install) + a case-insensitive block of `/signup` and any tRPC call naming `users.create` (batched too) | **NEW 2026-10-01** — catalog, `onboarding/karakeep.md` | **M 9202** (drill catalog): stranger 401 before the press; after it users.create / batched / upper-case / `//` / `/signup` all 403; 12 wrong key exchanges → the right one at once; after remove + restore the app's own switch still refuses, the route block is gone (R-773) (`felhom.eu/documentation/audits/new-apps-2026-10-01/box/karakeep/`) |
|
||
| kimai | 1 | `ADMIN_PASSWORD` → `ADMINPASS` | – | fine | R |
|
||
| **komga** | 4 | first visitor claims | **setup gate**, opened by probe `/api/v1/claim` → `isClaimed`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **lubelogger** | 1 | the image ships **NO LOGIN AT ALL** (`EnableAuth: false`) and the middleware mints a ticket with the `IsRootUser` role for every visitor | the compose entrypoint exports `EnableAuth=true` and the SHA-256 of the generated name and password (`StaticHelper.GetHash`), so the app's own login is on **before its first byte**; nothing to run after the install | **NEW 2026-10-10** — catalog, `onboarding/lubelogger.md` | **M bench + M 9202**: on a DEFAULT start a stranger got 200 on `/`, on `/api/vehicles` and on `/Home/Settings` and **created a vehicle**; with the template, the first answer the app ever gave a stranger was 401 / 302 → `/Login/Index`. Sign-up is closed by the app itself (`Invalid Token`); 25 wrong passwords then the household in at once (`felhom.eu/documentation/audits/new-apps-2026-10-10/box/lubelogger/`) |
|
||
| **mealie** | 3 | `changeme@example.com / MyPassword` | (b) its own user repository (`update_password`), password as `sys.argv[1]` | **FIXED** — catalog, 2026-09-29 | **M 9202**: fresh install — default 401, generated 200, wrong 401 (`felhom.eu/documentation/audits/login-gate-2026-09-29/D/`) |
|
||
| **metube** | 5 | NO login at all, by design | **the family gate** only (decision 64), no exceptions | **NEW 2026-10-02** — catalog, `onboarding/metube.md` | **M 9202**: a stranger's every path, the websocket included, 401/302 from the gate (`audits/family-gate-2026-10-02/A/items.txt`) |
|
||
| **n8n** | 4 | owner setup | **setup gate**, probe `GET /rest/settings` → `data.userManagement.showSetupOnFirstLoad` = false | **GATED** — catalog, 2026-09-29 | **M 9202**: as immich; opened by the probe ~20 s after the owner setup |
|
||
| **navidrome** | 4 | first user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| nextcloud | 1 | `NEXTCLOUD_ADMIN_PASSWORD` → auto-install | – | fine | R; **M** demo-hp 2026-09-28 |
|
||
| onlyoffice | 5 | JWT-protected API, no login screen | – | fine | R |
|
||
| **opengist** | 4 | first registered user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/-/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **outline** | 4 | e-mail / magic-link onboarding | **setup gate**, the household's press; needs e-mail or SSO to sign anyone in — not provable on 9202 | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| paperless-ngx | 1 | `PAPERLESS_ADMIN_PASSWORD` | – | fine | R |
|
||
| **papra** | 4 | open e-mail sign-up | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/auth/sign-up` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| plant-it | 4 | open, `USERS_LIMIT=-1` | `setup_gate: true` in the template; the catalog marks it NOT installable (`lifecycle: abandoned`) — nothing to prove | not installable | R |
|
||
| plex | 2 | the household's plex.tv claim token | – | fine | R |
|
||
| privatebin | 5 | anonymous pastes by design | – | fine | R |
|
||
| **radarr** | 4 | first visitor sets auth | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); `/initialize.json` hands anyone the API key BEFORE the setup — the gate hides it; after, it needs a login | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **radicale** | 1 | the box generates the password at install; the container writes Radicale's login file from it on the FIRST start only (Radicale 3 ships with `auth = denyall`) | — (no first-run screen, no sign-up route) | **NEW 2026-10-01** — catalog, onboarding record `onboarding/radicale.md` | **M 9202** (drill catalog): no login 401 from the first answer; wrong 401; right 207; 15 wrong tries → right at once (no lock, ~1.3 s delay each); remove + restore → the household's login comes back with the data (`felhom.eu/documentation/audits/new-apps-2026-10-01/box/radicale/`) |
|
||
| **rallly** | 4 | magic link to any e-mail | **setup gate**, the household's press; magic link by e-mail — not provable on 9202 | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **recipe-importer** | 4 | our own image, open until set | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); our own app: open until a password is set in its settings — the confirm says so | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **romm** | 4 | first unauthenticated `POST /api/users` creates the user (harness); the stale `admin / admin` note is **removed** (2026-09-29) | **setup gate**, opened by probe `/api/heartbeat` → `SYSTEM.SHOW_SETUP_WIZARD` = false; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **seerr** | 4 | setup wizard (needs a media server) | **setup gate**, the household's press; needs a media server to finish its setup — not provable on 9202 (its `initialized` status measured false before) | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **sonarr** | 4 | as radarr | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); as radarr | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **sparkyfitness** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/auth/sign-up` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **tandoor** | 4 | setup page while no users | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **termix** | 4 | first registered user is admin | **setup gate**, opened by probe `/users/setup-required` → `setup_required` = false; sign-up closed by the box after the setup: `/users/create` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **uptime-kuma** | 4 | first visitor creates admin (socket.io `setup`) | **setup gate**, no HTTP probe → the household's „Kész, beállítottam" | **GATED** — catalog, 2026-09-29 | **M 9202**: gate held across a controller restart; the press opened it (second press 409). The proof pressed WITHOUT doing the socket.io setup — the press trusts the household |
|
||
| vaultwarden | 1 | `ADMIN_TOKEN` generated; invite-only (R-512) | – | fine | R |
|
||
| **vikunja** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/v1/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **wanderer** | 4 | `PUBLIC_DISABLE_SIGNUP=false` | NOT gated (its web server calls its own database through the public name); no first-admin screen to take (PocketBase's superuser installer needs the one-time link from its log); sign-up closed by the household's „Close sign-up now” after its account (decision 48) | **LOCKED on the household's press** — catalog, 2026-09-29 evening | **M 9202**: before, a stranger made an account through PocketBase; after the press, every sign-up shape refused (`felhom.eu/documentation/audits/signup-lock-2026-09-29/D/`) |
|
||
| **wger** | 3 | `admin / adminadmin` | (b) Django `set_password`, password as `sys.argv[1]` | **FIXED** — catalog, 2026-09-29; + R-712 (a browser's https Origin was refused by CSRF) | **M 9202**: fresh install — default refused, generated signs in (302), wrong refused, with the browser's https Origin |
|
||
| **wishlist** | 4 | first sign-up is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **zipline** | 4 | v4 sets up on first run; the stale `admin / zipline` note is **removed** (2026-09-29) | **setup gate**, opened by probe `/api/server/public` → `firstSetup` = false; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
|
||
## Sign-up locks after the first admin (decision 47; controller ≥ 0.282.0) — measured on 9202, 2026-09-29 evening
|
||
|
||
Two locks per app where the app has its own switch: the app's own setting (set by `after_setup` when the gate opens) and
|
||
the address block (`signup_block`, case-insensitive). Tricks: each sign-up route tried in 8 shapes (as written, trailing
|
||
slash, UPPER, Mixed, last part UPPER, one letter percent-encoded, double slash, query string), through the public route.
|
||
Evidence: `felhom.eu/documentation/audits/signup-lock-2026-09-29/`.
|
||
|
||
| app | its own switch (env) | that switch also refuses the household's FIRST account? | address block (routes) | tricks (final run) |
|
||
|---|---|---|---|---|
|
||
| adventurelog | `DISABLE_REGISTRATION` | yes | `/signup`, allauth API, `/accounts/signup` | all refused (block) |
|
||
| calcom | `NEXT_PUBLIC_DISABLE_SIGNUP` (read at runtime; invites with a token still work) | no | `/signup`, `/auth/signup`, `/api/auth/signup` | all refused |
|
||
| gitea | `GITEA__service__DISABLE_REGISTRATION` (env-to-ini at every start) | no (the installer makes the admin) | `/user/sign_up` | all refused |
|
||
| gramps-web | `GRAMPSWEB_REGISTRATION_DISABLED` | no (create_owner) | `/api/users/<name>/register/` | all refused |
|
||
| homebox | `HBOX_OPTIONS_ALLOW_REGISTRATION` | yes | `/api/v1/users/register` | all refused |
|
||
| papra | `AUTH_IS_REGISTRATION_ENABLED` | yes | `/api/auth/sign-up/*` | all refused |
|
||
| sparkyfitness | `SPARKY_FITNESS_DISABLE_SIGNUP` | yes | `/api/auth/sign-up/*` | all refused |
|
||
| termix | `ALLOW_REGISTRATION` | yes | `/users/create` — **its router ignores case**: `/users/CREATE` reached the sign-up before the block was made case-insensitive (its own switch refused it) | all refused |
|
||
| vikunja | `VIKUNJA_SERVICE_ENABLEREGISTRATION` | yes (its register route answers 404) | `/api/v1/register` | all refused (its `/register` PAGE is only HTML; the API is blocked) |
|
||
| karakeep | `DISABLE_SIGNUPS` | yes | `/signup`, tRPC `users.create` (any batch, any case) | all refused (2026-10-01) |
|
||
| opengist | none reachable (an admin setting in its database) | — | `/-/register` | all refused (block only) |
|
||
| wishlist | none reachable (`system_config.enableSignup` in its database) | — | `/signup` | all refused (block only) |
|
||
| wanderer | `PUBLIC_DISABLE_SIGNUP` (web only — PocketBase's API ignores it) | — | `/register` + PocketBase `POST /api/collections/(users\|_pb_users_auth_)/records`, any case — **the collection id and a case change both got in before the fix** | all refused; the batch API is off by the app |
|
||
|
||
The household's 15-minute window lifts both locks (the app restarts once) and the loop puts both back (measured on
|
||
homebox). "Close sign-up now" (decision 49) is offered on an app installed before the rule — and on wanderer, which is
|
||
not gated: the household makes its account, then presses it (measured on 9202).
|
||
|
||
**Counts (computed from the table, 2026-09-29 afternoon):** class 1: 8 · class 2: 1 · class 3: 5 · class 4: 34 · class 5: 5.
|
||
**Fixed: 5.** **Gated: 32** (3 of them without a proven opening). **Not gated: 2** (wanderer — its sign-up is locked by the household's press instead, decision 48; plant-it — not installable). Fine: 14.
|