"""Seed script — creates the initial admin user if it does not already exist. On first run the admin credentials are generated securely: - Username is read from ``ADMIN_USERNAME`` env var (default: ``admin``). - Password is read from ``ADMIN_PASSWORD`` env var. When the variable is **not set**, a cryptographically random 16-character password is generated automatically and printed to the startup logs so the operator can copy it. Usage: python -m app.seed """ # Import os import os # Import secrets import secrets # Import string import string # Import hash_password from app.auth from app.auth import hash_password # Import SessionLocal from app.database from app.database import SessionLocal # Import User from app.models.user from app.models.user import User # Characters for auto-generated passwords (alphanumeric + safe symbols) _PW_ALPHABET = string.ascii_letters + string.digits + "!@#$%&*-_+" # Define function _generate_password def _generate_password(length: int = 16) -> str: """Return a cryptographically random password of *length* characters.""" # Return "".join(secrets.choice(_PW_ALPHABET) for _ in range(length)) return "".join(secrets.choice(_PW_ALPHABET) for _ in range(length)) # Define function seed_admin def seed_admin() -> None: """Create the initial admin user when it is missing. Reads ``ADMIN_USERNAME`` and ``ADMIN_PASSWORD`` from the environment. If ``ADMIN_PASSWORD`` is empty or unset a secure random password is generated and displayed in the logs. """ # Assign db = SessionLocal() db = SessionLocal() # Attempt the following; catch errors below try: # Assign admin_username = os.environ.get("ADMIN_USERNAME", "admin").strip() or "admin" admin_username = os.environ.get("ADMIN_USERNAME", "admin").strip() or "admin" # Assign existing = db.query(User).filter(User.username == admin_username).first() existing = db.query(User).filter(User.username == admin_username).first() # Check: existing if existing: # Call print() print(f"Admin user '{admin_username}' already exists — skipping.") # Return control to caller return # Assign admin_password = os.environ.get("ADMIN_PASSWORD", "").strip() admin_password = os.environ.get("ADMIN_PASSWORD", "").strip() # Assign password_was_generated = False password_was_generated = False # Check: not admin_password if not admin_password: # Assign admin_password = _generate_password() admin_password = _generate_password() # Assign password_was_generated = True password_was_generated = True # Assign admin = User( admin = User( # Keyword argument: username username=admin_username, # Keyword argument: hashed_password hashed_password=hash_password(admin_password), # Keyword argument: role role="admin", ) # Stage new record(s) for database insertion db.add(admin) # Commit all pending changes to the database db.commit() # ── Display credentials in startup logs ────────────────────── print() # Call print() print("=" * 60) # Call print() print(" AEGIS — Initial Admin User Created") # Call print() print("=" * 60) # Call print() print(f" Username : {admin_username}") # Check: password_was_generated if password_was_generated: # Call print() print(f" Password : {admin_password}") # Call print() print() # Call print() print(" ** This password was auto-generated because") # Call print() print(" ADMIN_PASSWORD was not set in the environment. **") # Call print() print(" ** Save it now — it will NOT be shown again. **") # Fallback: handle remaining cases else: # Call print() print(" Password : (set via ADMIN_PASSWORD env var)") # Call print() print("=" * 60) # Call print() print() # Always execute this cleanup block finally: # Close the database session db.close() # Check: __name__ == "__main__" if __name__ == "__main__": # Call seed_admin() seed_admin()