"""Artifact audit: every raw record validates against the schema; every table/figure has a provenance entry; no secrets in the tree.""" from __future__ import annotations import json, re, glob from pathlib import Path from .util import ROOT, read_jsonl from .records import validate_record SECRET_RE = re.compile(r"(sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9]{32,}|hf_[A-Za-z0-9]{20,})") def main(root: str) -> int: root = Path(root).resolve(); ok = True n = bad = 0 for p in glob.glob(str(root / "runs/raw/*.jsonl")): if p.endswith("E6_network.jsonl") or "E6_" in p: continue for r in read_jsonl(p): n += 1 if validate_record(r): bad += 1 print(f"records: {n} total, {bad} invalid"); ok &= bad == 0 leaks = [] for p in glob.glob(str(root / "**/*"), recursive=True): pp = Path(p) if pp.is_dir() or ".venv" in p or ".git/" in p or pp.suffix in (".npz", ".safetensors", ".pdf", ".png", ".parquet", ".pyc"): continue try: t = pp.read_text(errors="ignore") except Exception: continue if SECRET_RE.search(t): leaks.append(str(pp.relative_to(root))) print("secret-like strings in tree:", leaks); ok &= not leaks prov = root / "results/provenance.json" if prov.exists(): pv = json.load(open(prov)) missing = [k for k, v in pv.items() if not (root / k).exists()] print(f"provenance entries: {len(pv)}, missing artifacts: {missing}"); ok &= not missing else: print("no results/provenance.json yet") return 0 if ok else 1