FIRST-ADMIN.md: the 53-app first-admin audit (decision 45); CHANGELOG + REPORT
gates / gates (push) Successful in 1s
gates / gates (push) Successful in 1s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -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 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
|
- **claper: PostgreSQL 16 → 17** (`4a249b9`, alone in its commit, written by `upgrade-test.py --write-ladder`). Its upstream
|
||||||
|
|||||||
@@ -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:<pw>` — **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.
|
||||||
@@ -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
|
Architecture: `09-update-architecture.md` §3 decision 45 (new); `01-topology-and-trust.md` links the audit.
|
||||||
decisions 35–42 (42's reasoning applied as decision 43).
|
|
||||||
|
|
||||||
| 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 |
|
| claper | seeds admin@claper.co / claper (measured: authenticates) | `bin/claper rpc` update_user_password | default fails · generated works · wrong fails · restore keeps it | `9dc8a05` |
|
||||||
| calcom | memory 768M → 1536M (`9555e73`) | — | 768M OOM-killed every start; 1536M anon peak 817 MiB (53 %) | fixed, R-703 closed |
|
| bookstack | admin@admin.com / password (measured, also on demo-hp) | `artisan bookstack:create-admin --initial` | default fails · generated works · wrong fails | this commit |
|
||||||
| 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 |
|
| 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`.
|
The full table: `FIRST-ADMIN.md`. Evidence: `felhom.eu/documentation/audits/logins-nvme-2026-09-28/B/`.
|
||||||
- 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/`.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user