diff --git a/appveyor.yml b/appveyor.yml index 05d321142..d20b784b9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,13 +4,19 @@ image: Ubuntu environment: matrix: - TOXENV: py27 + PYTHON_VERSION: '2.7' - TOXENV: py36 + PYTHON_VERSION: '3.6' - TOXENV: py37 + PYTHON_VERSION: '3.7' - TOXENV: py38 + PYTHON_VERSION: '3.8' build: off install: +- sh: "source ${HOME}/venv${PYTHON_VERSION}/bin/activate" +- sh: "python --version" - make init test_script: diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index 0cb75661c..b91f00e75 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -23,6 +23,7 @@ class LambdaFunction(Resource): "Layers": PropertyType(False, list_of(one_of(is_str(), is_type(dict)))), "ReservedConcurrentExecutions": PropertyType(False, any_type()), "FileSystemConfigs": PropertyType(False, list_of(is_type(dict))), + "CodeSigningConfigArn": PropertyType(False, is_str()), } runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")} diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 007a3ded1..c6cf50760 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -82,6 +82,7 @@ class SamFunction(SamResourceMacro): "VersionDescription": PropertyType(False, is_str()), "ProvisionedConcurrencyConfig": PropertyType(False, is_type(dict)), "FileSystemConfigs": PropertyType(False, list_of(is_type(dict))), + "CodeSigningConfigArn": PropertyType(False, is_str()), } event_resolver = ResourceTypeResolver( samtranslator.model.eventsources, @@ -412,6 +413,8 @@ def _construct_lambda_function(self): if self.DeadLetterQueue: lambda_function.DeadLetterConfig = {"TargetArn": self.DeadLetterQueue["TargetArn"]} + lambda_function.CodeSigningConfigArn = self.CodeSigningConfigArn + return lambda_function def _add_event_invoke_managed_policy(self, dest_config, logical_id, condition, dest_arn): diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index cf5fb7fb0..f75beb3ec 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -41,6 +41,7 @@ class Globals(object): "AssumeRolePolicyDocument", "EventInvokeConfig", "FileSystemConfigs", + "CodeSigningConfigArn", ], # Everything except # DefinitionBody: because its hard to reason about merge of Swagger dictionaries diff --git a/tests/translator/input/function_with_signing_profile.yaml b/tests/translator/input/function_with_signing_profile.yaml new file mode 100644 index 000000000..09a032367 --- /dev/null +++ b/tests/translator/input/function_with_signing_profile.yaml @@ -0,0 +1,24 @@ +Resources: + + FunctionWithSigningProfile: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs12.x + CodeSigningConfigArn: !Ref MySignedFunctionCodeSigningConfig + + MySignedFunctionCodeSigningConfig: + Type: AWS::Lambda::CodeSigningConfig + Properties: + Description: "Code Signing for MySignedLambdaFunction" + AllowedPublishers: + SigningProfileVersionArns: + - !GetAtt SigningProfile.ProfileVersionArn + CodeSigningPolicies: + UntrustedArtifactOnDeployment: "Enforce" + + SigningProfile: + Type: AWS::Signer::SigningProfile + Properties: + PlatformId: AWSLambda-SHA384-ECDSA \ No newline at end of file diff --git a/tests/translator/output/aws-cn/function_with_signing_profile.json b/tests/translator/output/aws-cn/function_with_signing_profile.json new file mode 100644 index 000000000..d25c7e526 --- /dev/null +++ b/tests/translator/output/aws-cn/function_with_signing_profile.json @@ -0,0 +1,85 @@ +{ + "Resources": { + "FunctionWithSigningProfile": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Role": { + "Fn::GetAtt": [ + "FunctionWithSigningProfileRole", + "Arn" + ] + }, + "CodeSigningConfigArn": { + "Ref": "MySignedFunctionCodeSigningConfig" + } + } + }, + "FunctionWithSigningProfileRole": { + "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" + } + ] + } + }, + "MySignedFunctionCodeSigningConfig": { + "Type": "AWS::Lambda::CodeSigningConfig", + "Properties": { + "CodeSigningPolicies": { + "UntrustedArtifactOnDeployment": "Enforce" + }, + "AllowedPublishers": { + "SigningProfileVersionArns": [ + { + "Fn::GetAtt": [ + "SigningProfile", + "ProfileVersionArn" + ] + } + ] + }, + "Description": "Code Signing for MySignedLambdaFunction" + } + }, + "SigningProfile": { + "Type": "AWS::Signer::SigningProfile", + "Properties": { + "PlatformId": "AWSLambda-SHA384-ECDSA" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/function_with_signing_profile.json b/tests/translator/output/aws-us-gov/function_with_signing_profile.json new file mode 100644 index 000000000..fb4065fa5 --- /dev/null +++ b/tests/translator/output/aws-us-gov/function_with_signing_profile.json @@ -0,0 +1,85 @@ +{ + "Resources": { + "FunctionWithSigningProfile": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Role": { + "Fn::GetAtt": [ + "FunctionWithSigningProfileRole", + "Arn" + ] + }, + "CodeSigningConfigArn": { + "Ref": "MySignedFunctionCodeSigningConfig" + } + } + }, + "FunctionWithSigningProfileRole": { + "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" + } + ] + } + }, + "MySignedFunctionCodeSigningConfig": { + "Type": "AWS::Lambda::CodeSigningConfig", + "Properties": { + "CodeSigningPolicies": { + "UntrustedArtifactOnDeployment": "Enforce" + }, + "AllowedPublishers": { + "SigningProfileVersionArns": [ + { + "Fn::GetAtt": [ + "SigningProfile", + "ProfileVersionArn" + ] + } + ] + }, + "Description": "Code Signing for MySignedLambdaFunction" + } + }, + "SigningProfile": { + "Type": "AWS::Signer::SigningProfile", + "Properties": { + "PlatformId": "AWSLambda-SHA384-ECDSA" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/error_globals_unsupported_property.json b/tests/translator/output/error_globals_unsupported_property.json index a97faaf6a..2b2dfbf18 100644 --- a/tests/translator/output/error_globals_unsupported_property.json +++ b/tests/translator/output/error_globals_unsupported_property.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'EventInvokeConfig', 'FileSystemConfigs']" + "errorMessage": "'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn']" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs']" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'SomeKey' is not a supported property of 'Function'. Must be one of the following values - ['Handler', 'Runtime', 'CodeUri', 'DeadLetterQueue', 'Description', 'MemorySize', 'Timeout', 'VpcConfig', 'Environment', 'Tags', 'Tracing', 'KmsKeyArn', 'AutoPublishAlias', 'Layers', 'DeploymentPreference', 'PermissionsBoundary', 'ReservedConcurrentExecutions', 'ProvisionedConcurrencyConfig', 'AssumeRolePolicyDocument', 'EventInvokeConfig', 'FileSystemConfigs', 'CodeSigningConfigArn']" } diff --git a/tests/translator/output/function_with_signing_profile.json b/tests/translator/output/function_with_signing_profile.json new file mode 100644 index 000000000..1b878970d --- /dev/null +++ b/tests/translator/output/function_with_signing_profile.json @@ -0,0 +1,85 @@ +{ + "Resources": { + "FunctionWithSigningProfile": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Runtime": "nodejs12.x", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "Role": { + "Fn::GetAtt": [ + "FunctionWithSigningProfileRole", + "Arn" + ] + }, + "CodeSigningConfigArn": { + "Ref": "MySignedFunctionCodeSigningConfig" + } + } + }, + "FunctionWithSigningProfileRole": { + "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" + } + ] + } + }, + "MySignedFunctionCodeSigningConfig": { + "Type": "AWS::Lambda::CodeSigningConfig", + "Properties": { + "CodeSigningPolicies": { + "UntrustedArtifactOnDeployment": "Enforce" + }, + "AllowedPublishers": { + "SigningProfileVersionArns": [ + { + "Fn::GetAtt": [ + "SigningProfile", + "ProfileVersionArn" + ] + } + ] + }, + "Description": "Code Signing for MySignedLambdaFunction" + } + }, + "SigningProfile": { + "Type": "AWS::Signer::SigningProfile", + "Properties": { + "PlatformId": "AWSLambda-SHA384-ECDSA" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_function_resources.py b/tests/translator/test_function_resources.py index f5c8c2ab1..aa2d57f4e 100644 --- a/tests/translator/test_function_resources.py +++ b/tests/translator/test_function_resources.py @@ -25,6 +25,37 @@ def setUp(self): self.lambda_func = self._make_lambda_function(self.sam_func.logical_id) self.lambda_version = self._make_lambda_version("VersionLogicalId", self.sam_func) + @patch("boto3.session.Session.region_name", "us-west-2") + def test_sam_function_with_code_signer(self): + code_signing_config_arn = "code_signing_config_arn" + func = { + "Type": "AWS::Serverless::Function", + "Properties": { + "CodeUri": self.code_uri, + "Runtime": "nodejs12.x", + "Handler": "index.handler", + "CodeSigningConfigArn": code_signing_config_arn, + }, + } + + sam_func = SamFunction.from_dict(logical_id="foo", resource_dict=func) + + kwargs = {} + kwargs["managed_policy_map"] = {"a": "b"} + kwargs["event_resources"] = [] + kwargs["intrinsics_resolver"] = self.intrinsics_resolver_mock + self.intrinsics_resolver_mock.resolve_parameter_refs.return_value = { + "S3Bucket": "bucket", + "S3Key": "key", + "S3ObjectVersion": "version", + } + resources = sam_func.to_cloudformation(**kwargs) + + lambda_functions = [r.to_dict() for r in resources if r.resource_type == LambdaFunction.resource_type] + self.assertEqual(len(lambda_functions), 1) + expected_code_signing_config_arn = lambda_functions[0]["foo"]["Properties"]["CodeSigningConfigArn"] + self.assertEqual(expected_code_signing_config_arn, code_signing_config_arn) + @patch("boto3.session.Session.region_name", "ap-southeast-1") @patch.object(SamFunction, "_get_resolved_alias_name") def test_sam_function_with_alias(self, get_resolved_alias_name_mock): diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index bc3848b23..58820d59f 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -251,6 +251,7 @@ class TestTranslatorEndToEnd(TestCase): "function_with_conditional_policy_template", "function_with_conditional_policy_template_and_ref_no_value", "function_with_request_parameters", + "function_with_signing_profile", "global_handle_path_level_parameter", "globals_for_function", "globals_for_api", diff --git a/tox.ini b/tox.ini index 2df512827..63aea07e2 100644 --- a/tox.ini +++ b/tox.ini @@ -17,7 +17,7 @@ envlist = py27, py36, py37, py38 # resource. Tox tries to simulate Py3 behavior in Py2.7 by setting PYTHONHASHSEED to random values on every run. # This results in unit test failures. This happens only within Tox. To fix this, we are unsetting the seed value # specifically for Py27 in Tox. -passenv = AWS* +passenv = AWS* CODECOV_TOKEN setenv = PYTHONHASHSEED = 0 commands = make pr2.7 codecov @@ -26,5 +26,5 @@ commands = make pr2.7 commands = make pr codecov deps = codecov>=1.4.0 -passenv = AWS* TONXENV CI TRAVIS TRAVIS_* -whitelist_externals = make, black +passenv = AWS* TONXENV CI TRAVIS TRAVIS_* CODECOV_TOKEN +whitelist_externals = make, black, codecov