forked from aws-cloudformation/cfn-lint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNumberSize.py
127 lines (110 loc) · 4.61 KB
/
NumberSize.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""
from cfnlint.rules import CloudFormationLintRule
from cfnlint.rules import RuleMatch
from cfnlint.helpers import RESOURCE_SPECS
class NumberSize(CloudFormationLintRule):
"""Check if a Number has a length within the limit"""
id = 'E3034'
shortdesc = 'Check if a number is between min and max'
description = 'Check numbers (integers and floats) for its value being between the minimum and maximum'
source_url = 'https://github.com/awslabs/cfn-python-lint/blob/main/docs/cfn-resource-specification.md#allowedpattern'
tags = ['resources', 'property', 'number', 'size']
def initialize(self, cfn):
"""Initialize the rule"""
for resource_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get(
'ResourceTypes'
):
self.resource_property_types.append(resource_type_spec)
for property_type_spec in RESOURCE_SPECS.get(cfn.regions[0]).get(
'PropertyTypes'
):
self.resource_sub_property_types.append(property_type_spec)
def _check_number_value(self, value, path, **kwargs):
"""Check if the value is in the given ranges"""
matches = []
number_min = kwargs.get('number_min')
number_max = kwargs.get('number_max')
number_types = (
float,
int,
)
if isinstance(value, str):
try:
value = float(value)
except ValueError:
message = 'Value has to be between {0} and {1} at {2}'
matches.append(
RuleMatch(
path,
message.format(
number_min, number_max, '/'.join(map(str, path))
),
)
)
if isinstance(value, number_types):
if not number_min <= value <= number_max:
message = 'Value has to be between {0} and {1} at {2}'
matches.append(
RuleMatch(
path,
message.format(
number_min, number_max, '/'.join(map(str, path))
),
)
)
return matches
def check(self, cfn, properties, specs, path):
"""Check itself"""
matches = []
for p_value, p_path in properties.items_safe(path[:]):
for prop in p_value:
if prop in specs:
value_type = specs.get(prop).get('Value', {}).get('ValueType', '')
if value_type:
property_type = specs.get(prop).get('PrimitiveType')
value_specs = (
RESOURCE_SPECS.get(cfn.regions[0])
.get('ValueTypes')
.get(value_type, {})
)
if (
value_specs.get('NumberMax') is not None
and value_specs.get('NumberMin') is not None
):
if property_type in ['Integer', 'Double', 'Long', 'String']:
matches.extend(
cfn.check_value(
properties,
prop,
p_path,
check_value=self._check_number_value,
number_max=value_specs.get('NumberMax'),
number_min=value_specs.get('NumberMin'),
)
)
return matches
def match_resource_sub_properties(self, properties, property_type, path, cfn):
"""Match for sub properties"""
matches = []
specs = (
RESOURCE_SPECS.get(cfn.regions[0])
.get('PropertyTypes')
.get(property_type, {})
.get('Properties', {})
)
matches.extend(self.check(cfn, properties, specs, path))
return matches
def match_resource_properties(self, properties, resource_type, path, cfn):
"""Check CloudFormation Properties"""
matches = []
specs = (
RESOURCE_SPECS.get(cfn.regions[0])
.get('ResourceTypes')
.get(resource_type, {})
.get('Properties', {})
)
matches.extend(self.check(cfn, properties, specs, path))
return matches