47 lines
1.3 KiB
Python
47 lines
1.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
D2 — fingerprint_schema.py
|
|
Deterministischer SHA-256 über ein Captured-Schema-Modell.
|
|
|
|
Usage:
|
|
fingerprint_schema.py <model.json>
|
|
→ schreibt nur den Hex-Digest auf stdout (fail-closed: exit 0 bei Erfolg)
|
|
fingerprint_schema.py <model.json> --expect <digest>
|
|
→ exit 0 wenn MATCH, sonst exit 1 (FAIL CLOSED)
|
|
|
|
Der Fingerprint deckt ab: Tabellenexistenz, Spaltenname, ordinal_position,
|
|
Datentyp, Nullability, Default, PK, UNIQUE, FK, CHECK, Index-Definitionen (§8).
|
|
"""
|
|
import sys
|
|
import argparse
|
|
from canonical_schema import fingerprint, load_model
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("model")
|
|
ap.add_argument("--expect", default=None, help="Erwarteter Digest (fail-closed Vergleich)")
|
|
ap.add_argument("--no-hash", action="store_true", help="Nur kanonische Serialisierung ausgeben")
|
|
args = ap.parse_args()
|
|
|
|
model = load_model(args.model)
|
|
digest, doc = fingerprint(model)
|
|
|
|
if args.no_hash:
|
|
print(doc)
|
|
return 0
|
|
|
|
if args.expect:
|
|
if digest == args.expect:
|
|
print(f"MATCH {digest}")
|
|
return 0
|
|
else:
|
|
print(f"MISMATCH expected={args.expect} actual={digest}", file=sys.stderr)
|
|
return 1 # FAIL CLOSED
|
|
|
|
print(digest)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|