Spaces:
Sleeping
Sleeping
| """Load and validate SIP evidence bundles against the frozen contract schema. | |
| The schema lives on disk at ``specs/sip_evidence_bundle_schema.json`` (the G3 | |
| contract freeze) and is the single integration boundary between SIP and the | |
| UofA surrogate pack. Validation runs at bundle-emit time (before signing) and | |
| again at UofA-ingest time (v2). | |
| ``jsonschema`` is an optional dependency shipped in the ``[interrogate]`` extra; | |
| an import error surfaces an install hint rather than a bare ``ModuleNotFound``. | |
| The schema must be reachable both from a source checkout and from an installed | |
| wheel. ``paths.find_repo_root()`` returns the wheel-bundled ``_data/repo`` | |
| snapshot when running from a pip install, so ``specs/`` must be force-included | |
| into the wheel (``pyproject.toml``) for the firewall's schema layer to run for | |
| real users — see ``AGENTS.md`` §12. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| from uofa_cli.paths import find_repo_root | |
| SCHEMA_FILENAME = "sip_evidence_bundle_schema.json" | |
| def schema_path(root: Path | None = None) -> Path: | |
| """Return the on-disk path to the SIP evidence-bundle schema.""" | |
| root = root or find_repo_root() | |
| return root / "specs" / SCHEMA_FILENAME | |
| def load_schema(root: Path | None = None) -> dict: | |
| """Load and parse the SIP evidence-bundle schema. | |
| Returns a fresh dict each call (no caching) so callers may freely mutate | |
| the result without poisoning a shared instance. | |
| """ | |
| return json.loads(schema_path(root).read_text(encoding="utf-8")) | |
| def validate_bundle(bundle: dict, root: Path | None = None) -> None: | |
| """Validate ``bundle`` against the SIP contract schema; raise if invalid. | |
| Raises ``jsonschema.ValidationError`` when the bundle violates the | |
| contract — including carrying any forbidden verdict field (the firewall). | |
| Callers must invoke this *before* signing so a forbidden field can never be | |
| given a signature. | |
| """ | |
| try: | |
| import jsonschema | |
| except ImportError as exc: # pragma: no cover - exercised only without the extra | |
| raise RuntimeError( | |
| "jsonschema is required to validate SIP evidence bundles. " | |
| "Install with: pip install uofa[interrogate]" | |
| ) from exc | |
| jsonschema.validate(bundle, load_schema(root)) | |