#!/usr/bin/env python3 import json import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] errors = [] SECRET_RE = re.compile(r"(BEGIN (RSA |OPENSSH |EC |DSA )?PRIVATE KEY|AWS_SECRET_ACCESS_KEY|ghp_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9]{20,}|xox[baprs]-)") for p in [ROOT/'inventory'/'raw_scan.jsonl', ROOT/'inventory'/'projects.jsonl']: if not p.exists() or p.stat().st_size == 0: errors.append(f"missing_or_empty: {p.relative_to(ROOT)}") projects = [] for jsonl in [ROOT/'inventory'/'raw_scan.jsonl', ROOT/'inventory'/'projects.jsonl']: if not jsonl.exists(): continue for i, line in enumerate(jsonl.read_text(encoding='utf-8', errors='ignore').splitlines(), 1): if not line.strip(): continue if SECRET_RE.search(line): errors.append(f"secret_like_content: {jsonl.relative_to(ROOT)}:{i}") try: obj = json.loads(line) except Exception as e: errors.append(f"invalid_jsonl: {jsonl.relative_to(ROOT)}:{i}: {e}") continue if jsonl.name == 'projects.jsonl': projects.append(obj) for k in ['project_id','name','path','last_modified','is_git_repo','technologies','risk_level','evidence_file','triage_status','score']: if k not in obj: errors.append(f"projects.jsonl:{i} missing {k}") ev = obj.get('evidence_file') if ev: ep = ROOT / ev try: ep.resolve().relative_to((ROOT/'inventory'/'evidence').resolve()) except Exception: errors.append(f"evidence outside evidence dir: {ev}") if not ep.exists(): errors.append(f"missing evidence: {ev}") if not projects: errors.append('no_projects_found') if errors: print('verify_inventory: failed') for e in errors: print(f'- {e}') raise SystemExit(1) print(f'verify_inventory: passed ({len(projects)} projects)')