diff --git a/samtranslator/intrinsics/resolver.py b/samtranslator/intrinsics/resolver.py index 0a2c23787..519f856fe 100644 --- a/samtranslator/intrinsics/resolver.py +++ b/samtranslator/intrinsics/resolver.py @@ -1,6 +1,7 @@ # Help resolve intrinsic functions from samtranslator.intrinsics.actions import Action, SubAction, RefAction, GetAttAction +from samtranslator.model.exceptions import InvalidTemplateException, InvalidDocumentException # All intrinsics are supported by default DEFAULT_SUPPORTED_INTRINSICS = {action.intrinsic_name: action() for action in [RefAction, SubAction, GetAttAction]} @@ -17,7 +18,9 @@ def __init__(self, parameters, supported_intrinsics=DEFAULT_SUPPORTED_INTRINSICS """ if parameters is None or not isinstance(parameters, dict): - raise TypeError("parameters must be a valid dictionary") + raise InvalidDocumentException( + [InvalidTemplateException("'Mappings' or 'Parameters' is either null or not a valid dictionary.")] + ) if not isinstance(supported_intrinsics, dict) or not all( [isinstance(value, Action) for value in supported_intrinsics.values()] diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index 04a6c02db..85b131855 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -534,6 +534,14 @@ def set_path_default_authorizer( for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]): # If no integration given, then we don't need to process this definition (could be AWS::NoValue) + if not isinstance(method_definition, dict): + raise InvalidDocumentException( + [ + InvalidTemplateException( + "{} for path {} is not a valid dictionary.".format(method_definition, path) + ) + ] + ) if not self.method_definition_has_integration(method_definition): continue existing_security = method_definition.get("security", []) @@ -548,6 +556,14 @@ def set_path_default_authorizer( # (e.g. sigv4 (AWS_IAM), api_key (API Key/Usage Plans), NONE (marker for ignoring default)) # We want to ensure only a single Authorizer security entry exists while keeping everything else for security in existing_security: + if not isinstance(security, dict): + raise InvalidDocumentException( + [ + InvalidTemplateException( + "{} in Security for path {} is not a valid dictionary.".format(security, path) + ) + ] + ) if authorizer_names.isdisjoint(security.keys()): existing_non_authorizer_security.append(security) else: diff --git a/tests/intrinsics/test_resolver.py b/tests/intrinsics/test_resolver.py index 29d2be39b..2f62b510f 100644 --- a/tests/intrinsics/test_resolver.py +++ b/tests/intrinsics/test_resolver.py @@ -2,6 +2,7 @@ from mock import Mock, patch from samtranslator.intrinsics.resolver import IntrinsicsResolver from samtranslator.intrinsics.actions import Action +from samtranslator.model.exceptions import InvalidDocumentException class TestParameterReferenceResolution(TestCase): @@ -101,11 +102,11 @@ def test_skip_invalid_values_for_sub(self): self.assertEqual(output, expected) def test_throw_on_empty_parameters(self): - with self.assertRaises(TypeError): + with self.assertRaises(InvalidDocumentException): IntrinsicsResolver(None).resolve_parameter_refs({}) def test_throw_on_non_dict_parameters(self): - with self.assertRaises(TypeError): + with self.assertRaises(InvalidDocumentException): IntrinsicsResolver([1, 2, 3]).resolve_parameter_refs({}) def test_short_circuit_on_empty_parameters(self): diff --git a/tests/translator/input/error_invalid_method_definition.yaml b/tests/translator/input/error_invalid_method_definition.yaml new file mode 100644 index 000000000..fd9b6617f --- /dev/null +++ b/tests/translator/input/error_invalid_method_definition.yaml @@ -0,0 +1,66 @@ +Globals: + Api: + Name: "some api" + CacheClusterEnabled: True + CacheClusterSize: "1.6" + Auth: + DefaultAuthorizer: MyCognitoAuth + Authorizers: + MyCognitoAuth: + UserPoolArn: !GetAtt MyUserPool.Arn + Variables: + SomeVar: Value + +Resources: + ImplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs12.x + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: SomeStage + DefinitionBody: + swagger: 2.0 + info: + version: '1.0' + title: !Ref AWS::StackName + paths: + "/": + parameters: + - name: domain + in: path + description: Application domain + type: string + required: true + tags: + - InvalidMethodDefinition + get: + x-amazon-apigateway-integration: + httpMethod: POST + type: aws_proxy + uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations + responses: {} + + MyUserPool: + Type: AWS::Cognito::UserPool + Properties: + UserPoolName: UserPoolName + Policies: + PasswordPolicy: + MinimumLength: 8 + UsernameAttributes: + - email + Schema: + - AttributeDataType: String + Name: email + Required: false \ No newline at end of file diff --git a/tests/translator/input/error_mappings_is_null.yaml b/tests/translator/input/error_mappings_is_null.yaml new file mode 100644 index 000000000..56eb56091 --- /dev/null +++ b/tests/translator/input/error_mappings_is_null.yaml @@ -0,0 +1,23 @@ +Mappings: + +Parameters: + Stage: + Type: String + Default: 'beta' + Deployment: + Type: String + Default: 'AllAtOnce' + Custom: + Type: String + Default: 'CustomDeployment' + +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + AutoPublishAlias: live + DeploymentPreference: + Type: TestDeploymentConfiguration \ No newline at end of file diff --git a/tests/translator/input/error_swagger_security_not_dict.yaml b/tests/translator/input/error_swagger_security_not_dict.yaml new file mode 100644 index 000000000..c9c69a6d4 --- /dev/null +++ b/tests/translator/input/error_swagger_security_not_dict.yaml @@ -0,0 +1,70 @@ +transformId: AWS::Serverless-2016-10-31 +AWSTemplateFormatVersion: '2010-09-09' +Resources: + AuthFunction: + Type: AWS::Serverless::Function + AccessingPartyAPI: + Type: AWS::Serverless::Api + Properties: + EndpointConfiguration: REGIONAL + StageName: demo + Auth: + DefaultAuthorizer: CustomAuthorizer + Authorizers: + CustomAuthorizer: + FunctionPayloadType: TOKEN + FunctionArn: + Fn::GetAtt: + - AuthFunction + - Arn + AddDefaultAuthorizerToCorsPreflight: false + DefinitionBody: + paths: + "/path": + put: + responses: + '201': + content: + application/json: + schema: + "$ref": "abcd" + x-amazon-apigateway-integration: + contentHandling: CONVERT_TO_TEXT + responses: + default: + statusCode: '200' + uri: + Fn::Sub: foobar + httpMethod: POST + passthroughBehavior: when_no_match + type: aws_proxy + requestBody: + content: + application/json: + schema: + required: + - readoutId + - status + type: object + security: + CustomAuthorizer: [] + + openapi: 3.0.3 + components: + securitySchemes: + CustomAuthorizer: + in: header + type: apiKey + name: Authorization + + AccessingPartyAPIFunction: + Type: AWS::Serverless::Function + Properties: + Events: + PutReservation: + Type: Api + Properties: + Path: "/path" + RestApiId: + Ref: AccessingPartyAPI + Method: put \ No newline at end of file diff --git a/tests/translator/output/error_invalid_method_definition.json b/tests/translator/output/error_invalid_method_definition.json new file mode 100644 index 000000000..01ff1502c --- /dev/null +++ b/tests/translator/output/error_invalid_method_definition.json @@ -0,0 +1 @@ +{"errorMessage":"Invalid Serverless Application Specification document. Number of errors found: 1. Structure of the SAM template is invalid. ['InvalidMethodDefinition'] for path / is not a valid dictionary."} \ No newline at end of file diff --git a/tests/translator/output/error_mappings_is_null.json b/tests/translator/output/error_mappings_is_null.json new file mode 100644 index 000000000..04839dad3 --- /dev/null +++ b/tests/translator/output/error_mappings_is_null.json @@ -0,0 +1 @@ +{"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Structure of the SAM template is invalid. 'Mappings' or 'Parameters' is either null or not a valid dictionary."} \ No newline at end of file diff --git a/tests/translator/output/error_swagger_security_not_dict.json b/tests/translator/output/error_swagger_security_not_dict.json new file mode 100644 index 000000000..9f00e5bbf --- /dev/null +++ b/tests/translator/output/error_swagger_security_not_dict.json @@ -0,0 +1,3 @@ +{ + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Structure of the SAM template is invalid. CustomAuthorizer in Security for path /path is not a valid dictionary." +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index bc3848b23..4db7f1f23 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -666,6 +666,9 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw "error_httpapi_mtls_configuration_invalid_type", "error_resource_policy_not_dict", "error_implicit_http_api_auth_any_method", + "error_invalid_method_definition", + "error_mappings_is_null", + "error_swagger_security_not_dict", ], ) @patch("boto3.session.Session.region_name", "ap-southeast-1")