#!/usr/bin/env python3 """ seed_test_users.py — Velocity-OS Test Credential Seeder ======================================================== FOR TESTING ONLY. Never include in production build. Inserts 7 test broker accounts into users_and_roles. All passwords follow the pattern: Name@Velocity26 All emails follow: name@desineuron.in Run against the local or remote Velocity-OS PostgreSQL: python seed_test_users.py # uses env vars python seed_test_users.py --dsn "postgresql://..." # explicit DSN """ import argparse import hashlib import os import sys # ── Generate bcrypt hashes OFFLINE (no DB dep) ──────────────────────────── # Uses passlib with same config as backend/auth/dependencies.py try: from passlib.context import CryptContext pwd_ctx = CryptContext(schemes=["bcrypt"], deprecated="auto") def hash_password(plain: str) -> str: raw = plain.encode("utf-8") if len(raw) > 72: plain = raw[:72].decode("utf-8", errors="ignore") return pwd_ctx.hash(plain) except ImportError: print("[ERROR] passlib not installed. Run: pip install passlib[bcrypt]") sys.exit(1) # ── Test user definitions ───────────────────────────────────────────────── # Format: (full_name, email, plain_password, role) TEST_USERS = [ ("Sagnik", "sagnik@desineuron.in", "Sagnik@Velocity26", "ADMIN"), ("Sayan", "sayan@desineuron.in", "Sayan@Velocity26", "ADMIN"), ("Sourik", "sourik@desineuron.in", "Sourik@Velocity26", "ADMIN"), ("Abantika", "abantika@desineuron.in", "Abantika@Velocity26", "ADMIN"), ("Sinjini", "sinjini@desineuron.in", "Sinjini@Velocity26", "ADMIN"), ("Swastika", "swastika@desineuron.in", "Swastika@Velocity26", "ADMIN"), ("Debargha", "debargha@desineuron.in", "Debargha@Velocity26", "ADMIN"), ] TENANT_ID = "tenant_velocity" def build_sql() -> str: """Generate idempotent INSERT SQL (ON CONFLICT DO NOTHING).""" lines = [ "-- ================================================================", "-- Velocity-OS Test Users Seed (FOR TESTING ONLY — NOT FOR PROD)", "-- ================================================================", "-- Generated by seed_test_users.py", "", "BEGIN;", "", ] for full_name, email, plain, role in TEST_USERS: pw_hash = hash_password(plain) lines.append(f"-- {full_name} ({role})") lines.append("INSERT INTO users_and_roles") lines.append(" (email, password_hash, role, tenant_id, full_name, is_active)") lines.append("VALUES") lines.append(f" ('{email}', '{pw_hash}', '{role}', '{TENANT_ID}', '{full_name}', TRUE)") lines.append("ON CONFLICT (email) DO UPDATE") lines.append(" SET password_hash = EXCLUDED.password_hash,") lines.append(" role = EXCLUDED.role,") lines.append(" full_name = EXCLUDED.full_name,") lines.append(" is_active = TRUE;") lines.append("") lines.append("COMMIT;") lines.append("") lines.append("-- Verify:") lines.append("SELECT email, role, full_name FROM users_and_roles ORDER BY role DESC, email;") return "\n".join(lines) def run_against_db(dsn: str, sql: str) -> None: try: import asyncpg import asyncio async def _insert(): conn = await asyncpg.connect(dsn) try: await conn.execute(sql) print("[OK] Test users inserted successfully.") finally: await conn.close() asyncio.run(_insert()) except ImportError: print("[WARN] asyncpg not installed — writing SQL file only.") write_sql_file(sql) def write_sql_file(sql: str) -> None: out = os.path.join(os.path.dirname(__file__), "seed_test_users.sql") with open(out, "w", encoding="utf-8") as f: f.write(sql) print(f"[OK] SQL written to: {out}") print(" Apply with: psql -U velocity_user -d velocity_db -f seed_test_users.sql") def main(): parser = argparse.ArgumentParser(description="Seed Velocity-OS test users") parser.add_argument("--dsn", help="PostgreSQL DSN (overrides env VELOCITY_DB_DSN)") parser.add_argument("--sql-only", action="store_true", help="Only write SQL file, don't connect") args = parser.parse_args() sql = build_sql() print("Generating bcrypt hashes for test users...") print("Users to seed:") for full_name, email, plain, role in TEST_USERS: print(f" [{role:16}] {email:30} / {plain}") print() if args.sql_only: write_sql_file(sql) return dsn = args.dsn or os.getenv("VELOCITY_DB_DSN") or os.getenv("DATABASE_URL") if dsn: run_against_db(dsn, sql) else: print("[INFO] No DSN provided — writing SQL file for manual application.") write_sql_file(sql) if __name__ == "__main__": main()