red-teaming-api
red-teaming-api
Stub FastAPI service for splitting backend functionality into standalone apps.
Endpoints
GET /health-> runsSELECT 1against configured SQL DBGET /version->{"version":"0.1.0"}(orAPP_VERSIONenv var)GET /openapi.json-> generated OpenAPI document for all CRUD resourcesGET /docs-> Swagger UI for the OpenAPI document
CRUD API
The API now exposes CRUD routes for every relational table under /api/v1/....
- Collection routes:
GET /api/v1/<resource>-> list rowsPOST /api/v1/<resource>-> create a row
- Single-column primary keys:
GET /api/v1/<resource>/{id}PATCH /api/v1/<resource>/{id}DELETE /api/v1/<resource>/{id}
- Composite primary keys:
GET /api/v1/<resource>/item?<pk1>=...&<pk2>=...PATCH /api/v1/<resource>/item?<pk1>=...&<pk2>=...DELETE /api/v1/<resource>/item?<pk1>=...&<pk2>=...
Examples:
# Create an agent
curl -X POST http://localhost:8080/api/v1/agents \
-H 'content-type: application/json' \
-d '{"agent_id":"alexbot","name":"alexbot","app_name":"mangrove-alexbot"}'
# Read a single-key resource
curl http://localhost:8080/api/v1/agents/alexbot
# Read a composite-key resource
curl 'http://localhost:8080/api/v1/bug_votes/item?bug_id=bug-1&user_key=karl'
Database Connectivity
Set DATABASE_URL before starting the API or running migrations.
export DATABASE_URL='postgresql+psycopg://USER:PASSWORD@HOST:5432/fdcdb?sslmode=require'
For Fly deployment:
flyctl secrets set DATABASE_URL='postgresql+psycopg://USER:PASSWORD@HOST:5432/fdcdb?sslmode=require' --app red-teaming-api
Migrations
cd red-teaming/api
uv run alembic upgrade head # apply all migrations
uv run alembic downgrade -1 # rollback one migration
The container entrypoint now runs alembic upgrade head automatically before starting uvicorn when DATABASE_URL is set.
Schema coverage
The current migration chain now creates a relational schema that mirrors the main Firebase RTDB domains used by the live red-teaming site and proxy:
agents,userspersonal_notes,shared_notes,note_ordercustom_metagames,metagame_votescustom_scenarios,scenario_votesbugs,bug_votes,bug_fixesdatasets,community_templatesdaily_logs,daily_log_entity_summariesworkspace_snapshots,workspace_snapshot_files,agent_daily_memory_logs
Document-shaped fields that are still variable in the RTDB payloads, such as evidence, highlights, memory diffs, stats, and template file maps, are stored as JSON columns for now.
Run locally
cd red-teaming/api
export DATABASE_URL='sqlite+pysqlite:///./local.db'
uv run uvicorn app.main:app --reload --port 8080
Run tests
cd red-teaming/api
uv run pytest
Deploy manually
cd red-teaming/api
flyctl deploy --remote-only --app red-teaming-api
Always-on policy
fly.toml is configured to keep this app warm:
auto_stop_machines = "off"min_machines_running = 1[[restart]] policy = "always"
After a deploy, verify at least one machine is running:
flyctl machine list --app red-teaming-api --json | jq -r '.[] | [.id, .state, (.config.restart.policy // "unset")] | @tsv'
If the app is already suspended/stopped, recover with:
flyctl machine list --app red-teaming-api --json | jq -r '.[] | select(.state != "destroyed") | .id' | head -n1 | xargs -I{} flyctl machine start {} --app red-teaming-api
