mirror of https://github.com/OISF/suricata
schema: add script to check or sort the schema
parent
5a4eba2f57
commit
371d7cba06
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Script to sort or just check that properties are in alphabetic order
|
||||
|
||||
|
||||
import json
|
||||
import sys
|
||||
import argparse
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
def sort_properties(obj, path=""):
|
||||
"""Recursively sort 'properties' keys in a JSON schema object."""
|
||||
if isinstance(obj, dict):
|
||||
new_obj = OrderedDict()
|
||||
|
||||
for key, value in obj.items():
|
||||
current_path = f"{path}.{key}" if path else key
|
||||
|
||||
if key == "properties" and isinstance(value, dict):
|
||||
sorted_properties = OrderedDict(sorted(value.items()))
|
||||
new_obj[key] = sorted_properties
|
||||
for prop_key, prop_value in sorted_properties.items():
|
||||
new_obj[key][prop_key] = sort_properties(
|
||||
prop_value, f"{current_path}.{prop_key}"
|
||||
)
|
||||
else:
|
||||
new_obj[key] = sort_properties(value, current_path)
|
||||
|
||||
return new_obj
|
||||
|
||||
elif isinstance(obj, list):
|
||||
return [sort_properties(item, f"{path}[{i}]") for i, item in enumerate(obj)]
|
||||
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def check_properties_sorted(obj, path=""):
|
||||
"""Check if all 'properties' keys have their contents sorted alphabetically."""
|
||||
errors = []
|
||||
|
||||
if isinstance(obj, dict):
|
||||
for key, value in obj.items():
|
||||
current_path = f"{path}.{key}" if path else key
|
||||
if key == "properties" and isinstance(value, dict):
|
||||
keys_list = list(value.keys())
|
||||
sorted_keys = sorted(keys_list)
|
||||
|
||||
if keys_list != sorted_keys:
|
||||
errors.append(f"Properties not sorted at path: {current_path}")
|
||||
errors.append(f" Current order: {keys_list}")
|
||||
errors.append(f" Should be: {sorted_keys}")
|
||||
|
||||
for prop_key, prop_value in value.items():
|
||||
errors.extend(
|
||||
check_properties_sorted(
|
||||
prop_value, f"{current_path}.{prop_key}"
|
||||
)
|
||||
)
|
||||
else:
|
||||
errors.extend(check_properties_sorted(value, current_path))
|
||||
|
||||
elif isinstance(obj, list):
|
||||
for i, item in enumerate(obj):
|
||||
errors.extend(check_properties_sorted(item, f"{path}[{i}]"))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Sort JSON schema properties alphabetically"
|
||||
)
|
||||
parser.add_argument("schema_file", help="Path to the JSON schema file")
|
||||
parser.add_argument(
|
||||
"--check",
|
||||
action="store_true",
|
||||
help="Check if properties are sorted (exit 1 if not)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--in-place",
|
||||
action="store_true",
|
||||
help="Sort the file in place (only if not in check mode)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
with open(args.schema_file, "r") as f:
|
||||
schema = json.load(f, object_pairs_hook=OrderedDict)
|
||||
except Exception as e:
|
||||
print(f"Error reading schema file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.check:
|
||||
errors = check_properties_sorted(schema)
|
||||
|
||||
if errors:
|
||||
print("Schema properties are not sorted!", file=sys.stderr)
|
||||
for error in errors:
|
||||
print(error, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("Schema properties are properly sorted.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
sorted_schema = sort_properties(schema)
|
||||
|
||||
if args.in_place:
|
||||
try:
|
||||
with open(args.schema_file, "w") as f:
|
||||
json.dump(sorted_schema, f, indent=4)
|
||||
f.write("\n")
|
||||
print(f"Sorted schema written to {args.schema_file}")
|
||||
except Exception as e:
|
||||
print(f"Error writing schema file: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(json.dumps(sorted_schema, indent=4))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue