Skip to content

Commit 80c5b8f

Browse files
authored
Return resolution errors (#3402)
* Return resolution errors back to functions * Don't skip pseudo parameters in satisfaction * Update testing for validator resolution
1 parent c446ec4 commit 80c5b8f

File tree

4 files changed

+75
-4
lines changed

4 files changed

+75
-4
lines changed

src/cfnlint/conditions/conditions.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from cfnlint.conditions._equals import Equal, EqualParameter
2020
from cfnlint.conditions._errors import UnknownSatisfisfaction
2121
from cfnlint.conditions._utils import get_hash
22-
from cfnlint.helpers import PSEUDOPARAMS
2322

2423
LOGGER = logging.getLogger(__name__)
2524

@@ -371,20 +370,20 @@ def satisfiable(
371370

372371
cnf = self._cnf.copy()
373372
at_least_one_param_found = False
373+
374374
for condition_name, opt in conditions.items():
375375
for c_equals in self._conditions[condition_name].equals:
376376
found_params = {}
377377
for param, value in parameter_values.items():
378-
if param in PSEUDOPARAMS:
379-
continue
380-
381378
ref_hash = get_hash({"Ref": param})
379+
382380
for c_equal_param in c_equals.parameters:
383381
if isinstance(c_equal_param, EqualParameter):
384382
if c_equal_param.satisfiable is False:
385383
raise UnknownSatisfisfaction(
386384
f"Can't resolve satisfaction for {condition_name!r}"
387385
)
386+
388387
if ref_hash in c_equals.parameters:
389388
found_params = {ref_hash: value}
390389

src/cfnlint/jsonschema/validators.py

+2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ def resolve_value(self, instance: Any) -> ResolutionResult:
180180
except UnknownSatisfisfaction as err:
181181
LOGGER.debug(err)
182182
return
183+
else:
184+
yield None, self, r_errs # type: ignore
183185
return
184186

185187
# The return type is a Protocol and we are returning an instance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from collections import deque
7+
from typing import Any
8+
9+
import pytest
10+
11+
from cfnlint.jsonschema._resolvers_cfn import ResolutionResult, Validator
12+
from cfnlint.jsonschema.exceptions import ValidationError
13+
from cfnlint.jsonschema.validators import CfnTemplateValidator
14+
15+
16+
def _resolver(validator: Validator, instance: Any) -> ResolutionResult:
17+
if instance == "fail":
18+
yield None, validator, ValidationError("Foo")
19+
return
20+
21+
yield "foo", validator, None
22+
23+
24+
@pytest.fixture
25+
def validator():
26+
validator = CfnTemplateValidator({})
27+
validator.fn_resolvers = {
28+
"Ref": _resolver,
29+
}
30+
validator.context = validator.context.evolve(functions=["Ref"])
31+
return validator
32+
33+
34+
@pytest.mark.parametrize(
35+
"name,instance,expected",
36+
[
37+
(
38+
"Valid with function",
39+
{"Ref": "fail"},
40+
[(None, ValidationError("Foo", path=deque(["Ref"])))],
41+
),
42+
("Valid string", "foo", [("foo", None)]),
43+
("Valid with function", {"Ref": "pass"}, [("foo", None)]),
44+
],
45+
)
46+
def test_validator_resolver(name, instance, expected, validator):
47+
results = list(validator.resolve_value(instance))
48+
49+
if len(results) > len(expected):
50+
for result, expected_result in zip(results, expected):
51+
assert result[0] == expected_result[0]
52+
assert result[2] == expected_result[1]
53+
else:
54+
for expected_result, result in zip(expected, results):
55+
assert result[0] == expected_result[0]
56+
assert result[2] == expected_result[1]

test/unit/rules/functions/test_find_in_map.py

+14
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ def context(cfn):
147147
),
148148
],
149149
),
150+
(
151+
"Invalid Fn::FindInMap with a bad map key",
152+
{"Fn::FindInMap": ["A", "C", "B"]},
153+
{"type": "string"},
154+
{"transforms": Transforms(["AWS::LanguageExtensions"])},
155+
[ValidationError("Foo")],
156+
[
157+
ValidationError(
158+
"'C' is not one of ['B']",
159+
path=deque(["Fn::FindInMap", 1]),
160+
schema_path=deque([]),
161+
),
162+
],
163+
),
150164
(
151165
"Valid Fn::FindInMap with a Ref to AWS::NoValue",
152166
{

0 commit comments

Comments
 (0)