@@ -13,92 +13,107 @@ class Select(CloudFormationLintRule):
13
13
description = "Making sure the Select function is properly configured"
14
14
source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-select.html"
15
15
tags = ["functions" , "select" ]
16
+ supported_functions = [
17
+ "Fn::FindInMap" ,
18
+ "Fn::GetAtt" ,
19
+ "Fn::GetAZs" ,
20
+ "Fn::If" ,
21
+ "Fn::Split" ,
22
+ "Fn::Cidr" ,
23
+ "Ref" ,
24
+ ]
16
25
17
- def match (self , cfn ):
26
+ def _test_index_obj (self , index_obj , path ):
18
27
matches = []
28
+ if isinstance (index_obj , dict ):
29
+ if len (index_obj ) == 1 :
30
+ for index_key , _ in index_obj .items ():
31
+ if index_key not in [
32
+ "Ref" ,
33
+ "Fn::FindInMap" ,
34
+ "Fn::Select" ,
35
+ ]:
36
+ message = "Select index should be an Integer or a function Ref, Fn::FindInMap, or Fn::Select for {0}"
37
+ matches .append (
38
+ RuleMatch (
39
+ path ,
40
+ message .format ("/" .join (map (str , path ))),
41
+ )
42
+ )
43
+ else :
44
+ message = "Select index should be an Integer or a function Ref, Fn::FindInMap, or Fn::Select for {0}"
45
+ matches .append (
46
+ RuleMatch (
47
+ path ,
48
+ message .format ("/" .join (map (str , path ))),
49
+ )
50
+ )
51
+ elif not isinstance (index_obj , int ):
52
+ try :
53
+ int (index_obj )
54
+ except (ValueError , TypeError ):
55
+ message = "Select index should be an Integer or a function of Ref, Fn::FindInMap, or Fn::Select for {0}"
56
+ matches .append (
57
+ RuleMatch (path , message .format ("/" .join (map (str , path ))))
58
+ )
19
59
20
- select_objs = cfn .search_deep_keys ("Fn::Select" )
21
-
22
- supported_functions = [
23
- "Fn::FindInMap" ,
24
- "Fn::GetAtt" ,
25
- "Fn::GetAZs" ,
26
- "Fn::If" ,
27
- "Fn::Split" ,
28
- "Fn::Cidr" ,
29
- "Ref" ,
30
- ]
60
+ return matches
31
61
32
- for select_obj in select_objs :
33
- select_value_obj = select_obj [- 1 ]
34
- tree = select_obj [:- 1 ]
35
- if isinstance (select_value_obj , list ):
36
- if len (select_value_obj ) == 2 :
37
- index_obj = select_value_obj [0 ]
38
- list_of_objs = select_value_obj [1 ]
39
- if isinstance (index_obj , dict ):
40
- if len (index_obj ) == 1 :
41
- for index_key , _ in index_obj .items ():
42
- if index_key not in [
43
- "Ref" ,
44
- "Fn::FindInMap" ,
45
- "Fn::Select" ,
46
- ]:
47
- message = "Select index should be an Integer or a function Ref or FindInMap for {0}"
48
- matches .append (
49
- RuleMatch (
50
- tree ,
51
- message .format ("/" .join (map (str , tree ))),
52
- )
53
- )
54
- elif not isinstance (index_obj , int ):
55
- try :
56
- int (index_obj )
57
- except ValueError :
58
- message = "Select index should be an Integer or a function of Ref or FindInMap for {0}"
59
- matches .append (
60
- RuleMatch (
61
- tree , message .format ("/" .join (map (str , tree )))
62
- )
63
- )
64
- if isinstance (list_of_objs , dict ):
65
- if len (list_of_objs ) == 1 :
66
- for key , _ in list_of_objs .items ():
67
- if key not in supported_functions :
68
- message = (
69
- "Select should use a supported function of {0}"
70
- )
71
- matches .append (
72
- RuleMatch (
73
- tree ,
74
- message .format (
75
- ", " .join (map (str , supported_functions ))
76
- ),
77
- )
78
- )
79
- else :
80
- message = "Select should use a supported function of {0}"
81
- matches .append (
82
- RuleMatch (
83
- tree ,
84
- message .format (
85
- ", " .join (map (str , supported_functions ))
86
- ),
87
- )
88
- )
89
- elif not isinstance (list_of_objs , list ):
90
- message = "Select should be an array of values for {0}"
62
+ def _test_list_obj (self , list_obj , path ):
63
+ matches = []
64
+ if isinstance (list_obj , dict ):
65
+ if len (list_obj ) == 1 :
66
+ for key , _ in list_obj .items ():
67
+ if key not in self .supported_functions :
68
+ message = "Select should use a supported function of {0}"
91
69
matches .append (
92
- RuleMatch (tree , message .format ("/" .join (map (str , tree ))))
70
+ RuleMatch (
71
+ path ,
72
+ message .format (
73
+ ", " .join (map (str , self .supported_functions ))
74
+ ),
75
+ )
93
76
)
94
- else :
95
- message = "Select should be a list of 2 elements for {0}"
96
- matches .append (
97
- RuleMatch (tree , message .format ("/" .join (map (str , tree ))))
98
- )
99
77
else :
100
- message = "Select should be a list of 2 elements for {0}"
78
+ message = "Select should use a supported function of {0}"
101
79
matches .append (
102
- RuleMatch (tree , message .format ("/" .join (map (str , tree ))))
80
+ RuleMatch (
81
+ path ,
82
+ message .format (", " .join (map (str , self .supported_functions ))),
83
+ )
103
84
)
85
+ elif not isinstance (list_obj , list ):
86
+ message = "Select should be an array of values for {0}"
87
+ matches .append (RuleMatch (path , message .format ("/" .join (map (str , path )))))
88
+
89
+ return matches
90
+
91
+ def _test_select_obj (self , select_obj , path ):
92
+ matches = []
93
+ if not isinstance (select_obj , list ):
94
+ message = "Select should be a list of 2 elements for {0}"
95
+ matches .append (RuleMatch (path , message .format ("/" .join (map (str , path )))))
96
+ return matches
97
+ if len (select_obj ) != 2 :
98
+ message = "Select should be a list of 2 elements for {0}"
99
+ matches .append (RuleMatch (path , message .format ("/" .join (map (str , path )))))
100
+ return matches
101
+
102
+ index_obj = select_obj [0 ]
103
+ list_of_objs = select_obj [1 ]
104
+ matches .extend (self ._test_index_obj (index_obj , path [:] + [0 ]))
105
+ matches .extend (self ._test_list_obj (list_of_objs , path [:] + [1 ]))
106
+
107
+ return matches
108
+
109
+ def match (self , cfn ):
110
+ matches = []
111
+
112
+ select_objs = cfn .search_deep_keys ("Fn::Select" )
113
+
114
+ for select_obj in select_objs :
115
+ select_value_obj = select_obj [- 1 ]
116
+ tree = select_obj [:- 1 ]
117
+ matches .extend (self ._test_select_obj (select_value_obj , tree [:]))
118
+
104
119
return matches
0 commit comments