11#!/usr/bin/python
22# -*- coding: utf-8 -*-
3- """This hook checks Jamf JSON schemas for inconsistencies and common issues."""
3+ """This hook checks Jamf JSON schema custom app manifests for inconsistencies and common issues."""
44
55# References:
6- # - https://developer.apple.com/library/archive/documentation/MacOSXServer/Conceptual/Preference_schema_Files/Preface/Preface.html
7- # - https://github.com/ProfileCreator/Profileschemas/wiki/schema-Format
8- # - https://mosen.github.io/profiledocs/schema.html
6+ # - https://docs.jamf.com/technical-papers/jamf-pro/json-schema/10.19.0/Understanding_the_Structure_of_a_JSON_Schema_Manifest.html
7+ # - https://github.com/Jamf-Custom-Profile-Schemas
98
109import argparse
1110import json
1211from datetime import datetime
1312
1413from pre_commit_hooks .util import PLIST_TYPES , validate_required_keys
1514
16- # Types found in the Jamf JSON schemas
17- SCHEMA_TYPES = (
18- "string" ,
19- "boolean" ,
20- "object" ,
21- "integer" ,
15+ # Types found in the Jamf JSON manifests
16+ MANIFEST_TYPES = (
2217 "array" ,
18+ "boolean" ,
2319 "data" ,
20+ "date" ,
2421 "float" ,
22+ "integer" ,
23+ "number" ,
24+ "object" ,
2525 "real" ,
26- "date " ,
26+ "string " ,
2727)
2828
2929# List keys and their expected item types
30- SCHEMA_LIST_TYPES = {
30+ MANIFEST_LIST_TYPES = {
3131 "enum_titles" : str ,
3232 "enum" : (str , int , float , bool ),
3333 "links" : dict ,
@@ -45,10 +45,10 @@ def build_argument_parser():
4545 return parser
4646
4747
48- def validate_schema_key_types (name , schema , filename ):
49- """Validation of schema key types."""
48+ def validate_key_types (name , manifest , filename ):
49+ """Validation of manifest key types."""
5050
51- # Schema keys and their known types. Omitted keys are left unvalidated.
51+ # Manifest keys and their known types. Omitted keys are left unvalidated.
5252 key_types = {
5353 "description" : str ,
5454 "enum_titles" : list ,
@@ -67,16 +67,16 @@ def validate_schema_key_types(name, schema, filename):
6767 }
6868
6969 passed = True
70- for schema_key , expected_type in key_types .items ():
71- if schema_key in schema :
72- if not isinstance (schema [ schema_key ], expected_type ):
70+ for manifest_key , expected_type in key_types .items ():
71+ if manifest_key in manifest :
72+ if not isinstance (manifest [ manifest_key ], expected_type ):
7373 print (
7474 "{}: {} key {} should be type {}, not type {}" .format (
7575 filename ,
7676 name ,
77- schema_key ,
77+ manifest_key ,
7878 expected_type ,
79- type (schema [ schema_key ]),
79+ type (manifest [ manifest_key ]),
8080 )
8181 )
8282 passed = False
@@ -97,32 +97,32 @@ def validate_type(name, property, filename):
9797 type_found = t
9898 break
9999
100- if type_found not in SCHEMA_TYPES :
100+ if type_found not in MANIFEST_TYPES :
101101 print ('{}: Unexpected "{}" type "{}"' .format (filename , name , type_found ))
102102 passed = False
103103
104104 return passed , type_found
105105
106106
107- def validate_list_item_types (name , schema , filename ):
107+ def validate_list_item_types (name , manifest , filename ):
108108 """Validation of list member items."""
109109
110110 passed = True
111- for name in SCHEMA_LIST_TYPES :
112- if name in schema :
111+ for name in MANIFEST_LIST_TYPES :
112+ if name in manifest :
113113 try :
114- actual_type = type (schema [name ][0 ])
114+ actual_type = type (manifest [name ][0 ])
115115 except IndexError :
116116 # Probably an empty array; no way to validate items
117117 continue
118- if isinstance (SCHEMA_LIST_TYPES [name ], tuple ):
119- desired_types = SCHEMA_LIST_TYPES [name ]
118+ if isinstance (MANIFEST_LIST_TYPES [name ], tuple ):
119+ desired_types = MANIFEST_LIST_TYPES [name ]
120120 else :
121- desired_types = [SCHEMA_LIST_TYPES [name ]]
121+ desired_types = [MANIFEST_LIST_TYPES [name ]]
122122 if actual_type not in desired_types :
123123 print (
124124 '{}: "{}" items should be {}, not {}' .format (
125- filename , name , SCHEMA_LIST_TYPES [name ], actual_type
125+ filename , name , MANIFEST_LIST_TYPES [name ], actual_type
126126 )
127127 )
128128 passed = False
@@ -203,7 +203,7 @@ def validate_properties(properties, filename):
203203 passed = False
204204
205205 # TODO: Validate pfm_conditionals
206- # https://github.com/ProfileCreator/Profileschemas /wiki/schema -Format#example-conditions--exclusions
206+ # https://github.com/ProfileCreator/ProfileManifests /wiki/Manifest -Format#example-conditions--exclusions
207207
208208 # TODO: Process $ref references
209209
@@ -226,27 +226,27 @@ def main(argv=None):
226226 for filename in args .filenames :
227227 try :
228228 with open (filename , "rb" ) as openfile :
229- schema = json .load (openfile )
229+ manifest = json .load (openfile )
230230 except json .decoder .JSONDecodeError as err :
231231 print ("{}: json parsing error: {}" .format (filename , err ))
232232 retval = 1
233233 break # No need to continue checking this file
234234
235235 # Check for presence of required keys.
236236 required_keys = ("title" , "properties" , "description" )
237- if not validate_required_keys (schema , filename , required_keys ):
237+ if not validate_required_keys (manifest , filename , required_keys ):
238238 retval = 1
239239 break # No need to continue checking this file
240240
241241 # Ensure top level keys and their list items have expected types.
242- if not validate_schema_key_types ("<root>" , schema , filename ):
242+ if not validate_key_types ("<root>" , manifest , filename ):
243243 retval = 1
244- if not validate_list_item_types ("<root>" , schema , filename ):
244+ if not validate_list_item_types ("<root>" , manifest , filename ):
245245 retval = 1
246246
247247 # Run checks recursively for all properties
248- if "properties" in schema :
249- if not validate_properties (schema ["properties" ], filename ):
248+ if "properties" in manifest :
249+ if not validate_properties (manifest ["properties" ], filename ):
250250 retval = 1
251251
252252 return retval
0 commit comments