""" AUTH.3D — test_approval_helpers.py Gemeinsame Test-Helper: synthetische Keypairs, kanonische Payloads, Zeitgeber. NUR synthetische Test-Keypairs. KEINE echten Keys. """ from __future__ import annotations import datetime import uuid from typing import Any, Dict from approval_payload import build_payload from approval_signature import generate_test_keypair, key_id, sign # Feste Test-Referenzzeit (UTC) REF_TIME = datetime.datetime(2026, 8, 27, 12, 0, 0, tzinfo=datetime.timezone.utc) def make_iso(dt: datetime.datetime) -> str: return dt.strftime("%Y-%m-%dT%H:%M:%SZ") def now_iso() -> str: return make_iso(REF_TIME) def future_iso(minutes: int = 60) -> str: return make_iso(REF_TIME + datetime.timedelta(minutes=minutes)) def past_iso(minutes: int = 60) -> str: return make_iso(REF_TIME - datetime.timedelta(minutes=minutes)) def make_payload( *, approval_id: str = None, mission_id: str = None, delete_request_id: str = None, object_id: str = None, vault_path: str = "/vault/obj-a.md", expected_commit: str = "a" * 40, expected_provenance_hash: str = "b" * 64, nonce: str = None, issued_at: str = None, expires_at: str = None, **overrides, ) -> Dict[str, Any]: """Baut einen gültigen kanonischen Payload (Defaults gültig).""" return build_payload( approval_id=approval_id or str(uuid.uuid4()), mission_id=mission_id or str(uuid.uuid4()), delete_request_id=delete_request_id or str(uuid.uuid4()), object_id=object_id or str(uuid.uuid4()), vault_path=vault_path, expected_commit=expected_commit, expected_provenance_hash=expected_provenance_hash, nonce=nonce or str(uuid.uuid4()), issued_at=issued_at or now_iso(), expires_at=expires_at or future_iso(), **overrides, ) def make_signed_approval(private_key, payload: Dict[str, Any]): """Signiert einen Payload und liefert (payload, signature, key_id).""" sig = sign(private_key, payload) return payload, sig, key_id(private_key.public_key()) def make_valid_approval(private_key, **payload_overrides): """Baut + signiert eine gültige Approval. Liefert (payload, sig, key_id).""" payload = make_payload(**payload_overrides) return make_signed_approval(private_key, payload) def make_verifier(public_key, revoked_key_ids=None, now_fn=None): """Baut einen ApprovalVerifier mit einem Public Key.""" from approval_verifier import ApprovalVerifier kid = key_id(public_key) return ApprovalVerifier( public_keys={kid: public_key}, revoked_key_ids=revoked_key_ids, now_fn=now_fn or (lambda: REF_TIME), ) def make_expected(payload: Dict[str, Any]) -> Dict[str, str]: """Erwartete Kontext-Werte aus einem Payload (für verify_approval).""" return { "expected_mission_id": payload["mission_id"], "expected_delete_request_id": payload["delete_request_id"], "expected_object_id": payload["object_id"], "expected_vault_path": payload["vault_path"], "expected_commit": payload["expected_commit"], "expected_provenance_hash": payload["expected_provenance_hash"], "expected_nonce": payload["nonce"], }