171 lines
5.4 KiB
Python
171 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
import hashlib
|
|
import unittest
|
|
|
|
from govoplan_core.core.sanctions import (
|
|
CAPABILITY_CONNECTORS_SANCTIONS_SNAPSHOTS,
|
|
CAPABILITY_RISK_COMPLIANCE_SANCTIONS_SCREENING,
|
|
SanctionsScreeningEvidence,
|
|
SanctionsScreeningFreshness,
|
|
SanctionsScreeningFreshnessRequest,
|
|
SanctionsScreeningPolicy,
|
|
SanctionsScreeningProvider,
|
|
SanctionsScreeningRequest,
|
|
SanctionsScreeningResult,
|
|
SanctionsScreeningSubject,
|
|
SanctionsSnapshotPayload,
|
|
SanctionsSnapshotProvider,
|
|
SanctionsSnapshotReference,
|
|
sanctions_screening_provider,
|
|
sanctions_snapshot_provider,
|
|
)
|
|
|
|
|
|
class _Provider:
|
|
def list_snapshots(self, session, principal, *, limit=100):
|
|
del session, principal, limit
|
|
return ()
|
|
|
|
def get_snapshot(self, session, principal, *, snapshot_ref):
|
|
del session, principal, snapshot_ref
|
|
return None
|
|
|
|
def read_snapshot(self, session, principal, *, snapshot_ref):
|
|
del session, principal, snapshot_ref
|
|
raise LookupError
|
|
|
|
|
|
class _Registry:
|
|
def __init__(self, provider):
|
|
self.provider = provider
|
|
|
|
def has_capability(self, name):
|
|
return name == CAPABILITY_CONNECTORS_SANCTIONS_SNAPSHOTS
|
|
|
|
def capability(self, name):
|
|
return self.provider if self.has_capability(name) else None
|
|
|
|
|
|
class _ScreeningProvider:
|
|
def request_screening(self, session, principal, request):
|
|
del session, principal, request
|
|
raise NotImplementedError
|
|
|
|
def check_freshness(self, session, principal, request):
|
|
del session, principal, request
|
|
raise NotImplementedError
|
|
|
|
|
|
class _ScreeningRegistry:
|
|
def __init__(self, provider):
|
|
self.provider = provider
|
|
|
|
def has_capability(self, name):
|
|
return name == CAPABILITY_RISK_COMPLIANCE_SANCTIONS_SCREENING
|
|
|
|
def capability(self, name):
|
|
return self.provider if self.has_capability(name) else None
|
|
|
|
|
|
class SanctionsContractTests(unittest.TestCase):
|
|
def test_snapshot_evidence_is_versioned_and_bounded(self) -> None:
|
|
content = b"<CONSOLIDATED_LIST/>"
|
|
snapshot = SanctionsSnapshotReference(
|
|
ref="sanctions-snapshot:snapshot-1",
|
|
tenant_id="tenant-1",
|
|
provider_id="un.security_council",
|
|
publisher="United Nations Security Council",
|
|
jurisdiction="UN",
|
|
list_type="consolidated",
|
|
source_id="unsc-consolidated",
|
|
source_version="2026-07-22",
|
|
publication_at=None,
|
|
effective_at=None,
|
|
acquired_at=datetime.now(timezone.utc),
|
|
content_type="application/xml",
|
|
byte_count=len(content),
|
|
sha256=hashlib.sha256(content).hexdigest(),
|
|
parser_version="unsc-xml-v1",
|
|
raw_evidence_ref="connector-evidence:snapshot-1",
|
|
connector_run_id="run-1",
|
|
)
|
|
|
|
payload = SanctionsSnapshotPayload(
|
|
snapshot=snapshot,
|
|
content=content,
|
|
)
|
|
provider = _Provider()
|
|
|
|
self.assertEqual(content, payload.content)
|
|
self.assertIsInstance(provider, SanctionsSnapshotProvider)
|
|
self.assertIs(
|
|
provider,
|
|
sanctions_snapshot_provider(_Registry(provider)),
|
|
)
|
|
|
|
def test_screening_evidence_and_freshness_are_versioned(self) -> None:
|
|
subject = SanctionsScreeningSubject(
|
|
subject_type="person",
|
|
primary_name="Example Person",
|
|
)
|
|
policy = SanctionsScreeningPolicy(failure_policy="review")
|
|
request = SanctionsScreeningRequest(
|
|
list_snapshot_id="snapshot-1",
|
|
idempotency_key="request-1",
|
|
subject=subject,
|
|
policy=policy,
|
|
)
|
|
evidence = SanctionsScreeningEvidence(
|
|
ref="risk-screening:run-1",
|
|
run_id="run-1",
|
|
outcome="clear",
|
|
candidate_count=0,
|
|
list_snapshot_id=request.list_snapshot_id,
|
|
source_version="2026-07-30",
|
|
subject_fingerprint="a" * 64,
|
|
matcher_version="matcher-v1",
|
|
normalization_version="normalization-v1",
|
|
policy_version="policy-v1",
|
|
completed_at=datetime.now(timezone.utc),
|
|
)
|
|
freshness_request = SanctionsScreeningFreshnessRequest(
|
|
evidence_ref=evidence.ref,
|
|
current_subject=subject,
|
|
policy=policy,
|
|
)
|
|
freshness = SanctionsScreeningFreshness(
|
|
evidence=evidence,
|
|
fresh=True,
|
|
reasons=(),
|
|
checked_at=datetime.now(timezone.utc),
|
|
current_list_snapshot_id=request.list_snapshot_id,
|
|
gate_decision="allow",
|
|
gate_reasons=("screening_clear",),
|
|
)
|
|
result = SanctionsScreeningResult(
|
|
evidence=evidence,
|
|
freshness=freshness,
|
|
created=True,
|
|
)
|
|
provider = _ScreeningProvider()
|
|
|
|
self.assertEqual(evidence.ref, freshness_request.evidence_ref)
|
|
self.assertTrue(result.freshness.fresh)
|
|
self.assertIsInstance(provider, SanctionsScreeningProvider)
|
|
self.assertIs(
|
|
provider,
|
|
sanctions_screening_provider(
|
|
_ScreeningRegistry(provider)
|
|
),
|
|
)
|
|
|
|
def test_screening_contract_rejects_ambiguous_subjects(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
SanctionsScreeningSubject(subject_type="entity")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|