Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/introduction/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,8 @@ To bootstrap CORS headers, you must provide `cors_allowed_origins` or `cors_allo

Additional params:

- `cors_allowed_methods`
- `cors_allowed_headers`
- `cors_allowed_methods` defaults to `["*"]`, allowing all standard HTTP methods.
- `cors_allowed_headers` defaults to `[]`, allowing only the framework’s built-in CORS headers.
- `cors_exposed_headers`
- `cors_allowed_credentials`
- `cors_max_age`
Expand Down
14 changes: 14 additions & 0 deletions docs/migration/to-2.x.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Migration guide for lite-bootstrap 2.x

## CORS methods on FastAPI and Litestar

In 2.x, `cors_allowed_methods` defaults to `["*"]`. If you configure allowed
origins and omit the method list, preflight requests can now succeed for all
standard HTTP methods, including POST.

Set `cors_allowed_methods` explicitly to restrict cross-origin requests to the
methods your application supports, such as `["GET", "POST"]`.

`cors_allowed_headers` defaults to `[]`. Both frameworks allow their built-in
CORS headers, including `Content-Type`. Add headers such as `Authorization`
explicitly if your application needs them.
2 changes: 1 addition & 1 deletion lite_bootstrap/instruments/cors_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@dataclasses.dataclass(kw_only=True, frozen=True)
class CorsConfig(BaseConfig):
cors_allowed_origins: list[str] = dataclasses.field(default_factory=list)
cors_allowed_methods: list[str] = dataclasses.field(default_factory=list)
cors_allowed_methods: list[str] = dataclasses.field(default_factory=lambda: ["*"])
cors_allowed_headers: list[str] = dataclasses.field(default_factory=list)
cors_exposed_headers: list[str] = dataclasses.field(default_factory=list)
cors_allowed_credentials: bool = False
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ nav:
- Installation: introduction/installation.md
- Configuration: introduction/configuration.md
- Performance: introduction/performance.md
- Migration:
- Upgrading to 2.x: migration/to-2.x.md
- Integrations:
- Litestar: integrations/litestar.md
- FastStream: integrations/faststream.md
Expand Down
2 changes: 1 addition & 1 deletion tests/instruments/test_cors_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def test_cors_instrument_configured_with_both() -> None:
def test_cors_instrument_config_defaults() -> None:
config = CorsConfig()
assert config.cors_allowed_origins == []
assert config.cors_allowed_methods == []
assert config.cors_allowed_methods == ["*"]
assert config.cors_allowed_headers == []
assert config.cors_exposed_headers == []
assert config.cors_allowed_credentials is False
Expand Down
21 changes: 21 additions & 0 deletions tests/test_fastapi_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@ def test_config_rejects_comma_in_opentelemetry_excluded_url(
config_class(opentelemetry_excluded_urls=[pattern])


def test_origins_only_cors_allows_json_post_preflight() -> None:
origin = "https://a.example"
config = FastAPIConfig(cors_allowed_origins=[origin])
application = FastAPIBootstrapper(bootstrap_config=config).bootstrap()

with TestClient(application) as client:
response = client.options(
"/x",
headers={
"Origin": origin,
"Access-Control-Request-Method": "POST",
"Access-Control-Request-Headers": "content-type",
},
)

assert response.is_success
assert response.headers["access-control-allow-origin"] == origin
assert "POST" in response.headers["access-control-allow-methods"].split(", ")
assert "content-type" in response.headers["access-control-allow-headers"].lower().split(", ")


@pytest.fixture
def fastapi_config() -> FastAPIConfig:
return FastAPIConfig(
Expand Down
21 changes: 21 additions & 0 deletions tests/test_litestar_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,27 @@
logger = structlog.getLogger(__name__)


def test_origins_only_cors_allows_json_post_preflight() -> None:
origin = "https://a.example"
config = LitestarConfig(cors_allowed_origins=[origin])
application = LitestarBootstrapper(bootstrap_config=config).bootstrap()

with TestClient(application) as client:
response = client.options(
"/x",
headers={
"Origin": origin,
"Access-Control-Request-Method": "POST",
"Access-Control-Request-Headers": "content-type",
},
)

assert response.is_success
assert response.headers["access-control-allow-origin"] == origin
assert "POST" in response.headers["access-control-allow-methods"].split(", ")
assert "content-type" in response.headers["access-control-allow-headers"].lower().split(", ")


@pytest.fixture
def litestar_config() -> LitestarConfig:
return LitestarConfig(
Expand Down
Loading