refactor(server): remove bootstrap admin path #34

Merged
bvandeusen merged 262 commits from dev into main 2026-05-08 22:19:41 -04:00
bvandeusen commented 2026-05-08 22:17:46 -04:00 (Migrated from git.fabledsword.com)

Removes the env-driven auth.Bootstrap() path that creates an "admin" user on first start with a stderr-printed password. With self-registration shipped (#376), the first user to register on a fresh instance becomes admin via CreateUserFirstAdminRace, so the bootstrap path is just a second source of truth that confuses operators and leaves an account in the DB nobody asked for.

Removed

  • internal/auth/bootstrap.go + its test
  • auth.Bootstrap() call from cmd/minstrel/main.go
  • AuthConfig + AdminBootstrapConfig structs from internal/config
  • MINSTREL_AUTH_ADMIN_USERNAME / MINSTREL_AUTH_ADMIN_PASSWORD env reads + their test
  • The auth: block from config.example.yaml
  • Bootstrap-related comments in docker-compose.yml and the README

New first-run flow

  1. docker compose up
  2. Visit http://<host>/register
  3. Fill in your username + password — first user on an empty DB becomes admin automatically (existing behaviour, just now the only path)

The README quickstart text updated to reflect this.

Migration for existing instances

Operator stood the prod DB down for a fresh start, so this PR has no migration path baked in. For any future operator who upgrades with a bootstrap-admin row already in place: log in as the bootstrap admin, generate an invite from /admin/users, register a new admin via /register with that token, promote them, then delete the bootstrap account (last-admin guard requires the new admin to be promoted first).

Recovery story

Forgotten admin password on a single-admin instance is now only recoverable via Fable #321 (admin password reset CLI), which doesn't ship yet. Worth scheduling soon. Not blocking on this PR — the bootstrap path didn't help with forgotten passwords either (it only fired when users table was empty).

Default registration mode

Unchanged: registration_settings.mode still defaults to invite_only per migration 0022_user_management. After the operator registers as user #1, additional users need an invite token (generated via the new /admin/users Invites section). No UI yet for switching modes — filing as a small follow-up.

Test plan

CI runs Go tests + container build + Flutter checks.

  • CI green
  • Operator: deploy fresh, visit /register, register user #1, confirm is_admin = true
  • Operator: from /admin/users, generate an invite, register a friend with that token, confirm friend lands as non-admin
  • Operator: confirm no MINSTREL_AUTH_ADMIN_* env var noise in logs / docker-compose / README
Removes the env-driven `auth.Bootstrap()` path that creates an "admin" user on first start with a stderr-printed password. With self-registration shipped (#376), the first user to register on a fresh instance becomes admin via `CreateUserFirstAdminRace`, so the bootstrap path is just a second source of truth that confuses operators and leaves an account in the DB nobody asked for. ## Removed - `internal/auth/bootstrap.go` + its test - `auth.Bootstrap()` call from `cmd/minstrel/main.go` - `AuthConfig` + `AdminBootstrapConfig` structs from `internal/config` - `MINSTREL_AUTH_ADMIN_USERNAME` / `MINSTREL_AUTH_ADMIN_PASSWORD` env reads + their test - The `auth:` block from `config.example.yaml` - Bootstrap-related comments in `docker-compose.yml` and the README ## New first-run flow 1. `docker compose up` 2. Visit `http://<host>/register` 3. Fill in your username + password — first user on an empty DB becomes admin automatically (existing behaviour, just now the only path) The README quickstart text updated to reflect this. ## Migration for existing instances Operator stood the prod DB down for a fresh start, so this PR has no migration path baked in. For any future operator who upgrades with a bootstrap-admin row already in place: log in as the bootstrap admin, generate an invite from `/admin/users`, register a new admin via `/register` with that token, promote them, then delete the bootstrap account (last-admin guard requires the new admin to be promoted first). ## Recovery story Forgotten admin password on a single-admin instance is now only recoverable via Fable **#321** (admin password reset CLI), which doesn't ship yet. Worth scheduling soon. Not blocking on this PR — the bootstrap path didn't help with forgotten passwords either (it only fired when users table was empty). ## Default registration mode Unchanged: `registration_settings.mode` still defaults to `invite_only` per migration `0022_user_management`. After the operator registers as user #1, additional users need an invite token (generated via the new `/admin/users` Invites section). No UI yet for switching modes — filing as a small follow-up. ## Test plan CI runs Go tests + container build + Flutter checks. - [ ] CI green - [ ] Operator: deploy fresh, visit `/register`, register user #1, confirm `is_admin = true` - [ ] Operator: from `/admin/users`, generate an invite, register a friend with that token, confirm friend lands as non-admin - [ ] Operator: confirm no `MINSTREL_AUTH_ADMIN_*` env var noise in logs / docker-compose / README
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/minstrel#34