From 18470583547926082982a1fa7478069d39be8ef2 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Fri, 26 Jun 2026 21:11:37 +0300 Subject: [PATCH] fix: correct CORS allowed-methods/headers defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cors_allowed_methods and cors_allowed_headers defaulted to [""], a list holding one empty string. That is not "allow all" (which needs "*") nor empty — it made litestar's CORSConfig emit an empty Access-Control-Allow-Methods on preflight, so a browser at the configured dev origin (localhost:5173) had every preflighted write (POST/PUT with JSON) blocked. allowed-headers likewise emitted a stray leading-comma token. Default both to ["*"] (permissive dev defaults; tighten via env in prod). Add a preflight integration test asserting POST/PUT appear in Access-Control-Allow-Methods through the real settings -> bootstrap -> middleware path; it fails on the old [""] default. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/settings.py | 4 ++-- tests/test_cors.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 tests/test_cors.py diff --git a/app/settings.py b/app/settings.py index ccf0586..1d74bdc 100644 --- a/app/settings.py +++ b/app/settings.py @@ -24,8 +24,8 @@ class Settings(pydantic_settings.BaseSettings): swagger_offline_docs: bool = True cors_allowed_origins: list[str] = ["http://localhost:5173"] - cors_allowed_methods: list[str] = [""] - cors_allowed_headers: list[str] = [""] + cors_allowed_methods: list[str] = ["*"] + cors_allowed_headers: list[str] = ["*"] cors_exposed_headers: list[str] = [] request_max_body_size: int = 1024 * 1024 # 1MB limit diff --git a/tests/test_cors.py b/tests/test_cors.py new file mode 100644 index 0000000..02565e7 --- /dev/null +++ b/tests/test_cors.py @@ -0,0 +1,19 @@ +from typing import TYPE_CHECKING + + +if TYPE_CHECKING: + from httpx import AsyncClient + + +async def test_cors_preflight_allows_write_methods(client: AsyncClient) -> None: + response = await client.options( + "/api/decks/", + headers={ + "Origin": "http://localhost:5173", + "Access-Control-Request-Method": "POST", + }, + ) + + allow_methods = response.headers.get("access-control-allow-methods", "") + assert "POST" in allow_methods + assert "PUT" in allow_methods