Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ dependencies = [
# regex is not a direct dependency of SAM CLI, exclude version 2021.10.8 due to not working on M1 Mac
"regex!=2021.10.8",
"tzlocal==5.4.4",
"cfn-lint>=1.51.3,<1.56",
# Bounded to the versions that lint every SAM resource type, see #9249
"cfn-lint>=1.52.0,<1.54",
"boto3-stubs[apigateway,cloudformation,ecr,iam,lambda,s3,schemas,secretsmanager,signer,stepfunctions,sts,xray,sqs,kinesis]>=1.41.0",
"python-dotenv>=1.0,<1.3",
]
Expand Down
10 changes: 6 additions & 4 deletions requirements/reproducible-linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ aws-lambda-builders==1.67.0 \
aws-sam-translator==1.113.0 \
--hash=sha256:3a24b3c5bab9c24b6389cdf18a7a745d338363c57803364e028718fb078259e5 \
--hash=sha256:b2db7e4f7c6ee8fafa89e718a82bfa33b8e97c4e64be643aa3595b27cd7a2e2b
# via aws-sam-cli (pyproject.toml)
# via
# aws-sam-cli (pyproject.toml)
# cfn-lint
awscrt==0.36.0 \
--hash=sha256:01a55a4de4d3d915714590bd50cd3cc430e8f5bce78a4c6b6308c6a7f513ca12 \
--hash=sha256:0ef852c7bd977402f2c82959d9b6c68e39c74bca885d4578cec86e6a3b60c864 \
Expand Down Expand Up @@ -206,9 +208,9 @@ cffi==2.1.1 \
--hash=sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4 \
--hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264
# via cryptography
cfn-lint==1.55.1 \
--hash=sha256:1e870ec3dfad17bf2cf164decba961551aed00a3eb3e51182eca6987eddb5562 \
--hash=sha256:4de4ced80c898ce0753b64fc5707bebf011601eb2d027d95e2ab3f91692b99d8
cfn-lint==1.53.3 \
--hash=sha256:2ed701460d68314e905165a9ceed4a9ddf874a03f5022a1070b96e3869b1a931 \
--hash=sha256:739bd8294f07d184b32b2768caa63c18db17b1160d3dd2842abf4efc2980dbe3
# via aws-sam-cli (pyproject.toml)
charset-normalizer==3.5.1 \
--hash=sha256:00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45 \
Expand Down
10 changes: 6 additions & 4 deletions requirements/reproducible-mac.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ aws-lambda-builders==1.67.0 \
aws-sam-translator==1.113.0 \
--hash=sha256:3a24b3c5bab9c24b6389cdf18a7a745d338363c57803364e028718fb078259e5 \
--hash=sha256:b2db7e4f7c6ee8fafa89e718a82bfa33b8e97c4e64be643aa3595b27cd7a2e2b
# via aws-sam-cli (pyproject.toml)
# via
# aws-sam-cli (pyproject.toml)
# cfn-lint
awscrt==0.36.0 \
--hash=sha256:01a55a4de4d3d915714590bd50cd3cc430e8f5bce78a4c6b6308c6a7f513ca12 \
--hash=sha256:0ef852c7bd977402f2c82959d9b6c68e39c74bca885d4578cec86e6a3b60c864 \
Expand Down Expand Up @@ -206,9 +208,9 @@ cffi==2.1.1 \
--hash=sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4 \
--hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264
# via cryptography
cfn-lint==1.55.1 \
--hash=sha256:1e870ec3dfad17bf2cf164decba961551aed00a3eb3e51182eca6987eddb5562 \
--hash=sha256:4de4ced80c898ce0753b64fc5707bebf011601eb2d027d95e2ab3f91692b99d8
cfn-lint==1.53.3 \
--hash=sha256:2ed701460d68314e905165a9ceed4a9ddf874a03f5022a1070b96e3869b1a931 \
--hash=sha256:739bd8294f07d184b32b2768caa63c18db17b1160d3dd2842abf4efc2980dbe3
# via aws-sam-cli (pyproject.toml)
charset-normalizer==3.5.1 \
--hash=sha256:00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45 \
Expand Down
10 changes: 6 additions & 4 deletions requirements/reproducible-win.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ aws-lambda-builders==1.67.0 \
aws-sam-translator==1.113.0 \
--hash=sha256:3a24b3c5bab9c24b6389cdf18a7a745d338363c57803364e028718fb078259e5 \
--hash=sha256:b2db7e4f7c6ee8fafa89e718a82bfa33b8e97c4e64be643aa3595b27cd7a2e2b
# via aws-sam-cli (pyproject.toml)
# via
# aws-sam-cli (pyproject.toml)
# cfn-lint
awscrt==0.36.0 \
--hash=sha256:01a55a4de4d3d915714590bd50cd3cc430e8f5bce78a4c6b6308c6a7f513ca12 \
--hash=sha256:0ef852c7bd977402f2c82959d9b6c68e39c74bca885d4578cec86e6a3b60c864 \
Expand Down Expand Up @@ -206,9 +208,9 @@ cffi==2.1.1 \
--hash=sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4 \
--hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264
# via cryptography
cfn-lint==1.55.1 \
--hash=sha256:1e870ec3dfad17bf2cf164decba961551aed00a3eb3e51182eca6987eddb5562 \
--hash=sha256:4de4ced80c898ce0753b64fc5707bebf011601eb2d027d95e2ab3f91692b99d8
cfn-lint==1.53.3 \
--hash=sha256:2ed701460d68314e905165a9ceed4a9ddf874a03f5022a1070b96e3869b1a931 \
--hash=sha256:739bd8294f07d184b32b2768caa63c18db17b1160d3dd2842abf4efc2980dbe3
# via aws-sam-cli (pyproject.toml)
charset-normalizer==3.5.1 \
--hash=sha256:00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45 \
Expand Down
128 changes: 128 additions & 0 deletions tests/unit/commands/validate/test_lint_sam_resource_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""
Guards `sam validate --lint` against a cfn-lint that does not cover every SAM resource type.

