Skip to content

Commit aa16b08

Browse files
authored
Bugfix: Allow comments and new lines in custom rules file (#2757)
* 🐛 Add a check for comments and new lines in custom rules In the documentation, comments are allowed to start with `#`. Currently, cfn-lint throws an error of `not in supported operators` which means the comment is being parsed as a custom error. This is now fixed to allow any amount of comments anywhere in the custom rules file. New lines are now allowed just for readability. Currently, cfn-lint throws a traceback error of `UnboundLocalError: cannot access local variable 'operator' where it is not associated with a value` which is not an intuitive error message just for a blank new line. This is now fixed to allow new lines anywhere in the custom rules file. * ✅ Add unit tests for comments and whitespace in custom rules. * ✏️ Update docs for custom rules to allow new lines and comments.
1 parent 431cf4f commit aa16b08

File tree

3 files changed

+78
-69
lines changed

3 files changed

+78
-69
lines changed

docs/custom_rules.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ The template used for each custom rules have been included below. Angle brackets
1313

1414
* The ruleID is auto-generated based on the line number. The E9XXX and W9XXX blocks are allocated towards custom rules.
1515
* As an example, custom rule on line 4 of the rules file which has error level “ERROR” would become E9004
16-
* Comments are supported through the use of the # symbol at the beginning of a line (e.g `#This is a comment`)
16+
* Comments are supported through the use of the # symbol at the beginning of a line (e.g `# This is a comment`)
17+
* New lines are supported throughout the rules file
1718
* The syntax is "quote-flexible" and will support all permutations shown below
1819
```
1920
AWS::EC2::Instance Property EQUALS "Cloud Formation"
@@ -69,6 +70,7 @@ Pre-Requisites: The Custom Error Message requires an error level to be specified
6970
A custom error message can be used to override the existing fallback messages. (e.g `Show me this custom message`)
7071

7172
## Example
73+
7274
This following example shows how a you can create a custom rule.
7375

7476
This rule validates all EC2 instances in a template aren’t using the instance type “p3.2xlarge”.
@@ -84,5 +86,3 @@ AWS::Lambda::Function Environment.Variables.NODE_ENV IS DEFINED
8486
```
8587

8688
To include this rules, include your custom rules text file using the `-z custom_rules.txt` argument when running cfn-lint.
87-
88-

src/cfnlint/rules/custom/__init__.py

+71-65
Original file line numberDiff line numberDiff line change
@@ -42,73 +42,79 @@ def process_sets(raw_value):
4242
return raw_value
4343

4444
line = line.rstrip()
45-
rule_id = lineNumber + 9000
46-
line = line.split(" ", 3)
47-
error_level = "E"
48-
if len(line) == 4:
49-
resourceType = line[0]
50-
prop = line[1]
51-
operator = line[2]
52-
value = None
53-
error_message = None
54-
if "WARN" in line[3]:
55-
error_level = "W"
56-
value, error_message = set_arguments(line[3], "WARN")
57-
elif "ERROR" in line[3]:
58-
error_level = "E"
59-
value, error_message = set_arguments(line[3], "ERROR")
60-
else:
61-
value = process_sets(line[3])
62-
value = get_value(line[3])
45+
# check line is not a comment or empty line
46+
if not line.startswith("#") and line != "":
47+
rule_id = lineNumber + 9000
48+
line = line.split(" ", 3)
49+
error_level = "E"
50+
if len(line) == 4:
51+
resourceType = line[0]
52+
prop = line[1]
53+
operator = line[2]
54+
value = None
55+
error_message = None
56+
if "WARN" in line[3]:
57+
error_level = "W"
58+
value, error_message = set_arguments(line[3], "WARN")
59+
elif "ERROR" in line[3]:
60+
error_level = "E"
61+
value, error_message = set_arguments(line[3], "ERROR")
62+
else:
63+
value = process_sets(line[3])
64+
value = get_value(line[3])
6365

64-
if isinstance(value, str):
65-
value = value.strip().strip('"')
66+
if isinstance(value, str):
67+
value = value.strip().strip('"')
6668

67-
if operator in ["EQUALS", "=="]:
68-
return cfnlint.rules.custom.Operators.CreateEqualsRule(
69-
error_level + str(rule_id), resourceType, prop, value, error_message
70-
)
71-
if operator in ["NOT_EQUALS", "!="]:
72-
return cfnlint.rules.custom.Operators.CreateNotEqualsRule(
73-
error_level + str(rule_id), resourceType, prop, value, error_message
74-
)
75-
if operator == "REGEX_MATCH":
76-
return cfnlint.rules.custom.Operators.CreateRegexMatchRule(
77-
error_level + str(rule_id), resourceType, prop, value, error_message
78-
)
79-
if operator == "IN":
80-
return cfnlint.rules.custom.Operators.CreateInSetRule(
81-
error_level + str(rule_id), resourceType, prop, value, error_message
82-
)
83-
if operator == "NOT_IN":
84-
return cfnlint.rules.custom.Operators.CreateNotInSetRule(
85-
error_level + str(rule_id), resourceType, prop, value, error_message
86-
)
87-
if operator == ">":
88-
return cfnlint.rules.custom.Operators.CreateGreaterRule(
89-
error_level + str(rule_id), resourceType, prop, value, error_message
90-
)
91-
if operator == ">=":
92-
return cfnlint.rules.custom.Operators.CreateGreaterEqualRule(
93-
error_level + str(rule_id), resourceType, prop, value, error_message
94-
)
95-
if operator == "<":
96-
return cfnlint.rules.custom.Operators.CreateLesserRule(
97-
error_level + str(rule_id), resourceType, prop, value, error_message
98-
)
99-
if operator == "<=":
100-
return cfnlint.rules.custom.Operators.CreateLesserEqualRule(
101-
error_level + str(rule_id), resourceType, prop, value, error_message
102-
)
103-
if operator == "IS":
104-
if value in ["DEFINED", "NOT_DEFINED"]:
105-
return cfnlint.rules.custom.Operators.CreateCustomIsDefinedRule(
69+
if operator in ["EQUALS", "=="]:
70+
return cfnlint.rules.custom.Operators.CreateEqualsRule(
71+
error_level + str(rule_id), resourceType, prop, value, error_message
72+
)
73+
if operator in ["NOT_EQUALS", "!="]:
74+
return cfnlint.rules.custom.Operators.CreateNotEqualsRule(
75+
error_level + str(rule_id), resourceType, prop, value, error_message
76+
)
77+
if operator == "REGEX_MATCH":
78+
return cfnlint.rules.custom.Operators.CreateRegexMatchRule(
79+
error_level + str(rule_id), resourceType, prop, value, error_message
80+
)
81+
if operator == "IN":
82+
return cfnlint.rules.custom.Operators.CreateInSetRule(
83+
error_level + str(rule_id), resourceType, prop, value, error_message
84+
)
85+
if operator == "NOT_IN":
86+
return cfnlint.rules.custom.Operators.CreateNotInSetRule(
10687
error_level + str(rule_id), resourceType, prop, value, error_message
10788
)
108-
return cfnlint.rules.custom.Operators.CreateInvalidRule(
109-
"E" + str(rule_id), f"{operator} {value}"
110-
)
89+
if operator == ">":
90+
return cfnlint.rules.custom.Operators.CreateGreaterRule(
91+
error_level + str(rule_id), resourceType, prop, value, error_message
92+
)
93+
if operator == ">=":
94+
return cfnlint.rules.custom.Operators.CreateGreaterEqualRule(
95+
error_level + str(rule_id), resourceType, prop, value, error_message
96+
)
97+
if operator == "<":
98+
return cfnlint.rules.custom.Operators.CreateLesserRule(
99+
error_level + str(rule_id), resourceType, prop, value, error_message
100+
)
101+
if operator == "<=":
102+
return cfnlint.rules.custom.Operators.CreateLesserEqualRule(
103+
error_level + str(rule_id), resourceType, prop, value, error_message
104+
)
105+
if operator == "IS":
106+
if value in ["DEFINED", "NOT_DEFINED"]:
107+
return cfnlint.rules.custom.Operators.CreateCustomIsDefinedRule(
108+
error_level + str(rule_id),
109+
resourceType,
110+
prop,
111+
value,
112+
error_message,
113+
)
114+
return cfnlint.rules.custom.Operators.CreateInvalidRule(
115+
"E" + str(rule_id), f"{operator} {value}"
116+
)
111117

112-
return cfnlint.rules.custom.Operators.CreateInvalidRule(
113-
"E" + str(rule_id), operator
114-
)
118+
return cfnlint.rules.custom.Operators.CreateInvalidRule(
119+
"E" + str(rule_id), operator
120+
)
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#This is a comment to ensure comments in custom rules work
12
AWS::IAM::Role AssumeRolePolicyDocument.Version EQUALS "2012-10-17"
23
AWS::IAM::Role AssumeRolePolicyDocument.Version IN [2012-10-16,2012-10-17,2012-10-18]
34
AWS::IAM::Role AssumeRolePolicyDocument.Version NOT_EQUALS "2012-10-15"
@@ -6,10 +7,12 @@ AWS::IAM::Policy PolicyName EQUALS "root" WARN ABC
67
AWS::IAM::Policy PolicyName IN [2012-10-16,root,2012-10-18] ERROR ABC
78
AWS::IAM::Policy PolicyName NOT_EQUALS "user" WARN ABC
89
AWS::IAM::Policy PolicyName NOT_IN [2012-10-16,2012-11-20,2012-10-18] ERROR ABC
10+
# Adding a comment in the middle of custom rules and new line for readability
11+
912
AWS::EC2::Instance BlockDeviceMappings.Ebs.VolumeSize >= 20 WARN
1013
AWS::EC2::Instance BlockDeviceMappings.Ebs.VolumeSize > 10 ERROR ABC
1114
AWS::EC2::Instance BlockDeviceMappings.Ebs.VolumeSize <= 50 ERROR DEF
1215
AWS::EC2::Instance BlockDeviceMappings.Ebs.VolumeSize < 40 WARN ABC
1316
AWS::CloudFormation::Stack TemplateURL REGEX_MATCH "^https.*$" WARN ABC
1417
AWS::Lambda::Function Environment.Variables.NODE_ENV IS DEFINED
15-
AWS::Lambda::Function Environment.Variables.PRIVATE_KEY IS NOT_DEFINED
18+
AWS::Lambda::Function Environment.Variables.PRIVATE_KEY IS NOT_DEFINED

0 commit comments

Comments
 (0)