"""Bootstrap default permissions, roles, and the first superuser. Idempotent: safe to run repeatedly. Reads the superuser credentials from settings (env vars or .env). Usage: uv run python -m scripts.seed """ import asyncio from app.core.config import settings from app.core.database import AsyncSessionLocal, init_db from app.crud import role as role_crud from app.crud import user as user_crud # Default permission catalogue: ":". PERMISSIONS = [ ("users:read", "View users"), ("users:write", "Create and update users"), ("users:delete", "Delete users"), ("roles:read", "View roles and permissions"), ("roles:write", "Create, update and delete roles"), ] # Default roles -> permission names. "admin" gets everything. ROLES = { "admin": [name for name, _ in PERMISSIONS], "user": ["users:read"], } async def seed() -> None: await init_db() async with AsyncSessionLocal() as db: # Permissions perms = {} for name, description in PERMISSIONS: perm = await role_crud.get_permission_by_name(db, name) if perm is None: perm = await role_crud.create_permission(db, name=name, description=description) perms[name] = perm # Roles roles = {} for role_name, perm_names in ROLES.items(): role = await role_crud.get_by_name(db, role_name) if role is None: role = await role_crud.create( db, name=role_name, description=f"{role_name.title()} role", permission_ids=[perms[p].id for p in perm_names], ) roles[role_name] = role # Superuser existing = await user_crud.get_by_email(db, settings.first_superuser_email) if existing is None: await user_crud.create( db, email=settings.first_superuser_email, password=settings.first_superuser_password, full_name="Administrator", is_superuser=True, role_ids=[roles["admin"].id], ) print(f"Created superuser: {settings.first_superuser_email}") else: print(f"Superuser already exists: {settings.first_superuser_email}") print("Seed complete.") if __name__ == "__main__": asyncio.run(seed())