46 lines
1.7 KiB
Python
46 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate JSON files and CVE identity; nonzero exit status on errors."""
|
|
import argparse
|
|
import json
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PAT = re.compile(r'CVE-(\d{4})-\d{4,}')
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument('--changed-only', action='store_true', help='Validate files modified in the last Git worktree diff (including staged)')
|
|
args = p.parse_args()
|
|
if args.changed_only:
|
|
import subprocess
|
|
changed = subprocess.run(['git', 'status', '--porcelain', '-uall'], cwd=ROOT, capture_output=True, text=True, check=True).stdout
|
|
files = []
|
|
for line in changed.splitlines():
|
|
if len(line) < 4:
|
|
continue
|
|
path = line[3:]
|
|
if path.startswith('data/') and path.endswith('.json') and (ROOT / path).is_file():
|
|
files.append(ROOT / path)
|
|
else:
|
|
files = list((ROOT / 'data').glob('*/*.json'))
|
|
errors = []
|
|
for path in files:
|
|
try:
|
|
record = json.loads(path.read_text(encoding='utf-8'))
|
|
identifier = record['id']
|
|
match = PAT.fullmatch(identifier)
|
|
assert match and path.name == identifier + '.json' and path.parent.name == match.group(1)
|
|
assert isinstance(record.get('published'), str)
|
|
assert isinstance(record.get('lastModified'), str)
|
|
assert isinstance(record.get('vulnStatus'), str)
|
|
except Exception as exc:
|
|
errors.append(f'{path}: {exc}')
|
|
for error in errors[:30]:
|
|
print(error, file=sys.stderr)
|
|
print(f'Validated {len(files)} files; errors: {len(errors)}')
|
|
sys.exit(1 if errors else 0)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|