From a791aae057518004bf279646e6824a99e1e59f96 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 28 Sep 2026 18:59:24 +0200 Subject: [PATCH] FIRST-ADMIN.md: the 53-app first-admin audit (decision 45); CHANGELOG + REPORT Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- CHANGELOG.md | 13 ++++++++ FIRST-ADMIN.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ REPORT.md | 20 +++++------- 3 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 FIRST-ADMIN.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c9f89..9577b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## No app goes live with a login a stranger knows — first two apps; the audit (2026-09-28 evening, `09` §3 decision 45) + +- **`FIRST-ADMIN.md`** (new): how each of the 53 apps gets its first admin — class, fix route, status, and whether each + claim was measured or read. 2 fixed, 37 open (3 hard-coded defaults, 34 open first-run screens), 14 fine. +- **claper** (`9dc8a05`) and **bookstack**: a generated `ADMIN_PASSWORD` (`type: password`, shown on the app page as the + first password) and an `after_install:` command through the app's own CLI that replaces the known default + (`bin/claper rpc … update_user_password`; `artisan bookstack:create-admin --initial`). Needs controller ≥ 0.279.0 (the + floor). Proven on 9202 on a fresh install each: the default no longer logs in, the generated password does, a wrong + one does not; for claper a restore keeps it. First steps (hu + en) now say to sign in with the first password. +- **Copy freeze:** the new and changed Hungarian strings of both apps signed off (`--capture-freeze`, diff = those strings only). +- Found, not changed: romm's `default_creds` (`admin / admin`) does not log in on demo-hp (stale); zipline's looks + stale; calibre-web's route needs a generated password with a special character (its password policy). + ## claper → PostgreSQL 17, calcom → 1536M and PostgreSQL 18 (2026-09-28, `09` §3 decision 43) - **claper: PostgreSQL 16 → 17** (`4a249b9`, alone in its commit, written by `upgrade-test.py --write-ladder`). Its upstream diff --git a/FIRST-ADMIN.md b/FIRST-ADMIN.md new file mode 100644 index 0000000..81740ac --- /dev/null +++ b/FIRST-ADMIN.md @@ -0,0 +1,82 @@ +# 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):** +- `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`) + +**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-28:** 2 apps fixed (claper, bookstack). 37 apps of class 3/4 remain (3 of class 3, 34 of class 4) — they are the work of the next +sessions (R-707). Until each is fixed, a class-3 app shows the sentence (its `default_creds` is in the catalog); a +class-4 app has no default to show, so 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 | (b) `POST /init` | open | R, fixture | +| 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:` — **needs a password with a special character** (its policy), our generator has none | open — needs a controller generator | **M 9202** (default works; `-s` refused an alphanumeric one); **M demo-hp**: default works (page warns) | +| **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 | (b) `POST /api/auth/admin-sign-up` | open | U | +| 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) login + users API | open | R; fixture (login works) | +| n8n | 4 | owner setup | (b) `POST /rest/owner/setup` | open | R, fixture | +| 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) | catalog note `admin / admin` is **stale**: on demo-hp it answers 401 like a wrong password; a first unauthenticated `POST /api/users` created the user (harness) | (b) `POST /api/users` | open — **the page warns with a login that does not exist** | **M demo-hp** (401); 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 | (b) socket.io `setup` | open | U | +| 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) `manage.py shell -c` set_password | open | R | +| wishlist | 4 | first sign-up is admin | (b) `POST /signup` | open | R, fixture | +| zipline | 4 (catalog said 3) | catalog note `admin / zipline` looks **stale** (v4 sets up on first run) | (b) setup API (U) | open | R; audit logs | + +**Counts (computed from the table):** class 1: 8 · class 2: 1 · class 3: 5 (bookstack, calibre-web, claper, mealie, wger; +romm and zipline were listed as 3 and are 4) · class 4: 34 · class 5: 5. **Fixed: 2.** **Open: 37.** Fine: 14. diff --git a/REPORT.md b/REPORT.md index f7f8fd8..a7f8511 100644 --- a/REPORT.md +++ b/REPORT.md @@ -1,17 +1,11 @@ -# REPORT — 2026-09-28: claper → PostgreSQL 17; calcom → 1536M and PostgreSQL 18 +# REPORT — 2026-09-28 evening: no app goes live with a login a stranger knows (decision 45) — the audit and the first two apps -Brief: "golden, Day-0 vouch, kept data from off-site…" Part C. Architecture read: `09-update-architecture.md` §3 -decisions 35–42 (42's reasoning applied as decision 43). +Architecture: `09-update-architecture.md` §3 decision 45 (new); `01-topology-and-trust.md` links the audit. -| app | move | bench (LXC 9401, demo-hp) | box 9202 (guarded Update) | result | +| app | before | route | proof (9202, fresh install, controller 0.279.0) | live | |---|---|---|---|---| -| claper | postgres 16 → 17 | proven — converted 30.8 s, 32 tables equal, seed back, peaks 75.8 % / 78.3 %, 0 kills | proven — CONVERTED in 7.2 s, done 47 s, PG_VERSION 17, seed back | live catalog `4a249b9`, engine gate ALLOWED | -| calcom | memory 768M → 1536M (`9555e73`) | — | 768M OOM-killed every start; 1536M anon peak 817 MiB (53 %) | fixed, R-703 closed | -| calcom | postgres 16 → 18 | proven — converted 35.0 s, 122 tables equal, seed back, anon 61.5 %, 0 kills | proven — converted, done 68 s, PG_VERSION 18, seed back | live catalog `037f956`, engine gate ALLOWED | +| claper | seeds admin@claper.co / claper (measured: authenticates) | `bin/claper rpc` update_user_password | default fails · generated works · wrong fails · restore keeps it | `9dc8a05` | +| bookstack | admin@admin.com / password (measured, also on demo-hp) | `artisan bookstack:create-admin --initial` | default fails · generated works · wrong fails | this commit | +| calibre-web | admin / admin123 (measured, also on demo-hp) | `cps.py -s` refuses an alphanumeric password | — | open: needs a special-character generator | -- Fixture: claper `rpc register_user` + authenticate readback (negative control: wrong password refuses) — `c5015ce`. -- calcom fixture: `POST /api/auth/setup` + public page readback (negative control: unknown name 404) — `b35fc7f`. -- New rows: R-702 (claper default admin `admin@claper.co`/`claper`, P1, open), R-703 (calcom OOM at 768 MB — closed by `9555e73`), R-704 (a crash-loop hold survives remove + reinstall). -- Bench LXC 9401 created twice and destroyed twice (hostname checked), template removed; `local-lvm` 55.6 % at teardown. - -Evidence: `felhom.eu/documentation/audits/pg-calcom-claper-2026-09-28/`. +The full table: `FIRST-ADMIN.md`. Evidence: `felhom.eu/documentation/audits/logins-nvme-2026-09-28/B/`.