Skip to content

Commit 4b60246

Browse files
Fix Lambda function alias name checks (#10227)
1 parent fd067cb commit 4b60246

File tree

6 files changed

+193
-2
lines changed

6 files changed

+193
-2
lines changed

localstack/services/lambda_/api_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
# Pattern for an alias qualifier
8484
# Rules: https://docs.aws.amazon.com/lambda/latest/dg/API_CreateAlias.html#SSS-CreateAlias-request-Name
8585
# The original regex from AWS misses ^ and $ in the second regex, which allowed for partial substring matches
86-
ALIAS_REGEX = re.compile(r"(?!^[0-9]+)(^[a-zA-Z0-9-_]+$)")
86+
ALIAS_REGEX = re.compile(r"(?!^[0-9]+$)(^[a-zA-Z0-9-_]+$)")
8787
# Permission statement id
8888
STATEMENT_ID_REGEX = re.compile(r"^[a-zA-Z0-9-_]+$")
8989

localstack/services/lambda_/provider.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,11 @@ def create_alias(
15131513
routing_config: AliasRoutingConfiguration = None,
15141514
**kwargs,
15151515
) -> AliasConfiguration:
1516+
if not api_utils.qualifier_is_alias(name):
1517+
raise ValidationException(
1518+
f"1 validation error detected: Value '{name}' at 'name' failed to satisfy constraint: Member must satisfy regular expression pattern: (?!^[0-9]+$)([a-zA-Z0-9-_]+)"
1519+
)
1520+
15161521
account_id, region = api_utils.get_account_and_region(function_name, context)
15171522
function_name = api_utils.get_function_name(function_name, context)
15181523
target_version = self._get_function_version(

tests/aws/services/lambda_/test_lambda_api.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,55 @@ def test_notfound_and_invalid_routingconfigs(
16361636
)
16371637
snapshot.match("alias_does_not_exist_esc", e.value.response)
16381638

1639+
@markers.snapshot.skip_snapshot_verify(paths=["$..LoggingConfig"])
1640+
@markers.aws.validated
1641+
def test_alias_naming(self, aws_client, snapshot, create_lambda_function_aws, lambda_su_role):
1642+
"""
1643+
numbers can be included and can even start the alias name, but it can't be purely a number
1644+
"""
1645+
function_name = f"alias-fn-{short_uid()}"
1646+
create_response = create_lambda_function_aws(
1647+
FunctionName=function_name,
1648+
Handler="index.handler",
1649+
Code={
1650+
"ZipFile": create_lambda_archive(
1651+
load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True
1652+
)
1653+
},
1654+
PackageType="Zip",
1655+
Role=lambda_su_role,
1656+
Runtime=Runtime.python3_9,
1657+
Environment={"Variables": {"testenv": "staging"}},
1658+
)
1659+
snapshot.match("create_response", create_response)
1660+
1661+
publish_v1 = aws_client.lambda_.publish_version(FunctionName=function_name)
1662+
snapshot.match("publish_v1", publish_v1)
1663+
1664+
# alias in date format
1665+
alias_name = "2024-01-02"
1666+
create_alias_date = aws_client.lambda_.create_alias(
1667+
FunctionName=function_name,
1668+
Name=alias_name,
1669+
FunctionVersion="1",
1670+
Description="custom-alias",
1671+
)
1672+
snapshot.match("create_alias_date", create_alias_date)
1673+
get_alias_date = aws_client.lambda_.get_alias(FunctionName=function_name, Name=alias_name)
1674+
snapshot.match("get_alias_date", get_alias_date)
1675+
aws_client.lambda_.invoke(FunctionName=f"{function_name}:{alias_name}")
1676+
1677+
# alias as a number should fail
1678+
alias_name_number = "2024"
1679+
with pytest.raises(aws_client.lambda_.exceptions.ClientError) as e:
1680+
aws_client.lambda_.create_alias(
1681+
FunctionName=function_name,
1682+
Name=alias_name_number,
1683+
FunctionVersion="1",
1684+
Description="custom-alias",
1685+
)
1686+
snapshot.match("create_alias_number_exception", e.value.response)
1687+
16391688

16401689
class TestLambdaRevisions:
16411690
@markers.snapshot.skip_snapshot_verify(

tests/aws/services/lambda_/test_lambda_api.snapshot.json

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13630,5 +13630,137 @@
1363013630
}
1363113631
}
1363213632
}
13633+
},
13634+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": {
13635+
"recorded-date": "13-02-2024, 08:44:31",
13636+
"recorded-content": {
13637+
"create_response": {
13638+
"Architectures": [
13639+
"x86_64"
13640+
],
13641+
"CodeSha256": "<code-sha256:1>",
13642+
"CodeSize": "<code-size>",
13643+
"Description": "",
13644+
"Environment": {
13645+
"Variables": {
13646+
"testenv": "staging"
13647+
}
13648+
},
13649+
"EphemeralStorage": {
13650+
"Size": 512
13651+
},
13652+
"FunctionArn": "arn:aws:lambda:<region>:111111111111:function:<function-name:1>",
13653+
"FunctionName": "<function-name:1>",
13654+
"Handler": "index.handler",
13655+
"LastModified": "date",
13656+
"LoggingConfig": {
13657+
"LogFormat": "Text",
13658+
"LogGroup": "/aws/lambda/<function-name:1>"
13659+
},
13660+
"MemorySize": 128,
13661+
"PackageType": "Zip",
13662+
"RevisionId": "<uuid:1>",
13663+
"Role": "arn:aws:iam::111111111111:role/<resource:1>",
13664+
"Runtime": "python3.9",
13665+
"RuntimeVersionConfig": {
13666+
"RuntimeVersionArn": "arn:aws:lambda:<region>::runtime:<resource:2>"
13667+
},
13668+
"SnapStart": {
13669+
"ApplyOn": "None",
13670+
"OptimizationStatus": "Off"
13671+
},
13672+
"State": "Pending",
13673+
"StateReason": "The function is being created.",
13674+
"StateReasonCode": "Creating",
13675+
"Timeout": 3,
13676+
"TracingConfig": {
13677+
"Mode": "PassThrough"
13678+
},
13679+
"Version": "$LATEST",
13680+
"ResponseMetadata": {
13681+
"HTTPHeaders": {},
13682+
"HTTPStatusCode": 201
13683+
}
13684+
},
13685+
"publish_v1": {
13686+
"Architectures": [
13687+
"x86_64"
13688+
],
13689+
"CodeSha256": "<code-sha256:1>",
13690+
"CodeSize": "<code-size>",
13691+
"Description": "",
13692+
"Environment": {
13693+
"Variables": {
13694+
"testenv": "staging"
13695+
}
13696+
},
13697+
"EphemeralStorage": {
13698+
"Size": 512
13699+
},
13700+
"FunctionArn": "arn:aws:lambda:<region>:111111111111:function:<function-name:1>:1",
13701+
"FunctionName": "<function-name:1>",
13702+
"Handler": "index.handler",
13703+
"LastModified": "date",
13704+
"LastUpdateStatus": "Successful",
13705+
"LoggingConfig": {
13706+
"LogFormat": "Text",
13707+
"LogGroup": "/aws/lambda/<function-name:1>"
13708+
},
13709+
"MemorySize": 128,
13710+
"PackageType": "Zip",
13711+
"RevisionId": "<uuid:2>",
13712+
"Role": "arn:aws:iam::111111111111:role/<resource:1>",
13713+
"Runtime": "python3.9",
13714+
"RuntimeVersionConfig": {
13715+
"RuntimeVersionArn": "arn:aws:lambda:<region>::runtime:<resource:2>"
13716+
},
13717+
"SnapStart": {
13718+
"ApplyOn": "None",
13719+
"OptimizationStatus": "Off"
13720+
},
13721+
"State": "Active",
13722+
"Timeout": 3,
13723+
"TracingConfig": {
13724+
"Mode": "PassThrough"
13725+
},
13726+
"Version": "1",
13727+
"ResponseMetadata": {
13728+
"HTTPHeaders": {},
13729+
"HTTPStatusCode": 201
13730+
}
13731+
},
13732+
"create_alias_date": {
13733+
"AliasArn": "arn:aws:lambda:<region>:111111111111:function:<function-name:1>:2024-01-02",
13734+
"Description": "custom-alias",
13735+
"FunctionVersion": "1",
13736+
"Name": "2024-01-02",
13737+
"RevisionId": "<uuid:3>",
13738+
"ResponseMetadata": {
13739+
"HTTPHeaders": {},
13740+
"HTTPStatusCode": 201
13741+
}
13742+
},
13743+
"get_alias_date": {
13744+
"AliasArn": "arn:aws:lambda:<region>:111111111111:function:<function-name:1>:2024-01-02",
13745+
"Description": "custom-alias",
13746+
"FunctionVersion": "1",
13747+
"Name": "2024-01-02",
13748+
"RevisionId": "<uuid:3>",
13749+
"ResponseMetadata": {
13750+
"HTTPHeaders": {},
13751+
"HTTPStatusCode": 200
13752+
}
13753+
},
13754+
"create_alias_number_exception": {
13755+
"Error": {
13756+
"Code": "ValidationException",
13757+
"Message": "1 validation error detected: Value '2024' at 'name' failed to satisfy constraint: Member must satisfy regular expression pattern: (?!^[0-9]+$)([a-zA-Z0-9-_]+)"
13758+
},
13759+
"ResponseMetadata": {
13760+
"HTTPHeaders": {},
13761+
"HTTPStatusCode": 400
13762+
}
13763+
}
13764+
}
1363313765
}
1363413766
}

tests/aws/services/lambda_/test_lambda_api.validation.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": {
1818
"last_validated_date": "2023-11-20T15:57:06+00:00"
1919
},
20+
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": {
21+
"last_validated_date": "2024-02-13T08:47:11+00:00"
22+
},
2023
"tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": {
2124
"last_validated_date": "2023-11-20T15:57:21+00:00"
2225
},

tests/unit/services/lambda_/test_api_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ def test_qualifier_is_version(self):
6060
def test_qualifier_is_alias(self):
6161
assert qualifier_is_alias("abczABCZ")
6262
assert qualifier_is_alias("a01239")
63-
assert not qualifier_is_alias("1numeric")
63+
assert qualifier_is_alias("1numeric")
64+
assert qualifier_is_alias("2024-01-01")
65+
assert not qualifier_is_alias("20240101")
6466
assert not qualifier_is_alias("invalid-with-$-char")
6567
assert not qualifier_is_alias("invalid-with-?-char")

0 commit comments

Comments
 (0)