diff --git a/backend/app/config.py b/backend/app/config.py index 7102d57..03d58cf 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -4,10 +4,10 @@ from __future__ import annotations import os import secrets from functools import lru_cache -from typing import List +from typing import Annotated, List from pydantic import Field, field_validator -from pydantic_settings import BaseSettings, SettingsConfigDict +from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict class Settings(BaseSettings): @@ -32,13 +32,29 @@ class Settings(BaseSettings): admin_setup_token: str = "" # CORS - cors_origins: List[str] = Field(default_factory=lambda: ["http://localhost:5173"]) + # `NoDecode` tells pydantic-settings NOT to JSON-parse the env value, so a + # plain comma-separated string like "http://localhost:5173,http://localhost:8080" + # reaches our `@field_validator` intact, which then splits it into a list. + cors_origins: Annotated[List[str], NoDecode] = Field( + default_factory=lambda: ["http://localhost:5173"] + ) @field_validator("cors_origins", mode="before") @classmethod def _split_origins(cls, v): if isinstance(v, str): + # Allow both JSON arrays (e.g. '["http://a","http://b"]') and plain + # comma-separated strings (e.g. "http://a,http://b") from env vars. + v = v.strip() + if v.startswith("["): + import json + try: + return [o.strip() for o in json.loads(v) if o.strip()] + except Exception: + pass return [o.strip() for o in v.split(",") if o.strip()] + if isinstance(v, (list, tuple)): + return [str(o).strip() for o in v if str(o).strip()] return v # Logging