Files
app-catalog-felhom.eu/FIRST-ADMIN.md
T

90 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:** 5 fixed by a generated first password (bookstack, calibre-web, claper, mealie, wger — every
class-3 app); 4 class-4 apps gated (immich, n8n, audiobookshelf, uptime-kuma). **30 class-4 apps remain open** — the
next sessions gate them app by app (R-707): a probe measured on 9202 where the app has one, the button where it has
none. Until an app is gated, its risk is the window until the household opens it first.
| app | class | how the first admin exists | fix route | status | source |
|---|---|---|---|---|---|
| actualbudget | 4 | first visitor sets the server password | (b) `POST /account/bootstrap` | open | R, harness fixture |
| adventurelog | 4 | open sign-up | (a) `DJANGO_ADMIN_*` env; (b) `createsuperuser --noinput` | open | R; U (env) |
| **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`) | (b) `POST /api/auth/setup`; (a) `NEXT_PUBLIC_DISABLE_SIGNUP` | open | **M 9202** (setup 200 once, then 400) |
| **calibre-web** | 3 | `admin / admin123` | (b) `cps.py -p /config/app.db -s admin:<pw>` as `abc`; `generate: password:24:special` (controller ≥ 0.280.0) | **FIXED** — catalog, 2026-09-29 | **M 9202**: fresh install — default refused, generated signs in (302), wrong refused; **M demo-hp**: the installed app's password changed by the operator's ruling (Part A) |
| **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 |
| docmost | 4 | first registered user is admin | (b) `POST /api/auth/setup` | open | R, fixture |
| emby | 4 | setup wizard | (b) `/Startup/*` API | open | U |
| ghost | 4 | `/ghost/` setup | (b) `POST /ghost/api/admin/authentication/setup/` | open | U |
| gitea | 4 | web installer open (no `INSTALL_LOCK`) | (a) `INSTALL_LOCK` + (b) `gitea admin user create` | open | R; R-624 |
| 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 | (b) `python3 -m gramps_webapi user add` | open | U |
| home-assistant | 4 | onboarding | (b) `POST /api/onboarding/users` | open | R, fixture |
| homebox | 4 | open registration | (b) register API; (a) disable registration after | open | U |
| 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 | (b) `/Startup/*` | open | U |
| kimai | 1 | `ADMIN_PASSWORD` → `ADMINPASS` | – | fine | R |
| komga | 4 | first visitor claims | (b) `POST /api/v1/claim` | open | U |
| **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/`) |
| **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 | (a) `ND_DEVAUTOCREATEADMINPASSWORD`; (b) `/auth/createAdmin` | open | R, fixture; U (env) |
| 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 | (b) `POST /register`; (a) `OG_DISABLE_SIGNUP` | open | R, fixture |
| outline | 4 | e-mail / magic-link onboarding | (c) none found (R-624) | open — page note needed | R |
| paperless-ngx | 1 | `PAPERLESS_ADMIN_PASSWORD` | – | fine | R |
| papra | 4 | open e-mail sign-up | (b) sign-up API; (a) disable registration | open | R, fixture |
| plant-it | 4 | open, `USERS_LIMIT=-1` | (a) `USERS_LIMIT=1` + (b) sign-up | open | U |
| 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 | (b) `PUT /api/v3/config/host` with the apikey | open | U |
| rallly | 4 | magic link to any e-mail | (a) `INITIAL_ADMIN_EMAIL` + `ALLOWED_EMAILS` | open | U |
| recipe-importer | 4 | our own image, open until set | (c) now; our own code | open | R |
| romm | 4 (catalog said 3) | first unauthenticated `POST /api/users` creates the user (harness); the stale `admin / admin` note is **removed** (2026-09-29) | (b) `POST /api/users`; or the setup gate | open | **M demo-hp** (401 for the old note); fixture |
| seerr | 4 | setup wizard (needs a media server) | (c) | open | U |
| sonarr | 4 | as radarr | (b) | open | U |
| sparkyfitness | 4 | open registration | (a) `SPARKY_FITNESS_ADMIN_EMAIL` + disable sign-up | open | U |
| tandoor | 4 | setup page while no users | (b) `createsuperuser --noinput` | open | R, fixture |
| termix | 4 | first registered user is admin | (b) user-create API | open | U |
| **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 | (b) `vikunja user create`; (a) disable registration | open | R, fixture |
| wanderer | 4 | `PUBLIC_DISABLE_SIGNUP=false` | (a) disable after first user | open | U |
| **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 | (b) `POST /signup` | open | R, fixture |
| zipline | 4 (catalog said 3) | v4 sets up on first run; the stale `admin / zipline` note is **removed** (2026-09-29) | (b) setup API (U); or the setup gate (probe `/api/setup` `firstSetup`, U) | open | R; audit logs |
**Counts (computed from the table, 2026-09-29):** class 1: 8 · class 2: 1 · class 3: 5 · class 4: 34 · class 5: 5.
**Fixed: 5** (every class-3 app). **Gated: 4.** **Open: 30** (class 4). Fine: 14.