Files
whetstone_DSL/tools/mcp/verify_grammar_manifest.py

68 lines
2.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Verify grammar manifest and lock digest against current schema/artifacts.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import sys
from pathlib import Path
def _sha(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--schemas", default="tools/mcp/whetstone_tool_schemas.json")
ap.add_argument("--grammars-dir", default="tools/mcp/grammars")
args = ap.parse_args()
gdir = Path(args.grammars_dir)
manifest_path = gdir / "manifest.json"
lock_path = gdir / "manifest.lock"
dispatch_gbnf_path = gdir / "dispatch.gbnf"
dispatch_schema_path = gdir / "dispatch_schema.json"
if not manifest_path.exists() or not lock_path.exists():
print("Manifest files missing")
sys.exit(2)
manifest = json.loads(manifest_path.read_text())
schemas = json.loads(Path(args.schemas).read_text())
dispatch_gbnf = dispatch_gbnf_path.read_text()
dispatch_schema = json.loads(dispatch_schema_path.read_text())
expected = {
"tool_count": len(schemas),
"tool_schema_sha256": _sha(json.dumps(schemas, sort_keys=True, separators=(",", ":"))),
"dispatch_gbnf_sha256": _sha(dispatch_gbnf),
"dispatch_schema_sha256": _sha(json.dumps(dispatch_schema, sort_keys=True, separators=(",", ":"))),
}
failures = []
for k, v in expected.items():
if manifest.get(k) != v:
failures.append(f"manifest mismatch: {k}")
expected_lock = _sha(json.dumps(manifest, sort_keys=True, separators=(",", ":")))
actual_lock = lock_path.read_text().strip()
if expected_lock != actual_lock:
failures.append("manifest lock mismatch")
if failures:
print("Manifest verification FAILED")
for f in failures:
print(f"- {f}")
sys.exit(2)
print("Manifest verification PASSED")
if __name__ == "__main__":
main()