Phase 01: Core Infrastructure & Security - 5 plans in 3 waves - 3 parallel (Wave 1-2), 1 sequential (Wave 3) - Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.2 KiB
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-core-infrastructure-security | 03 | execute | 2 |
|
|
true |
|
Purpose: Protect the API from abuse and common web vulnerabilities (INFR-06, INFR-07). Output: FastAPI application with layered security: rate limiting (100/min), CSRF protection, trusted hosts, CORS, and security headers.
<execution_context> @/home/mikkel/.claude/get-shit-done/workflows/execute-plan.md @/home/mikkel/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/01-core-infrastructure-security/01-RESEARCH.md (Pattern 3: FastAPI Security Middleware Stack) @.planning/phases/01-core-infrastructure-security/01-01-SUMMARY.md @.planning/phases/01-core-infrastructure-security/01-02-SUMMARY.md Task 1: Configure rate limiting and CSRF protection backend/app/core/security.py backend/app/api/deps.py Create backend/app/core/security.py: - Import and configure slowapi Limiter: - key_func=get_remote_address - default_limits=["100/minute"] - storage_uri from settings (default to memory, Redis for production) - Configure fastapi-csrf-protect CsrfProtect: - Create CsrfSettings Pydantic model with: - secret_key from settings - cookie_samesite = "lax" - cookie_secure = True (HTTPS only) - cookie_httponly = True - Implement @CsrfProtect.load_config decoratorCreate backend/app/api/deps.py:
- Import get_db from app.db.session
- Re-export for cleaner imports in endpoints
- Create optional dependency for CSRF validation:
async def validate_csrf(csrf_protect: CsrfProtect = Depends()): await csrf_protect.validate_csrf_in_cookies()
Run: cd /home/mikkel/repos/debate && ruff check backend/app/core/security.py backend/app/api/deps.py
Expected: No errors.
Rate limiter configured at 100/minute, CSRF protection configured with secure cookie settings.
-
TrustedHostMiddleware:
- allowed_hosts from settings.allowed_hosts
- Block requests with invalid Host header
-
CORSMiddleware:
- allow_origins from settings.allowed_origins
- allow_credentials=True
- allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]
- allow_headers=["*"]
- max_age=600 (cache preflight for 10 min)
-
Rate limiting:
- app.state.limiter = limiter
- Add RateLimitExceeded exception handler
-
Custom middleware for security headers:
- Strict-Transport-Security: max-age=31536000; includeSubDomains
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: strict-origin-when-cross-origin
Update backend/app/api/v1/endpoints/health.py:
- Keep GET /health as simple {"status": "healthy"}
- Add GET /health/db that checks database connectivity:
- Depends on get_db session
- Execute "SELECT 1" query
- Return {"status": "healthy", "database": "connected"} on success
- Return {"status": "unhealthy", "database": "error", "detail": str(e)} on failure
- Add @limiter.exempt decorator to health endpoints (don't rate limit health checks) Start the server and test:
cd /home/mikkel/repos/debate
source .venv/bin/activate
uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 &
sleep 2
# Test health endpoint
curl -s http://localhost:8000/health
# Test database health
curl -s http://localhost:8000/api/v1/health/db
# Test security headers
curl -sI http://localhost:8000/health | grep -E "(X-Content-Type|X-Frame|Strict-Transport)"
# Test rate limiting (make 110 requests)
for i in {1..110}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8000/health; done | sort | uniq -c
Expected: First 100+ requests return 200, some return 429 (rate limited). Kill the server after testing. Security middleware applied, health endpoints check database, rate limiting blocks excess requests.
1. `curl -sI http://localhost:8000/health` includes security headers (X-Content-Type-Options, X-Frame-Options) 2. `curl http://localhost:8000/api/v1/health/db` returns database status 3. Rapid requests (>100/min) return 429 Too Many Requests 4. Invalid Host header returns 400 Bad Request 5. `ruff check backend/` passes<success_criteria>
- Rate limiting enforced at 100 requests/minute per IP (INFR-06)
- CSRF protection configured (INFR-07)
- Security headers present in all responses
- Health endpoints verify database connectivity
- All middleware applied in correct order </success_criteria>