Files
openclaw-mission-control/backend
Hugh Brown 94988deef2 security: add rate limiting to agent auth and webhook ingest
Agent token auth performed O(n) PBKDF2 operations per request with no
rate limiting, enabling CPU exhaustion attacks. Webhook ingest had no
rate limits either. Add an in-memory token-bucket rate limiter:
- Agent auth: 20 requests/minute per IP
- Webhook ingest: 60 requests/minute per IP

Includes unit tests for the rate limiter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:35:10 +05:30
..

Mission Control Backend (FastAPI)

This directory contains the Mission Control backend API (FastAPI + SQLModel) and its database migrations (Alembic).

Requirements

  • Python 3.12+
  • uv (recommended; used by this repo)
  • Postgres (local or Docker)

Quick start (local backend + Docker Postgres)

From the repo root:

# start dependencies
cp .env.example .env
docker compose -f compose.yml --env-file .env up -d db

# run backend
cd backend
cp .env.example .env

uv sync --extra dev
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

Verify:

curl -f http://localhost:8000/healthz

Configuration / environment variables

Backend settings are defined in app/core/config.py via pydantic-settings.

The backend loads env files in this order:

  1. backend/.env (preferred)
  2. .env (current working directory)

A starter file exists at backend/.env.example.

Core

  • ENVIRONMENT (default: dev)
    • In dev, if you dont explicitly set DB_AUTO_MIGRATE, the backend defaults it to true.
  • LOG_LEVEL (default: INFO)
  • DATABASE_URL
    • Default: postgresql+psycopg://postgres:postgres@localhost:5432/openclaw_agency
    • Recommended local/dev default (matches backend/.env.example): postgresql+psycopg://postgres:postgres@localhost:5432/mission_control
  • CORS_ORIGINS (comma-separated)
    • Example: http://localhost:3000
  • BASE_URL (required for gateway provisioning/agent heartbeat templates; no fallback)

Database lifecycle

  • DB_AUTO_MIGRATE
    • If true: on startup, the backend attempts to run Alembic migrations (alembic upgrade head).
    • If there are no Alembic revision files yet, it falls back to SQLModel.metadata.create_all.

Auth (Clerk)

Clerk is used for user authentication (optional for local/self-host in many setups).

  • CLERK_SECRET_KEY (required)
    • Used to fetch user profile fields (email/name) from Clerk when JWT claims are minimal.
  • CLERK_API_URL (default: https://api.clerk.com)
  • CLERK_VERIFY_IAT (default: true)
  • CLERK_LEEWAY (default: 10.0)

Database migrations (Alembic)

Migrations live in backend/migrations/versions/*.

Common commands:

cd backend

# apply migrations
uv run alembic upgrade head

# create a new migration (example)
uv run alembic revision --autogenerate -m "add foo"

Notes:

  • The backend can also auto-run migrations on startup when DB_AUTO_MIGRATE=true.
  • The database URL is normalized so postgresql://... becomes postgresql+psycopg://....

Running tests / lint / typecheck

From repo root (recommended):

make backend-lint
make backend-test
make backend-coverage

make backend-lint runs backend format checks (isort, black), lint (flake8), and typecheck (mypy) in one command.

Or from backend/:

cd backend
uv run pytest
uv run isort . --check-only --diff
uv run black . --check --diff
uv run flake8 --config .flake8
uv run mypy

Formatting:

make backend-format
make backend-format-check

Scripts

Backend scripts live in backend/scripts/:

  • export_openapi.py export OpenAPI schema
  • seed_demo.py seed demo data (if applicable)
  • sync_gateway_templates.py sync repo templates to an existing gateway

Run with:

cd backend
uv run python scripts/export_openapi.py

Troubleshooting

Backend cant connect to Postgres

  • If you started Postgres via compose, make sure it is healthy:

    docker compose -f compose.yml --env-file .env ps
    docker compose -f compose.yml --env-file .env logs -f --tail=200 db
    
  • If backend runs locally (not in compose), DATABASE_URL should usually point at localhost.

CORS issues from the frontend

  • Set CORS_ORIGINS=http://localhost:3000 (or a comma-separated list) in backend/.env.
  • Restart the backend after changing env vars.

Alembic / migrations not applying

  • If you want deterministic behavior, run migrations manually:

    cd backend
    uv run alembic upgrade head
    
  • If DB_AUTO_MIGRATE=false, the backend may use create_all instead of Alembic.