From a62ca2a85db3a092faf50bad7d35bf6f555a23a0 Mon Sep 17 00:00:00 2001 From: Kevin DeJong Date: Thu, 11 Jul 2024 11:02:40 -0700 Subject: [PATCH] Convert resolver errors to warnings --- src/cfnlint/rules/functions/FindInMap.py | 4 ++- .../rules/functions/FindInMapResolved.py | 16 +++++++++ src/cfnlint/rules/functions/GetAz.py | 2 +- src/cfnlint/rules/functions/GetAzResolved.py | 16 +++++++++ src/cfnlint/rules/functions/Join.py | 10 +++--- src/cfnlint/rules/functions/JoinResolved.py | 14 ++++++++ src/cfnlint/rules/functions/Ref.py | 6 ++-- src/cfnlint/rules/functions/RefResolved.py | 14 ++++++++ src/cfnlint/rules/functions/Select.py | 2 +- src/cfnlint/rules/functions/SelectResolved.py | 16 +++++++++ src/cfnlint/rules/functions/Split.py | 2 +- src/cfnlint/rules/functions/SplitResolved.py | 16 +++++++++ src/cfnlint/rules/functions/Sub.py | 12 ++++--- src/cfnlint/rules/functions/SubResolved.py | 14 ++++++++ src/cfnlint/rules/functions/ToJsonString.py | 1 + .../rules/functions/ToJsonStringResolved.py | 16 +++++++++ src/cfnlint/rules/functions/_BaseFn.py | 11 +++++- .../results/quickstart/nist_application.json | 36 +++++++++---------- .../quickstart/nist_vpc_management.json | 12 +++---- .../non_strict/nist_application.json | 36 +++++++++---------- test/unit/rules/functions/test_basefn.py | 9 ++++- test/unit/rules/functions/test_select.py | 3 ++ test/unit/rules/functions/test_sub.py | 10 +++--- test/unit/rules/outputs/test_value.py | 7 +++- 24 files changed, 219 insertions(+), 66 deletions(-) create mode 100644 src/cfnlint/rules/functions/FindInMapResolved.py create mode 100644 src/cfnlint/rules/functions/GetAzResolved.py create mode 100644 src/cfnlint/rules/functions/JoinResolved.py create mode 100644 src/cfnlint/rules/functions/RefResolved.py create mode 100644 src/cfnlint/rules/functions/SelectResolved.py create mode 100644 src/cfnlint/rules/functions/SplitResolved.py create mode 100644 src/cfnlint/rules/functions/SubResolved.py create mode 100644 src/cfnlint/rules/functions/ToJsonStringResolved.py diff --git a/src/cfnlint/rules/functions/FindInMap.py b/src/cfnlint/rules/functions/FindInMap.py index 78734f240e..0232d2104f 100644 --- a/src/cfnlint/rules/functions/FindInMap.py +++ b/src/cfnlint/rules/functions/FindInMap.py @@ -21,7 +21,9 @@ class FindInMap(BaseFn): tags = ["functions", "findinmap"] def __init__(self) -> None: - super().__init__("Fn::FindInMap", ("array",) + singular_types) + super().__init__( + "Fn::FindInMap", ("array",) + singular_types, resolved_rule="W1034" + ) def schema(self, validator: Validator, instance: Any) -> dict[str, Any]: scalar_schema = { diff --git a/src/cfnlint/rules/functions/FindInMapResolved.py b/src/cfnlint/rules/functions/FindInMapResolved.py new file mode 100644 index 0000000000..e983d8d0b0 --- /dev/null +++ b/src/cfnlint/rules/functions/FindInMapResolved.py @@ -0,0 +1,16 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class FindInMapResolved(CloudFormationLintRule): + id = "W1034" + shortdesc = "Validate the values that come from a Fn::FindInMap function" + description = ( + "Resolve the Fn::FindInMap and then validate the values against the schema" + ) + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html" + tags = ["functions", "findinmap"] diff --git a/src/cfnlint/rules/functions/GetAz.py b/src/cfnlint/rules/functions/GetAz.py index ebe3d2cb1d..36ece11e06 100644 --- a/src/cfnlint/rules/functions/GetAz.py +++ b/src/cfnlint/rules/functions/GetAz.py @@ -22,7 +22,7 @@ class GetAz(BaseFn): tags = ["functions", "getaz"] def __init__(self) -> None: - super().__init__("Fn::GetAZs", ("array",), ("Ref",)) + super().__init__("Fn::GetAZs", ("array",), ("Ref",), resolved_rule="W1036") self.fn_getazs = self.validate def schema(self, validator: Validator, instance: Any) -> dict[str, Any]: diff --git a/src/cfnlint/rules/functions/GetAzResolved.py b/src/cfnlint/rules/functions/GetAzResolved.py new file mode 100644 index 0000000000..c3b27654a1 --- /dev/null +++ b/src/cfnlint/rules/functions/GetAzResolved.py @@ -0,0 +1,16 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class FindInMapResolved(CloudFormationLintRule): + id = "W1036" + shortdesc = "Validate the values that come from a Fn::GetAZs function" + description = ( + "Resolve the Fn::GetAZs and then validate the values against the schema" + ) + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html" + tags = ["functions", "getazs"] diff --git a/src/cfnlint/rules/functions/Join.py b/src/cfnlint/rules/functions/Join.py index 755e591c64..eba88a4073 100644 --- a/src/cfnlint/rules/functions/Join.py +++ b/src/cfnlint/rules/functions/Join.py @@ -22,10 +22,12 @@ class Join(BaseFn): tags = ["functions", "join"] def __init__(self) -> None: - super().__init__("Fn::Join", ("string",)) - self.child_rules = { - "I1022": None, - } + super().__init__("Fn::Join", ("string",), resolved_rule="W1032") + self.child_rules.update( + { + "I1022": None, + } + ) def schema(self, validator, instance) -> dict[str, Any]: return { diff --git a/src/cfnlint/rules/functions/JoinResolved.py b/src/cfnlint/rules/functions/JoinResolved.py new file mode 100644 index 0000000000..f3fa4eb543 --- /dev/null +++ b/src/cfnlint/rules/functions/JoinResolved.py @@ -0,0 +1,14 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class JoinResolved(CloudFormationLintRule): + id = "W1032" + shortdesc = "Validate the values that come from a Fn::Join function" + description = "Resolve the Fn::Join and then validate the values against the schema" + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-join.html" + tags = ["functions", "join"] diff --git a/src/cfnlint/rules/functions/Ref.py b/src/cfnlint/rules/functions/Ref.py index 75c4a7b203..6f0221d4f8 100644 --- a/src/cfnlint/rules/functions/Ref.py +++ b/src/cfnlint/rules/functions/Ref.py @@ -22,11 +22,11 @@ class Ref(BaseFn): tags = ["functions", "ref"] def __init__(self) -> None: - super().__init__("Ref", all_types) + super().__init__("Ref", all_types, resolved_rule="W1030") self._all_refs = [ "W2010", ] - self.child_rules = dict.fromkeys(self._all_refs) + self.child_rules.update(dict.fromkeys(self._all_refs)) def schema(self, validator, instance) -> dict[str, Any]: return { @@ -94,5 +94,7 @@ def ref(self, validator, subschema, instance, schema): for rule in self.child_rules.values(): if not rule or rule.id in self._all_refs: continue + if not hasattr(rule, "keywords"): + continue if keyword in rule.keywords: yield from rule.validate(validator, keyword, instance, schema) diff --git a/src/cfnlint/rules/functions/RefResolved.py b/src/cfnlint/rules/functions/RefResolved.py new file mode 100644 index 0000000000..63f6f37eca --- /dev/null +++ b/src/cfnlint/rules/functions/RefResolved.py @@ -0,0 +1,14 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class RefResolved(CloudFormationLintRule): + id = "W1030" + shortdesc = "Validate the values that come from a Ref function" + description = "Resolve the Ref and then validate the values against the schema" + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" + tags = ["functions", "ref"] diff --git a/src/cfnlint/rules/functions/Select.py b/src/cfnlint/rules/functions/Select.py index b474a42e56..f5456d7560 100644 --- a/src/cfnlint/rules/functions/Select.py +++ b/src/cfnlint/rules/functions/Select.py @@ -21,7 +21,7 @@ class Select(BaseFn): tags = ["functions", "select"] def __init__(self) -> None: - super().__init__("Fn::Select", all_types) + super().__init__("Fn::Select", all_types, resolved_rule="W1035") self.fn_select = self.validate def schema(self, validator: Validator, instance: Any) -> dict[str, Any]: diff --git a/src/cfnlint/rules/functions/SelectResolved.py b/src/cfnlint/rules/functions/SelectResolved.py new file mode 100644 index 0000000000..274af75088 --- /dev/null +++ b/src/cfnlint/rules/functions/SelectResolved.py @@ -0,0 +1,16 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class SelectResolved(CloudFormationLintRule): + id = "W1035" + shortdesc = "Validate the values that come from a Fn::Select function" + description = ( + "Resolve the Fn::Select and then validate the values against the schema" + ) + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-select.html" + tags = ["functions", "select"] diff --git a/src/cfnlint/rules/functions/Split.py b/src/cfnlint/rules/functions/Split.py index 1267c3708e..fceba8eb9f 100644 --- a/src/cfnlint/rules/functions/Split.py +++ b/src/cfnlint/rules/functions/Split.py @@ -26,7 +26,7 @@ class Split(BaseFn): tags = ["functions", "split"] def __init__(self) -> None: - super().__init__("Fn::Split", ("array",)) + super().__init__("Fn::Split", ("array",), resolved_rule="W1033") def schema(self, validator: Validator, instance: Any) -> dict[str, Any]: return { diff --git a/src/cfnlint/rules/functions/SplitResolved.py b/src/cfnlint/rules/functions/SplitResolved.py new file mode 100644 index 0000000000..a26f59fdca --- /dev/null +++ b/src/cfnlint/rules/functions/SplitResolved.py @@ -0,0 +1,16 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class SplitResolved(CloudFormationLintRule): + id = "W1033" + shortdesc = "Validate the values that come from a Fn::Split function" + description = ( + "Resolve the Fn::Split and then validate the values against the schema" + ) + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-split.html" + tags = ["functions", "split"] diff --git a/src/cfnlint/rules/functions/Sub.py b/src/cfnlint/rules/functions/Sub.py index 9e4c5b708a..b4883d8ab5 100644 --- a/src/cfnlint/rules/functions/Sub.py +++ b/src/cfnlint/rules/functions/Sub.py @@ -25,12 +25,14 @@ class Sub(BaseFn): tags = ["functions", "sub"] def __init__(self) -> None: - super().__init__("Fn::Sub", ("string",)) + super().__init__("Fn::Sub", ("string",), resolved_rule="W1031") self.sub_parameter_types = ["string", "integer", "number", "boolean"] - self.child_rules = { - "W1019": None, - "W1020": None, - } + self.child_rules.update( + { + "W1019": None, + "W1020": None, + } + ) self._functions = [ "Fn::Base64", "Fn::FindInMap", diff --git a/src/cfnlint/rules/functions/SubResolved.py b/src/cfnlint/rules/functions/SubResolved.py new file mode 100644 index 0000000000..ba605c762b --- /dev/null +++ b/src/cfnlint/rules/functions/SubResolved.py @@ -0,0 +1,14 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class SubResolved(CloudFormationLintRule): + id = "W1031" + shortdesc = "Validate the values that come from a Fn::Sub function" + description = "Resolve the Fn::Sub and then validate the values against the schema" + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html" + tags = ["functions", "sub"] diff --git a/src/cfnlint/rules/functions/ToJsonString.py b/src/cfnlint/rules/functions/ToJsonString.py index 50a8c1e179..592e35735b 100644 --- a/src/cfnlint/rules/functions/ToJsonString.py +++ b/src/cfnlint/rules/functions/ToJsonString.py @@ -34,6 +34,7 @@ def __init__(self) -> None: "Fn::Split", "Ref", ), + resolved_rule="W1040", ) def schema(self, validator: Validator, instance: Any) -> dict[str, Any]: diff --git a/src/cfnlint/rules/functions/ToJsonStringResolved.py b/src/cfnlint/rules/functions/ToJsonStringResolved.py new file mode 100644 index 0000000000..9b29e5aa1a --- /dev/null +++ b/src/cfnlint/rules/functions/ToJsonStringResolved.py @@ -0,0 +1,16 @@ +""" +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: MIT-0 +""" + +from cfnlint.rules import CloudFormationLintRule + + +class ToJsonStringResolved(CloudFormationLintRule): + id = "W1040" + shortdesc = "Validate the values that come from a Fn::ToJsonString function" + description = ( + "Resolve the Fn::ToJsonString and then validate the values against the schema" + ) + source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ToJsonString.html" + tags = ["functions", "tojsonstring"] diff --git a/src/cfnlint/rules/functions/_BaseFn.py b/src/cfnlint/rules/functions/_BaseFn.py index 8385045e56..b2edd69fc3 100644 --- a/src/cfnlint/rules/functions/_BaseFn.py +++ b/src/cfnlint/rules/functions/_BaseFn.py @@ -23,11 +23,14 @@ def __init__( name: str = "", types: Tuple[str, ...] | None = None, functions: Tuple[str, ...] | None = None, + resolved_rule: str = "", ) -> None: super().__init__() self.fn = ToPy(name) self.types = types or tuple([]) self.functions = functions or tuple([]) + self.resolved_rule = resolved_rule + self.child_rules[self.resolved_rule] = None def key_value(self, instance: dict[str, Any]) -> Tuple[str, Any]: return list(instance.keys())[0], instance.get(self.fn.name) @@ -60,6 +63,9 @@ def resolve( instance: Any, schema: Any, ) -> ValidationResult: + if not self.resolved_rule: + return + key, _ = self.key_value(instance) validator = validator.evolve( @@ -90,7 +96,10 @@ def resolve( err.message = f"{err.message} when {self.fn.name!r} is resolved" all_errs.append(err) - yield from iter(all_errs) + for err in all_errs: + if self.child_rules[self.resolved_rule]: + err.rule = self.child_rules[self.resolved_rule] + yield err def _resolve_ref(self, validator, schema) -> Any: diff --git a/test/fixtures/results/quickstart/nist_application.json b/test/fixtures/results/quickstart/nist_application.json index 2ebab9530b..f291af9372 100644 --- a/test/fixtures/results/quickstart/nist_application.json +++ b/test/fixtures/results/quickstart/nist_application.json @@ -419,8 +419,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "99444d58-b2c3-aee5-41f9-b2252a17fc41", - "Level": "Error", + "Id": "6ecda82c-9ccf-e772-b940-41eafbc02f6e", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -441,10 +441,10 @@ "Message": "{'Ref': 'pAppAmi'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { @@ -644,8 +644,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "36b41df4-77e9-d1c7-179f-feb9bec8cf8b", - "Level": "Error", + "Id": "300dd743-adad-ad4c-c09d-63fd5e9efcf2", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -666,10 +666,10 @@ "Message": "{'Ref': 'pWebServerAMI'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { @@ -1672,8 +1672,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "2d2c5854-e28f-1351-9543-77260d81770e", - "Level": "Error", + "Id": "ce028b65-d316-4519-8018-ac6ec0477964", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -1694,10 +1694,10 @@ "Message": "{'Ref': 'pWebServerAMI'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { diff --git a/test/fixtures/results/quickstart/nist_vpc_management.json b/test/fixtures/results/quickstart/nist_vpc_management.json index 51a6483f40..f3166597b5 100644 --- a/test/fixtures/results/quickstart/nist_vpc_management.json +++ b/test/fixtures/results/quickstart/nist_vpc_management.json @@ -416,8 +416,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_vpc_management.yaml", - "Id": "52edbc3e-89e3-9de8-2e50-09ed7fad4979", - "Level": "Error", + "Id": "f0f419da-862a-4317-0b95-8af2df6e8ad2", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -438,10 +438,10 @@ "Message": "{'Ref': 'pBastionAmi'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { diff --git a/test/fixtures/results/quickstart/non_strict/nist_application.json b/test/fixtures/results/quickstart/non_strict/nist_application.json index 5fcd812841..d1e295eacd 100644 --- a/test/fixtures/results/quickstart/non_strict/nist_application.json +++ b/test/fixtures/results/quickstart/non_strict/nist_application.json @@ -419,8 +419,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "99444d58-b2c3-aee5-41f9-b2252a17fc41", - "Level": "Error", + "Id": "6ecda82c-9ccf-e772-b940-41eafbc02f6e", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -441,10 +441,10 @@ "Message": "{'Ref': 'pAppAmi'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { @@ -615,8 +615,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "36b41df4-77e9-d1c7-179f-feb9bec8cf8b", - "Level": "Error", + "Id": "300dd743-adad-ad4c-c09d-63fd5e9efcf2", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -637,10 +637,10 @@ "Message": "{'Ref': 'pWebServerAMI'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { @@ -877,8 +877,8 @@ }, { "Filename": "test/fixtures/templates/quickstart/nist_application.yaml", - "Id": "2d2c5854-e28f-1351-9543-77260d81770e", - "Level": "Error", + "Id": "ce028b65-d316-4519-8018-ac6ec0477964", + "Level": "Warning", "Location": { "End": { "ColumnNumber": 12, @@ -899,10 +899,10 @@ "Message": "{'Ref': 'pWebServerAMI'} is not a 'AWS::EC2::Image.Id' when 'Ref' is resolved", "ParentId": null, "Rule": { - "Description": "Check that a AMI id matches a pattern", - "Id": "E1152", - "ShortDescription": "Validate AMI id format", - "Source": "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/format_keyword.md#AWS::EC2::Image.Id" + "Description": "Resolve the Ref and then validate the values against the schema", + "Id": "W1030", + "ShortDescription": "Validate the values that come from a Ref function", + "Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html" } }, { diff --git a/test/unit/rules/functions/test_basefn.py b/test/unit/rules/functions/test_basefn.py index 3cfbdc4783..255b46652a 100644 --- a/test/unit/rules/functions/test_basefn.py +++ b/test/unit/rules/functions/test_basefn.py @@ -8,12 +8,18 @@ import pytest from cfnlint.jsonschema import ValidationError +from cfnlint.rules import CloudFormationLintRule from cfnlint.rules.functions._BaseFn import BaseFn +class _ChildRule(CloudFormationLintRule): + id = "XXXXX" + + @pytest.fixture(scope="module") def rule(): - rule = BaseFn() + rule = BaseFn(resolved_rule="XXXXX") + rule.child_rules["XXXXX"] = _ChildRule() yield rule @@ -46,6 +52,7 @@ def rule(): path=deque(["Fn::Sub"]), validator="", schema_path=deque(["enum"]), + rule=_ChildRule(), ) ], ), diff --git a/test/unit/rules/functions/test_select.py b/test/unit/rules/functions/test_select.py index 129c29531e..88b0d06628 100644 --- a/test/unit/rules/functions/test_select.py +++ b/test/unit/rules/functions/test_select.py @@ -9,11 +9,13 @@ from cfnlint.jsonschema import ValidationError from cfnlint.rules.functions.Select import Select +from cfnlint.rules.functions.SelectResolved import SelectResolved @pytest.fixture(scope="module") def rule(): rule = Select() + rule.child_rules["W1035"] = SelectResolved() yield rule @@ -116,6 +118,7 @@ def template(): path=deque(["Fn::Select"]), schema_path=deque(["type"]), validator="fn_select", + rule=SelectResolved(), ), ], ), diff --git a/test/unit/rules/functions/test_sub.py b/test/unit/rules/functions/test_sub.py index 2499cbbab1..73b1ff9308 100644 --- a/test/unit/rules/functions/test_sub.py +++ b/test/unit/rules/functions/test_sub.py @@ -12,12 +12,14 @@ from cfnlint.rules.functions.GetAtt import GetAtt from cfnlint.rules.functions.Ref import Ref from cfnlint.rules.functions.Sub import Sub +from cfnlint.rules.functions.SubResolved import SubResolved from cfnlint.template import Template @pytest.fixture(scope="module") def rule(): rule = Sub() + rule.child_rules["W1031"] = SubResolved() yield rule @@ -199,12 +201,6 @@ def context(cfn): ), validator="fn_sub", ), - ValidationError( - ("'foo' is not of type 'string' " "when 'Ref' is resolved"), - path=deque(["Fn::Sub"]), - schema_path=deque([]), - validator="fn_sub", - ), ], ), ( @@ -289,12 +285,14 @@ def context(cfn): path=deque(["Fn::Sub"]), schema_path=deque(["const"]), validator="fn_sub", + rule=SubResolved(), ), ValidationError( ("'three' was expected when 'Fn::Sub' is resolved"), path=deque(["Fn::Sub"]), schema_path=deque(["const"]), validator="fn_sub", + rule=SubResolved(), ), ], ), diff --git a/test/unit/rules/outputs/test_value.py b/test/unit/rules/outputs/test_value.py index c3146fde5c..e2739cfec9 100644 --- a/test/unit/rules/outputs/test_value.py +++ b/test/unit/rules/outputs/test_value.py @@ -11,6 +11,7 @@ from cfnlint.rules.functions.Cidr import Cidr from cfnlint.rules.functions.Join import Join from cfnlint.rules.functions.Ref import Ref +from cfnlint.rules.functions.RefResolved import RefResolved from cfnlint.rules.outputs.Value import Value # pylint: disable=E0401 @@ -54,10 +55,13 @@ def template(): @pytest.fixture def validator(cfn): + + ref = Ref() + ref.child_rules["W1030"] = RefResolved() yield CfnTemplateValidator(schema={}).extend( validators={ "fn_join": Join().fn_join, - "ref": Ref().ref, + "ref": ref.ref, "fn_cidr": Cidr().fn_cidr, } )( @@ -173,6 +177,7 @@ def validator(cfn): ["fn_join", "fn_items", "fn_cidr", "fn_items", "ref", "pattern"] ), path=deque(["Value", "Fn::Join", 1, "Fn::Cidr", 0, "Ref"]), + rule=RefResolved(), ) ], ),