Skip to content
Closed
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
5 changes: 5 additions & 0 deletions .cfnlintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ ignore_templates:
- tests/translator/output/**/connector_sfn_to_function.json
- tests/translator/output/**/connector_sns_to_function.json
- tests/translator/output/**/connector_table_to_function.json
- tests/translator/output/**/graphqlapi_api_cache.json # Fail by design: intentionally invalid CachingConfig enum values to test error path
- tests/translator/output/**/eventbridgerule_with_dlq.json
- tests/translator/output/**/function_event_conditions.json
- tests/translator/output/**/function_with_condition.json
Expand Down Expand Up @@ -112,6 +113,10 @@ ignore_templates:
- tests/translator/output/**/function_with_logging_config.json # cfnlint is not updated to recognize the LoggingConfig property
- tests/translator/output/aws-*/*capacity_provider*.json # Ignore Capacity Provider test format in non-aws partitions
- tests/translator/output/**/capacity_provider_managed_resource_tags.json # cfnlint not updated for CapacityProvider mode (Phase 2)
- tests/translator/output/**/webfunction_basic.json # New AWS::Lambda::WebFunction* types cfn-lint does not recognize; DependsOn is intentional (W3005)
- tests/translator/output/**/webfunction_with_all_properties.json # New AWS::Lambda::WebFunction* types cfn-lint does not recognize; DependsOn is intentional (W3005)
- tests/translator/output/**/webfunction_multiregion.json # New AWS::Lambda::WebFunction* types cfn-lint does not recognize; DependsOn is intentional (W3005)
- tests/translator/output/**/basic_function.json # W1030: fixture uses Ref for VpcConfig SubnetIds, which cannot match the subnet-id pattern

ignore_checks:
- E2531 # Deprecated runtime; not relevant for transform tests
Expand Down
9 changes: 9 additions & 0 deletions bin/run_cfn_lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ set -eux

VENV=.venv_cfn_lint

# cfn-lint requires Python >= 3.10, which this project also requires (see python_requires in setup.py).
# Fail loudly rather than skipping: a silent "exit 0" here would turn the lint gate into a no-op on a
# misconfigured interpreter and report success without checking a single template.
PYTHON_MINOR=$(python3 -c "import sys; print(sys.version_info.minor)")
if [ "$PYTHON_MINOR" -lt 10 ]; then
echo "ERROR: cfn-lint requires Python >= 3.10, but python3 is 3.${PYTHON_MINOR}. Use a supported interpreter." >&2
exit 1
fi

# Install to separate venv to avoid circular dependency; cfn-lint depends on samtranslator
# See https://github.com/aws/serverless-application-model/issues/1042
if [ ! -d "${VENV}" ]; then
Expand Down
4 changes: 3 additions & 1 deletion integration/config/code_key_to_file_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"definitionuri": "swagger1.json",
"microvmcodeuri": "microvm_code.zip",
"mtlsuri": "MTLSCert.pem",
"templateurl": "template.yaml"
"templateurl": "template.yaml",
"webfunccodeuri": "webfunc_code.zip",
"webfunccodeuri2": "webfunc_code2.zip"
}
8 changes: 8 additions & 0 deletions integration/config/file_to_s3_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,13 @@
"template.yaml": {
"type": "http",
"uri": ""
},
"webfunc_code.zip": {
"type": "s3",
"uri": ""
},
"webfunc_code2.zip": {
"type": "s3",
"uri": ""
}
}
5 changes: 5 additions & 0 deletions integration/config/region_service_inclusion.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
regions:
us-east-1:
- CustomDomain
- WebFunction
us-west-2:
- WebFunction
eu-west-1:
- WebFunction
Metadata:
SamTransformTest: true
1 change: 1 addition & 0 deletions integration/config/service_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
LAMBDA_URL = "LambdaUrl"
LAMBDA_MANAGED_INSTANCES = "LambdaManagedInstances"
MICROVM_IMAGE = "MicrovmImage"
WEB_FUNCTION = "WebFunction"
LAMBDA_ENV_VARS = "LambdaEnvVars"
EVENT_INVOKE_CONFIG = "EventInvokeConfig"
API_KEY = "ApiKey"
Expand Down
41 changes: 32 additions & 9 deletions integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,32 @@ def _get_all_buckets():
return s3.buckets.all()


