fix: seed builtin admin only on empty DB; recover page-load sessions with one refresh
Auth seeding (last-resort guard) - `_seed_builtin_admin()` in get_db() now skips when VACUUM_WALL_SEED_BUILTIN_ADMIN=0 or when the users table already contains any user — previously a fresh service start after a non-default bootstrap (e.g. --mgmt-user alice) seeded a hard-coded `admin` with an unrecoverable random password, shadowing the operator's account - bootstrap_auth.py sets VACUUM_WALL_SEED_BUILTIN_ADMIN=0: bootstrap creates the operator user itself on a fresh install, so exactly one account exists and no seeded admin can appear Frontend (session recovery) - on page load/restore the in-memory TTL timer is gone, so a valid 7-day refresh token could sit in sessionStorage while the access token is already expired server-side: the session `check` now attempts exactly one refresh (POST /api/auth/refresh with the stored refresh token) on 401 before treating the session as dead - extract shared `_doRefresh()` used by both the `check` 401 fallback and the `refresh` action (removes the duplicated rotation logic) Tests - update seeding tests to the new any-user-present check; add test_seed_skipped_when_users_exist, test_seed_skipped_via_env, test_bootstrap_flow_creates_exactly_one_user, and the auth-model JS test suite (tests/test-auth-model.js) Docs - AGENTS.md: document VACUUM_WALL_SEED_BUILTIN_ADMIN - architecture.md / hoover.md / security.md: describe the bootstrap check 401 → one-refresh fallback path
This commit is contained in:
@@ -7,6 +7,10 @@ Idempotent — safe to run on every install (and re-install):
|
||||
- Creates the admin user if missing; if the user already exists, updates
|
||||
the admin password to the provided value (docs/deployment.md: "On
|
||||
re-run, updates the admin password if already present").
|
||||
- Suppresses the last-resort builtin admin seed (VACUUM_WALL_SEED_BUILTIN_ADMIN=0):
|
||||
bootstrap is the operator user's creator on a fresh install, so exactly
|
||||
one account exists and no hardcoded admin with an unrecoverable random
|
||||
password is left behind.
|
||||
|
||||
Usage:
|
||||
python scripts/bootstrap_auth.py --project-dir /path/to/project \
|
||||
@@ -39,6 +43,9 @@ def main() -> None:
|
||||
db_path = str(project_dir / "data" / "auth.db")
|
||||
os.environ["VACUUM_WALL_DB_BACKEND"] = "sqlite"
|
||||
os.environ["VACUUM_WALL_DB_PATH"] = db_path
|
||||
# Suppress the last-resort builtin admin seed in get_db(): bootstrap
|
||||
# creates the operator user itself, so no seeded admin may shadow it.
|
||||
os.environ["VACUUM_WALL_SEED_BUILTIN_ADMIN"] = "0"
|
||||
|
||||
from lib.auth_users import (
|
||||
ALL_SUBSYSTEMS,
|
||||
|
||||
Reference in New Issue
Block a user