Skip to content

Commit

Permalink
Convert resolver errors to warnings (#3493)
Browse files Browse the repository at this point in the history
  • Loading branch information
kddejong authored Jul 15, 2024
1 parent b56947d commit 6c99760
Show file tree
Hide file tree
Showing 24 changed files with 219 additions and 60 deletions.
4 changes: 3 additions & 1 deletion src/cfnlint/rules/functions/FindInMap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
16 changes: 16 additions & 0 deletions src/cfnlint/rules/functions/FindInMapResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
2 changes: 1 addition & 1 deletion src/cfnlint/rules/functions/GetAz.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down
16 changes: 16 additions & 0 deletions src/cfnlint/rules/functions/GetAzResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
10 changes: 6 additions & 4 deletions src/cfnlint/rules/functions/Join.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
14 changes: 14 additions & 0 deletions src/cfnlint/rules/functions/JoinResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
6 changes: 4 additions & 2 deletions src/cfnlint/rules/functions/Ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
14 changes: 14 additions & 0 deletions src/cfnlint/rules/functions/RefResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
2 changes: 1 addition & 1 deletion src/cfnlint/rules/functions/Select.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down
16 changes: 16 additions & 0 deletions src/cfnlint/rules/functions/SelectResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
2 changes: 1 addition & 1 deletion src/cfnlint/rules/functions/Split.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
16 changes: 16 additions & 0 deletions src/cfnlint/rules/functions/SplitResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
12 changes: 7 additions & 5 deletions src/cfnlint/rules/functions/Sub.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 14 additions & 0 deletions src/cfnlint/rules/functions/SubResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
1 change: 1 addition & 0 deletions src/cfnlint/rules/functions/ToJsonString.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__(self) -> None:
"Fn::Split",
"Ref",
),
resolved_rule="W1040",
)

def schema(self, validator: Validator, instance: Any) -> dict[str, Any]:
Expand Down
16 changes: 16 additions & 0 deletions src/cfnlint/rules/functions/ToJsonStringResolved.py
Original file line number Diff line number Diff line change
@@ -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"]
11 changes: 10 additions & 1 deletion src/cfnlint/rules/functions/_BaseFn.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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:

Expand Down
36 changes: 18 additions & 18 deletions test/fixtures/results/quickstart/nist_application.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"
}
},
{
Expand Down Expand Up @@ -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,
Expand All @@ -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"
}
},
{
Expand Down Expand Up @@ -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,
Expand All @@ -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"
}
},
{
Expand Down
12 changes: 6 additions & 6 deletions test/fixtures/results/quickstart/nist_vpc_management.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"
}
},
{
Expand Down
Loading

0 comments on commit 6c99760

Please sign in to comment.