feat(auth): first-run account setup via .firstrun marker (refs #3) #14

Merged
vmruiz merged 3 commits from feat/first-run-setup into main 2026-08-23 22:42:51 +02:00
Owner

Issue #3 - Make first-run account creation easy

Implements a guided, web-only first-run flow to create the initial admin account, with no container exec and no insecure default credential.

Approach: explicit setup gate (not "users table empty")

The seed (runs in the Forgejo deploy pipeline) may preload an admin, so basing the flow on count(User) == 0 would never trigger in seeded environments and is fragile on clean prod. Instead the app uses an explicit signal:

  • DATA_DIR/.firstrun marker exists => setup mode is ON (when local login + setup are allowed).
  • On boot the app creates the marker only if the users table is empty (clean prod auto-starts the flow).
  • After the first admin is created via /auth/setup, the marker is deleted so the flow can never reappear.

This lets the seed coexist: leave .firstrun absent to use the seeded account, or drop an empty DATA_DIR/.firstrun to force the guided flow for E2E testing on a seeded box.

Changes

  • app/config.py: new local_setup_allowed (default True).
  • app/auth.py: ensure_firstrun_marker, is_setup_mode, mark_setup_complete.
  • app/main.py: bootstrap marker at startup; new POST /auth/setup (creates an admins user; rejects when not in setup mode or password too weak); login_page passes setup_mode.
  • app/templates/login.html: Create the first account panel shown only in setup mode.
  • README.md: documents the first-run flow.
  • .gitignore: ignore .firstrun.

Tests

  • New tests/test_firstrun_setup.py: 12 tests (gate detection, marker lifecycle, endpoint, login panel, docs). All pass.
  • Regression: tests/test_auth.py + tests/test_local_auth.py = 20/20 pass. Roles, Argon2id, lockout and the existing auth flow are untouched.

No insecure default is created; the password is supplied through the form and hashed with Argon2id, preserving the admins/users role model.

## Issue #3 - Make first-run account creation easy Implements a guided, web-only first-run flow to create the initial admin account, with no container exec and no insecure default credential. ### Approach: explicit setup gate (not "users table empty") The seed (runs in the Forgejo deploy pipeline) may preload an admin, so basing the flow on count(User) == 0 would never trigger in seeded environments and is fragile on clean prod. Instead the app uses an explicit signal: - DATA_DIR/.firstrun marker exists => setup mode is ON (when local login + setup are allowed). - On boot the app creates the marker only if the users table is empty (clean prod auto-starts the flow). - After the first admin is created via /auth/setup, the marker is deleted so the flow can never reappear. This lets the seed coexist: leave .firstrun absent to use the seeded account, or drop an empty DATA_DIR/.firstrun to force the guided flow for E2E testing on a seeded box. ### Changes - app/config.py: new local_setup_allowed (default True). - app/auth.py: ensure_firstrun_marker, is_setup_mode, mark_setup_complete. - app/main.py: bootstrap marker at startup; new POST /auth/setup (creates an admins user; rejects when not in setup mode or password too weak); login_page passes setup_mode. - app/templates/login.html: Create the first account panel shown only in setup mode. - README.md: documents the first-run flow. - .gitignore: ignore .firstrun. ### Tests - New tests/test_firstrun_setup.py: 12 tests (gate detection, marker lifecycle, endpoint, login panel, docs). All pass. - Regression: tests/test_auth.py + tests/test_local_auth.py = 20/20 pass. Roles, Argon2id, lockout and the existing auth flow are untouched. No insecure default is created; the password is supplied through the form and hashed with Argon2id, preserving the admins/users role model.
Add local_setup_allowed setting and setup-mode helpers
(ensure_firstrun_marker/is_setup_mode/mark_setup_complete). The app
bootstraps the marker on a clean install and removes it after the first
admin is created. Decouples the feature from 'table empty' so an external
seed never blocks or breaks it.
feat(ui): show first-run setup panel on login + docs (refs #3)
All checks were successful
Deploy Development Branch / deploy-dev (push) Successful in 1m31s
Clean Up Development Branch / cleanup-dev (pull_request) Successful in 19s
bf20c8be91
vmruiz merged commit 2582cefff1 into main 2026-08-23 22:42:51 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
vmruiz/telegramarr!14
No description provided.