Skip to content

Commit 559d6b7

Browse files
authoredJun 4, 2025··
Merge pull request #3775 from aws/release-v1.98.0
Release 1.98.0 (to main)
·
v1.100.0v1.98.0
2 parents dba5126 + ad5b4d6 commit 559d6b7

17 files changed

+2214
-359
lines changed
 

‎samtranslator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.97.0"
1+
__version__ = "1.98.0"

‎samtranslator/model/sam_resources.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
""" SAM macro definitions """
22

33
import copy
4+
import re
45
from contextlib import suppress
56
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union, cast
67

@@ -238,7 +239,6 @@ class SamFunction(SamResourceMacro):
238239

239240
# DeadLetterQueue
240241
dead_letter_queue_policy_actions = {"SQS": "sqs:SendMessage", "SNS": "sns:Publish"}
241-
#
242242

243243
# Conditions
244244
conditions: Dict[str, Any] = {} # TODO: Replace `Any` with something more specific
@@ -325,7 +325,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P
325325
resources.append(url_permission)
326326

327327
self._validate_deployment_preference_and_add_update_policy(
328-
kwargs.get("deployment_preference_collection", None),
328+
kwargs.get("deployment_preference_collection"),
329329
lambda_alias,
330330
intrinsics_resolver,
331331
cast(IntrinsicsResolver, mappings_resolver), # TODO: better handle mappings_resolver's Optional
@@ -1002,7 +1002,22 @@ def _construct_alias(self, name: str, function: LambdaFunction, version: LambdaV
10021002
if not name:
10031003
raise InvalidResourceException(self.logical_id, "Alias name is required to create an alias")
10041004

1005-
logical_id = f"{function.logical_id}Alias{name}"
1005+
# Validate alias name against the required pattern: (?!^[0-9]+$)([a-zA-Z0-9-_]+)
1006+
# This ensures the alias name:
1007+
# 1. Contains only alphanumeric characters, hyphens, and underscores
1008+
# 2. Is not purely numeric
1009+
ALIAS_REGEX = r"(?!^[0-9]+$)([a-zA-Z0-9\-_]+)$"
1010+
if not re.match(ALIAS_REGEX, name):
1011+
raise InvalidResourceException(
1012+
self.logical_id,
1013+
f"AutoPublishAlias name ('{name}') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern.",
1014+
)
1015+
1016+
# Strip hyphens and underscores from the alias name for the logical ID
1017+
# This ensures the logical ID contains only alphanumeric characters
1018+
alias_alphanumeric_name = name.replace("-", "D").replace("_", "U")
1019+
1020+
logical_id = f"{function.logical_id}Alias{alias_alphanumeric_name}"
10061021
alias = LambdaAlias(logical_id=logical_id, attributes=self.get_passthrough_resource_attributes())
10071022
alias.Name = name
10081023
alias.FunctionName = function.get_runtime_attr("name")
@@ -1014,7 +1029,7 @@ def _construct_alias(self, name: str, function: LambdaFunction, version: LambdaV
10141029

10151030
def _validate_deployment_preference_and_add_update_policy( # noqa: PLR0913
10161031
self,
1017-
deployment_preference_collection: DeploymentPreferenceCollection,
1032+
deployment_preference_collection: Optional[DeploymentPreferenceCollection],
10181033
lambda_alias: Optional[LambdaAlias],
10191034
intrinsics_resolver: IntrinsicsResolver,
10201035
mappings_resolver: IntrinsicsResolver,

‎samtranslator/region_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def is_apigw_edge_configuration_supported(cls) -> bool:
1818
:return: True, if API Gateway does not support Edge configuration
1919
"""
2020
partition = ArnGenerator.get_partition_name()
21-
if partition.startswith("aws-iso") or partition in ["aws-us-gov", "aws-cn"]:
21+
if partition.startswith("aws-iso") or partition in ["aws-us-gov", "aws-cn", "aws-eusc"]:
2222
return False
2323
return True
2424

‎samtranslator/schema/schema.json

Lines changed: 93 additions & 93 deletions
Large diffs are not rendered by default.

‎samtranslator/translator/arn_generator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def _region_to_partition(region: str) -> str:
2424
"us-gov": "aws-us-gov",
2525
"eu-isoe": "aws-iso-e",
2626
"us-isof": "aws-iso-f",
27+
"eusc-": "aws-eusc",
2728
}
2829
for key, value in region_to_partition_map.items():
2930
if region_string.startswith(key):

‎schema_source/cloudformation-docs.json

Lines changed: 456 additions & 157 deletions
Large diffs are not rendered by default.

‎schema_source/cloudformation.schema.json

Lines changed: 93 additions & 93 deletions
Large diffs are not rendered by default.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Resources:
2+
MyFunction:
3+
Type: AWS::Serverless::Function
4+
Properties:
5+
CodeUri: s3://sam-demo-bucket/hello.zip
6+
Handler: hello.handler
7+
Runtime: python3.9
8+
# Using an invalid alias name with special characters that can't be properly transformed
9+
AutoPublishAlias: invalid*alias@name
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
Resources:
2+
FunctionAliasNameCamelCase:
3+
Type: AWS::Serverless::Function
4+
Properties:
5+
CodeUri: s3://sam-demo-bucket/hello.zip
6+
Handler: hello.handler
7+
Runtime: python3.9
8+
AutoPublishAlias: camelCaseName
9+
VersionDescription: sam-testing
10+
11+
FunctionAliasNameUpperCase:
12+
Type: AWS::Serverless::Function
13+
Properties:
14+
CodeUri: s3://sam-demo-bucket/hello.zip
15+
Handler: hello.handler
16+
Runtime: python3.9
17+
AutoPublishAlias: UPPERCASE
18+
VersionDescription: sam-testing
19+
20+
FunctionAliasNameLowerCase:
21+
Type: AWS::Serverless::Function
22+
Properties:
23+
CodeUri: s3://sam-demo-bucket/hello.zip
24+
Handler: hello.handler
25+
Runtime: python3.9
26+
AutoPublishAlias: lowercase
27+
VersionDescription: sam-testing
28+
29+
FunctionAliasNameUnderscore:
30+
Type: AWS::Serverless::Function
31+
Properties:
32+
CodeUri: s3://sam-demo-bucket/hello.zip
33+
Handler: hello.handler
34+
Runtime: python3.9
35+
AutoPublishAlias: _underscore_name_
36+
VersionDescription: sam-testing
37+
38+
FunctionAliasNameDash:
39+
Type: AWS::Serverless::Function
40+
Properties:
41+
CodeUri: s3://sam-demo-bucket/hello.zip
42+
Handler: hello.handler
43+
Runtime: python3.9
44+
AutoPublishAlias: underscore-name
45+
VersionDescription: sam-testing
46+
47+
FunctionAliasNameMix:
48+
Type: AWS::Serverless::Function
49+
Properties:
50+
CodeUri: s3://sam-demo-bucket/hello.zip
51+
Handler: hello.handler
52+
Runtime: python3.9
53+
AutoPublishAlias: underScoreNAME_with-dash-01234
54+
VersionDescription: sam-testing

‎tests/translator/output/aws-cn/function_with_alias_valid_names.json

Lines changed: 472 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/translator/output/aws-us-gov/function_with_alias_valid_names.json

Lines changed: 472 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"_autoGeneratedBreakdownErrorMessage": [
3+
"Invalid Serverless Application Specification document. ",
4+
"Number of errors found: 1. ",
5+
"Resource with id [MyFunction] is invalid. ",
6+
"AutoPublishAlias name ('invalid*alias@name') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern."
7+
],
8+
"errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyFunction] is invalid. AutoPublishAlias name ('invalid*alias@name') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern."
9+
}

‎tests/translator/output/function_with_alias_valid_names.json

Lines changed: 472 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/translator/test_arn_generator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def setUp(self):
1818
("eu-isoe-west-1", "aws-iso-e"),
1919
("US-EAST-1", "aws"),
2020
("us-isof-east-1", "aws-iso-f"),
21+
("eusc-de-east-1", "aws-eusc"),
2122
]
2223
)
2324
def test_get_partition_name(self, region, expected):

‎tests/translator/test_function_resources.py

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -765,20 +765,68 @@ def test_version_logical_id_changes_with_snapstart(self):
765765
self.assertNotEqual(version1.logical_id, version_snapstart.logical_id)
766766
self.assertEqual(version1.logical_id, version_snapstart_none.logical_id)
767767

768-
def test_alias_creation(self):
769-
name = "aliasname"
770-
771-
alias = self.sam_func._construct_alias(name, self.lambda_func, self.lambda_version)
768+
@parameterized.expand(
769+
[
770+
# Valid cases
771+
# Expect logical id should be {fn name}{'Alias'}{alphanumerica alias name without `-` or `_`}
772+
("aliasname", "fooAliasaliasname"),
773+
("alias-name", "fooAliasaliasDname"),
774+
("alias_name", "fooAliasaliasUname"),
775+
("alias123", "fooAliasalias123"),
776+
("123alias", "fooAlias123alias"),
777+
("UPPERCASE", "fooAliasUPPERCASE"),
778+
("mixed-Case_123", "fooAliasmixedDCaseU123"),
779+
("a", "fooAliasa"), # Single character
780+
("1a", "fooAlias1a"), # Starts with number
781+
# Check the placement of dash and underscore
782+
("1-1_1", "fooAlias1D1U1"),
783+
("1_1-1", "fooAlias1U1D1"),
784+
("11-1", "fooAlias11D1"),
785+
("1-11", "fooAlias1D11"),
786+
("11_1", "fooAlias11U1"),
787+
("1_11", "fooAlias1U11"),
788+
("1-1-1", "fooAlias1D1D1"),
789+
("-1-1-1-", "fooAliasD1D1D1D"),
790+
("_1_1-1-", "fooAliasU1U1D1D"),
791+
]
792+
)
793+
def test_alias_creation(self, alias_name, expected_logical_id):
794+
alias = self.sam_func._construct_alias(alias_name, self.lambda_func, self.lambda_version)
772795

773-
expected_logical_id = f"{self.lambda_func.logical_id}Alias{name}"
774796
self.assertEqual(alias.logical_id, expected_logical_id)
775-
self.assertEqual(alias.Name, name)
797+
self.assertEqual(alias.Name, alias_name)
776798
self.assertEqual(alias.FunctionName, {"Ref": self.lambda_func.logical_id})
777799
self.assertEqual(alias.FunctionVersion, {"Fn::GetAtt": [self.lambda_version.logical_id, "Version"]})
778800

779-
def test_alias_creation_error(self):
780-
with self.assertRaises(InvalidResourceException):
781-
self.sam_func._construct_alias(None, self.lambda_func, self.lambda_version)
801+
@parameterized.expand(
802+
[
803+
# Invalid cases
804+
("", "Resource with id [foo] is invalid. Alias name is required to create an alias"),
805+
(None, "Resource with id [foo] is invalid. Alias name is required to create an alias"),
806+
(
807+
"123",
808+
"Resource with id [foo] is invalid. AutoPublishAlias name ('123') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern.",
809+
),
810+
(
811+
"name with space",
812+
"Resource with id [foo] is invalid. AutoPublishAlias name ('name with space') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern.",
813+
),
814+
(
815+
"alias@name",
816+
"Resource with id [foo] is invalid. AutoPublishAlias name ('alias@name') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern.",
817+
),
818+
(
819+
"alias/name",
820+
"Resource with id [foo] is invalid. AutoPublishAlias name ('alias/name') must contain only alphanumeric characters, hyphens, or underscores matching (?!^[0-9]+$)([a-zA-Z0-9-_]+) pattern.",
821+
),
822+
]
823+
)
824+
def test_alias_creation_error(self, alias_name, expected_error_massage):
825+
with self.assertRaises(InvalidResourceException) as context:
826+
self.sam_func._construct_alias(alias_name, self.lambda_func, self.lambda_version)
827+
828+
error = context.exception
829+
self.assertEqual(str(error.message), expected_error_massage)
782830

783831
def test_get_resolved_alias_name_must_work(self):
784832
property_name = "something"

‎tests/unit/test_region_configuration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ def test_when_apigw_edge_configuration_supported(self, partition):
2020

2121
self.assertTrue(RegionConfiguration.is_apigw_edge_configuration_supported())
2222

23-
@parameterized.expand([["aws-cn"], ["aws-us-gov"], ["aws-iso"], ["aws-iso-b"], ["aws-iso-e"], ["aws-iso-f"]])
23+
@parameterized.expand(
24+
[["aws-cn"], ["aws-us-gov"], ["aws-iso"], ["aws-iso-b"], ["aws-iso-e"], ["aws-iso-f"], ["aws-eusc"]]
25+
)
2426
def test_when_apigw_edge_configuration_is_not_supported(self, partition):
2527
with patch(
2628
"samtranslator.translator.arn_generator.ArnGenerator.get_partition_name"

‎tests/unit/translator/test_arn_generator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TestArnGenerator(TestCase):
1515
["us-iso-east-1", "aws-iso"],
1616
["us-isob-east-1", "aws-iso-b"],
1717
["eu-isoe-west-1", "aws-iso-e"],
18+
["eusc-de-east-1", "aws-eusc"],
1819
]
1920
)
2021
def test_get_partition_name(self, region, expected_partition):

0 commit comments

Comments
 (0)
Please sign in to comment.