OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 ''' | 6 ''' |
7 Checks a policy_templates.json file for conformity to its syntax specification. | 7 Checks a policy_templates.json file for conformity to its syntax specification. |
8 ''' | 8 ''' |
9 | 9 |
10 import json | 10 import json |
(...skipping 10 matching lines...) Expand all Loading... |
21 | 21 |
22 # Convert a 'type' to its corresponding schema type. | 22 # Convert a 'type' to its corresponding schema type. |
23 TYPE_TO_SCHEMA = { | 23 TYPE_TO_SCHEMA = { |
24 'int': 'integer', | 24 'int': 'integer', |
25 'list': 'array', | 25 'list': 'array', |
26 'dict': 'object', | 26 'dict': 'object', |
27 'main': 'boolean', | 27 'main': 'boolean', |
28 'string': 'string', | 28 'string': 'string', |
29 'int-enum': 'integer', | 29 'int-enum': 'integer', |
30 'string-enum': 'string', | 30 'string-enum': 'string', |
| 31 'external': 'object', |
31 } | 32 } |
32 | 33 |
33 # List of boolean policies that have been introduced with negative polarity in | 34 # List of boolean policies that have been introduced with negative polarity in |
34 # the past and should not trigger the negative polarity check. | 35 # the past and should not trigger the negative polarity check. |
35 LEGACY_INVERTED_POLARITY_WHITELIST = [ | 36 LEGACY_INVERTED_POLARITY_WHITELIST = [ |
36 'DeveloperToolsDisabled', | 37 'DeveloperToolsDisabled', |
37 'DeviceAutoUpdateDisabled', | 38 'DeviceAutoUpdateDisabled', |
38 'Disable3DAPIs', | 39 'Disable3DAPIs', |
39 'DisableAuthNegotiateCnameLookup', | 40 'DisableAuthNegotiateCnameLookup', |
40 'DisablePluginFinder', | 41 'DisablePluginFinder', |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 def _CheckPolicy(self, policy, is_in_group, policy_ids): | 167 def _CheckPolicy(self, policy, is_in_group, policy_ids): |
167 if not isinstance(policy, dict): | 168 if not isinstance(policy, dict): |
168 self._Error('Each policy must be a dictionary.', 'policy', None, policy) | 169 self._Error('Each policy must be a dictionary.', 'policy', None, policy) |
169 return | 170 return |
170 | 171 |
171 # There should not be any unknown keys in |policy|. | 172 # There should not be any unknown keys in |policy|. |
172 for key in policy: | 173 for key in policy: |
173 if key not in ('name', 'type', 'caption', 'desc', 'device_only', | 174 if key not in ('name', 'type', 'caption', 'desc', 'device_only', |
174 'supported_on', 'label', 'policies', 'items', | 175 'supported_on', 'label', 'policies', 'items', |
175 'example_value', 'features', 'deprecated', 'future', | 176 'example_value', 'features', 'deprecated', 'future', |
176 'id', 'schema'): | 177 'id', 'schema', 'max_size'): |
177 self.warning_count += 1 | 178 self.warning_count += 1 |
178 print ('In policy %s: Warning: Unknown key: %s' % | 179 print ('In policy %s: Warning: Unknown key: %s' % |
179 (policy.get('name'), key)) | 180 (policy.get('name'), key)) |
180 | 181 |
181 # Each policy must have a name. | 182 # Each policy must have a name. |
182 self._CheckContains(policy, 'name', str, regexp_check=NO_WHITESPACE) | 183 self._CheckContains(policy, 'name', str, regexp_check=NO_WHITESPACE) |
183 | 184 |
184 # Each policy must have a type. | 185 # Each policy must have a type. |
| 186 policy_types = ('group', 'main', 'string', 'int', 'list', 'int-enum', |
| 187 'string-enum', 'dict', 'external') |
185 policy_type = self._CheckContains(policy, 'type', str) | 188 policy_type = self._CheckContains(policy, 'type', str) |
186 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', | 189 if policy_type not in policy_types: |
187 'string-enum', 'dict'): | 190 self._Error('Policy type must be one of: ' + ', '.join(policy_types), |
188 self._Error('Policy type must be either of: group, main, string, int, ' | 191 'policy', policy.get('name'), policy_type) |
189 'list, int-enum, string-enum, dict', | |
190 'policy', policy, policy_type) | |
191 return # Can't continue for unsupported type. | 192 return # Can't continue for unsupported type. |
192 | 193 |
193 # Each policy must have a caption message. | 194 # Each policy must have a caption message. |
194 self._CheckContains(policy, 'caption', str) | 195 self._CheckContains(policy, 'caption', str) |
195 | 196 |
196 # Each policy must have a description message. | 197 # Each policy must have a description message. |
197 self._CheckContains(policy, 'desc', str) | 198 self._CheckContains(policy, 'desc', str) |
198 | 199 |
199 # If 'label' is present, it must be a string. | 200 # If 'label' is present, it must be a string. |
200 self._CheckContains(policy, 'label', str, True) | 201 self._CheckContains(policy, 'label', str, True) |
201 | 202 |
202 # If 'deprecated' is present, it must be a bool. | 203 # If 'deprecated' is present, it must be a bool. |
203 self._CheckContains(policy, 'deprecated', bool, True) | 204 self._CheckContains(policy, 'deprecated', bool, True) |
204 | 205 |
205 # If 'future' is present, it must be a bool. | 206 # If 'future' is present, it must be a bool. |
206 self._CheckContains(policy, 'future', bool, True) | 207 self._CheckContains(policy, 'future', bool, True) |
207 | 208 |
208 if policy_type == 'group': | 209 if policy_type == 'group': |
209 | |
210 # Groups must not be nested. | 210 # Groups must not be nested. |
211 if is_in_group: | 211 if is_in_group: |
212 self._Error('Policy groups must not be nested.', 'policy', policy) | 212 self._Error('Policy groups must not be nested.', 'policy', policy) |
213 | 213 |
214 # Each policy group must have a list of policies. | 214 # Each policy group must have a list of policies. |
215 policies = self._CheckContains(policy, 'policies', list) | 215 policies = self._CheckContains(policy, 'policies', list) |
216 | 216 |
217 # Check sub-policies. | 217 # Check sub-policies. |
218 if policies is not None: | 218 if policies is not None: |
219 for nested_policy in policies: | 219 for nested_policy in policies: |
220 self._CheckPolicy(nested_policy, True, policy_ids) | 220 self._CheckPolicy(nested_policy, True, policy_ids) |
221 | 221 |
222 # Groups must not have an |id|. | 222 # Groups must not have an |id|. |
223 if 'id' in policy: | 223 if 'id' in policy: |
224 self._Error('Policies of type "group" must not have an "id" field.', | 224 self._Error('Policies of type "group" must not have an "id" field.', |
225 'policy', policy) | 225 'policy', policy) |
226 | 226 |
227 # Statistics. | 227 # Statistics. |
228 self.num_groups += 1 | 228 self.num_groups += 1 |
| 229 |
229 else: # policy_type != group | 230 else: # policy_type != group |
230 | |
231 # Each policy must have a protobuf ID. | 231 # Each policy must have a protobuf ID. |
232 id = self._CheckContains(policy, 'id', int) | 232 id = self._CheckContains(policy, 'id', int) |
233 self._AddPolicyID(id, policy_ids, policy) | 233 self._AddPolicyID(id, policy_ids, policy) |
234 | 234 |
235 # 'schema' is the new 'type'. | 235 # 'schema' is the new 'type'. |
236 # TODO(joaodasilva): remove the 'type' checks once 'schema' is used | 236 # TODO(joaodasilva): remove the 'type' checks once 'schema' is used |
237 # everywhere. | 237 # everywhere. |
238 self._CheckPolicySchema(policy, policy_type) | 238 self._CheckPolicySchema(policy, policy_type) |
239 | 239 |
240 # Each policy must have a supported_on list. | 240 # Each policy must have a supported_on list. |
(...skipping 30 matching lines...) Expand all Loading... |
271 | 271 |
272 # Each policy must have an 'example_value' of appropriate type. | 272 # Each policy must have an 'example_value' of appropriate type. |
273 if policy_type == 'main': | 273 if policy_type == 'main': |
274 value_type = bool | 274 value_type = bool |
275 elif policy_type in ('string', 'string-enum'): | 275 elif policy_type in ('string', 'string-enum'): |
276 value_type = str | 276 value_type = str |
277 elif policy_type in ('int', 'int-enum'): | 277 elif policy_type in ('int', 'int-enum'): |
278 value_type = int | 278 value_type = int |
279 elif policy_type == 'list': | 279 elif policy_type == 'list': |
280 value_type = list | 280 value_type = list |
281 elif policy_type == 'dict': | 281 elif policy_type in ('dict', 'external'): |
282 value_type = dict | 282 value_type = dict |
283 else: | 283 else: |
284 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) | 284 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) |
285 self._CheckContains(policy, 'example_value', value_type) | 285 self._CheckContains(policy, 'example_value', value_type) |
286 | 286 |
287 # Statistics. | 287 # Statistics. |
288 self.num_policies += 1 | 288 self.num_policies += 1 |
289 if is_in_group: | 289 if is_in_group: |
290 self.num_policies_in_groups += 1 | 290 self.num_policies_in_groups += 1 |
291 | 291 |
292 if policy_type in ('int-enum', 'string-enum'): | 292 if policy_type in ('int-enum', 'string-enum'): |
293 | |
294 # Enums must contain a list of items. | 293 # Enums must contain a list of items. |
295 items = self._CheckContains(policy, 'items', list) | 294 items = self._CheckContains(policy, 'items', list) |
296 if items is not None: | 295 if items is not None: |
297 if len(items) < 1: | 296 if len(items) < 1: |
298 self._Error('"items" must not be empty.', 'policy', policy, items) | 297 self._Error('"items" must not be empty.', 'policy', policy, items) |
299 for item in items: | 298 for item in items: |
300 # Each item must have a name. | 299 # Each item must have a name. |
301 # Note: |policy.get('name')| is used instead of |policy['name']| | 300 # Note: |policy.get('name')| is used instead of |policy['name']| |
302 # because it returns None rather than failing when no key called | 301 # because it returns None rather than failing when no key called |
303 # 'name' exists. | 302 # 'name' exists. |
304 self._CheckContains(item, 'name', str, container_name='item', | 303 self._CheckContains(item, 'name', str, container_name='item', |
305 identifier=policy.get('name'), | 304 identifier=policy.get('name'), |
306 regexp_check=NO_WHITESPACE) | 305 regexp_check=NO_WHITESPACE) |
307 | 306 |
308 # Each item must have a value of the correct type. | 307 # Each item must have a value of the correct type. |
309 self._CheckContains(item, 'value', value_type, container_name='item', | 308 self._CheckContains(item, 'value', value_type, container_name='item', |
310 identifier=policy.get('name')) | 309 identifier=policy.get('name')) |
311 | 310 |
312 # Each item must have a caption. | 311 # Each item must have a caption. |
313 self._CheckContains(item, 'caption', str, container_name='item', | 312 self._CheckContains(item, 'caption', str, container_name='item', |
314 identifier=policy.get('name')) | 313 identifier=policy.get('name')) |
315 | 314 |
| 315 if policy_type == 'external': |
| 316 # Each policy referencing external data must specify a maximum data size. |
| 317 self._CheckContains(policy, 'max_size', int) |
| 318 |
316 def _CheckMessage(self, key, value): | 319 def _CheckMessage(self, key, value): |
317 # |key| must be a string, |value| a dict. | 320 # |key| must be a string, |value| a dict. |
318 if not isinstance(key, str): | 321 if not isinstance(key, str): |
319 self._Error('Each message key must be a string.', 'message', key, key) | 322 self._Error('Each message key must be a string.', 'message', key, key) |
320 return | 323 return |
321 | 324 |
322 if not isinstance(value, dict): | 325 if not isinstance(value, dict): |
323 self._Error('Each message must be a dictionary.', 'message', key, value) | 326 self._Error('Each message must be a dictionary.', 'message', key, value) |
324 return | 327 return |
325 | 328 |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 if filename is None: | 492 if filename is None: |
490 if len(args) != 2: | 493 if len(args) != 2: |
491 parser.print_help() | 494 parser.print_help() |
492 sys.exit(1) | 495 sys.exit(1) |
493 filename = args[1] | 496 filename = args[1] |
494 return self.Main(filename, options) | 497 return self.Main(filename, options) |
495 | 498 |
496 | 499 |
497 if __name__ == '__main__': | 500 if __name__ == '__main__': |
498 sys.exit(PolicyTemplateChecker().Run(sys.argv)) | 501 sys.exit(PolicyTemplateChecker().Run(sys.argv)) |
OLD | NEW |