Repository navigation
fix(backend): parse BACKEND_CORS_ORIGINS correctly instead of bracket-string literal - #27
Merged
Merged
Conversation
…-string literal pydantic-settings pre-decodes list-typed env values as JSON before the field validator runs, so a plain comma-separated origin list crashed startup, while the JSON-array default in compose (["http://localhost"]) slipped through as the literal bracketed string, matching no real Origin header. Opt the field out of that pre-decode (NoDecode) and parse JSON array or comma-separated strings explicitly, rejecting anything else. Align dev/stand compose defaults on the comma-separated format already documented in .env.example/README.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
BACKEND_CORS_ORIGINSwas split on commas even when compose supplied a JSON array default (["http://localhost"]), so the real origin became the literal bracketed/quoted string and never matched a browser'sOriginheader — CORS was effectively broken in every environment..env.example/README) would have crashed startup outright once it reached that code path.NoDecode), and raises a clear error for anything else (malformed JSON, non-string array items, empty value).docker-compose.ymlanddocker-compose.stand.ymldefaults plus.env.standon the comma-separated format already used in.env.example/README, so there's one format across dev/stand instead of a silent split.docker-compose.prod.ymlnever setBACKEND_CORS_ORIGINSand is left untouched — adding it would be expanding CORS config, which is out of scope.Acceptance criteria
services/backend/tests/api/test_config.py::TestParseCorsOriginsandTestSettingsFromEnv(the latter exercises the real pydantic-settings env pipeline, not just the validator function).docker-compose.yml,docker-compose.stand.yml,.env.standnow all use the comma-separated format.personal_site_standcompose stack withBACKEND_CORS_ORIGINS=http://localhost:4331from.env.stand.curl -H "Origin: http://localhost:4331"against/api/healthand an OPTIONS preflight against/api/v1/profileboth returnedaccess-control-allow-origin: http://localhost:4331(clean, no brackets/quotes); a mismatchedOrigin: http://evil.examplegot no CORS header. Confirmed in-container thatSettings().BACKEND_CORS_ORIGINS == ['http://localhost:4331'].Full backend suite (
pytest --cov=app, ruff check, ruff format --check, mypy) passes; pre-existing ruff-format findings in 3 unrelated alembic files andprofile.pyare untouched by this change (verified against the pre-change tree).