feat: rate-limit public reads and deploy to Fly.io on merge - #122
Conversation
GET /v1/places and GET /v1/places/{id} had no rate limiting at the app
layer, only authenticated writes did. Adds a per-IP token-bucket
limiter (20 req/s, burst 20) ahead of the OpenAPI validator, skipped
for requests carrying X-API-Key since those already have their own
per-key limiter.
Adds fly.toml (cmd/api, Frankfurt region, scale-to-zero) and a CI job that runs flyctl deploy only after all required checks pass on push to main, so a failing build/test/lint/scan never reaches production. Also ignores the local Supabase CLI's session cache directory.
|
Claude finished @koinsaari's task in 2m 22s —— View job Review
🔴 ImportantPublic rate limiter is bypassed by sending any if r.Header.Get("X-API-Key") == "" && !rl.Allow(ClientIP(r)) {This only checks whether the header is present, not whether it authenticates. Fix: gate the skip on a successful authentication result (e.g. check 🟡 Nits
No other issues found — SQL/GORM usage, JSONB types, and the a11y/validation ordering invariants are untouched by this diff. Note: I was unable to set the |
|
Claude finished @koinsaari's task in 1m 48s —— View job Review
The 🔴 Important finding from the previous review has been fixed in
All 🟡 Nits from the previous pass are resolved except one minor, non-blocking item:
No other issues found. No blocking issues. Note: I was unable to set the |
Ran before the OpenAPI validator/authenticate and only checked header presence, not validity. Now runs after the validator, keyed off APIKeyIDFromCtx, which is only set once a key is verified. Extracts buildV1Handler so a test covers the real composed chain instead of a hand-copied approximation. Also drops the redundant memory_mb in fly.toml.
17edf14 to
73101c6
Compare
Summary
fly.tomland a CI job that deployscmd/apito Fly.io, gated on all required checks passing, only on push tomain.🤖 Generated with Claude Code