Skip to content

Commit c0e2823

Browse files
authored
add rule E1041 to validate Ref format (#3914)
* add rule E1041 to validate Ref format * Add function to get cfn path in Template
1 parent c2ccd76 commit c0e2823

File tree

431 files changed

+3305
-510
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

431 files changed

+3305
-510
lines changed

docs/format_keyword.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,22 @@ In `cfn-lint`, we have extended the `format` keyword to support custom formats t
1212

1313
This format ensures that the value is a valid VPC ID, which is a string of the pattern `vpc-[0-9a-f]{8}` or `vpc-[0-9a-f]{17}`.
1414

15-
### AWS::EC2::SecurityGroup.GroupId
15+
### AWS::EC2::SecurityGroup.Id
1616

1717
This format validates that the value is a valid Security Group ID, which is a string of the pattern `sg-[0-9a-f]{8}` or `sg-[0-9a-f]{17}`.
1818

19-
### AWS::EC2::SecurityGroup.GroupName
19+
### AWS::EC2::SecurityGroup.Ids
20+
21+
This format validates that the value is a valid list of Security Group IDs, which is a string of the pattern `sg-[0-9a-f]{8}` or `sg-[0-9a-f]{17}`.
22+
23+
### AWS::EC2::SecurityGroup.Name
2024

2125
This format validates that the value is a valid Security Group Name, which must be a string of 1 to 255 characters, starting with a letter, and containing only letters, numbers, and certain special characters.
2226

2327
### AWS::EC2::Image.Id
2428

2529
This format validates that the value is a valid Amazon Machine Image (AMI), which is a string of the pattern `ami-[0-9a-f]{8}` or `ami-[0-9a-f]{17}`. More info in [docs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/resource-ids.html)
30+
31+
### AWS::Logs::LogGroup.Name
32+
33+
This format validates that the value is a valid log group name, which is a string of the pattern `^[\.\-_\/#A-Za-z0-9]{1,512}\Z`. More info in [docs](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_LogGroup.html)

scripts/update_schemas_format.py

+51-10
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def _create_security_group_ids_patch(type_name: str, ref: str, resolver: RefReso
7676
ref=resolved["$ref"],
7777
resolver=resolver,
7878
)
79+
if resolved.get("type") != "array":
80+
return []
7981
items = resolved.get("items")
8082
if items:
8183
if "$ref" in items:
@@ -89,7 +91,7 @@ def _create_security_group_ids_patch(type_name: str, ref: str, resolver: RefReso
8991
path=ref[1:],
9092
),
9193
_create_patch(
92-
{"format": "AWS::EC2::SecurityGroup.GroupId"},
94+
{"format": "AWS::EC2::SecurityGroup.Id"},
9395
items_path,
9496
resolver=resolver,
9597
),
@@ -110,7 +112,7 @@ def _create_security_group_id(type_name: str, ref: str, resolver: RefResolver):
110112

111113
return [
112114
_create_patch(
113-
{"format": "AWS::EC2::SecurityGroup.GroupId"},
115+
{"format": "AWS::EC2::SecurityGroup.Id"},
114116
ref,
115117
resolver=resolver,
116118
)
@@ -129,7 +131,7 @@ def _create_security_group_name(type_name: str, ref: str, resolver: RefResolver)
129131

130132
return [
131133
_create_patch(
132-
{"format": "AWS::EC2::SecurityGroup.GroupName"},
134+
{"format": "AWS::EC2::SecurityGroup.Name"},
133135
ref,
134136
resolver=resolver,
135137
)
@@ -150,23 +152,32 @@ def _create_patch(value: dict[str, str], ref: Sequence[str], resolver: RefResolv
150152
_manual_patches = {
151153
"AWS::EC2::SecurityGroup": [
152154
Patch(
153-
values={"format": "AWS::EC2::SecurityGroup.GroupId"},
155+
values={"format": "AWS::EC2::SecurityGroup.Id"},
154156
path="/properties/GroupId",
155157
),
156158
Patch(
157-
values={"format": "AWS::EC2::SecurityGroup.GroupName"},
159+
values={"format": "AWS::EC2::SecurityGroup.Name"},
158160
path="/properties/GroupName",
159161
),
162+
Patch(
163+
values={
164+
"anyOf": [
165+
{"format": "AWS::EC2::SecurityGroup.Id"},
166+
{"format": "AWS::EC2::SecurityGroup.Name"},
167+
]
168+
},
169+
path="/properties/Id",
170+
),
160171
],
161172
"AWS::EC2::SecurityGroupIngress": [
162173
Patch(
163-
values={"format": "AWS::EC2::SecurityGroup.GroupId"},
174+
values={"format": "AWS::EC2::SecurityGroup.Id"},
164175
path="/properties/GroupId",
165176
),
166177
],
167178
"AWS::EC2::SecurityGroupEgress": [
168179
Patch(
169-
values={"format": "AWS::EC2::SecurityGroup.GroupId"},
180+
values={"format": "AWS::EC2::SecurityGroup.Id"},
170181
path="/properties/GroupId",
171182
),
172183
],
@@ -231,7 +242,30 @@ def main():
231242
)
232243
)
233244

234-
for path in _descend(obj, ["SecurityGroupIds", "SecurityGroups"]):
245+
for path in _descend(obj, ["LogGroupName"]):
246+
if path[-2] == "properties":
247+
resource_patches.append(
248+
_create_patch(
249+
value={"format": "AWS::Logs::LogGroup.Name"},
250+
ref="#/" + "/".join(path),
251+
resolver=resolver,
252+
)
253+
)
254+
255+
for path in _descend(
256+
obj,
257+
[
258+
"CustomSecurityGroupIds",
259+
"DBSecurityGroups",
260+
"Ec2SecurityGroupIds",
261+
"GroupSet",
262+
"InputSecurityGroups",
263+
"SecurityGroupIdList",
264+
"SecurityGroupIds",
265+
"SecurityGroups",
266+
"VpcSecurityGroupIds",
267+
],
268+
):
235269
if path[-2] == "properties":
236270
resource_patches.extend(
237271
_create_security_group_ids_patch(
@@ -242,11 +276,14 @@ def main():
242276
for path in _descend(
243277
obj,
244278
[
279+
"ClusterSecurityGroupId",
245280
"DefaultSecurityGroup",
246-
"SourceSecurityGroupId",
247281
"DestinationSecurityGroupId",
282+
"EC2SecurityGroupId",
248283
"SecurityGroup",
249284
"SecurityGroupId",
285+
"SecurityGroupIngress" "SourceSecurityGroupId",
286+
"VpcSecurityGroupId",
250287
],
251288
):
252289
if path[-2] == "properties":
@@ -259,7 +296,11 @@ def main():
259296
for path in _descend(
260297
obj,
261298
[
262-
"SourceSecurityGroupName",
299+
"CacheSecurityGroupName",
300+
"ClusterSecurityGroupName",
301+
"DBSecurityGroupName",
302+
"EC2SecurityGroupName",
303+
"SourceSecurityGroupName" "SourceSecurityGroupName",
263304
],
264305
):
265306
if path[-2] == "properties":

scripts/update_snapshot_results.sh

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ cfn-lint test/fixtures/templates/integration/resources-cloudformation-init.yaml
66
cfn-lint test/fixtures/templates/integration/ref-no-value.yaml -e -c I --format json > test/fixtures/results/integration/ref-no-value.json
77
cfn-lint test/fixtures/templates/integration/availability-zones.yaml -e -c I --format json > test/fixtures/results/integration/availability-zones.json
88
cfn-lint test/fixtures/templates/integration/getatt-types.yaml -e -c I --format json > test/fixtures/results/integration/getatt-types.json
9+
cfn-lint test/fixtures/templates/integration/ref-types.yaml -e -c I --format json > test/fixtures/results/integration/ref-types.json
10+
cfn-lint test/fixtures/templates/integration/formats.yaml -e -c I --format json > test/fixtures/results/integration/formats.json
911
cfn-lint test/fixtures/templates/integration/aws-ec2-networkinterface.yaml -e -c I --format json > test/fixtures/results/integration/aws-ec2-networkinterface.json
1012
cfn-lint test/fixtures/templates/integration/aws-ec2-instance.yaml -e -c I --format json > test/fixtures/results/integration/aws-ec2-instance.json
1113
cfn-lint test/fixtures/templates/integration/aws-ec2-launchtemplate.yaml -e -c I --format json > test/fixtures/results/integration/aws-ec2-launchtemplate.json

src/cfnlint/context/context.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def ref_value(self, instance: str) -> Iterator[Tuple[str | list[str], "Context"]
198198
yield pseudo_value, self.evolve(ref_values={instance: pseudo_value})
199199
return
200200
if instance in self.parameters:
201-
for v, path in self.parameters[instance].ref(self):
201+
for v, path in self.parameters[instance].ref_value(self):
202202

203203
# validate that ref is possible with path
204204
# need to evaluate if Fn::If would be not true if value is
@@ -278,7 +278,11 @@ class _Ref(ABC):
278278
"""
279279

280280
@abstractmethod
281-
def ref(self, context: Context) -> Iterator[Any]:
281+
def ref(self, region: str) -> dict[str, Any]:
282+
pass
283+
284+
@abstractmethod
285+
def ref_value(self, context: Context) -> Iterator[Tuple[Any, deque]]:
282286
pass
283287

284288

@@ -351,7 +355,10 @@ def __post_init__(self, parameter) -> None:
351355
if parameter.get("NoEcho") in list(BOOLEAN_STRINGS_TRUE) + [True]:
352356
self.no_echo = True
353357

354-
def ref(self, context: Context) -> Iterator[Tuple[Any, deque]]:
358+
def ref(self, region: str = REGION_PRIMARY) -> dict[str, Any]:
359+
return {}
360+
361+
def ref_value(self, context: Context) -> Iterator[Tuple[Any, deque]]:
355362
if self.allowed_values:
356363
for i, allowed_value in enumerate(self.allowed_values):
357364
if isinstance(allowed_value, list):
@@ -402,10 +409,13 @@ def __post_init__(self, resource) -> None:
402409
raise ValueError("Condition must be a string")
403410
self.condition = c
404411

405-
def get_atts(self, region: str = "us-east-1") -> AttributeDict:
412+
def get_atts(self, region: str = REGION_PRIMARY) -> AttributeDict:
406413
return PROVIDER_SCHEMA_MANAGER.get_type_getatts(self.type, region)
407414

408-
def ref(self, context: Context) -> Iterator[Any]:
415+
def ref(self, region: str = REGION_PRIMARY) -> dict[str, Any]:
416+
return PROVIDER_SCHEMA_MANAGER.get_type_ref(self.type, region)
417+
418+
def ref_value(self, context: Context) -> Iterator[Tuple[Any, deque]]:
409419
return
410420
yield
411421

src/cfnlint/data/schemas/extensions/aws_ecs_taskdefinition/logging_configuration.json

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
"then": {
1515
"properties": {
1616
"Options": {
17+
"properties": {
18+
"awslogs-group": {
19+
"format": "AWS::Logs::LogGroup.Name",
20+
"type": "string"
21+
}
22+
},
1723
"propertyNames": {
1824
"enum": [
1925
"awslogs-create-group",

src/cfnlint/data/schemas/patches/extensions/all/aws_amazonmq_broker/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/properties/SecurityGroups/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

src/cfnlint/data/schemas/patches/extensions/all/aws_apigatewayv2_vpclink/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/properties/SecurityGroupIds/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/definitions/Log/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
},
7+
{
8+
"op": "add",
9+
"path": "/definitions/WindowsEvent/properties/LogGroupName/format",
10+
"value": "AWS::Logs::LogGroup.Name"
11+
}
12+
]

src/cfnlint/data/schemas/patches/extensions/all/aws_apprunner_vpcconnector/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
{
1818
"op": "add",
1919
"path": "/properties/SecurityGroups/items/format",
20-
"value": "AWS::EC2::SecurityGroup.GroupId"
20+
"value": "AWS::EC2::SecurityGroup.Id"
2121
}
2222
]

src/cfnlint/data/schemas/patches/extensions/all/aws_appstream_appblockbuilder/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

src/cfnlint/data/schemas/patches/extensions/all/aws_appstream_fleet/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

src/cfnlint/data/schemas/patches/extensions/all/aws_appstream_imagebuilder/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

src/cfnlint/data/schemas/patches/extensions/all/aws_aps_scraper/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/definitions/SecurityGroupId/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

src/cfnlint/data/schemas/patches/extensions/all/aws_autoscaling_launchconfiguration/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
{
1313
"op": "add",
1414
"path": "/properties/SecurityGroups/items/format",
15-
"value": "AWS::EC2::SecurityGroup.GroupId"
15+
"value": "AWS::EC2::SecurityGroup.Id"
1616
}
1717
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
}
7+
]

src/cfnlint/data/schemas/patches/extensions/all/aws_batch_computeenvironment/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@
2222
{
2323
"op": "add",
2424
"path": "/definitions/ComputeResources/properties/SecurityGroupIds/items/format",
25-
"value": "AWS::EC2::SecurityGroup.GroupId"
25+
"value": "AWS::EC2::SecurityGroup.Id"
2626
}
2727
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/definitions/LoggingConfig/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
}
7+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
}
7+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/definitions/LoggingConfig/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
}
7+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/definitions/LoggingConfig/properties/LogGroupName/format",
5+
"value": "AWS::Logs::LogGroup.Name"
6+
}
7+
]

src/cfnlint/data/schemas/patches/extensions/all/aws_codebuild_fleet/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
{
2828
"op": "add",
2929
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
30-
"value": "AWS::EC2::SecurityGroup.GroupId"
30+
"value": "AWS::EC2::SecurityGroup.Id"
3131
}
3232
]

src/cfnlint/data/schemas/patches/extensions/all/aws_codebuild_project/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@
2222
{
2323
"op": "add",
2424
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
25-
"value": "AWS::EC2::SecurityGroup.GroupId"
25+
"value": "AWS::EC2::SecurityGroup.Id"
2626
}
2727
]

src/cfnlint/data/schemas/patches/extensions/all/aws_comprehend_documentclassifier/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
{
1818
"op": "add",
1919
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
20-
"value": "AWS::EC2::SecurityGroup.GroupId"
20+
"value": "AWS::EC2::SecurityGroup.Id"
2121
}
2222
]

src/cfnlint/data/schemas/patches/extensions/all/aws_comprehend_flywheel/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
{
1818
"op": "add",
1919
"path": "/definitions/VpcConfig/properties/SecurityGroupIds/items/format",
20-
"value": "AWS::EC2::SecurityGroup.GroupId"
20+
"value": "AWS::EC2::SecurityGroup.Id"
2121
}
2222
]

src/cfnlint/data/schemas/patches/extensions/all/aws_dax_cluster/format.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
{
88
"op": "add",
99
"path": "/properties/SecurityGroupIds/items/format",
10-
"value": "AWS::EC2::SecurityGroup.GroupId"
10+
"value": "AWS::EC2::SecurityGroup.Id"
1111
}
1212
]

0 commit comments

Comments
 (0)