From 6c7617f1b548dfb083496cc233230c9cda3281d6 Mon Sep 17 00:00:00 2001 From: Motoko Date: Mon, 30 Mar 2026 16:38:43 +0000 Subject: [PATCH] Fix: Create initial admin user from environment variables on startup --- app/database.py | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/app/database.py b/app/database.py index acaed11..ff6e992 100644 --- a/app/database.py +++ b/app/database.py @@ -1,5 +1,4 @@ import asyncio -import hashlib import uuid from contextlib import asynccontextmanager from pathlib import Path @@ -69,6 +68,47 @@ async def init_db(): # Create all tables via SQL (not ORM) to handle SQLite-specific features await conn.run_sync(_create_schema) + # Create initial admin user if configured and doesn't exist + await _create_initial_admin() + + +async def _create_initial_admin(): + """Create initial admin user from environment variables if it doesn't exist.""" + import bcrypt + + if not settings.INITIAL_ADMIN_USERNAME or not settings.INITIAL_ADMIN_PASSWORD: + return + + async with AsyncSessionLocal() as session: + # Check if admin already exists + result = await session.execute( + text("SELECT id FROM agents WHERE username = :username AND role = 'admin'"), + {"username": settings.INITIAL_ADMIN_USERNAME} + ) + existing = result.fetchone() + + if existing: + return # Admin already exists + + # Create admin user with bcrypt hash + password_hash = bcrypt.hashpw( + settings.INITIAL_ADMIN_PASSWORD.encode("utf-8"), + bcrypt.gensalt() + ).decode("utf-8") + + await session.execute( + text(""" + INSERT INTO agents (id, username, password_hash, role, created_at, updated_at) + VALUES (:id, :username, :password_hash, 'admin', datetime('now'), datetime('now')) + """), + { + "id": str(uuid.uuid4()), + "username": settings.INITIAL_ADMIN_USERNAME, + "password_hash": password_hash + } + ) + await session.commit() + def _create_schema(sync_conn): """Create all tables, views, FTS5 tables, and triggers synchronously."""