From 946a6203ba76e32c8692245b1e1fe34eceb84925 Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Sat, 3 Aug 2024 20:02:53 +0000 Subject: [PATCH 1/3] fix: cors is opt out if enabled --- .../required_dependencies/test_api_gateway.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/functional/event_handler/required_dependencies/test_api_gateway.py b/tests/functional/event_handler/required_dependencies/test_api_gateway.py index ef36ab00587..d486ecb0125 100644 --- a/tests/functional/event_handler/required_dependencies/test_api_gateway.py +++ b/tests/functional/event_handler/required_dependencies/test_api_gateway.py @@ -331,7 +331,7 @@ def test_cors(): def with_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") - @app.get("/without-cors") + @app.get("/without-cors", cors=False) def without_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") @@ -350,17 +350,17 @@ def handler(event, context): assert headers["Access-Control-Allow-Headers"] == [",".join(sorted(CORSConfig._REQUIRED_HEADERS))] # THEN for routes without cors flag return no cors headers - mock_event = {"path": "/my/request", "httpMethod": "GET"} + mock_event = {"path": "/without-cors", "httpMethod": "GET"} result = handler(mock_event, None) assert "Access-Control-Allow-Origin" not in result["multiValueHeaders"] def test_cors_no_request_origin(): - # GIVEN a function with cors=True + # GIVEN a function # AND http method set to GET - app = ApiGatewayResolver() + app = ApiGatewayResolver(cors=CORSConfig()) - @app.get("/my/path", cors=True) + @app.get("/my/path") def with_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") @@ -381,7 +381,7 @@ def handler(event, context): def test_cors_allow_all_request_origins(): - # GIVEN a function with cors=True + # GIVEN a function # AND http method set to GET app = ApiGatewayResolver( cors=CORSConfig( @@ -390,11 +390,11 @@ def test_cors_allow_all_request_origins(): ), ) - @app.get("/my/path", cors=True) + @app.get("/my/path") def with_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") - @app.get("/without-cors") + @app.get("/without-cors", cors=False) def without_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") @@ -413,7 +413,7 @@ def handler(event, context): assert headers["Access-Control-Allow-Headers"] == [",".join(sorted(CORSConfig._REQUIRED_HEADERS))] # THEN for routes without cors flag return no cors headers - mock_event = {"path": "/my/request", "httpMethod": "GET"} + mock_event = {"path": "/without-cors", "httpMethod": "GET"} result = handler(mock_event, None) assert "Access-Control-Allow-Origin" not in result["multiValueHeaders"] From d6386b85e6dce4397e16fc7e80ccdd77f078a810 Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Mon, 5 Aug 2024 19:31:03 +0000 Subject: [PATCH 2/3] test: opt-out instead opt-in for cors endpoints --- aws_lambda_powertools/event_handler/api_gateway.py | 12 +++++++----- .../required_dependencies/test_api_gateway.py | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 8e84a74ef60..b0aee1713f4 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -122,20 +122,22 @@ class CORSConfig: Examples -------- - Simple cors example using the default permissive cors, not this should only be used during early prototyping + Simple CORS example using the default permissive CORS, note that this should only be used during early prototyping. ```python - from aws_lambda_powertools.event_handler import APIGatewayRestResolver + from aws_lambda_powertools.event_handler.api_gateway import ( + APIGatewayRestResolver, CORSConfig + ) - app = APIGatewayRestResolver() + app = APIGatewayRestResolver(cors=CORSConfig()) - @app.get("/my/path", cors=True) + @app.get("/my/path") def with_cors(): return {"message": "Foo"} ``` Using a custom CORSConfig where `with_cors` used the custom provided CORSConfig and `without_cors` - do not include any cors headers. + do not include any CORS headers. ```python from aws_lambda_powertools.event_handler.api_gateway import ( diff --git a/tests/functional/event_handler/required_dependencies/test_api_gateway.py b/tests/functional/event_handler/required_dependencies/test_api_gateway.py index d486ecb0125..f2bf56084c1 100644 --- a/tests/functional/event_handler/required_dependencies/test_api_gateway.py +++ b/tests/functional/event_handler/required_dependencies/test_api_gateway.py @@ -323,11 +323,11 @@ def handler(event, context): def test_cors(): - # GIVEN a function with cors=True + # GIVEN a function # AND http method set to GET app = ApiGatewayResolver(cors=CORSConfig("https://aws.amazon.com", allow_credentials=True)) - @app.get("/my/path", cors=True) + @app.get("/my/path") def with_cors() -> Response: return Response(200, content_types.TEXT_HTML, "test") @@ -811,7 +811,7 @@ def test_custom_preflight_response(): # AND the request matches this custom preflight route app = ApiGatewayResolver(cors=CORSConfig()) - @app.route(method="OPTIONS", rule="/some-call", cors=True) + @app.route(method="OPTIONS", rule="/some-call") def custom_preflight(): return Response( status_code=200, @@ -820,7 +820,7 @@ def custom_preflight(): headers={"Access-Control-Allow-Methods": ["CUSTOM"]}, ) - @app.route(method="CUSTOM", rule="/some-call", cors=True) + @app.route(method="CUSTOM", rule="/some-call") def custom_method(): ... # AND the request includes an origin @@ -903,7 +903,7 @@ def internal_server_error(): assert result["body"] == json_dump(expected) # GIVEN an ServiceError with a custom status code - @app.get(rule="/service-error", cors=True) + @app.get(rule="/service-error") def service_error(): raise ServiceError(502, "Something went wrong!") From ac74e4df7665b249605e7c97564ed886e406a28c Mon Sep 17 00:00:00 2001 From: Nico Tonnhofer Date: Mon, 5 Aug 2024 19:32:07 +0000 Subject: [PATCH 3/3] test: catch some UserWarnings --- .../required_dependencies/test_api_gateway.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/functional/event_handler/required_dependencies/test_api_gateway.py b/tests/functional/event_handler/required_dependencies/test_api_gateway.py index f2bf56084c1..4e26cc872cd 100644 --- a/tests/functional/event_handler/required_dependencies/test_api_gateway.py +++ b/tests/functional/event_handler/required_dependencies/test_api_gateway.py @@ -964,7 +964,8 @@ def raises_error(): def test_powertools_dev_sets_debug_mode(monkeypatch): # GIVEN a debug mode environment variable is set monkeypatch.setenv(constants.POWERTOOLS_DEV_ENV, "true") - app = ApiGatewayResolver() + with pytest.warns(UserWarning, match="POWERTOOLS_DEV environment variable is enabled."): + app = ApiGatewayResolver() # WHEN calling app._debug # THEN the debug mode is enabled @@ -1428,7 +1429,8 @@ def get_func(): def get_func_another_duplicate(): raise RuntimeError() - app.include_router(router) + with pytest.warns(UserWarning, match="A route like this was already registered"): + app.include_router(router) # WHEN calling the handler result = app(LOAD_GW_EVENT, None) @@ -1707,7 +1709,12 @@ def my_path(): @event_source(data_class=APIGatewayProxyEventV2) def handler(event: APIGatewayProxyEventV2, context): assert isinstance(event, APIGatewayProxyEventV2) - return app.resolve(event, context) + + with pytest.warns( + UserWarning, + match="You don't need to serialize event to Event Source Data Class when using Event Handler", + ): + return app.resolve(event, context) # THEN result = handler(load_event("apiGatewayProxyV2Event.json"), None)