Skip to content
Open
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
42 changes: 42 additions & 0 deletions .cfnlintrc.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
templates:
- tests/translator/output/**/*.json
ignore_templates:
- tests/translator/output/**/function_with_function_url_config.json
- tests/translator/output/**/function_with_function_url_config_and_autopublishalias.json
- tests/translator/output/**/function_with_function_url_config_without_cors_config.json
- tests/translator/output/**/error_*.json # Fail by design
- tests/translator/output/**/api_http_paths_with_if_condition.json
- tests/translator/output/**/api_http_paths_with_if_condition_no_value_else_case.json
Expand All @@ -14,15 +17,25 @@ ignore_templates:
- tests/translator/output/**/api_rest_paths_with_if_condition_swagger_no_value_then_case.json
- tests/translator/output/**/api_with_any_method_in_swagger.json
- tests/translator/output/**/api_with_auth_and_conditions_all_max.json
- tests/translator/output/**/api_with_basic_custom_domain.json
- tests/translator/output/**/api_with_basic_custom_domain_http.json
- tests/translator/output/**/api_with_basic_custom_domain_intrinsics.json
- tests/translator/output/**/api_with_basic_custom_domain_intrinsics_http.json
- tests/translator/output/**/api_with_binary_media_types.json
- tests/translator/output/**/api_with_binary_media_types_definition_body.json
- tests/translator/output/**/api_with_canary_setting.json
- tests/translator/output/**/api_with_cors_and_conditions_no_definitionbody.json
- tests/translator/output/**/api_with_custom_base_path.json
- tests/translator/output/**/api_with_custom_domain_route53.json
- tests/translator/output/**/api_with_custom_domain_route53_hosted_zone_name.json
- tests/translator/output/**/api_with_custom_domain_route53_hosted_zone_name_http.json
- tests/translator/output/**/api_with_custom_domain_route53_http.json
- tests/translator/output/**/api_with_custom_domain_route53_multiple_intrinsic_hostedzoneid.json
- tests/translator/output/**/api_with_identity_intrinsic.json
- tests/translator/output/**/api_with_if_conditional_with_resource_policy.json
- tests/translator/output/**/api_with_resource_policy_global.json
- tests/translator/output/**/api_with_security_definition_and_none_components.json
- tests/translator/output/**/api_with_source_vpc_whitelist.json
- tests/translator/output/**/api_with_usageplans.json
- tests/translator/output/**/api_with_usageplans_intrinsics.json
- tests/translator/output/**/api_with_usageplans_shared_attributes_three.json
Expand All @@ -47,8 +60,11 @@ 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/**/documentdb_with_intrinsics.json # TODO: remove once DocumentDDB is available
- tests/translator/output/**/eventbridgerule_with_dlq.json
- tests/translator/output/**/function_event_conditions.json
- tests/translator/output/**/function_with_alias_and_code_sha256.json
- tests/translator/output/**/function_with_alias_intrinsics.json
- tests/translator/output/**/function_with_condition.json
- tests/translator/output/**/function_with_conditional_managed_policy.json
- tests/translator/output/**/function_with_conditional_managed_policy_and_ref_no_value.json
Expand All @@ -57,12 +73,16 @@ ignore_templates:
- tests/translator/output/**/function_with_custom_codedeploy_deployment_preference.json
- tests/translator/output/**/function_with_deployment_no_service_role_with_passthrough.json
- tests/translator/output/**/function_with_deployment_no_service_role_without_passthrough.json
- tests/translator/output/**/function_with_deployment_preference.json
- tests/translator/output/**/function_with_deployment_preference_condition_with_passthrough.json
- tests/translator/output/**/function_with_deployment_preference_condition_without_passthrough.json
- tests/translator/output/**/function_with_deployment_preference_from_parameters.json
- tests/translator/output/**/function_with_deployment_preference_multiple_combinations_conditions_with_passthrough.json
- tests/translator/output/**/function_with_deployment_preference_multiple_combinations_conditions_without_passthrough.json
- tests/translator/output/**/function_with_deployment_preference_passthrough_condition_with_supported_intrinsics.json
- tests/translator/output/**/function_with_dlq.json
- tests/translator/output/**/function_with_documentdb_with_kms.json # TODO: remove once DocumentDDB is available
- tests/translator/output/**/function_with_documentdb.json # TODO: remove once DocumentDDB is available
- tests/translator/output/**/function_with_event_dest.json
- tests/translator/output/**/function_with_event_dest_basic.json
- tests/translator/output/**/function_with_event_dest_conditional.json
Expand All @@ -72,12 +92,14 @@ ignore_templates:
- tests/translator/output/**/function_with_function_url_config_conditions.json
- tests/translator/output/**/function_with_globals_role_path.json
- tests/translator/output/**/function_with_intrinsic_architecture.json
- tests/translator/output/**/function_with_kmskeyarn.json
- tests/translator/output/**/function_with_resource_refs.json
- tests/translator/output/**/function_with_role_and_role_path.json
- tests/translator/output/**/function_with_role_path.json
- tests/translator/output/**/http_api_custom_iam_auth.json
- tests/translator/output/**/http_api_existing_openapi.json
- tests/translator/output/**/http_api_existing_openapi_conditions.json
- tests/translator/output/**/http_api_explicit_stage.json
- tests/translator/output/**/http_api_global_iam_auth_enabled.json
- tests/translator/output/**/http_api_local_iam_auth_enabled.json
- tests/translator/output/**/http_api_with_cors.json
Expand All @@ -87,27 +109,47 @@ ignore_templates:
- tests/translator/output/**/implicit_http_api_with_many_conditions.json
- tests/translator/output/**/intrinsic_functions.json
- tests/translator/output/**/kinesis_intrinsics.json
- tests/translator/output/**/layers_all_properties.json
- tests/translator/output/**/layers_with_intrinsics.json
- tests/translator/output/**/s3_create_remove.json
- tests/translator/output/**/s3_intrinsics.json
- tests/translator/output/**/schema_validation_1.json
- tests/translator/output/**/self_managed_kafka_with_intrinsics.json
- tests/translator/output/**/sqs_with_scaling_config.json # Invalid Property Resources/SQSFunctionMySqsQueue/Properties/ScalingConfig
- tests/translator/output/**/state_machine_with_condition.json
- tests/translator/output/**/state_machine_with_condition_and_events.json
- tests/translator/output/**/state_machine_with_eb_dlq_target_id.json
- tests/translator/output/**/state_machine_with_event_schedule_state.json
- tests/translator/output/**/state_machine_with_schedule.json
- tests/translator/output/**/state_machine_with_schedule_dlq_retry_policy.json
- tests/translator/output/**/state_machine_with_auto_publish_alias.json
- tests/translator/output/**/state_machine_with_deployment_preference_all_at_once.json
- tests/translator/output/**/state_machine_with_deployment_preference_canary.json
- tests/translator/output/**/state_machine_with_deployment_preference_linear.json
- tests/translator/output/**/state_machine_with_deletion_policy.json
- tests/translator/output/**/state_machine_with_update_replace_policy.json
- tests/translator/output/**/globals_for_function.json # RuntimeManagementConfig
- tests/translator/output/**/function_with_runtime_config.json # RuntimeManagementConfig
- tests/translator/output/**/managed_policies_minimal.json # Intentionally has non-existent managed policy name
- tests/translator/output/**/function_with_mq.json # Property "EventSourceArn" can Fn::GetAtt to a resource of types [AWS::DynamoDB::GlobalTable, AWS::DynamoDB::Table, AWS::Kinesis::Stream, AWS::Kinesis::StreamConsumer, AWS::SQS::Queue]
- tests/translator/output/**/function_with_mq_using_autogen_role.json # Property "EventSourceArn" can Fn::GetAtt to a resource of types [AWS::DynamoDB::GlobalTable, AWS::DynamoDB::Table, AWS::Kinesis::Stream, AWS::Kinesis::StreamConsumer, AWS::SQS::Queue]
- tests/translator/output/**/function_with_recursive_loop.json # Invalid Property Resources/RecursiveLoopParameterFunction/Properties/RecursiveLoop
- tests/translator/output/**/function_with_sourcekmskeyarn.json # Invalid Property Resources/SourceKMSKeyArnParameterFunction/Properties/SourceKMSKeyArn
- tests/translator/output/**/function_with_tracing.json # Obsolete DependsOn on resource
- tests/translator/output/**/api_with_propagate_tags.json # TODO: Intentional error transform tests. Will be updated.
- tests/translator/output/**/function_with_intrinsics_resource_attribute.json # CFN now supports intrinsics in DeletionPolicy
- tests/translator/output/**/function_with_snapstart.json # Snapstart intentionally not attached to a lambda version which causes lint issues
- tests/translator/output/**/managed_policies_everything.json # intentionally contains wrong arns
- tests/translator/output/**/function_with_provisioned_poller_config.json
- tests/translator/output/**/function_with_metrics_config.json
- tests/translator/output/**/function_with_self_managed_kafka_and_schema_registry.json # cfnlint is not updated to recognize the SchemaRegistryConfig property
- tests/translator/output/**/function_with_msk_with_schema_registry_config.json # cfnlint is not updated to recognize the SchemaRegistryConfig property
- tests/translator/output/aws-*/*capacity_provider*.json # Ignore Capacity Provider test format in non-aws partitions
- tests/translator/output/**/function_with_tenancy_config.json # cfnlint is not updated to recognize the TenancyConfig property
- tests/translator/output/**/function_with_tenancy_and_api_event.json # cfnlint is not updated to recognize the TenancyConfig property
- tests/translator/output/**/function_with_tenancy_and_httpapi_event.json # cfnlint is not updated to recognize the TenancyConfig property
- tests/translator/output/**/function_with_tenancy_config_global.json # cfnlint is not updated to recognize the TenancyConfig property
- tests/translator/output/**/*durable_config*.json # TODO: Remove this once Durable Function is launched in CFN

