diff --git a/.env.example b/.env.example index 12193bc..2028a86 100644 --- a/.env.example +++ b/.env.example @@ -40,6 +40,9 @@ GITHUB_REDIRECT_URI=http://localhost:3000/auth/github/callback # CORS Configuration (Security) # Comma-separated list of allowed origins ALLOWED_ORIGINS=http://localhost:3000 +# Regex for dynamic CORS origins (Vercel preview deploys) +# Scoped to our project name so only our previews can call the backend +# ALLOW_ORIGIN_REGEX=https://opencodeintel.*\.vercel\.app # Redis (auto-configured in Docker, set REDIS_URL in Railway) REDIS_HOST=redis diff --git a/backend/config/startup_checks.py b/backend/config/startup_checks.py index 5aa0e60..4d8510e 100644 --- a/backend/config/startup_checks.py +++ b/backend/config/startup_checks.py @@ -29,6 +29,8 @@ ("GITHUB_CLIENT_ID", "GitHub OAuth client ID", "GitHub repo import disabled"), ("GITHUB_CLIENT_SECRET", "GitHub OAuth client secret", "GitHub repo import disabled"), ("DISCORD_FEEDBACK_WEBHOOK", "Discord webhook for feedback", "Feedback notifications disabled"), + ("ALLOW_ORIGIN_REGEX", "CORS regex for preview deploys", "Only explicit origins allowed"), + ("GITHUB_TOKEN", "GitHub API token for repo analysis", "Using unauthenticated rate limit (60/hr)"), ] diff --git a/backend/main.py b/backend/main.py index 8e7d12e..76465c0 100644 --- a/backend/main.py +++ b/backend/main.py @@ -75,9 +75,13 @@ async def dispatch(self, request: Request, call_next): app.add_middleware(RequestSizeLimitMiddleware) ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000").split(",") +# Allow Vercel preview deploys so PRs can be tested against prod backend. +# Set to project-scoped regex: https://opencodeintel.*\.vercel\.app +ALLOW_ORIGIN_REGEX = os.getenv("ALLOW_ORIGIN_REGEX", "") app.add_middleware( CORSMiddleware, allow_origins=ALLOWED_ORIGINS, + allow_origin_regex=ALLOW_ORIGIN_REGEX or None, allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type"],