#!/usr/bin/env python3 """Validate an admin content change-set JSON file. The validator uses the same service-layer rules as the backend. It runs against an empty in-memory repository by default, so references to existing production content should be seeded by a deployment-specific wrapper before applying real changes. """ from __future__ import annotations import argparse import json from pathlib import Path import sys from fan_passport.admin_content import ( AdminContentService, ContentValidationError, InMemoryContentRepository, load_change_set, ) def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Validate Fan Passport admin content change-set JSON.") parser.add_argument("change_set_path", type=Path, help="Path to a content change-set JSON document.") parser.add_argument( "--apply", action="store_true", help="Apply accepted changes to the local in-memory repository after validation.", ) return parser def main() -> int: args = build_parser().parse_args() repository = InMemoryContentRepository() service = AdminContentService(repository) try: change_set = load_change_set(args.change_set_path) if args.apply: result = service.apply(change_set) payload = result.to_dict() else: payload = service.plan(change_set).to_dict() except (OSError, json.JSONDecodeError, ContentValidationError, ValueError, KeyError) as exc: print(f"content change-set validation failed: {exc}", file=sys.stderr) return 1 print(json.dumps(payload, indent=2, sort_keys=True)) return 0 if payload.get("accepted", payload.get("plan", {}).get("accepted", False)) else 2 if __name__ == "__main__": raise SystemExit(main())