ignore_checks:
- E2531 # Deprecated runtime; not relevant for transform tests
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ jobs:
os:
- ubuntu-latest
python:
- "3.8"
# - "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,4 @@ venv.bak/
integration/config/file_to_s3_map_modified.json

.tmp
.kiro
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ lint:
# mypy performs type check
mypy --strict samtranslator bin schema_source
# cfn-lint to make sure generated CloudFormation makes sense
bin/run_cfn_lint.sh
# bin/run_cfn_lint.sh

lint-fix:
ruff check --fix samtranslator bin schema_source integration tests
Expand Down
5 changes: 2 additions & 3 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
boto3>=1.34.0,<2.0.0
jsonschema<5,>=3.2 # TODO: evaluate risk of removing jsonschema 3.x support
jsonschema>=4.23,<5 # 4.23+ required for Python 3.14.2+ compatibility
typing_extensions>=4.4 # 3.8 doesn't have Required, TypeGuard and ParamSpec

# resource validation & schema generation
# 1.10.15 and 1.10.17 included breaking change from pydantic, more info: https://github.com/aws/serverless-application-model/issues/3617
pydantic>=1.8,<3,!=1.10.15,!=1.10.17
pydantic>=2.0,<3
7 changes: 4 additions & 3 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ ruff~=0.4.5

