From 8aa002275127599aeaed4f1e064d06e52199bc6c Mon Sep 17 00:00:00 2001 From: Daniel Mil <84205762+mildaniel@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:34:21 -0700 Subject: [PATCH] fix: Avoid crashing on invalid function name (#7392) * fix: Avoid crashing on invalid function name * Remove unused exception --- samcli/lib/providers/exceptions.py | 9 ++++ samcli/lib/providers/sam_function_provider.py | 5 ++- samcli/local/apigw/local_apigw_service.py | 5 +++ .../local/lib/test_sam_function_provider.py | 4 +- .../local/apigw/test_local_apigw_service.py | 43 +++++++++++++++++++ 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/samcli/lib/providers/exceptions.py b/samcli/lib/providers/exceptions.py index 1370bf9af8..d5e3b330e7 100644 --- a/samcli/lib/providers/exceptions.py +++ b/samcli/lib/providers/exceptions.py @@ -83,3 +83,12 @@ def resource_identifier(self) -> "ResourceIdentifier": @property def property_name(self) -> str: return self._property_name + + +class MissingFunctionNameException(Exception): + """ + Exception when a resource does not have function name specified + """ + + def __init__(self) -> None: + super().__init__("Unable to get Lambda function because the function identifier is not defined.") diff --git a/samcli/lib/providers/sam_function_provider.py b/samcli/lib/providers/sam_function_provider.py index e08dfc43fb..5787fb409f 100644 --- a/samcli/lib/providers/sam_function_provider.py +++ b/samcli/lib/providers/sam_function_provider.py @@ -11,7 +11,7 @@ from samcli.commands._utils.template import TemplateFailedParsingException from samcli.commands.local.cli_common.user_exceptions import InvalidLayerVersionArn from samcli.lib.build.exceptions import MissingFunctionHandlerException -from samcli.lib.providers.exceptions import InvalidLayerReference +from samcli.lib.providers.exceptions import InvalidLayerReference, MissingFunctionNameException from samcli.lib.utils.colors import Colored, Colors from samcli.lib.utils.file_observer import FileObserver from samcli.lib.utils.packagetype import IMAGE, ZIP @@ -119,7 +119,8 @@ def get(self, name: str) -> Optional[Function]: """ if not name: - raise ValueError("Function name is required") + LOG.debug("Function name is not defined, unable to fetch Lambda function.") + raise MissingFunctionNameException() resolved_function = None diff --git a/samcli/local/apigw/local_apigw_service.py b/samcli/local/apigw/local_apigw_service.py index 78104c0f7b..78f600beba 100644 --- a/samcli/local/apigw/local_apigw_service.py +++ b/samcli/local/apigw/local_apigw_service.py @@ -15,6 +15,7 @@ from samcli.commands.local.lib.exceptions import UnsupportedInlineCodeError from samcli.commands.local.lib.local_lambda import LocalLambdaRunner +from samcli.lib.providers.exceptions import MissingFunctionNameException from samcli.lib.providers.provider import Api, Cors from samcli.lib.telemetry.event import EventName, EventTracker, UsedFeature from samcli.lib.utils.stream_writer import StreamWriter @@ -733,6 +734,10 @@ def _request_handler(self, **kwargs): endpoint_service_error = ServiceErrorResponses.lambda_body_failure_response() except DockerContainerCreationFailedException as ex: endpoint_service_error = ServiceErrorResponses.container_creation_failed(ex.message) + except MissingFunctionNameException as ex: + endpoint_service_error = ServiceErrorResponses.lambda_failure_response( + f"Failed to execute endpoint. Got an invalid function name ({str(ex)})", + ) if endpoint_service_error: return endpoint_service_error diff --git a/tests/unit/commands/local/lib/test_sam_function_provider.py b/tests/unit/commands/local/lib/test_sam_function_provider.py index 0c57430a9b..00a3363c78 100644 --- a/tests/unit/commands/local/lib/test_sam_function_provider.py +++ b/tests/unit/commands/local/lib/test_sam_function_provider.py @@ -11,7 +11,7 @@ from samcli.commands.local.cli_common.user_exceptions import InvalidLayerVersionArn from samcli.lib.providers.provider import Function, LayerVersion, Stack, FunctionBuildInfo from samcli.lib.providers.sam_function_provider import SamFunctionProvider, RefreshableSamFunctionProvider -from samcli.lib.providers.exceptions import InvalidLayerReference +from samcli.lib.providers.exceptions import InvalidLayerReference, MissingFunctionNameException from samcli.lib.utils.packagetype import IMAGE, ZIP @@ -1908,7 +1908,7 @@ class TestSamFunctionProvider_get(TestCase): def test_raise_on_invalid_name(self): provider = SamFunctionProvider([]) - with self.assertRaises(ValueError): + with self.assertRaises(MissingFunctionNameException): provider.get(None) def test_must_return_function_value(self): diff --git a/tests/unit/local/apigw/test_local_apigw_service.py b/tests/unit/local/apigw/test_local_apigw_service.py index 6c0f4bfdae..6cde64c063 100644 --- a/tests/unit/local/apigw/test_local_apigw_service.py +++ b/tests/unit/local/apigw/test_local_apigw_service.py @@ -8,6 +8,7 @@ from parameterized import parameterized, param from werkzeug.datastructures import Headers +from samcli.lib.providers.exceptions import MissingFunctionNameException from samcli.lib.providers.provider import Api from samcli.lib.providers.provider import Cors from samcli.lib.telemetry.event import EventName, EventTracker, UsedFeature @@ -23,6 +24,7 @@ LambdaResponseParseException, PayloadFormatVersionValidateException, ) +from samcli.local.apigw.service_error_responses import ServiceErrorResponses from samcli.local.docker.exceptions import DockerContainerCreationFailedException from samcli.local.lambdafn.exceptions import FunctionNotFound from samcli.commands.local.lib.exceptions import UnsupportedInlineCodeError @@ -1040,6 +1042,47 @@ def test_authorizer_function_not_found_invokes_endpoint( self.api_gateway_route.function_name, ANY, stdout=ANY, stderr=self.stderr ) + @patch.object(LocalApigwService, "get_request_methods_endpoints") + @patch.object(LocalApigwService, "_generate_lambda_authorizer_event") + @patch.object(LocalApigwService, "_valid_identity_sources") + @patch.object(LocalApigwService, "_invoke_lambda_function") + @patch.object(LocalApigwService, "_invoke_parse_lambda_authorizer") + @patch.object(EventTracker, "track_event") + @patch("samcli.local.apigw.local_apigw_service.construct_v1_event") + @patch("samcli.local.apigw.local_apigw_service.construct_v2_event_http") + @patch("samcli.local.apigw.local_apigw_service.ServiceErrorResponses") + def test_lambda_invoke_fails_no_function_name_exception( + self, + service_mock, + v2_event_mock, + v1_event_mock, + track_mock, + lambda_invoke_mock, + invoke_mock, + validate_id_mock, + gen_auth_event_mock, + request_mock, + ): + self.api_service._get_current_route = MagicMock() + + self.api_gateway_route.authorizer_object = Mock() + + self.api_service._get_current_route.return_value = self.api_gateway_route + self.api_service._get_current_route.methods = [] + self.api_service._get_current_route.return_value.payload_format_version = "2.0" + + invoke_mock.side_effect = MissingFunctionNameException() + service_mock.lambda_failure_response = Mock() + request_mock.return_value = ("test", "test") + v1_event_mock.return_value = {} + + self.api_service._request_handler() + + service_mock.lambda_failure_response.assert_called_once_with( + "Failed to execute endpoint. Got an invalid function name " + "(Unable to get Lambda function because the function identifier is not defined.)" + ) + class TestApiGatewayModel(TestCase): def setUp(self):