From e0eb0cefb6d761a52db3532200dfa7b5bb59681e Mon Sep 17 00:00:00 2001 From: gomi_ningen Date: Sun, 23 Jun 2019 02:07:50 +0900 Subject: [PATCH 1/3] fix: "Invalid permissions on Lambda function" on path parameter --- samtranslator/model/eventsources/push.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index 5fa986301..e681e8057 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -495,7 +495,7 @@ def _get_permission(self, resources_to_link, stage, suffix): if not stage or not suffix: raise RuntimeError("Could not add permission to lambda function.") - path = path.replace('{proxy+}', '*') + path = re.sub(r'{([a-zA-Z0-9._-]+|proxy\+)}', '*', path) method = '*' if self.Method.lower() == 'any' else self.Method.upper() api_id = self.RestApiId From 9e9a71a90272bad903b7e31184949ef977ce9055 Mon Sep 17 00:00:00 2001 From: gomi_ningen Date: Fri, 5 Jul 2019 01:35:08 +0900 Subject: [PATCH 2/3] Add tests for proxy resource and path params of API Gateway --- .../eventsources/test_api_event_source.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/model/eventsources/test_api_event_source.py b/tests/model/eventsources/test_api_event_source.py index df240b6fa..92d946bf3 100644 --- a/tests/model/eventsources/test_api_event_source.py +++ b/tests/model/eventsources/test_api_event_source.py @@ -51,6 +51,36 @@ def test_get_permission_with_trailing_slash(self): self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo") + @patch("boto3.session.Session.region_name", "eu-west-2") + def test_get_permission_with_path_parameter(self): + self.api_event_source.Path = "/foo/{userId}/bar" + cfn = self.api_event_source.to_cloudformation(function=self.func, explicit_api={}) + + perm = cfn[0] + self.assertIsInstance(perm, LambdaPermission) + + try: + arn = self._extract_path_from_arn("{}PermissionTest".format(self.logical_id), perm) + except AttributeError: + self.fail("Permission class isn't valid") + + self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo/*/bar") + + @patch("boto3.session.Session.region_name", "eu-west-2") + def test_get_permission_with_proxy_resource(self): + self.api_event_source.Path = "/foo/{proxy+}" + cfn = self.api_event_source.to_cloudformation(function=self.func, explicit_api={}) + + perm = cfn[0] + self.assertIsInstance(perm, LambdaPermission) + + try: + arn = self._extract_path_from_arn("{}PermissionTest".format(self.logical_id), perm) + except AttributeError: + self.fail("Permission class isn't valid") + + self.assertEqual(arn, "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/foo/*") + @patch("boto3.session.Session.region_name", "eu-west-2") def test_get_permission_with_just_slash(self): self.api_event_source.Path = "/" From 9208fde3ad9907a7f16d1d86b4cd533a922d275d Mon Sep 17 00:00:00 2001 From: gomi_ningen Date: Wed, 17 Jul 2019 03:06:18 +0900 Subject: [PATCH 3/3] Add input/output test --- .../input/api_with_path_parameters.yaml | 20 +++ .../output/api_with_path_parameters.json | 120 ++++++++++++++++ .../aws-cn/api_with_path_parameters.json | 128 ++++++++++++++++++ .../aws-us-gov/api_with_path_parameters.json | 128 ++++++++++++++++++ tests/translator/test_translator.py | 1 + 5 files changed, 397 insertions(+) create mode 100644 tests/translator/input/api_with_path_parameters.yaml create mode 100644 tests/translator/output/api_with_path_parameters.json create mode 100644 tests/translator/output/aws-cn/api_with_path_parameters.json create mode 100644 tests/translator/output/aws-us-gov/api_with_path_parameters.json diff --git a/tests/translator/input/api_with_path_parameters.yaml b/tests/translator/input/api_with_path_parameters.yaml new file mode 100644 index 000000000..4e1b75105 --- /dev/null +++ b/tests/translator/input/api_with_path_parameters.yaml @@ -0,0 +1,20 @@ +Resources: + HtmlFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: HtmlApi + Path: /{prameter}/resources + Method: get + + HtmlApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: s3://sam-demo-bucket/webpage_swagger.json diff --git a/tests/translator/output/api_with_path_parameters.json b/tests/translator/output/api_with_path_parameters.json new file mode 100644 index 000000000..e9c4f7e14 --- /dev/null +++ b/tests/translator/output/api_with_path_parameters.json @@ -0,0 +1,120 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_path_parameters.json b/tests/translator/output/aws-cn/api_with_path_parameters.json new file mode 100644 index 000000000..f8914fdb1 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_path_parameters.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_path_parameters.json b/tests/translator/output/aws-us-gov/api_with_path_parameters.json new file mode 100644 index 000000000..390e6c87e --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_path_parameters.json @@ -0,0 +1,128 @@ +{ + "Resources": { + "HtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "HtmlApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "HtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "HtmlApi" + }, + "StageName": "Prod" + } + }, + "HtmlFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "Prod", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/*/resources", + { + "__Stage__": "*", + "__ApiId__": "HtmlApi" + } + ] + } + } + }, + "HtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "HtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "HtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "HtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Handler": "index.gethtml", + "Role": { + "Fn::GetAtt": [ + "HtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index e536803ce..18508de99 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -263,6 +263,7 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_auth_and_conditions_all_max', 'api_with_apikey_default_override', 'api_with_apikey_required', + 'api_with_path_parameters', ], [ ("aws", "ap-southeast-1"),