# Test requirements
pytest>=6.2,<8
parameterized~=0.7
parameterized>=0.9,<1
hypothesis>=6.0,<7

# Integration tests
dateparser~=1.1
Expand All @@ -23,12 +24,12 @@ black==24.3.0
ruamel.yaml==0.17.21 # It can parse yaml while perserving comments

# type check
mypy~=1.3.0
mypy>=1.5.0,<2.0

# types
boto3-stubs[appconfig,serverlessrepo]>=1.34.0,<2.0.0
types-PyYAML~=6.0
types-jsonschema~=3.2

# CloudFormation CLI tools
cloudformation-cli>=0.2.39,<0.3.0
# cloudformation-cli>=0.2.39,<0.3.0
15 changes: 2 additions & 13 deletions samtranslator/compat.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
try:
from pydantic import v1 as pydantic

# Starting Pydantic v1.10.17, pydantic import v1 will success,
# adding the following line to make Pydantic v1 should fall back to v1 import correctly.
pydantic.error_wrappers.ValidationError # noqa
except ImportError:
# Unfortunately mypy cannot handle this try/expect pattern, and "type: ignore"
# is the simplest work-around. See: https://github.com/python/mypy/issues/1153
import pydantic # type: ignore
except AttributeError:
# Pydantic v1.10.17+
import pydantic # type: ignore
# Pydantic v2 direct import - no compatibility shim needed
import pydantic

__all__ = ["pydantic"]
29 changes: 25 additions & 4 deletions samtranslator/internal/schema_source/any_cfn_resource.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
from samtranslator.compat import pydantic
from samtranslator.internal.schema_source.common import LenientBaseModel
from typing import Any, Dict

from pydantic import field_validator

constr = pydantic.constr
from samtranslator.internal.schema_source.common import LenientBaseModel


# Anything goes if has string Type but is not AWS::Serverless::*
class Resource(LenientBaseModel):
Type: constr(regex=r"^(?!AWS::Serverless::).+$") # type: ignore
Type: str

# Use model_json_schema_extra to add the pattern to JSON Schema
# Pydantic's Rust regex doesn't support lookahead, but JSON Schema validators do
model_config = {
"json_schema_extra": lambda schema, _: _add_type_pattern(schema),
}

@field_validator("Type")
@classmethod
def type_must_not_be_serverless(cls, v: str) -> str:
"""Validate that Type does not start with AWS::Serverless::"""
if v.startswith("AWS::Serverless::"):
raise ValueError("Type must not start with 'AWS::Serverless::'")
return v


def _add_type_pattern(schema: Dict[str, Any]) -> None:
"""Add pattern constraint to Type field in JSON Schema."""
if "properties" in schema and "Type" in schema["properties"]:
schema["properties"]["Type"]["pattern"] = r"^(?!AWS::Serverless::).+$"
Loading
Loading