"""Conformance self-test for mizan.verdict/1 verifiers: one command, green or red. python -m mizan.conformance # MIZAN's own verifier (mizan.verify_token) python -m mizan.conformance --verifier yourpkg.verdict:verify # YOUR verifier, same published vectors python3 conformance.py --verifier yourpkg.verdict:verify # the same file, standalone (no mizan-sdk needed) Vectors: https://mizan.market/verdict/vectors.json (or --vectors PATH|URL). They are signed with a TEST key derived from a public seed; that key is never in MIZAN's key set, so a vector token can never pass against production keys. Your verifier is called as fn(token, keys, payee=..., rule=..., now=..., status=...) with only the arguments a vector sets (keys = {kid: base64 raw Ed25519 key}; now = the vectors' fixed clock). It returns a dict with "ok" and "code", or a tuple (ok, code). A vector passes when both equal the expected result. Exit 0 = every vector passed; 1 = any failed; 2 = could not run. Stdlib only. """ from __future__ import annotations import argparse import base64 import importlib import json import sys import time import urllib.request VECTORS_URL = "https://mizan.market/verdict/vectors.json" def load(src: str = VECTORS_URL) -> dict: if src.startswith(("http://", "https://")): req = urllib.request.Request(src, headers={"User-Agent": "mizan-conformance/1", "Accept": "application/json"}) with urllib.request.urlopen(req, timeout=20) as r: return json.loads(r.read()) with open(src) as f: return json.load(f) def _canonical(o) -> bytes: return json.dumps(o, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8") def _resolve(spec: str | None): if not spec: from mizan.verdict import verify_token # MIZAN's reference verifier return verify_token, "mizan.verify_token" mod, _, fn = spec.partition(":") if not fn: raise SystemExit("--verifier wants module:function, e.g. yourpkg.verdict:verify_token") sys.path.insert(0, ".") return getattr(importlib.import_module(mod), fn), spec def _norm(r): if isinstance(r, dict): return bool(r.get("ok")), str(r.get("code")) if isinstance(r, (tuple, list)) and len(r) >= 2: return bool(r[0]), str(r[1]) return None, f"unexpected return {type(r).__name__}" def run(data: dict, fn) -> list[dict]: out = [] can = data.get("canonicalisation") or {} if can: got = base64.urlsafe_b64encode(_canonical(can["claims"])).rstrip(b"=").decode() out.append({"name": "canonical_serialisation", "expect": "claims_b64", "ok": got == can["claims_b64"], "got": "matches" if got == can["claims_b64"] else "differs", "us": 0.0}) for v in data["vectors"]: kw = {"now": data["now"], **(v.get("verify") or {})} t0 = time.perf_counter() try: got = _norm(fn(v["token"], data["keys"], **kw)) except Exception as e: # a verifier that raises on a bad token fails that vector; it must return a code got = (None, f"raised {type(e).__name__}") us = (time.perf_counter() - t0) * 1e6 exp = (v["expect"]["ok"], v["expect"]["code"]) out.append({"name": v["name"], "expect": f"{exp[0]}/{exp[1]}", "got": f"{got[0]}/{got[1]}", "ok": got == exp, "us": us}) return out def main(argv=None) -> int: ap = argparse.ArgumentParser(prog="python -m mizan.conformance", description="mizan.verdict/1 verifier conformance self-test") ap.add_argument("--verifier", help="module:function to test (default: mizan.verify_token)") ap.add_argument("--vectors", default=VECTORS_URL, help="path or URL of vectors.json") ap.add_argument("--json", action="store_true", help="print the results as JSON") a = ap.parse_args(argv) try: data = load(a.vectors) fn, name = _resolve(a.verifier) except SystemExit: raise except Exception as e: print(f"could not run: {type(e).__name__}: {e}", file=sys.stderr) return 2 res = run(data, fn) passed = sum(r["ok"] for r in res) if a.json: print(json.dumps({"schema": data.get("schema"), "verifier": name, "passed": passed, "total": len(res), "results": res}, indent=1)) else: print(f"{data.get('schema')} · verifier {name} · vectors {a.vectors}") for r in res: print(f" {'PASS' if r['ok'] else 'FAIL'} {r['name']:<38} expect {r['expect']:<22} got {r['got']}") print(f"{passed}/{len(res)} passed" + (" · CONFORMANT" if passed == len(res) else " · NOT CONFORMANT")) return 0 if passed == len(res) else 1 if __name__ == "__main__": sys.exit(main())