Files
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

89 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""Validate starter JSON Schemas and their canonical examples.
Requires the development-only `jsonschema` package. The core `projectctl.py`
remains standard-library-only so repository state can be recovered first.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
def load(path: Path) -> Any:
return json.loads(path.read_text(encoding="utf-8"))
def main() -> int:
try:
from jsonschema import Draft202012Validator
from referencing import Registry, Resource
except ModuleNotFoundError:
print(
"ERROR: contract validation requires the development package 'jsonschema'.",
file=sys.stderr,
)
return 2
schema_paths = sorted((ROOT / "specs").glob("*.json"))
schemas: dict[str, dict[str, Any]] = {}
resources: list[tuple[str, Any]] = []
for path in schema_paths:
schema = load(path)
Draft202012Validator.check_schema(schema)
schema_id = schema.get("$id")
if not isinstance(schema_id, str) or not schema_id:
print(f"ERROR: {path.relative_to(ROOT)} has no $id", file=sys.stderr)
return 1
schemas[path.relative_to(ROOT).as_posix()] = schema
resource = Resource.from_contents(schema)
resources.append((schema_id, resource))
resources.append((path.resolve().as_uri(), resource))
registry = Registry().with_resources(resources)
checks: list[tuple[str, str]] = [
("config/metrics/catalog.example.json", "specs/metric-catalog.schema.json"),
("config/dashboards/default-overview.example.json", "specs/dashboard.schema.json"),
("config/alerts/default-rules.example.json", "specs/alert-rule-set.schema.json"),
("config/probes/probe.example.json", "specs/probe.schema.json"),
]
# The canonical private repository validates its implementation ledger. The
# curated public-source export deliberately excludes private planning state.
if (ROOT / "planning" / "task-ledger.json").exists():
checks.insert(0, ("planning/task-ledger.json", "specs/task-ledger.schema.json"))
checks.extend(
(path.relative_to(ROOT).as_posix(), "specs/simulator-scenario.schema.json")
for path in sorted((ROOT / "fixtures" / "scenarios").glob("*.json"))
)
failures = 0
for document_name, schema_name in checks:
document = load(ROOT / document_name)
schema = schemas[schema_name]
validator = Draft202012Validator(schema, registry=registry)
errors = sorted(validator.iter_errors(document), key=lambda item: list(item.path))
if not errors:
print(f"PASS: {document_name}")
continue
failures += len(errors)
print(f"FAIL: {document_name}", file=sys.stderr)
for error in errors:
location = "/".join(str(part) for part in error.path) or "<root>"
print(f"- {location}: {error.message}", file=sys.stderr)
if failures:
print(f"CONTRACT VALIDATION: FAIL ({failures} errors)", file=sys.stderr)
return 1
print(f"CONTRACT VALIDATION: PASS ({len(schema_paths)} schemas, {len(checks)} documents)")
return 0
if __name__ == "__main__":
raise SystemExit(main())