diff --git a/backend/app/main.py b/backend/app/main.py index 0499eddb..d922241a 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -5,7 +5,7 @@ from __future__ import annotations from contextlib import asynccontextmanager from typing import TYPE_CHECKING, Any -from fastapi import APIRouter, FastAPI, status +from fastapi import APIRouter, FastAPI, Request, Response, status from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.utils import get_openapi from fastapi_pagination import add_pagination @@ -467,6 +467,17 @@ else: install_error_handling(app) +@app.middleware("http") +async def security_headers(request: Request, call_next: Any) -> Response: + """Inject standard security headers into every response.""" + response: Response = await call_next(request) + response.headers.setdefault("X-Content-Type-Options", "nosniff") + response.headers.setdefault("X-Frame-Options", "DENY") + response.headers.setdefault("Referrer-Policy", "strict-origin-when-cross-origin") + response.headers.setdefault("Permissions-Policy", "camera=(), microphone=(), geolocation=()") + return response + + @app.get( "/health", tags=["health"], diff --git a/compose.yml b/compose.yml index 85930802..ddde29eb 100644 --- a/compose.yml +++ b/compose.yml @@ -21,6 +21,11 @@ services: image: redis:7-alpine ports: - "${REDIS_PORT:-6379}:6379" + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 backend: build: @@ -42,7 +47,7 @@ services: db: condition: service_healthy redis: - condition: service_started + condition: service_healthy ports: - "${BACKEND_PORT:-8000}:8000" @@ -75,7 +80,7 @@ services: - ./backend/.env.example depends_on: redis: - condition: service_started + condition: service_healthy db: condition: service_healthy environment: