#!/usr/bin/env python3 """check_mandate: consistency check of a human-written one-time mandate against an authorization request. stdlib only. Prints ACCEPT/REJECT JSON with reasons. LIMITATION: without real signature infrastructure this is a CONSISTENCY check only. It does NOT authenticate a human and it grants nothing. Exit codes: 0 ACCEPT, 3 REJECT, 2 usage/input error. """ import argparse import json import os import sys from datetime import datetime, timedelta, timezone sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from contract_diff import MAX_TTL_MINUTES, dumps, has_wildcard, is_human_role # noqa: E402 TS_FMT = "%Y-%m-%dT%H:%M:%SZ" def _ts(value): try: return datetime.strptime(value, TS_FMT).replace(tzinfo=timezone.utc) except (TypeError, ValueError): return None def reasons_for(request, mandate, used_nonces, now): r = [] if not isinstance(mandate, dict) or not isinstance(request, dict): return ["malformed input"] for f in ("action", "resource"): if mandate.get(f) != request.get(f): r.append("%s does not exactly match request" % f) if has_wildcard(mandate.get(f)): r.append("%s contains wildcard or is empty" % f) if mandate.get("request_id") != request.get("request_id"): r.append("request_id mismatch") if mandate.get("one_time") is not True: r.append("one_time must be true") ttl = mandate.get("ttl_minutes") if not isinstance(ttl, int) or isinstance(ttl, bool) or not 1 <= ttl <= MAX_TTL_MINUTES: r.append("ttl_minutes must be integer 1..%d" % MAX_TTL_MINUTES) elif isinstance(request.get("ttl_minutes"), int) and ttl > request["ttl_minutes"]: r.append("ttl_minutes exceeds requested ttl") issued, expires = _ts(mandate.get("issued_at")), _ts(mandate.get("expires_at")) if issued is None or expires is None: r.append("issued_at/expires_at must be UTC like 2026-01-01T00:00:00Z") else: if issued > now: r.append("mandate issued in the future") if expires <= now: r.append("mandate expired") if isinstance(ttl, int) and not isinstance(ttl, bool) and expires - issued > timedelta(minutes=ttl): r.append("expires_at later than issued_at + ttl_minutes") nonce = mandate.get("nonce") if not isinstance(nonce, str) or not nonce.strip(): r.append("nonce missing") elif nonce in used_nonces: r.append("nonce already used") if not is_human_role(mandate.get("signer_role")): r.append("signer_role is not an allowed human role") if mandate.get("signed_by_human") is not True: r.append("signed_by_human must be true") note = mandate.get("signature_note") if not isinstance(note, str) or not note.strip(): r.append("signature_note missing") return r def check_mandate(request, mandate, used_nonces=(), now=None): now = now or datetime.now(timezone.utc) reasons = reasons_for(request, mandate, set(used_nonces), now) # Hard guard independent of the list above: never ACCEPT without a human signer. if not reasons and (not isinstance(mandate, dict) or mandate.get("signed_by_human") is not True or not is_human_role(mandate.get("signer_role"))): reasons.append("hard guard: no human signer") return {"decision": "REJECT" if reasons else "ACCEPT", "reasons": sorted(reasons), "limitation": "consistency check only; does not authenticate a human and grants nothing"} def _load(path): with open(path, "r", encoding="utf-8") as fh: return json.load(fh) def main(argv=None): ap = argparse.ArgumentParser(description="Mandate consistency check (grants nothing).") ap.add_argument("--request", required=True, help="authorization_request JSON or full ContractDiff output") ap.add_argument("--mandate", required=True) ap.add_argument("--used-nonces", help='JSON {"used_nonces": [...]}') ap.add_argument("--now", help="UTC time like 2026-11-11T12:00:00Z (default: real UTC now)") try: a = ap.parse_args(argv) except SystemExit: return 2 try: req = _load(a.request) if isinstance(req, dict) and isinstance(req.get("authorization_request"), dict): req = req["authorization_request"] mandate = _load(a.mandate) used = (_load(a.used_nonces).get("used_nonces", []) if a.used_nonces else []) now = _ts(a.now) if a.now else datetime.now(timezone.utc) if now is None: raise ValueError("bad --now") except (OSError, ValueError, AttributeError) as exc: sys.stderr.write("error: %s\n" % exc) return 2 out = check_mandate(req, mandate, used, now) sys.stdout.write(dumps(out)) return 0 if out["decision"] == "ACCEPT" else 3 if __name__ == "__main__": sys.exit(main())