cfn-lint 1.54.0 dropped the SAM transform and started validating AWS::Serverless resources against
schemas it bundles itself, so a resource type it has no schema for fails a valid template with
E3006. See aws-cloudformation/cfn-lint#4678 and the cfn-lint bound in pyproject.toml.
"""

import inspect
import json
from typing import Any, Dict, Set
from unittest import TestCase

from cfnlint.api import ManualArgs, lint
from samtranslator.model import sam_resources

REGION = "us-east-1"


def get_sam_resource_types() -> Set[str]:
"""Every AWS::Serverless resource type the installed SAM translator can expand."""
resource_types = set()
for member in vars(sam_resources).values():
resource_type = getattr(member, "resource_type", None) if inspect.isclass(member) else None
if isinstance(resource_type, str) and resource_type.startswith("AWS::Serverless::"):
resource_types.add(resource_type)
return resource_types


def get_all_sam_resource_types_template() -> Dict[str, Any]:
"""A valid template holding one of every SAM resource type, so linting it must report nothing."""
return {
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::Serverless-2016-10-31",
"Resources": {
"Api": {
"Type": "AWS::Serverless::Api",
"Properties": {"StageName": "prod", "DefinitionUri": "s3://bucket/api.yaml"},
},
"Application": {
"Type": "AWS::Serverless::Application",
"Properties": {"Location": "s3://bucket/app.yaml"},
},
"CapacityProvider": {
"Type": "AWS::Serverless::CapacityProvider",
"Properties": {
"VpcConfig": {
"SubnetIds": ["subnet-0123456789abcdef0"],
"SecurityGroupIds": ["sg-0123456789abcdef0"],
}
},
},
"Connector": {
"Type": "AWS::Serverless::Connector",
"Properties": {
"Source": {"Id": "Function"},
"Destination": {"Id": "SimpleTable"},
"Permissions": ["Read"],
},
},
"Function": {
"Type": "AWS::Serverless::Function",
"Properties": {
"InlineCode": "def handler(event, context): pass",
"Handler": "index.handler",
"Runtime": "python3.13",
},
},
"GraphQLApi": {
"Type": "AWS::Serverless::GraphQLApi",
"Properties": {"Auth": {"Type": "AWS_IAM"}, "SchemaInline": "type Query { hello: String }"},
},
"HttpApi": {"Type": "AWS::Serverless::HttpApi", "Properties": {}},
"LayerVersion": {
"Type": "AWS::Serverless::LayerVersion",
"Properties": {"ContentUri": "s3://bucket/layer.zip"},
},
"MicrovmImage": {
"Type": "AWS::Serverless::MicrovmImage",
"Properties": {
"Name": "image",
"CodeUri": "s3://bucket/code.zip",
"BaseImageArn": "arn:aws:lambda:us-east-1:123456789012:microvm-base-image/base",
"BaseImageVersion": "1",
},
},
"NetworkConnector": {
"Type": "AWS::Serverless::NetworkConnector",
"Properties": {
"VpcConfig": {
"SubnetIds": ["subnet-0123456789abcdef0"],
"SecurityGroupIds": ["sg-0123456789abcdef0"],
"NetworkProtocol": "IPv4",
}
},
},
"SimpleTable": {"Type": "AWS::Serverless::SimpleTable", "Properties": {}},
"StateMachine": {
"Type": "AWS::Serverless::StateMachine",
"Properties": {"Definition": {"StartAt": "Done", "States": {"Done": {"Type": "Succeed"}}}},
},
"WebSocketApi": {
"Type": "AWS::Serverless::WebSocketApi",
"Properties": {
"RouteSelectionExpression": "$request.body.action",
"Routes": {"$connect": {"FunctionArn": {"Fn::GetAtt": ["Function", "Arn"]}}},
},
},
},
}


class TestLintEverySamResourceType(TestCase):
def test_lint_every_sam_resource_type(self):
# A resource type cfn-lint does not cover fails a valid template, so lint one of each.
template = get_all_sam_resource_types_template()

# Fails when SAM gains a resource type the template does not cover.
self.assertEqual(
{resource["Type"] for resource in template["Resources"].values()},
get_sam_resource_types(),
"Add the new SAM resource type to get_all_sam_resource_types_template",
)

# Reaches cfn-lint the same way samcli.commands.validate.validate._lint does.
matches = lint(json.dumps(template), config=ManualArgs(regions=[REGION]))

self.assertEqual(matches, [], f"cfn-lint rejected a valid SAM template: {matches}")
Comment thread
roger-zhangg marked this conversation as resolved.
Loading