14
14
from cfnlint .helpers import AVAILABILITY_ZONES , REGEX_SUB_PARAMETERS
15
15
from cfnlint .jsonschema import ValidationError , Validator
16
16
from cfnlint .jsonschema ._typing import ResolutionResult
17
+ from cfnlint .jsonschema ._utils import equal
17
18
18
19
19
20
def unresolvable (validator : Validator , instance : Any ) -> ResolutionResult :
@@ -39,11 +40,12 @@ def find_in_map(validator: Validator, instance: Any) -> ResolutionResult:
39
40
if len (instance ) not in [3 , 4 ]:
40
41
return
41
42
42
- default_value_found = None
43
+ default_value_found = False
43
44
if len (instance ) == 4 :
44
45
options = instance [3 ]
45
46
if validator .is_type (options , "object" ):
46
47
if "DefaultValue" in options :
48
+ default_value_found = True
47
49
for value , v , _ in validator .resolve_value (options ["DefaultValue" ]):
48
50
yield value , v .evolve (
49
51
context = v .context .evolve (
@@ -52,7 +54,6 @@ def find_in_map(validator: Validator, instance: Any) -> ResolutionResult:
52
54
)
53
55
),
54
56
), None
55
- default_value_found = True
56
57
57
58
if not default_value_found and not validator .context .mappings .maps :
58
59
if validator .context .mappings .is_transform :
@@ -65,54 +66,121 @@ def find_in_map(validator: Validator, instance: Any) -> ResolutionResult:
65
66
path = deque ([0 ]),
66
67
)
67
68
68
- if (
69
- validator .is_type (instance [0 ], "string" )
70
- and (
71
- validator .is_type (instance [1 ], "string" )
72
- or validator .is_type (instance [1 ], "integer" )
73
- )
74
- and validator .is_type (instance [2 ], "string" )
75
- ):
76
- map = validator .context .mappings .maps .get (instance [0 ])
77
- if map is None :
78
- if not default_value_found :
79
- yield None , validator , ValidationError (
80
- (
81
- f"{ instance [0 ]!r} is not one of "
82
- f"{ list (validator .context .mappings .maps .keys ())!r} "
83
- ),
84
- path = deque ([0 ]),
85
- )
86
- return
69
+ mappings = list (validator .context .mappings .maps .keys ())
70
+ results = []
71
+ found_valid_combination = False
72
+ for map_name , map_v , _ in validator .resolve_value (instance [0 ]):
73
+ if not validator .is_type (map_name , "string" ):
74
+ continue
87
75
88
- top_key = map .keys .get (instance [1 ])
89
- if top_key is None :
90
- if map .is_transform :
91
- return
76
+ if all (not (equal (map_name , each )) for each in mappings ):
92
77
if not default_value_found :
93
- yield None , validator , ValidationError (
78
+ results . append (
94
79
(
95
- f"{ instance [1 ]!r} is not one of "
96
- f"{ list (map .keys .keys ())!r} for "
97
- f"mapping { instance [0 ]!r} "
98
- ),
99
- path = deque ([1 ]),
80
+ None ,
81
+ map_v ,
82
+ ValidationError (
83
+ f"{ map_name !r} is not one of { mappings !r} " ,
84
+ path = deque ([0 ]),
85
+ ),
86
+ )
100
87
)
101
- return
88
+ continue
102
89
103
- value = top_key .keys .get (instance [2 ])
104
- if value is None :
105
- if top_key .is_transform :
106
- return
107
- if not default_value_found :
108
- yield value , validator , ValidationError (
109
- (
110
- f"{ instance [2 ]!r} is not one of "
111
- f"{ list (top_key .keys .keys ())!r} for mapping "
112
- f"{ instance [0 ]!r} and key { instance [1 ]!r} "
113
- ),
114
- path = deque ([2 ]),
90
+ if validator .context .mappings .maps [map_name ].is_transform :
91
+ continue
92
+
93
+ for top_level_key , top_v , _ in validator .resolve_value (instance [1 ]):
94
+ if validator .is_type (top_level_key , "integer" ):
95
+ top_level_key = str (top_level_key )
96
+ if not validator .is_type (top_level_key , "string" ):
97
+ continue
98
+
99
+ top_level_keys = list (validator .context .mappings .maps [map_name ].keys .keys ())
100
+ if all (not (equal (top_level_key , each )) for each in top_level_keys ):
101
+ if not default_value_found :
102
+ results .append (
103
+ (
104
+ None ,
105
+ top_v ,
106
+ ValidationError (
107
+ (
108
+ f"{ top_level_key !r} is not one of "
109
+ f"{ top_level_keys !r} for mapping "
110
+ f"{ map_name !r} "
111
+ ),
112
+ path = deque ([1 ]),
113
+ ),
114
+ )
115
+ )
116
+ continue
117
+
118
+ if (
119
+ not top_level_key
120
+ or validator .context .mappings .maps [map_name ]
121
+ .keys [top_level_key ]
122
+ .is_transform
123
+ ):
124
+ continue
125
+
126
+ for second_level_key , second_v , err in validator .resolve_value (instance [2 ]):
127
+ if validator .is_type (second_level_key , "integer" ):
128
+ second_level_key = str (second_level_key )
129
+ if not validator .is_type (second_level_key , "string" ):
130
+ continue
131
+ second_level_keys = list (
132
+ validator .context .mappings .maps [map_name ]
133
+ .keys [top_level_key ]
134
+ .keys .keys ()
115
135
)
136
+ if all (
137
+ not (equal (second_level_key , each )) for each in second_level_keys
138
+ ):
139
+ if not default_value_found :
140
+ results .append (
141
+ (
142
+ None ,
143
+ second_v ,
144
+ ValidationError (
145
+ (
146
+ f"{ second_level_key !r} is not "
147
+ f"one of { second_level_keys !r} "
148
+ f"for mapping { map_name !r} and "
149
+ f"key { top_level_key !r} "
150
+ ),
151
+ path = deque ([2 ]),
152
+ ),
153
+ )
154
+ )
155
+ continue
156
+
157
+ found_valid_combination = True
158
+
159
+ for value in validator .context .mappings .maps [map_name ].find_in_map (
160
+ top_level_key ,
161
+ second_level_key ,
162
+ ):
163
+ yield (
164
+ value ,
165
+ validator .evolve (
166
+ context = validator .context .evolve (
167
+ path = validator .context .path .evolve (
168
+ value_path = deque (
169
+ [
170
+ "Mappings" ,
171
+ map_name ,
172
+ top_level_key ,
173
+ second_level_key ,
174
+ ]
175
+ )
176
+ )
177
+ )
178
+ ),
179
+ None ,
180
+ )
181
+
182
+ if not found_valid_combination :
183
+ yield from iter (results )
116
184
117
185
118
186
def get_azs (validator : Validator , instance : Any ) -> ResolutionResult :
0 commit comments