fix(prod): harden production configuration for launch
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
- Gate Swagger/ReDoc/OpenAPI behind DEBUG (no public API schema in prod) - Sentry send_default_pii only in dev (no auth headers/bodies in events) - Remove alembic from Dockerfile CMD (releaseCommand owns migrations; CMD copy raced across replicas/restarts) - Decouple rate limiting from DEBUG via RATE_LIMIT_ENABLED (PR envs with DEBUG=true were unlimited); tests disable the live limiter in conftest - max_instances=1 on the 4 scheduler jobs missing it - Boot-time failure when SELF_SERVE_ENABLED without RESEND_API_KEY/ANTHROPIC_API_KEY/FRONTEND_URL - Reject localhost OAUTH_REDIRECT_BASE outside DEBUG - pool_pre_ping + pool_recycle on the app engine - Frontend: DEV-gate stale-async console.warn; document VITE_SELF_SERVE_ENABLED fallback semantics in Dockerfile Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,10 @@ class Settings(BaseSettings):
|
||||
# Security
|
||||
BCRYPT_ROUNDS: int = 12
|
||||
|
||||
# Rate limiting — independent of DEBUG so PR/staging envs running with
|
||||
# DEBUG=true still rate-limit auth and AI endpoints.
|
||||
RATE_LIMIT_ENABLED: bool = True
|
||||
|
||||
# Security Headers
|
||||
CSP_REPORT_ONLY: bool = True # Set False to enforce CSP
|
||||
CSP_EXTRA_SCRIPT_SOURCES: list[str] = [] # Additional script-src domains
|
||||
@@ -255,6 +259,18 @@ class Settings(BaseSettings):
|
||||
MS_CLIENT_SECRET: Optional[str] = None
|
||||
OAUTH_REDIRECT_BASE: str = "http://localhost:5173"
|
||||
|
||||
@field_validator("OAUTH_REDIRECT_BASE", mode="after")
|
||||
@classmethod
|
||||
def reject_localhost_redirect_in_production(cls, v: str, info) -> str:
|
||||
"""OAuth code exchange against a localhost redirect_uri is always a
|
||||
misconfiguration outside DEBUG — fail at boot, not at first sign-in."""
|
||||
debug = info.data.get("DEBUG", False)
|
||||
if not debug and v.startswith("http://localhost"):
|
||||
raise ValueError(
|
||||
"OAUTH_REDIRECT_BASE must be set to the public frontend URL in production"
|
||||
)
|
||||
return v
|
||||
|
||||
# Monitoring
|
||||
SENTRY_DSN: Optional[str] = None
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ from app.core.tenant_context import register_tenant_listener
|
||||
engine = create_async_engine(
|
||||
settings.DATABASE_URL,
|
||||
echo=settings.DEBUG,
|
||||
future=True
|
||||
future=True,
|
||||
# Detect connections dropped by DB restarts/maintenance instead of failing requests
|
||||
pool_pre_ping=True,
|
||||
pool_recycle=1800,
|
||||
)
|
||||
|
||||
# Create async session factory
|
||||
|
||||
@@ -3,4 +3,4 @@ from slowapi.util import get_remote_address
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
limiter = Limiter(key_func=get_remote_address, enabled=not settings.DEBUG)
|
||||
limiter = Limiter(key_func=get_remote_address, enabled=settings.RATE_LIMIT_ENABLED)
|
||||
|
||||
Reference in New Issue
Block a user