Skip to content

Commit

Permalink
Return all errors from resolution (#3489)
Browse files Browse the repository at this point in the history
  • Loading branch information
kddejong authored Jul 11, 2024
1 parent 46efe54 commit 1e7161b
Show file tree
Hide file tree
Showing 8 changed files with 25 additions and 48 deletions.
3 changes: 3 additions & 0 deletions src/cfnlint/context/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ class Context:

transforms: Transforms = field(init=True, default_factory=lambda: Transforms([]))

# is the value a resolved value
is_resolved_value: bool = field(init=True, default=False)

def evolve(self, **kwargs) -> "Context":
"""
Create a new context without merging together attributes
Expand Down
5 changes: 5 additions & 0 deletions src/cfnlint/jsonschema/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ def resolve_value(self, instance: Any) -> ResolutionResult:
r_validator.context.conditions.status,
r_validator.context.ref_values,
):
r_validator = r_validator.evolve(
context=r_validator.context.evolve(
is_resolved_value=True,
)
)
yield r_value, r_validator, r_errs
except UnknownSatisfisfaction as err:
LOGGER.debug(err)
Expand Down
16 changes: 6 additions & 10 deletions src/cfnlint/rules/functions/_BaseFn.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ def resolve(
) -> ValidationResult:
key, _ = self.key_value(instance)

return_err: ValidationError | None = None
validator = validator.evolve(
context=validator.context.evolve(
strict_types=False,
),
)
all_errs = []
for value, v, resolve_err in validator.resolve_value(instance):
if resolve_err:
yield resolve_err
Expand All @@ -85,16 +85,12 @@ def resolve(
if not errs:
return

return_err = errs[0]
for err in errs:
err.message = err.message.replace(f"{value!r}", f"{instance!r}")
err.message = f"{err.message} when {self.fn.name!r} is resolved"
all_errs.append(err)

if return_err:
return_err.message = return_err.message.replace(
f"{value!r}", f"{instance!r}"
)
return_err.message = (
f"{return_err.message} when {self.fn.name!r} is resolved"
)
yield return_err
yield from iter(all_errs)

def _resolve_ref(self, validator, schema) -> Any:

Expand Down
4 changes: 3 additions & 1 deletion src/cfnlint/rules/resources/properties/Type.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def type(self, validator, types, instance, schema):
):
return

if self.config.get("strict") or validator.context.strict_types:
if (
self.config.get("strict") or validator.context.strict_types
) and not validator.context.is_resolved_value:
validator = validator.evolve(
context=validator.context.evolve(strict_types=True)
)
Expand Down
35 changes: 0 additions & 35 deletions test/fixtures/results/public/watchmaker.json
Original file line number Diff line number Diff line change
Expand Up @@ -929,41 +929,6 @@
"Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html"
}
},
{
"Filename": "test/fixtures/templates/public/watchmaker.json",
"Id": "c686663b-d84c-9054-d89b-e04373ffff7a",
"Level": "Error",
"Location": {
"End": {
"ColumnNumber": 46,
"LineNumber": 1374
},
"Path": [
"Resources",
"WatchmakerInstance",
"Properties",
"BlockDeviceMappings",
1,
"Fn::If",
1,
"Ebs",
"VolumeSize",
"Ref"
],
"Start": {
"ColumnNumber": 41,
"LineNumber": 1374
}
},
"Message": "{'Ref': 'AppVolumeSize'} is not of type 'integer' when 'Ref' is resolved",
"ParentId": null,
"Rule": {
"Description": "Making sure the Ref has a String value (no other functions are supported)",
"Id": "E1020",
"ShortDescription": "Ref validation of value",
"Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html"
}
},
{
"Filename": "test/fixtures/templates/public/watchmaker.json",
"Id": "913a07a4-0962-ced6-de7c-a1e4b678ecc9",
Expand Down
2 changes: 1 addition & 1 deletion test/unit/module/cfn_yaml/test_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def setUp(self):
},
"generic_bad": {
"filename": "test/fixtures/templates/bad/generic.yaml",
"failures": 27,
"failures": 32,
},
}

Expand Down
2 changes: 1 addition & 1 deletion test/unit/module/test_rules_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_fail_run(self):
filename = "test/fixtures/templates/bad/generic.yaml"
template = cfnlint.decode.cfn_yaml.load(filename)
cfn = Template(filename, template, ["us-east-1"])
expected_err_count = 30
expected_err_count = 35
matches = []
matches.extend(self.rules.run(filename, cfn))
assert (
Expand Down
6 changes: 6 additions & 0 deletions test/unit/rules/functions/test_sub.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ def context(cfn):
schema_path=deque(["const"]),
validator="fn_sub",
),
ValidationError(
("'three' was expected when 'Fn::Sub' is resolved"),
path=deque(["Fn::Sub"]),
schema_path=deque(["const"]),
validator="fn_sub",
),
],
),
],
Expand Down

0 comments on commit 1e7161b

Please sign in to comment.