From 0f1a92c1072a378de9a11597cfb6cbed3df9e2d2 Mon Sep 17 00:00:00 2001 From: Ahmed Elbayaa Date: Sun, 16 May 2021 00:43:03 -0700 Subject: [PATCH 1/3] Fix a bad logic where a hash key is modified then refetched which results in KeyError --- samtranslator/swagger/swagger.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index 53ac00bee..668f4e78f 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -620,14 +620,13 @@ def set_path_default_apikey_required(self, path): :param string path: Path name """ - for method_name, _ in self.get_path(path).items(): + for method_name, method in self.get_path(path).items(): # Excluding parameters section if method_name == "parameters": continue - normalized_method_name = self._normalize_method_name(method_name) # It is possible that the method could have two definitions in a Fn::If block. - for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + for method_definition in self.get_method_contents(method): # If no integration given, then we don't need to process this definition (could be AWS::NoValue) if not self.method_definition_has_integration(method_definition): From b2fefdfe120ad6d309515eaf1be4b62717bb7ade Mon Sep 17 00:00:00 2001 From: Mehmet Nuri Deveci <5735811+mndeveci@users.noreply.github.com> Date: Fri, 18 Jun 2021 19:40:13 -0700 Subject: [PATCH 2/3] add unit tests and update other instance of same usage on line 534 --- samtranslator/swagger/swagger.py | 2 +- .../input/api_with_any_method_in_swagger.yaml | 44 ++++ .../api_with_any_method_in_swagger.json | 189 +++++++++++++++++ .../api_with_any_method_in_swagger.json | 197 ++++++++++++++++++ .../api_with_any_method_in_swagger.json | 197 ++++++++++++++++++ tests/translator/test_translator.py | 1 + 6 files changed, 629 insertions(+), 1 deletion(-) create mode 100644 tests/translator/input/api_with_any_method_in_swagger.yaml create mode 100644 tests/translator/output/api_with_any_method_in_swagger.json create mode 100644 tests/translator/output/aws-cn/api_with_any_method_in_swagger.json create mode 100644 tests/translator/output/aws-us-gov/api_with_any_method_in_swagger.json diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index 668f4e78f..0a88eedfa 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -531,7 +531,7 @@ def set_path_default_authorizer( if add_default_auth_to_preflight or normalized_method_name != "options": normalized_method_name = self._normalize_method_name(method_name) # It is possible that the method could have two definitions in a Fn::If block. - for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + for method_definition in self.get_method_contents(method): # If no integration given, then we don't need to process this definition (could be AWS::NoValue) if not isinstance(method_definition, dict): diff --git a/tests/translator/input/api_with_any_method_in_swagger.yaml b/tests/translator/input/api_with_any_method_in_swagger.yaml new file mode 100644 index 000000000..bd6b30474 --- /dev/null +++ b/tests/translator/input/api_with_any_method_in_swagger.yaml @@ -0,0 +1,44 @@ +Resources: + HttpApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/todo_list.zip + Handler: index.restapi + Runtime: python3.7 + Events: + SimpleCase: + Type: HttpApi + Properties: + ApiId: !Ref MyApi + BasePath: + Type: HttpApi + Properties: + ApiId: !Ref MyApi + Path: / + Method: get + + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: + Ref: Stage + Auth: + DefaultAuthorizer: "LambdaAuthorizer" + Authorizers: + LambdaAuthorizer: + FunctionPayloadType: "REQUEST" + Identity: + Headers: + - "Authorization" + DefinitionBody: + openapi: '3.0' + info: + title: !Sub ${AWS::StackName}-Api + paths: + /: + any: + x-amazon-apigateway-integration: + httpMethod: ANY + type: http_proxy + uri: https://www.alphavantage.co/ + payloadFormatVersion: '1.0' \ No newline at end of file diff --git a/tests/translator/output/api_with_any_method_in_swagger.json b/tests/translator/output/api_with_any_method_in_swagger.json new file mode 100644 index 000000000..c4f81f32b --- /dev/null +++ b/tests/translator/output/api_with_any_method_in_swagger.json @@ -0,0 +1,189 @@ +{ + "Resources": { + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "title": { + "Fn::Sub": "${AWS::StackName}-Api" + } + }, + "paths": { + "$default": { + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "isDefaultRoute": true, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + }, + "/": { + "any": { + "x-amazon-apigateway-integration": { + "httpMethod": "ANY", + "type": "http_proxy", + "uri": "https://www.alphavantage.co/", + "payloadFormatVersion": "1.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0", + "components": { + "securitySchemes": { + "LambdaAuthorizer": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "identitySource": "method.request.header.Authorization", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": null + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + } + } + } + } + } + }, + "HttpApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.restapi", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "todo_list.zip" + }, + "Role": { + "Fn::GetAtt": [ + "HttpApiFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "HttpApiFunctionSimpleCasePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HttpApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "HttpApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment69a80e7382" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": { + "Ref": "Stage" + } + } + }, + "MyApiDeployment69a80e7382": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 69a80e738222706cff079ab8d7f348c0d89eddab", + "StageName": "Stage" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_any_method_in_swagger.json b/tests/translator/output/aws-cn/api_with_any_method_in_swagger.json new file mode 100644 index 000000000..44e182380 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_any_method_in_swagger.json @@ -0,0 +1,197 @@ +{ + "Resources": { + "MyApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment37c803d096" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": { + "Ref": "Stage" + } + } + }, + "HttpApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApiDeployment37c803d096": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 37c803d09628334a047966047f087abf49267a2c", + "StageName": "Stage" + } + }, + "HttpApiFunctionSimpleCasePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HttpApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "HttpApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.restapi", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "todo_list.zip" + }, + "Role": { + "Fn::GetAtt": [ + "HttpApiFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "title": { + "Fn::Sub": "${AWS::StackName}-Api" + } + }, + "paths": { + "$default": { + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "isDefaultRoute": true, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + }, + "/": { + "any": { + "x-amazon-apigateway-integration": { + "httpMethod": "ANY", + "type": "http_proxy", + "uri": "https://www.alphavantage.co/", + "payloadFormatVersion": "1.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0", + "components": { + "securitySchemes": { + "LambdaAuthorizer": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "identitySource": "method.request.header.Authorization", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": null + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_any_method_in_swagger.json b/tests/translator/output/aws-us-gov/api_with_any_method_in_swagger.json new file mode 100644 index 000000000..9bd62ca94 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_any_method_in_swagger.json @@ -0,0 +1,197 @@ +{ + "Resources": { + "MyApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "MyApiDeployment0ebc8893a3" + }, + "RestApiId": { + "Ref": "MyApi" + }, + "StageName": { + "Ref": "Stage" + } + } + }, + "HttpApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.restapi", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "todo_list.zip" + }, + "Role": { + "Fn::GetAtt": [ + "HttpApiFunctionRole", + "Arn" + ] + }, + "Runtime": "python3.7", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "HttpApiFunctionSimpleCasePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "HttpApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "MyApi" + } + } + ] + } + } + }, + "HttpApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "MyApiDeployment0ebc8893a3": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "MyApi" + }, + "Description": "RestApi deployment id: 0ebc8893a30055fb944d26720dc8ffddacc6d27d", + "StageName": "Stage" + } + }, + "MyApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "title": { + "Fn::Sub": "${AWS::StackName}-Api" + } + }, + "paths": { + "$default": { + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "isDefaultRoute": true, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + }, + "/": { + "any": { + "x-amazon-apigateway-integration": { + "httpMethod": "ANY", + "type": "http_proxy", + "uri": "https://www.alphavantage.co/", + "payloadFormatVersion": "1.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + }, + "payloadFormatVersion": "2.0" + }, + "security": [ + { + "LambdaAuthorizer": [] + } + ], + "responses": {} + } + } + }, + "openapi": "3.0", + "components": { + "securitySchemes": { + "LambdaAuthorizer": { + "in": "header", + "type": "apiKey", + "name": "Unused", + "x-amazon-apigateway-authorizer": { + "type": "request", + "identitySource": "method.request.header.Authorization", + "authorizerUri": { + "Fn::Sub": [ + "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", + { + "__FunctionArn__": null + } + ] + } + }, + "x-amazon-apigateway-authtype": "custom" + } + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index fc89f799d..59af65932 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -316,6 +316,7 @@ class TestTranslatorEndToEnd(AbstractTestTranslator): "api_with_gateway_responses_string_status_code", "api_cache", "api_with_access_log_setting", + "api_with_any_method_in_swagger", "api_with_canary_setting", "api_with_xray_tracing", "api_request_model", From 5165ab455eabe3033acc085654ea4050dd0b3141 Mon Sep 17 00:00:00 2001 From: Mathieu Grandis Date: Fri, 25 Jun 2021 09:25:21 -0700 Subject: [PATCH 3/3] fix: Fix the same code in open_api.py --- samtranslator/open_api/open_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/open_api/open_api.py b/samtranslator/open_api/open_api.py index af6b47e49..54e00ed05 100644 --- a/samtranslator/open_api/open_api.py +++ b/samtranslator/open_api/open_api.py @@ -352,7 +352,7 @@ def set_path_default_authorizer(self, path, default_authorizer, authorizers, api ) ] ) - for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): + for method_definition in self.get_method_contents(method): # If no integration given, then we don't need to process this definition (could be AWS::NoValue) if not self.method_definition_has_integration(method_definition): continue