| 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 |