Prove reference journey compositions
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prove the governed Connectors -> Risk Compliance sanctions journey."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from govoplan_connectors.backend.db.models import (
|
||||
ConnectorSanctionsAcquisitionRun,
|
||||
ConnectorSanctionsSnapshot,
|
||||
)
|
||||
from govoplan_connectors.backend.sanctions_sources import (
|
||||
SANCTIONS_READ_SCOPE as CONNECTOR_SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_REFRESH_SCOPE,
|
||||
SYNTHETIC_PROVIDER_ID,
|
||||
)
|
||||
from govoplan_core.auth import ApiPrincipal
|
||||
from govoplan_core.core.access import PrincipalRef
|
||||
from govoplan_core.core.modules import ModuleContext
|
||||
from govoplan_core.core.recovery import RecoveryCheckpoint, RecoveryOperation
|
||||
from govoplan_core.core.runtime_coordination import (
|
||||
DistributedLease,
|
||||
RuntimeIdentity,
|
||||
bind_process_runtime_identity,
|
||||
)
|
||||
from govoplan_core.core.sanctions import (
|
||||
SanctionsScreeningFreshnessRequest,
|
||||
SanctionsScreeningPolicy,
|
||||
SanctionsScreeningRequest,
|
||||
SanctionsScreeningSubject,
|
||||
sanctions_screening_provider,
|
||||
sanctions_snapshot_provider,
|
||||
)
|
||||
from govoplan_core.db.base import Base
|
||||
from govoplan_core.server.registry import build_platform_registry
|
||||
from govoplan_risk_compliance.backend.db.models import (
|
||||
RiskAssuranceEdge,
|
||||
RiskAssuranceNode,
|
||||
RiskSanctionsAddress,
|
||||
RiskSanctionsAlias,
|
||||
RiskSanctionsDate,
|
||||
RiskSanctionsEntry,
|
||||
RiskSanctionsIdentifier,
|
||||
RiskSanctionsListSnapshot,
|
||||
RiskScreeningCandidate,
|
||||
RiskScreeningDisposition,
|
||||
RiskScreeningException,
|
||||
RiskScreeningRun,
|
||||
RiskScreeningSubjectSnapshot,
|
||||
)
|
||||
from govoplan_risk_compliance.backend.permissions import (
|
||||
SANCTIONS_ADMIN_SCOPE,
|
||||
SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
)
|
||||
from govoplan_risk_compliance.backend.review import (
|
||||
DispositionInput,
|
||||
record_disposition,
|
||||
)
|
||||
from govoplan_risk_compliance.backend.sanctions_catalog import (
|
||||
import_connector_snapshot,
|
||||
)
|
||||
from govoplan_risk_compliance.backend.screening import (
|
||||
get_screening_run,
|
||||
list_rescreening_requirements,
|
||||
)
|
||||
|
||||
|
||||
TABLES = (
|
||||
DistributedLease.__table__,
|
||||
RecoveryOperation.__table__,
|
||||
RecoveryCheckpoint.__table__,
|
||||
ConnectorSanctionsAcquisitionRun.__table__,
|
||||
ConnectorSanctionsSnapshot.__table__,
|
||||
RiskAssuranceNode.__table__,
|
||||
RiskAssuranceEdge.__table__,
|
||||
RiskSanctionsListSnapshot.__table__,
|
||||
RiskSanctionsEntry.__table__,
|
||||
RiskSanctionsAlias.__table__,
|
||||
RiskSanctionsIdentifier.__table__,
|
||||
RiskSanctionsDate.__table__,
|
||||
RiskSanctionsAddress.__table__,
|
||||
RiskScreeningSubjectSnapshot.__table__,
|
||||
RiskScreeningRun.__table__,
|
||||
RiskScreeningCandidate.__table__,
|
||||
RiskScreeningDisposition.__table__,
|
||||
RiskScreeningException.__table__,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
registry = build_platform_registry(("connectors", "risk_compliance"))
|
||||
registry.configure_capability_context(
|
||||
ModuleContext(registry=registry, settings=object())
|
||||
)
|
||||
snapshot_provider = sanctions_snapshot_provider(registry)
|
||||
screening_provider = sanctions_screening_provider(registry)
|
||||
refresh_source = getattr(snapshot_provider, "refresh_source", None)
|
||||
if snapshot_provider is None or not callable(refresh_source):
|
||||
raise RuntimeError("Connectors sanctions acquisition is unavailable.")
|
||||
if screening_provider is None:
|
||||
raise RuntimeError("Risk Compliance sanctions screening is unavailable.")
|
||||
|
||||
engine = create_engine("sqlite:///:memory:")
|
||||
Base.metadata.create_all(engine, tables=TABLES)
|
||||
bind_process_runtime_identity(
|
||||
RuntimeIdentity(
|
||||
installation_id="sanctions-composition-check",
|
||||
node_id="sanctions-worker",
|
||||
incarnation="sanctions-worker-incarnation",
|
||||
role="worker",
|
||||
software_version="test",
|
||||
composition_hash="d" * 64,
|
||||
)
|
||||
)
|
||||
try:
|
||||
with Session(engine) as session:
|
||||
operator = _principal("operator-1", operational=True)
|
||||
reviewer = _principal("reviewer-1", operational=False)
|
||||
|
||||
acquired = refresh_source(
|
||||
session,
|
||||
operator,
|
||||
provider_id=SYNTHETIC_PROVIDER_ID,
|
||||
idempotency_key="synthetic-sanctions-2026-08-01",
|
||||
)
|
||||
replay = refresh_source(
|
||||
session,
|
||||
operator,
|
||||
provider_id=SYNTHETIC_PROVIDER_ID,
|
||||
idempotency_key="synthetic-sanctions-2026-08-01",
|
||||
)
|
||||
if acquired.status != "succeeded" or acquired.snapshot is None:
|
||||
raise RuntimeError(f"Synthetic acquisition failed: {acquired!r}")
|
||||
if (
|
||||
replay.run_id != acquired.run_id
|
||||
or replay.snapshot is None
|
||||
or replay.snapshot.ref != acquired.snapshot.ref
|
||||
or replay.snapshot.sha256 != acquired.snapshot.sha256
|
||||
):
|
||||
raise RuntimeError("Acquisition idempotency did not replay exact evidence.")
|
||||
|
||||
imported, created = import_connector_snapshot(
|
||||
session,
|
||||
operator,
|
||||
registry=registry,
|
||||
connector_snapshot_ref=acquired.snapshot.ref,
|
||||
)
|
||||
imported_replay, replay_created = import_connector_snapshot(
|
||||
session,
|
||||
operator,
|
||||
registry=registry,
|
||||
connector_snapshot_ref=acquired.snapshot.ref,
|
||||
)
|
||||
if not created or replay_created or imported_replay.id != imported.id:
|
||||
raise RuntimeError("Risk Compliance snapshot import is not idempotent.")
|
||||
|
||||
subject = SanctionsScreeningSubject(
|
||||
subject_type="person",
|
||||
primary_name="Alex Example",
|
||||
subject_ref="party:fixture-person-1",
|
||||
)
|
||||
policy = SanctionsScreeningPolicy(failure_policy="block")
|
||||
request = SanctionsScreeningRequest(
|
||||
list_snapshot_id=imported.id,
|
||||
idempotency_key="fixture-party-screening-1",
|
||||
subject=subject,
|
||||
policy=policy,
|
||||
)
|
||||
screened = screening_provider.request_screening(
|
||||
session,
|
||||
operator,
|
||||
request,
|
||||
)
|
||||
screened_replay = screening_provider.request_screening(
|
||||
session,
|
||||
operator,
|
||||
request,
|
||||
)
|
||||
if not screened.created or screened_replay.created:
|
||||
raise RuntimeError("Screening request idempotency is not stable.")
|
||||
if screened.evidence.ref != screened_replay.evidence.ref:
|
||||
raise RuntimeError("Screening replay returned different evidence.")
|
||||
if screened.evidence.outcome != "potential" or screened.evidence.candidate_count != 1:
|
||||
raise RuntimeError(f"Synthetic match was not reviewable: {screened.evidence!r}")
|
||||
|
||||
run = get_screening_run(
|
||||
session,
|
||||
operator,
|
||||
run_id=screened.evidence.run_id,
|
||||
)
|
||||
candidate, disposition = record_disposition(
|
||||
session,
|
||||
reviewer,
|
||||
candidate_id=run.candidates[0].id,
|
||||
disposition=DispositionInput(
|
||||
decision="false_positive",
|
||||
reason="Independent fixture evidence excludes the screened party.",
|
||||
evidence_refs=(acquired.snapshot.raw_evidence_ref,),
|
||||
),
|
||||
)
|
||||
if candidate.review_status != "false_positive":
|
||||
raise RuntimeError("Independent review did not resolve the candidate.")
|
||||
if disposition.separation_status != "independent":
|
||||
raise RuntimeError("Reviewer separation evidence was not retained.")
|
||||
|
||||
cleared = screening_provider.check_freshness(
|
||||
session,
|
||||
operator,
|
||||
SanctionsScreeningFreshnessRequest(
|
||||
evidence_ref=screened.evidence.ref,
|
||||
current_subject=subject,
|
||||
expected_list_snapshot_id=imported.id,
|
||||
policy=policy,
|
||||
),
|
||||
)
|
||||
if not cleared.fresh or cleared.gate_decision != "allow":
|
||||
raise RuntimeError(f"Reviewed evidence did not clear the gate: {cleared!r}")
|
||||
|
||||
# Acquisition and review are separate durable commands in production.
|
||||
session.commit()
|
||||
session.expire_all()
|
||||
|
||||
refreshed = refresh_source(
|
||||
session,
|
||||
operator,
|
||||
provider_id=SYNTHETIC_PROVIDER_ID,
|
||||
idempotency_key="synthetic-sanctions-2026-08-02",
|
||||
)
|
||||
if refreshed.snapshot is None or refreshed.snapshot.ref == acquired.snapshot.ref:
|
||||
raise RuntimeError("A new acquisition did not create new immutable evidence.")
|
||||
current, current_created = import_connector_snapshot(
|
||||
session,
|
||||
operator,
|
||||
registry=registry,
|
||||
connector_snapshot_ref=refreshed.snapshot.ref,
|
||||
)
|
||||
if not current_created:
|
||||
raise RuntimeError("The refreshed list state was not imported separately.")
|
||||
|
||||
stale = screening_provider.check_freshness(
|
||||
session,
|
||||
operator,
|
||||
SanctionsScreeningFreshnessRequest(
|
||||
evidence_ref=screened.evidence.ref,
|
||||
current_subject=subject,
|
||||
expected_list_snapshot_id=current.id,
|
||||
policy=policy,
|
||||
),
|
||||
)
|
||||
if stale.fresh or stale.gate_decision != "block":
|
||||
raise RuntimeError(f"Changed source evidence did not close the gate: {stale!r}")
|
||||
if "source_snapshot_changed" not in stale.reasons:
|
||||
raise RuntimeError("Source change provenance was not reported.")
|
||||
requirements = list_rescreening_requirements(session, operator)
|
||||
if screened.evidence.run_id not in {item.run.id for item in requirements}:
|
||||
raise RuntimeError("The stale screening is absent from the rescreening queue.")
|
||||
|
||||
session.commit()
|
||||
if session.query(RecoveryOperation).count() != 2:
|
||||
raise RuntimeError("Connector acquisition recovery evidence is incomplete.")
|
||||
if session.query(RiskScreeningDisposition).count() != 1:
|
||||
raise RuntimeError("Disposition evidence was duplicated or lost.")
|
||||
finally:
|
||||
bind_process_runtime_identity(None)
|
||||
engine.dispose()
|
||||
|
||||
print(
|
||||
"Connectors -> immutable sanctions snapshot -> Risk Compliance review "
|
||||
"and rescreening composition passed."
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
def _principal(account_id: str, *, operational: bool) -> ApiPrincipal:
|
||||
scopes = {
|
||||
SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
}
|
||||
if operational:
|
||||
scopes.update(
|
||||
{
|
||||
CONNECTOR_SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_REFRESH_SCOPE,
|
||||
SANCTIONS_ADMIN_SCOPE,
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
}
|
||||
)
|
||||
return ApiPrincipal(
|
||||
principal=PrincipalRef(
|
||||
account_id=account_id,
|
||||
membership_id=f"membership-{account_id}",
|
||||
tenant_id="tenant-1",
|
||||
scopes=frozenset(scopes),
|
||||
),
|
||||
account=SimpleNamespace(id=account_id),
|
||||
user=SimpleNamespace(id=f"membership-{account_id}"),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user