forked from cartsnitch/cartsnitch
Merge pull request #56 from cartsnitch/feat/uat-seed-user
feat: add dedicated UAT seed user with known credentials
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# CartSnitch Common
|
||||
|
||||
Shared models, schemas, and utilities for CartSnitch services.
|
||||
|
||||
## Test Users
|
||||
|
||||
The following users are seeded by `cartsnitch-seed` and can be used for local development and UAT.
|
||||
|
||||
| Email | Password | Display Name | Notes |
|
||||
|---|---|---|---|
|
||||
| `uat@cartsnitch.com` | `CartSnitch-UAT-2026!` | UAT Tester | Primary UAT account. Use for regression testing in the CartSnitch frontend. Created by the seed runner via Better-Auth's bcrypt path — credentials work against the live auth service. Idempotent; re-running the seed skips this user if it already exists. |
|
||||
|
||||
### Running the Seed
|
||||
|
||||
```bash
|
||||
# Install with seed dependencies
|
||||
pip install -e "cartsnitch-common[seed]"
|
||||
|
||||
# Run (requires CARTSNITCH_DATABASE_URL_SYNC)
|
||||
CARTSNITCH_DATABASE_URL_SYNC=postgresql://user:pass@localhost:5432/cartsnitch \
|
||||
cartsnitch-seed
|
||||
```
|
||||
|
||||
### Architecture
|
||||
|
||||
- **Models** live in `src/cartsnitch_common/models/`
|
||||
- **Alembic migrations** run via the `api` service (`api/alembic/`)
|
||||
- **Seed runner** runs via `cartsnitch-seed` (installed as a package entry point)
|
||||
@@ -27,6 +27,7 @@ dev = [
|
||||
]
|
||||
seed = [
|
||||
"faker>=33.0,<34.0",
|
||||
"bcrypt>=4.0,<6.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
import random
|
||||
import time
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
import bcrypt
|
||||
from faker import Faker
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -184,6 +186,65 @@ def run_seed(
|
||||
|
||||
session.commit()
|
||||
|
||||
_seed_uat_user(session)
|
||||
|
||||
elapsed = time.monotonic() - t0
|
||||
_log("")
|
||||
_log(f"Seed complete in {elapsed:.1f}s")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# UAT seed user
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
UAT_EMAIL = "uat@cartsnitch.com"
|
||||
UAT_PASSWORD = "CartSnitch-UAT-2026!"
|
||||
UAT_DISPLAY_NAME = "UAT Tester"
|
||||
UAT_USER_ID = uuid.UUID("00000000-0000-0000-0000-000000000001")
|
||||
|
||||
|
||||
def _seed_uat_user(session: Session) -> None:
|
||||
"""Insert or verify the dedicated UAT test user.
|
||||
|
||||
The user is created via Better-Auth's bcrypt hashing path so credentials
|
||||
work against the live auth service. Idempotent — skips if the user already
|
||||
exists.
|
||||
"""
|
||||
existing = session.execute(
|
||||
text("SELECT id FROM users WHERE email = :email"),
|
||||
{"email": UAT_EMAIL},
|
||||
).fetchone()
|
||||
|
||||
if existing is not None:
|
||||
_log(f"UAT user {UAT_EMAIL} already exists — skipping")
|
||||
return
|
||||
|
||||
password_hash = bcrypt.hashpw(UAT_PASSWORD.encode(), bcrypt.gensalt()).decode()
|
||||
|
||||
session.execute(
|
||||
text(
|
||||
"INSERT INTO users (id, email, hashed_password, display_name, email_verified, created_at, updated_at) "
|
||||
"VALUES (:id, :email, :hashed_password, :display_name, true, now(), now())"
|
||||
),
|
||||
{
|
||||
"id": str(UAT_USER_ID),
|
||||
"email": UAT_EMAIL,
|
||||
"hashed_password": password_hash,
|
||||
"display_name": UAT_DISPLAY_NAME,
|
||||
},
|
||||
)
|
||||
|
||||
session.execute(
|
||||
text(
|
||||
"INSERT INTO accounts (id, user_id, account_id, provider_id, password, created_at, updated_at) "
|
||||
"VALUES (gen_random_uuid()::text, :user_id, :account_id, 'credential', :password, now(), now())"
|
||||
),
|
||||
{
|
||||
"user_id": str(UAT_USER_ID),
|
||||
"account_id": str(UAT_USER_ID),
|
||||
"password": password_hash,
|
||||
},
|
||||
)
|
||||
|
||||
session.commit()
|
||||
_log(f"UAT user {UAT_EMAIL} created")
|
||||
|
||||
Reference in New Issue
Block a user