Skip to content

Commit 1e7161b

Browse files
authored
Return all errors from resolution (#3489)
1 parent 46efe54 commit 1e7161b

File tree

8 files changed

+25
-48
lines changed

8 files changed

+25
-48
lines changed

src/cfnlint/context/context.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ class Context:
153153

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

156+
# is the value a resolved value
157+
is_resolved_value: bool = field(init=True, default=False)
158+
156159
def evolve(self, **kwargs) -> "Context":
157160
"""
158161
Create a new context without merging together attributes

src/cfnlint/jsonschema/validators.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ def resolve_value(self, instance: Any) -> ResolutionResult:
176176
r_validator.context.conditions.status,
177177
r_validator.context.ref_values,
178178
):
179+
r_validator = r_validator.evolve(
180+
context=r_validator.context.evolve(
181+
is_resolved_value=True,
182+
)
183+
)
179184
yield r_value, r_validator, r_errs
180185
except UnknownSatisfisfaction as err:
181186
LOGGER.debug(err)

src/cfnlint/rules/functions/_BaseFn.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ def resolve(
6262
) -> ValidationResult:
6363
key, _ = self.key_value(instance)
6464

65-
return_err: ValidationError | None = None
6665
validator = validator.evolve(
6766
context=validator.context.evolve(
6867
strict_types=False,
6968
),
7069
)
70+
all_errs = []
7171
for value, v, resolve_err in validator.resolve_value(instance):
7272
if resolve_err:
7373
yield resolve_err
@@ -85,16 +85,12 @@ def resolve(
8585
if not errs:
8686
return
8787

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

90-
if return_err:
91-
return_err.message = return_err.message.replace(
92-
f"{value!r}", f"{instance!r}"
93-
)
94-
return_err.message = (
95-
f"{return_err.message} when {self.fn.name!r} is resolved"
96-
)
97-
yield return_err
93+
yield from iter(all_errs)
9894

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

src/cfnlint/rules/resources/properties/Type.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ def type(self, validator, types, instance, schema):
4646
):
4747
return
4848

49-
if self.config.get("strict") or validator.context.strict_types:
49+
if (
50+
self.config.get("strict") or validator.context.strict_types
51+
) and not validator.context.is_resolved_value:
5052
validator = validator.evolve(
5153
context=validator.context.evolve(strict_types=True)
5254
)

test/fixtures/results/public/watchmaker.json

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -929,41 +929,6 @@
929929
"Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html"
930930
}
931931
},
932-
{
933-
"Filename": "test/fixtures/templates/public/watchmaker.json",
934-
"Id": "c686663b-d84c-9054-d89b-e04373ffff7a",
935-
"Level": "Error",
936-
"Location": {
937-
"End": {
938-
"ColumnNumber": 46,
939-
"LineNumber": 1374
940-
},
941-
"Path": [
942-
"Resources",
943-
"WatchmakerInstance",
944-
"Properties",
945-
"BlockDeviceMappings",
946-
1,
947-
"Fn::If",
948-
1,
949-
"Ebs",
950-
"VolumeSize",
951-
"Ref"
952-
],
953-
"Start": {
954-
"ColumnNumber": 41,
955-
"LineNumber": 1374
956-
}
957-
},
958-
"Message": "{'Ref': 'AppVolumeSize'} is not of type 'integer' when 'Ref' is resolved",
959-
"ParentId": null,
960-
"Rule": {
961-
"Description": "Making sure the Ref has a String value (no other functions are supported)",
962-
"Id": "E1020",
963-
"ShortDescription": "Ref validation of value",
964-
"Source": "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html"
965-
}
966-
},
967932
{
968933
"Filename": "test/fixtures/templates/public/watchmaker.json",
969934
"Id": "913a07a4-0962-ced6-de7c-a1e4b678ecc9",

test/unit/module/cfn_yaml/test_yaml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def setUp(self):
2727
},
2828
"generic_bad": {
2929
"filename": "test/fixtures/templates/bad/generic.yaml",
30-
"failures": 27,
30+
"failures": 32,
3131
},
3232
}
3333

test/unit/module/test_rules_collections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def test_fail_run(self):
6969
filename = "test/fixtures/templates/bad/generic.yaml"
7070
template = cfnlint.decode.cfn_yaml.load(filename)
7171
cfn = Template(filename, template, ["us-east-1"])
72-
expected_err_count = 30
72+
expected_err_count = 35
7373
matches = []
7474
matches.extend(self.rules.run(filename, cfn))
7575
assert (

test/unit/rules/functions/test_sub.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ def context(cfn):
290290
schema_path=deque(["const"]),
291291
validator="fn_sub",
292292
),
293+
ValidationError(
294+
("'three' was expected when 'Fn::Sub' is resolved"),
295+
path=deque(["Fn::Sub"]),
296+
schema_path=deque(["const"]),
297+
validator="fn_sub",
298+
),
293299
],
294300
),
295301
],

0 commit comments

Comments
 (0)