-
Notifications
You must be signed in to change notification settings - Fork 2
Add Dockerfile and fix CORS errors #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| FROM python:3.11-slim | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| COPY requirements.txt . | ||
| RUN pip install -r requirements.txt | ||
|
|
||
| COPY . . | ||
|
|
||
| EXPOSE 8000 | ||
|
|
||
| CMD ["bash", "/app/start.sh"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
| import shutil | ||
| import logging | ||
| from contextlib import asynccontextmanager | ||
| from urllib.parse import urlsplit | ||
|
|
||
| from dotenv import load_dotenv | ||
| from fastapi import FastAPI | ||
|
|
@@ -22,21 +23,47 @@ | |
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def _normalize_origin(origin: str) -> str | None: | ||
| """Normalize CORS entries to scheme://host[:port] and drop invalid values.""" | ||
| raw = origin.strip() | ||
| if not raw: | ||
| return None | ||
|
|
||
| parsed = urlsplit(raw) | ||
| if not parsed.scheme or not parsed.netloc: | ||
| logger.warning("Ignoring invalid CORS origin '%s'", origin) | ||
| return None | ||
|
|
||
| normalized = f"{parsed.scheme}://{parsed.netloc}" | ||
| if normalized != raw.rstrip("/"): | ||
| logger.warning("Normalized CORS origin '%s' to '%s'", origin, normalized) | ||
| return normalized | ||
|
|
||
|
|
||
| def _normalized_unique(origins: list[str]) -> list[str]: | ||
| result: list[str] = [] | ||
| for origin in origins: | ||
| normalized = _normalize_origin(origin) | ||
| if normalized and normalized not in result: | ||
| result.append(normalized) | ||
| return result | ||
|
|
||
|
|
||
| def _build_allowed_origins() -> list[str]: | ||
| """Build a strict CORS allow-list from environment variables.""" | ||
| allowed_origins_env = os.getenv("FRONTEND_ALLOWED_ORIGINS", "") | ||
| parsed = [origin.strip() for origin in allowed_origins_env.split(",") if origin.strip()] | ||
| parsed = _normalized_unique(allowed_origins_env.split(",")) | ||
|
|
||
| if parsed: | ||
| return parsed | ||
|
|
||
| # Backward-compatible fallback when comma-separated variable is not set. | ||
| legacy_origins = [o for o in [FRONTEND_DEV_URL, FRONTEND_PROD_URL] if o] | ||
| legacy_origins = _normalized_unique([FRONTEND_DEV_URL, FRONTEND_PROD_URL]) | ||
| if legacy_origins: | ||
| return legacy_origins | ||
|
|
||
| # Safe local fallback for development/test only. | ||
| return ["http://localhost:3000", "http://127.0.0.1:3000", "*"] | ||
| return ["http://localhost:3000", "http://127.0.0.1:3000"] | ||
|
Comment on lines
+26
to
+66
|
||
|
|
||
|
|
||
| ALLOWED_ORIGINS = _build_allowed_origins() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| window.APP_CONFIG = Object.freeze({ | ||
| API_URL: "https://mpvrppythonapi.pinite37.me" | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,11 +12,11 @@ WORKERS="${WORKERS:-2}" | |||||
|
|
||||||
| # Export DATABASE_URL (uses existing value if already set). | ||||||
| export DATABASE_URL="${DATABASE_URL:-sqlite:///./mpvrp_scoring.db}" | ||||||
| export FRONTEND_ALLOWED_ORIGINS="${FRONTEND_ALLOWED_ORIGINS:-https://ifri-ai-classes.github.io,https://ifri-ai-classes.github.io/MPVRP-CC,https://ifri-ai-classes.github.io/MPVRP-CC/pages}" | ||||||
|
||||||
| export FRONTEND_ALLOWED_ORIGINS="${FRONTEND_ALLOWED_ORIGINS:-https://ifri-ai-classes.github.io,https://ifri-ai-classes.github.io/MPVRP-CC,https://ifri-ai-classes.github.io/MPVRP-CC/pages}" | |
| export FRONTEND_ALLOWED_ORIGINS="${FRONTEND_ALLOWED_ORIGINS:-https://ifri-ai-classes.github.io,http://localhost:3000,http://127.0.0.1:3000,http://localhost:5173,http://127.0.0.1:5173}" |
Copilot
AI
Mar 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export SECRET_KEY="$(...)" overwrites any pre-set SECRET_KEY on every start, which breaks token validity across restarts and contradicts the "Require stable secret key" comment. It also makes the subsequent -z check effectively dead code. Prefer only generating a key when SECRET_KEY is unset (or fail fast in production) and keep the stability requirement enforceable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base image is Python 3.11, but the project declares requires-python ">=3.12" (pyproject.toml). This mismatch can cause runtime failures or dependency resolution issues in the container. Update the image to a 3.12 variant (or adjust the project requirement if 3.11 is actually supported).