Skip to content

Database

Each environment gets an Aurora PostgreSQL Serverless v2 cluster with IAM authentication (no passwords). With the default hawk:dbMinCapacity: "0", the cluster scales to zero after a few minutes of inactivity to save costs; the first connection after a pause takes ~30 seconds to wake up.

Database Roles

These login roles are created automatically:

Role Purpose
inspect_admin Migrations (rds_superuser)
inspect API read/write
inspect_ro Read-only access
middleman LLM proxy model config reads
inspect-importer Import pipeline (eval-log and scan importers); bypasses RLS. Name configurable via hawk:warehouseSystemUser

Row-level security is managed through NOLOGIN group roles that the login roles are granted into: rls_bypass (system pipelines), rls_reader (RLS-filtered reads), and model_access_all. See Security: Access Control for how permissions flow.

Connecting

Connect via IAM auth token (no passwords):

ENDPOINT=$(pulumi stack output database_endpoint)
TOKEN=$(aws rds generate-db-auth-token \
  --hostname $ENDPOINT --port 5432 --region <region> --username inspect)
PGPASSWORD="$TOKEN" psql "host=$ENDPOINT dbname=inspect user=inspect sslmode=require"

Running Migrations

Get the database URL from your infrastructure outputs:

export DATABASE_URL=$(pulumi stack output database_url_admin)

Run migrations:

cd hawk
alembic upgrade head

Creating a New Migration

After changing the SQLAlchemy models in hawk/core/db/models.py:

alembic revision --autogenerate -m "description of change"

Test it round-trips cleanly:

alembic upgrade head && alembic downgrade -1 && alembic upgrade head

Schema Conventions

  • All tables have a pk UUID primary key, and created_at/updated_at timestamps
  • All timestamps are timezone-aware and stored in UTC
  • Model names are singular