Skip to content

Commit 7b8deee

Browse files
kftsehkkddejong
andauthored
fix IS custom op on intrinsic functions (#2673)
Co-authored-by: Kevin DeJong <[email protected]>
1 parent 0ba5447 commit 7b8deee

File tree

5 files changed

+163
-36
lines changed

5 files changed

+163
-36
lines changed

src/cfnlint/rules/custom/Operators.py

+67-13
Original file line numberDiff line numberDiff line change
@@ -127,62 +127,116 @@ def _split_inset_properties(self, property_chain):
127127

128128
return None, []
129129

130-
def _check_value(self, value, path, property_chain, cfn):
130+
def _check_value_defined(self, value, path, property_chain, cfn, **_):
131131
matches = []
132132
child_property, new_property_chain = self._split_inset_properties(
133133
property_chain
134134
)
135-
if self.is_defined and (
136-
value is None or value.get(child_property, None) is None
135+
# Specific for !Ref AWS::NoValue, no callback even for pass_if_null=True
136+
if len(property_chain) == 1 and value == {
137+
child_property: {"Ref": "AWS::NoValue"}
138+
}:
139+
matches.append(
140+
cfnlint.rules.RuleMatch(
141+
path, error_message or f"{path} must be defined"
142+
)
143+
)
144+
return matches
145+
if value is None or (
146+
isinstance(value, dict) and value.get("Ref", None) == "AWS::NoValue"
137147
):
138148
matches.append(
139149
cfnlint.rules.RuleMatch(
140150
path, error_message or f"{path} must be defined"
141151
)
142152
)
153+
return matches
154+
143155
if child_property is not None:
144156
matches.extend(
145157
cfn.check_value(
146158
value,
147159
child_property,
148160
path,
149-
check_value=self._check_value,
161+
check_value=self._check_value_defined,
162+
check_ref=self._check_value_defined,
163+
check_get_att=self._check_value_defined,
164+
check_find_in_map=self._check_value_defined,
165+
check_split=self._check_value_defined,
166+
check_join=self._check_value_defined,
167+
check_import_value=self._check_value_defined,
168+
check_sub=self._check_value_defined,
169+
pass_if_null=True,
150170
property_chain=new_property_chain,
151171
cfn=cfn,
152172
)
153173
)
174+
return matches
175+
176+
def _check_value_not_defined(self, value, path, property_chain, cfn, **_):
177+
matches = []
178+
if value is None:
154179
return matches
155-
if not self.is_defined and value is not None:
180+
if len(property_chain) == 0 and value is not None:
156181
matches.append(
157182
cfnlint.rules.RuleMatch(
158183
path, error_message or f"{path} must not be defined"
159184
)
160185
)
186+
return matches
187+
188+
child_property, new_property_chain = self._split_inset_properties(
189+
property_chain
190+
)
191+
matches.extend(
192+
cfn.check_value(
193+
value,
194+
child_property,
195+
path,
196+
check_value=self._check_value_not_defined,
197+
check_ref=self._check_value_not_defined,
198+
check_get_att=self._check_value_not_defined,
199+
check_find_in_map=self._check_value_not_defined,
200+
check_split=self._check_value_not_defined,
201+
check_join=self._check_value_not_defined,
202+
check_import_value=self._check_value_not_defined,
203+
check_sub=self._check_value_not_defined,
204+
property_chain=new_property_chain,
205+
cfn=cfn,
206+
pass_if_null=True,
207+
)
208+
)
161209
return matches
162210

163211
def match_resource_properties(self, properties, _, path, cfn):
164212
child_property, new_property_chain = self._split_inset_properties(
165213
self.property_chain
166214
)
215+
check_fn = (
216+
self._check_value_defined
217+
if self.is_defined
218+
else self._check_value_not_defined
219+
)
167220
matches = []
168221
# here does nothing when the value is not defined, this is checked separately below
169222
matches.extend(
170223
cfn.check_value(
171224
properties,
172225
child_property,
173226
path,
174-
check_value=self._check_value,
227+
check_value=check_fn,
228+
check_ref=check_fn,
229+
check_get_att=check_fn,
230+
check_find_in_map=check_fn,
231+
check_split=check_fn,
232+
check_join=check_fn,
233+
check_import_value=check_fn,
234+
check_sub=check_fn,
175235
property_chain=new_property_chain,
176236
cfn=cfn,
237+
pass_if_null=True,
177238
)
178239
)
179-
# check child exists separately when checking is_defined
180-
if self.is_defined and properties.get(child_property, None) is None:
181-
matches.append(
182-
cfnlint.rules.RuleMatch(
183-
path, error_message or f"{path} must be defined"
184-
)
185-
)
186240
return matches
187241

188242
return CustomIsDefinedRule(
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,84 @@
1-
---
21
AWSTemplateFormatVersion: "2010-09-09"
32
Description: >
43
Testing for IS DEFINED rule
4+
Parameter:
5+
NodeEnv:
6+
Type: String
57
Resources:
68
LambdaExecutionRole:
7-
Type: AWS::IAM::Role
89
Properties:
910
AssumeRolePolicyDocument:
10-
Version: "2012-10-17"
1111
Statement:
12-
- Effect: Allow
12+
- Action:
13+
- sts:AssumeRole
14+
Effect: Allow
1315
Principal:
1416
Service:
1517
- lambda.amazonaws.com
1618
- ec2.amazonaws.com
17-
Action:
18-
- sts:AssumeRole
19+
Version: "2012-10-17"
1920
Path: "/"
20-
LambdaFunctionTestDefined:
21-
Type: AWS::Lambda::Function
21+
Type: AWS::IAM::Role
22+
LambdaFunctionTestDefinedArray:
2223
Properties:
24+
Code: ./
25+
Environment:
26+
Variables:
27+
NODE_ENV:
28+
- 1
29+
- 2
2330
Handler: index.handler
24-
Role: !GetAtt LambdaExecutionRole.Arn
31+
Role: !GetAtt "LambdaExecutionRole.Arn"
32+
Runtime: nodejs18.x
33+
Type: AWS::Lambda::Function
34+
LambdaFunctionTestDefinedEmpty:
35+
Properties:
36+
Code: ./
2537
Environment:
2638
Variables:
2739
NODE_ENV: ""
40+
Handler: index.handler
41+
Role: !GetAtt "LambdaExecutionRole.Arn"
42+
Runtime: nodejs18.x
43+
Type: AWS::Lambda::Function
44+
LambdaFunctionTestDefinedGetAttr:
45+
Properties:
2846
Code: ./
47+
Environment:
48+
Variables:
49+
NODE_ENV: !GetAtt "LambdaExecutionRole.Arn"
50+
Handler: index.handler
51+
Role: !GetAtt "LambdaExecutionRole.Arn"
2952
Runtime: nodejs18.x
53+
Type: AWS::Lambda::Function
54+
LambdaFunctionTestDefinedObject:
55+
Properties:
56+
Code: ./
57+
Environment:
58+
Variables:
59+
NODE_ENV:
60+
A: 1
61+
Handler: index.handler
62+
Role: !GetAtt "LambdaExecutionRole.Arn"
63+
Runtime: nodejs18.x
64+
Type: AWS::Lambda::Function
65+
LambdaFunctionTestDefinedRef:
66+
Properties:
67+
Code: ./
68+
Environment:
69+
Variables:
70+
NODE_ENV: !Ref 'NodeEnv'
71+
Handler: index.handler
72+
Role: !GetAtt "LambdaExecutionRole.Arn"
73+
Runtime: nodejs18.x
74+
Type: AWS::Lambda::Function
75+
LambdaFunctionTestDefinedValue:
76+
Properties:
77+
Code: ./
78+
Environment:
79+
Variables:
80+
NODE_ENV: value
81+
Handler: index.handler
82+
Role: !GetAtt "LambdaExecutionRole.Arn"
83+
Runtime: nodejs18.x
84+
Type: AWS::Lambda::Function
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,54 @@
1-
---
21
AWSTemplateFormatVersion: "2010-09-09"
32
Description: >
43
Testing for IS NOT_DEFINED rule
54
Resources:
65
LambdaExecutionRole:
7-
Type: AWS::IAM::Role
86
Properties:
97
AssumeRolePolicyDocument:
10-
Version: "2012-10-17"
118
Statement:
12-
- Effect: Allow
9+
- Action:
10+
- sts:AssumeRole
11+
Effect: Allow
1312
Principal:
1413
Service:
1514
- lambda.amazonaws.com
1615
- ec2.amazonaws.com
17-
Action:
18-
- sts:AssumeRole
16+
Version: "2012-10-17"
1917
Path: "/"
20-
LambdaFunctionTestNotDefined1:
21-
Type: AWS::Lambda::Function
18+
Type: AWS::IAM::Role
19+
LambdaFunctionTestNotDefinedFromParent:
2220
Properties:
21+
Code: ./
22+
Environment:
23+
Variables: !GetAtt "LambdaExecutionRole.Arn"
2324
Handler: index.handler
24-
Role: !GetAtt LambdaExecutionRole.Arn
25+
Role: !GetAtt "LambdaExecutionRole.Arn"
26+
Runtime: nodejs18.x
27+
Type: AWS::Lambda::Function
28+
LambdaFunctionTestNotDefinedFromProperties:
29+
Properties:
2530
Code: ./
31+
Handler: index.handler
32+
Role: !GetAtt "LambdaExecutionRole.Arn"
2633
Runtime: nodejs18.x
27-
LambdaFunctionTestNotDefined2:
2834
Type: AWS::Lambda::Function
35+
LambdaFunctionTestNotDefinedRefAWSNoValue:
2936
Properties:
37+
Code: ./
38+
Environment:
39+
Variables:
40+
NODE_ENV: !Ref "AWS::NoValue"
3041
Handler: index.handler
31-
Role: !GetAtt LambdaExecutionRole.Arn
42+
Role: !GetAtt "LambdaExecutionRole.Arn"
43+
Runtime: nodejs18.x
44+
Type: AWS::Lambda::Function
45+
LambdaFunctionTestNotDefinedWithSiblings:
46+
Properties:
47+
Code: ./
3248
Environment:
3349
Variables:
3450
OTHER_VARS: ""
35-
Code: ./
51+
Handler: index.handler
52+
Role: !GetAtt "LambdaExecutionRole.Arn"
3653
Runtime: nodejs18.x
54+
Type: AWS::Lambda::Function

test/unit/rules/custom/test_is_defined.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ def test_file_positive(self):
3232
def test_file_negative(self):
3333
"""Test failure"""
3434
self.helper_file_negative(
35-
"test/fixtures/templates/good/custom/is-not-defined.yaml", 2
35+
"test/fixtures/templates/good/custom/is-not-defined.yaml", 4
3636
)

test/unit/rules/custom/test_is_not_defined.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ def test_file_positive(self):
3232
def test_file_negative(self):
3333
"""Test failure"""
3434
self.helper_file_negative(
35-
"test/fixtures/templates/good/custom/is-defined.yaml", 1
35+
"test/fixtures/templates/good/custom/is-defined.yaml", 6
3636
)

0 commit comments

Comments
 (0)