Skip to content

Commit fdb72d6

Browse files
committed
fix: Allow resource Refs in Update/CreationPolicy
Revert #4641, which added resources={} to the E3016/E3055 validator context. Blanking the resource map to catch a bare intrinsic standing in for the whole policy object also blanked it for nested leaf properties, so a valid Ref to a template resource (e.g. CodeDeployLambdaAliasUpdate.ApplicationName: !Ref MyApp) was rejected with E1020 - a regression since 1.56.0. Validated against live CloudFormation: resource Refs at leaf properties deploy successfully (a real CodeDeploy deployment runs); a bare Ref as the whole policy object is rejected by CFN ("Expected an object") and is a follow-up to re-detect via Ref return-type modeling rather than a blanked resource map. This reverts commit 1a58c98. Fixes #4669
1 parent 162a611 commit fdb72d6

10 files changed

Lines changed: 33 additions & 342 deletions

File tree

src/cfnlint/jsonschema/_keywords.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,36 @@ def additionalProperties(
8383
def allOf(
8484
validator: Validator, allOf: Any, instance: Any, schema: dict[str, Any]
8585
) -> ValidationResult:
86-
# allOf is conjunctive: every subschema must hold and there is no branch to
87-
# select, so an unresolvable intrinsic function creates no ambiguity here
88-
# (unlike anyOf/oneOf/if). Validate each subschema and yield all errors.
8986
validator = validator.evolve(
9087
function_filter=validator.function_filter.evolve(
9188
add_cfn_lint_keyword=False,
9289
),
90+
context=validator.context.evolve(
91+
unresolvable_function_mode=True,
92+
),
9393
)
94+
has_unknown = False
95+
known_errors = []
96+
9497
for index, subschema in enumerate(allOf):
95-
yield from validator.descend(instance, subschema, schema_path=index)
98+
errs = list(validator.descend(instance, subschema, schema_path=index))
99+
100+
if any(getattr(err, "unknown", False) for err in errs):
101+
has_unknown = True
102+
else:
103+
known_errors.extend(errs)
104+
105+
# If we have unknown branches, we can't determine if allOf is satisfied
106+
if has_unknown:
107+
yield ValidationError(
108+
f"Cannot determine allOf for {instance!r}",
109+
unknown=True,
110+
)
111+
return
112+
113+
# Yield all known errors
114+
for err in known_errors:
115+
yield err
96116

97117

98118
def anyOf(

src/cfnlint/rules/functions/Ref.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@
77

88
from typing import Any
99

10-
from cfnlint.helpers import (
11-
PSEUDOPARAMS_MULTIPLE,
12-
PSEUDOPARAMS_SINGLE,
13-
VALID_PARAMETER_TYPES,
14-
VALID_PARAMETER_TYPES_LIST,
15-
)
10+
from cfnlint.helpers import VALID_PARAMETER_TYPES, VALID_PARAMETER_TYPES_LIST
1611
from cfnlint.jsonschema import ValidationError, Validator
1712
from cfnlint.rules.functions._BaseFn import BaseFn, all_types
1813

@@ -73,29 +68,6 @@ def ref(
7368
yield ValidationError(f"{instance!r} is not of type {reprs}")
7469
return
7570

76-
elif value in PSEUDOPARAMS_SINGLE or value in PSEUDOPARAMS_MULTIPLE:
77-
# Pseudo parameters resolve to a known type: the SINGLE set are
78-
# strings, PSEUDOPARAMS_MULTIPLE (AWS::NotificationARNs) is a list.
79-
# Validate that resolved type against the schema, the same way we
80-
# do for named parameters.
81-
schema_types = self.resolve_type(validator, subschema)
82-
if not schema_types:
83-
return
84-
reprs = ", ".join(repr(type) for type in schema_types)
85-
is_list = value in PSEUDOPARAMS_MULTIPLE
86-
87-
if all(
88-
st not in ["string", "boolean", "integer", "number"]
89-
for st in schema_types
90-
):
91-
if not is_list:
92-
yield ValidationError(f"{instance!r} is not of type {reprs}")
93-
return
94-
elif all(st not in ["array"] for st in schema_types):
95-
if is_list:
96-
yield ValidationError(f"{instance!r} is not of type {reprs}")
97-
return
98-
9971
for rule_id in self._all_refs:
10072
rule = self.child_rules.get(rule_id)
10173
if rule:

src/cfnlint/rules/resources/CreationPolicy.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from typing import Any
99

10-
from cfnlint.helpers import FUNCTIONS
1110
from cfnlint.jsonschema import Validator
1211
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema
1312

@@ -85,8 +84,13 @@ def validate(self, validator: Validator, dP: str, instance, schema):
8584

8685
validator = validator.evolve(
8786
context=validator.context.evolve(
88-
functions=list(FUNCTIONS),
89-
resources={},
87+
functions=[
88+
"Fn::Sub",
89+
"Fn::Select",
90+
"Fn::FindInMap",
91+
"Fn::If",
92+
"Ref",
93+
],
9094
strict_types=False,
9195
),
9296
schema=self._get_schema(resource_type),

src/cfnlint/rules/resources/updatepolicy/Configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from typing import Any
77

88
import cfnlint.data.schemas.other.resources
9+
import cfnlint.helpers
910
from cfnlint.helpers import FUNCTIONS
1011
from cfnlint.jsonschema import Validator
1112
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema, SchemaDetails
@@ -35,7 +36,6 @@ def validate(self, validator: Validator, keywords: Any, instance: Any, schema: A
3536
validator = validator.evolve(
3637
context=validator.context.evolve(
3738
functions=list(FUNCTIONS),
38-
resources={},
3939
strict_types=False,
4040
),
4141
schema=self._schema,

test/fixtures/results/integration/creationpolicy_yaml.json

Lines changed: 0 additions & 115 deletions
This file was deleted.

test/fixtures/results/integration/updatepolicy_yaml.json

Lines changed: 0 additions & 30 deletions
This file was deleted.

test/fixtures/templates/integration/creationpolicy.yaml

Lines changed: 0 additions & 40 deletions
This file was deleted.

test/fixtures/templates/integration/updatepolicy.yaml

Lines changed: 0 additions & 56 deletions
This file was deleted.

test/integration/test_integration_templates.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,20 +133,6 @@ class TestQuickStartTemplates(BaseCliTestCase):
133133
),
134134
"exit_code": 0,
135135
},
136-
{
137-
"filename": "test/fixtures/templates/integration/creationpolicy.yaml",
138-
"results_filename": (
139-
"test/fixtures/results/integration/creationpolicy_yaml.json"
140-
),
141-
"exit_code": 2,
142-
},
143-
{
144-
"filename": "test/fixtures/templates/integration/updatepolicy.yaml",
145-
"results_filename": (
146-
"test/fixtures/results/integration/updatepolicy_yaml.json"
147-
),
148-
"exit_code": 2,
149-
},
150136
]
151137

152138
def test_templates(self):

0 commit comments

Comments
 (0)