Skip to content

Commit

Permalink
Validate rate periods in rule E3027 (#3017)
Browse files Browse the repository at this point in the history
  • Loading branch information
kddejong committed Jan 18, 2024
1 parent 2660e6c commit 6c60641
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 23 deletions.
58 changes: 36 additions & 22 deletions src/cfnlint/rules/resources/events/RuleScheduleExpression.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,43 @@ def check_rate(self, value, path):
rate_expression = value[value.find("(") + 1 : value.find(")")]

if not rate_expression:
matches.append(
RuleMatch(path, "Rate value of ScheduleExpression cannot be empty")
)
else:
# Rate format: rate(Value Unit)
items = rate_expression.split(" ")

if len(items) != 2:
message = "Rate expression must contain 2 elements (Value Unit), rate contains {} elements"
matches.append(RuleMatch(path, message.format(len(items))))
else:
# Check the Value
if not items[0].isdigit():
message = "Rate Value ({}) should be of type Integer."
extra_args = {
"actual_type": type(items[0]).__name__,
"expected_type": int.__name__,
}
matches.append(
RuleMatch(path, message.format(items[0]), **extra_args)
)
return [RuleMatch(path, "Rate value of ScheduleExpression cannot be empty")]

# Rate format: rate(Value Unit)
items = rate_expression.split(" ")

if len(items) != 2:
message = "Rate expression must contain 2 elements (Value Unit), rate contains {} elements"
matches.append(RuleMatch(path, message.format(len(items))))
return [RuleMatch(path, message.format(len(items)))]

# Check the Value
if not items[0].isdigit():
message = "Rate Value ({}) should be of type Integer."
extra_args = {
"actual_type": type(items[0]).__name__,
"expected_type": int.__name__,
}
return [RuleMatch(path, message.format(items[0]), **extra_args)]

if float(items[0]) <= 0:
return [
RuleMatch(path, f"Rate Value {items[0]!r} should be greater than 0.")
]

if float(items[0]) <= 1:
valid_periods = ["minute", "hour", "day"]
elif float(items[0]) > 1:
valid_periods = ["minutes", "hours", "days"]
# Check the Unit
if items[1] not in valid_periods:
return [
RuleMatch(
path, f"Rate Unit {items[1]!r} should be one of {valid_periods!r}."
)
]

return matches
return []

def check_cron(self, value, path):
"""Check Cron configuration"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ Resources:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "cron(* 1 * * * *)" # specify the Day-of-month and Day-of-week fields in the same cron expression
MyScheduledRule9:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "rate(1 minutes)" # Value of 1 should be singular. 'minute' not 'minutes'
MyScheduledRule10:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "rate(2 hour)" # Value of 2 should be plural. 'hours' not `hour`
MyScheduledRule11:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "rate(0 hour)" # Value has to be greater than 0
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ def test_file_negative_alias(self):
"""Test failure"""
self.helper_file_negative(
"test/fixtures/templates/bad/resources/events/rule_schedule_expression.yaml",
8,
11,
)

0 comments on commit 6c60641

Please sign in to comment.