Skip to content

Commit 44e015c

Browse files
authored
Allow for Fn::Transform with other properties (#4137)
* Allow for Fn::Transform with other properties
1 parent bd0c0ce commit 44e015c

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

src/cfnlint/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
FUNCTION_VALUE_OF = "Fn::ValueOf"
204204
FUNCTION_VALUE_OF_ALL = "Fn::ValueOfAll"
205205
FUNCTION_FOR_EACH = re.compile(r"^Fn::ForEach::[a-zA-Z0-9]+$")
206+
FUNCTION_TRANSFORM = "Fn::Transform"
206207

207208
FUNCTION_CONDITIONS = frozenset(
208209
[FUNCTION_AND, FUNCTION_OR, FUNCTION_NOT, FUNCTION_EQUALS]

src/cfnlint/jsonschema/_keywords_cfn.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,49 @@
2020

2121
from typing import Any
2222

23+
import regex as re
24+
2325
import cfnlint.jsonschema._keywords as validators_standard
24-
from cfnlint.helpers import BOOLEAN_STRINGS, ensure_list, is_function
26+
from cfnlint.helpers import (
27+
BOOLEAN_STRINGS,
28+
FUNCTION_FOR_EACH,
29+
FUNCTION_TRANSFORM,
30+
ensure_list,
31+
is_function,
32+
)
2533
from cfnlint.jsonschema import ValidationError, Validator
2634
from cfnlint.jsonschema._typing import V, ValidationResult
2735

36+
_ap_exception_fns = set([FUNCTION_TRANSFORM, FUNCTION_FOR_EACH])
37+
2838

2939
def additionalProperties(
3040
validator: Validator, aP: Any, instance: Any, schema: Any
3141
) -> ValidationResult:
42+
# is function will just return if one item is present
43+
# as this is the standard. We will handle exceptions below
3244
k, _ = is_function(instance)
3345
if k in validator.context.functions:
3446
return
3547
for err in validators_standard.additionalProperties(
3648
validator, aP, instance, schema
3749
):
38-
yield err
50+
# Some functions can exist at the same level
51+
# so we need to validate that if those functions are
52+
# currently supported by the context and are part of the
53+
# error
54+
55+
# if the path is 0 just yield the error and return
56+
# this should never happen
57+
if not len(err.path) > 0: # pragma: no cover
58+
yield err # pragma: no cover
59+
return # pragma: no cover
60+
61+
for fn in list(_ap_exception_fns & set(validator.context.functions)):
62+
if re.fullmatch(fn, str(err.path[0])): # type: ignore
63+
break
64+
else:
65+
yield err
3966

4067

4168
def cfnContext(

test/unit/module/jsonschema/test_keywords_cfn.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,13 @@ def resolve(self, ref):
190190
)
191191
],
192192
),
193+
# Test case where function matches and should be allowed
194+
(
195+
{"Foo": True, "Fn::Transform": {}},
196+
{"additionalProperties": False, "properties": {"Foo": {}}},
197+
["Fn::Transform"],
198+
[],
199+
),
193200
# Test with empty instance
194201
(
195202
{},

0 commit comments

Comments
 (0)