def clean_bucket(s3_bucket_name, s3_client):
def empty_versioned_bucket(s3_bucket_name, s3_client):
"""
Empties and deletes the bucket used for the tests
Deletes every object version and delete marker from a bucket. Deleting objects without a VersionId
only adds delete markers on a versioned bucket, so the versions must be removed explicitly, otherwise
the bucket cannot be deleted (and CloudFormation's DeletionPolicy: Delete would leave the stack in
DELETE_FAILED). Works for non-versioned buckets too, where each object has a "null" version.
"""
s3 = boto3.resource("s3")
bucket = s3.Bucket(s3_bucket_name)
object_summary_iterator = bucket.objects.all()

for object_summary in object_summary_iterator:
paginator = s3_client.get_paginator("list_object_versions")
for page in paginator.paginate(Bucket=s3_bucket_name):
to_delete = [
{"Key": item["Key"], "VersionId": item["VersionId"]}
for item in (page.get("Versions", []) + page.get("DeleteMarkers", []))
]
if not to_delete:
continue
try:
s3_client.delete_object(Key=object_summary.key, Bucket=s3_bucket_name)
s3_client.delete_objects(Bucket=s3_bucket_name, Delete={"Objects": to_delete})
except ClientError as e:
LOG.error("Unable to delete object %s from bucket %s", object_summary.key, s3_bucket_name, exc_info=e)
LOG.error("Unable to delete object versions from bucket %s", s3_bucket_name, exc_info=e)


def clean_bucket(s3_bucket_name, s3_client):
"""
Empties and deletes the bucket used for the tests
"""
empty_versioned_bucket(s3_bucket_name, s3_client)
try:
s3_client.delete_bucket(Bucket=s3_bucket_name)
except ClientError as e:
Expand Down Expand Up @@ -201,6 +214,16 @@ def delete_companion_stack_once(get_prefix):
if os.environ.get("COMPANION_STACK_NAME"):
return
if not get_prefix:
# PreCreatedS3Bucket has versioning enabled, so CloudFormation cannot delete it while it still holds
# object versions or delete markers — the stack would be left in DELETE_FAILED and leak the bucket.
# Empty all versions first so DeletionPolicy: Delete can succeed.
try:
outputs = get_stack_outputs(get_stack_description(COMPANION_STACK_NAME))
bucket_name = outputs.get("PreCreatedS3Bucket")
if bucket_name:
empty_versioned_bucket(bucket_name, ClientProvider().s3_client)
except botocore.exceptions.ClientError as e:
LOG.error("Unable to empty companion bucket before deleting the companion stack", exc_info=e)
ClientProvider().cfn_client.delete_stack(StackName=COMPANION_STACK_NAME)


Expand Down
Binary file added integration/resources/code/webfunc_code.zip
Binary file not shown.
Binary file added integration/resources/code/webfunc_code2.zip
Binary file not shown.
18 changes: 18 additions & 0 deletions integration/resources/expected/single/basic_web_function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "CustomRole",
"ResourceType": "AWS::IAM::Role"
},
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"LogicalResourceId": "MyWebFunction",
"ResourceType": "AWS::Lambda::WebFunction"
},
{
"LogicalResourceId": "MyWebFunctionEndpoint",
"ResourceType": "AWS::Lambda::WebFunctionEndpoint"
},
{
"LogicalResourceId": "MyWebFunctionRevision",
"ResourceType": "AWS::Lambda::WebFunctionRevision"
},
{
"LogicalResourceId": "MyWebFunctionRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Resources:
MyWebFunction:
Type: AWS::Serverless::WebFunction
Properties:
Runtime: nodejs24.x
CodeUri: ${webfunccodeuri}
AuthType: ApplicationManaged
Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Resources:
MyWebFunction:
Type: AWS::Serverless::WebFunction
Properties:
Runtime: nodejs24.x
CodeUri: ${webfunccodeuri}
AuthType: ApplicationManaged
EndpointName: staging
Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Resources:
CustomRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

MyWebFunction:
Type: AWS::Serverless::WebFunction
Properties:
Runtime: nodejs24.x
CodeUri: ${webfunccodeuri}
AuthType: ApplicationManaged
ExecutionRoleArn: !GetAtt CustomRole.Arn
Metadata:
SamTransformTest: true
Loading
Loading