3.2 KiB
3.2 KiB
AI Gateway — Development Tasks
Per-Plugin Module Keys (Security)
Goal: Replace the single shared
AI_GATEWAY_KEYembedded in exported Live Practice plugin HTML with scoped, expiring, per-plugin keys. Existing modules and endpoints must not break.
Step 1 — DB Schema: Add expires_at and rate_limit_per_hour to Module
- Add
expires_at: DateTime, nullabletoapp/models/module.py—None= no expiry (existing modules unaffected) - Add
rate_limit_per_hour: Integer, nullabletoapp/models/module.py—None= falls back to global slowapi limit - Create
supabase/migrations/YYYYMMDD_plugin_keys.sql:ALTER TABLE public.modules ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ NULL; ALTER TABLE public.modules ADD COLUMN IF NOT EXISTS rate_limit_per_hour INTEGER NULL; - Run migration against Supabase DB
Step 2 — Enforce expiry in deps.py
- In
get_api_key()(app/api/deps.py): after DB lookup, checkmodule.expires_at— if set and in the past, raise HTTP 403 - Same check in
get_current_module()(app/api/deps.py) - Document in a comment that the TTLCache (5-min TTL) means expired keys have up to a 5-minute grace period
Step 3 — Per-key rate limiting
- In
app/core/limiter.py, replacekey_func=get_remote_addresswith a custom function that returns theX-API-Keyheader value when present, falling back to IP:def get_api_key_or_ip(request: Request) -> str: return request.headers.get("X-API-Key") or get_remote_address(request) - Verify existing endpoints still receive 429 responses correctly after the change
Step 4 — Provisioning endpoint
- Create
app/api/endpoints/provision.py—POST /api/v1/modules/provision:- Auth: global
API_KEYviaX-API-Keyheader (reuses existing static key check) - Body:
name,expires_in_days(int, default 365),rate_limit_per_hour(int, optional) - Creates a new
Modulerecord withsecrets.token_hex(32)assecret_key - Sets
expires_at = utcnow() + timedelta(days=expires_in_days) - Returns
{ secret_key, module_id, expires_at }
- Auth: global
- Register in
app/api/router.py:api_router.include_router(provision.router, prefix="/modules", tags=["provisioning"]) - Update
api_documentation.mdwith the new endpoint
Step 5 — Live Practice integration (handled in Live Practice repo)
These tasks are tracked in the Live Practice
TASKS.md, not here. Listed for cross-reference only.
- Add
ai_gateway_keycolumn topluginstable - Export route provisions a scoped key via
POST /api/v1/modules/provision(using server-sideAI_GATEWAY_KEYas admin credential) - Scoped per-plugin key is embedded in exported HTML instead of the shared
AI_GATEWAY_KEY - Preview-html route continues using
AI_GATEWAY_KEYdirectly (server-side only, safe)
Backlog
- Respect
rate_limit_per_hourcolumn per-module (currently stored but not enforced dynamically — globalRATE_LIMITsetting applies uniformly) - Admin UI or CLI command to list/revoke/rotate plugin keys
- Webhook or callback when a key nears expiry