feat: implement sanctions screening vertical
This commit is contained in:
@@ -1,14 +1,56 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
|
||||
from govoplan_core.core.modules import DocumentationLink, DocumentationTopic, ModuleManifest, PermissionDefinition, RoleTemplate
|
||||
from pathlib import Path
|
||||
|
||||
from govoplan_core.core.access import (
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
||||
)
|
||||
from govoplan_core.core.module_guards import (
|
||||
drop_table_retirement_provider,
|
||||
persistent_table_uninstall_guard,
|
||||
)
|
||||
from govoplan_core.core.modules import (
|
||||
DocumentationLink,
|
||||
DocumentationTopic,
|
||||
FrontendModule,
|
||||
FrontendRoute,
|
||||
MigrationSpec,
|
||||
ModuleInterfaceRequirement,
|
||||
ModuleManifest,
|
||||
NavItem,
|
||||
PermissionDefinition,
|
||||
RoleTemplate,
|
||||
)
|
||||
from govoplan_core.core.views import ViewSurface
|
||||
from govoplan_core.db.base import Base
|
||||
from govoplan_risk_compliance.backend.db.models import (
|
||||
RiskSanctionsAddress,
|
||||
RiskSanctionsAlias,
|
||||
RiskSanctionsDate,
|
||||
RiskSanctionsEntry,
|
||||
RiskSanctionsIdentifier,
|
||||
RiskSanctionsListSnapshot,
|
||||
RiskScreeningCandidate,
|
||||
RiskScreeningDisposition,
|
||||
RiskScreeningException,
|
||||
RiskScreeningRun,
|
||||
RiskScreeningSubjectSnapshot,
|
||||
)
|
||||
from govoplan_risk_compliance.backend.permissions import (
|
||||
ADMIN_SCOPE,
|
||||
READ_SCOPE,
|
||||
SANCTIONS_ADMIN_SCOPE,
|
||||
SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
WRITE_SCOPE,
|
||||
)
|
||||
|
||||
|
||||
MODULE_ID = "risk_compliance"
|
||||
MODULE_NAME = "Risk Compliance"
|
||||
MODULE_VERSION = "0.1.8"
|
||||
READ_SCOPE = "risk_compliance:workspace:read"
|
||||
WRITE_SCOPE = "risk_compliance:workspace:write"
|
||||
ADMIN_SCOPE = "risk_compliance:workspace:admin"
|
||||
OPTIONAL_DEPENDENCIES = (
|
||||
"audit",
|
||||
"policy",
|
||||
@@ -17,10 +59,28 @@ OPTIONAL_DEPENDENCIES = (
|
||||
"files",
|
||||
"tasks",
|
||||
"notifications",
|
||||
"connectors",
|
||||
)
|
||||
_PERSISTENT_MODELS = (
|
||||
RiskScreeningException,
|
||||
RiskScreeningDisposition,
|
||||
RiskScreeningCandidate,
|
||||
RiskScreeningRun,
|
||||
RiskScreeningSubjectSnapshot,
|
||||
RiskSanctionsAddress,
|
||||
RiskSanctionsDate,
|
||||
RiskSanctionsIdentifier,
|
||||
RiskSanctionsAlias,
|
||||
RiskSanctionsEntry,
|
||||
RiskSanctionsListSnapshot,
|
||||
)
|
||||
|
||||
|
||||
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
|
||||
def _permission(
|
||||
scope: str,
|
||||
label: str,
|
||||
description: str,
|
||||
) -> PermissionDefinition:
|
||||
module_id, resource, action = scope.split(":", 2)
|
||||
return PermissionDefinition(
|
||||
scope=scope,
|
||||
@@ -35,52 +95,159 @@ def _permission(scope: str, label: str, description: str) -> PermissionDefinitio
|
||||
|
||||
|
||||
PERMISSIONS = (
|
||||
_permission(READ_SCOPE, "View risk compliance workspace", "Read risk compliance records, configuration, and workflow context."),
|
||||
_permission(WRITE_SCOPE, "Manage risk compliance workspace", "Create and update risk compliance records and workflow state."),
|
||||
_permission(ADMIN_SCOPE, "Administer risk compliance workspace", "Configure risk compliance policies, templates, and tenant-level administration."),
|
||||
_permission(
|
||||
READ_SCOPE,
|
||||
"View risk compliance workspace",
|
||||
"Read risk compliance records, configuration, and workflow context.",
|
||||
),
|
||||
_permission(
|
||||
WRITE_SCOPE,
|
||||
"Manage risk compliance workspace",
|
||||
"Create and update risk compliance records and workflow state.",
|
||||
),
|
||||
_permission(
|
||||
ADMIN_SCOPE,
|
||||
"Administer risk compliance workspace",
|
||||
"Configure risk compliance policies, templates, and tenant administration.",
|
||||
),
|
||||
_permission(
|
||||
SANCTIONS_READ_SCOPE,
|
||||
"View sanctions screening evidence",
|
||||
"Read list snapshots, screening runs, and candidate evidence.",
|
||||
),
|
||||
_permission(
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
"Run sanctions screening",
|
||||
"Submit subjects for deterministic screening against an immutable list.",
|
||||
),
|
||||
_permission(
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
"Review sanctions candidates",
|
||||
"Record evidence-backed candidate dispositions.",
|
||||
),
|
||||
_permission(
|
||||
SANCTIONS_ADMIN_SCOPE,
|
||||
"Administer sanctions screening",
|
||||
"Import source snapshots, configure policy, and authorize review overrides.",
|
||||
),
|
||||
)
|
||||
|
||||
ROLE_TEMPLATES = (
|
||||
RoleTemplate(
|
||||
slug="risk_compliance_manager",
|
||||
name="Risk Compliance manager",
|
||||
description="Manage risk compliance records and workflow state.",
|
||||
permissions=(READ_SCOPE, WRITE_SCOPE),
|
||||
description=(
|
||||
"Manage compliance workflows and administer sanctions screening."
|
||||
),
|
||||
permissions=(
|
||||
READ_SCOPE,
|
||||
WRITE_SCOPE,
|
||||
SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
SANCTIONS_ADMIN_SCOPE,
|
||||
),
|
||||
),
|
||||
RoleTemplate(
|
||||
slug="risk_compliance_reviewer",
|
||||
name="Risk Compliance reviewer",
|
||||
description=(
|
||||
"Run screenings and independently review potential matches."
|
||||
),
|
||||
permissions=(
|
||||
READ_SCOPE,
|
||||
SANCTIONS_READ_SCOPE,
|
||||
SANCTIONS_SCREEN_SCOPE,
|
||||
SANCTIONS_REVIEW_SCOPE,
|
||||
),
|
||||
),
|
||||
RoleTemplate(
|
||||
slug="risk_compliance_viewer",
|
||||
name="Risk Compliance viewer",
|
||||
description="Read risk compliance records and workflow context.",
|
||||
permissions=(READ_SCOPE,),
|
||||
description="Read risk compliance records and screening evidence.",
|
||||
permissions=(READ_SCOPE, SANCTIONS_READ_SCOPE),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _route_factory(_context):
|
||||
from govoplan_risk_compliance.backend.router import router
|
||||
|
||||
return router
|
||||
|
||||
|
||||
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
|
||||
return {
|
||||
"risk_sanctions_list_snapshots": (
|
||||
session.query(RiskSanctionsListSnapshot)
|
||||
.filter(
|
||||
RiskSanctionsListSnapshot.tenant_id == tenant_id
|
||||
)
|
||||
.count()
|
||||
),
|
||||
"risk_screening_runs": (
|
||||
session.query(RiskScreeningRun)
|
||||
.filter(RiskScreeningRun.tenant_id == tenant_id)
|
||||
.count()
|
||||
),
|
||||
"risk_pending_screening_candidates": (
|
||||
session.query(RiskScreeningCandidate)
|
||||
.filter(
|
||||
RiskScreeningCandidate.tenant_id == tenant_id,
|
||||
RiskScreeningCandidate.review_status.in_(
|
||||
("pending", "exception_review")
|
||||
),
|
||||
)
|
||||
.count()
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
DOCUMENTATION = (
|
||||
DocumentationTopic(
|
||||
id=f"{MODULE_ID}.module-boundary",
|
||||
title=f"{MODULE_NAME} module boundary",
|
||||
summary="Risk and compliance workflows for data protection incidents, DPIAs, compliance controls, audit measures, risk registers, and internal-control evidence.",
|
||||
summary=(
|
||||
"Risk and compliance workflows own legal evaluation, immutable "
|
||||
"screening evidence, review, and dispositions."
|
||||
),
|
||||
body=(
|
||||
"This repository is currently a platform module seed. It registers the domain boundary, "
|
||||
"permission surface, role templates, and documentation metadata before runtime APIs, "
|
||||
"database models, migrations, and WebUI routes are introduced."
|
||||
"Connectors may acquire source evidence, but Risk Compliance "
|
||||
"owns immutable normalized sanctions lists, version-pinned "
|
||||
"screening, candidate review, and legal dispositions. Fuzzy "
|
||||
"matching only creates candidates and never confirms a match."
|
||||
),
|
||||
layer="available",
|
||||
documentation_types=("admin",),
|
||||
audience=("operator", "module_admin", "product_owner"),
|
||||
documentation_types=("admin", "user"),
|
||||
audience=(
|
||||
"operator",
|
||||
"module_admin",
|
||||
"compliance_reviewer",
|
||||
),
|
||||
order=100,
|
||||
related_modules=OPTIONAL_DEPENDENCIES,
|
||||
links=(
|
||||
DocumentationLink(
|
||||
label="Repository domain boundary",
|
||||
href="govoplan-risk-compliance/docs/RISK_COMPLIANCE_DOMAIN_BOUNDARY.md",
|
||||
href=(
|
||||
"govoplan-risk-compliance/"
|
||||
"docs/RISK_COMPLIANCE_DOMAIN_BOUNDARY.md"
|
||||
),
|
||||
kind="repository",
|
||||
),
|
||||
),
|
||||
metadata={
|
||||
"seed": True,
|
||||
"domain_objects": ['risk registers', 'compliance controls', 'DPIA records', 'data protection incident records', 'audit measures', 'internal-control evidence'],
|
||||
"first_slice": "Define risk register, control, evidence, DPIA, incident, measure, and review-cycle concepts.",
|
||||
"domain_objects": [
|
||||
"sanctions list snapshots",
|
||||
"screening runs",
|
||||
"candidate evidence",
|
||||
"review dispositions",
|
||||
"time-bounded exceptions",
|
||||
],
|
||||
"privacy": (
|
||||
"Queue and audit summaries contain stable references and "
|
||||
"minimal subject data."
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -91,12 +258,111 @@ manifest = ModuleManifest(
|
||||
version=MODULE_VERSION,
|
||||
dependencies=("access",),
|
||||
optional_dependencies=OPTIONAL_DEPENDENCIES,
|
||||
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
||||
required_capabilities=(
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
||||
),
|
||||
requires_interfaces=(
|
||||
ModuleInterfaceRequirement(
|
||||
name="connectors.sanctions_snapshots",
|
||||
version_min="1.0.0",
|
||||
version_max_exclusive="2.0.0",
|
||||
optional=True,
|
||||
),
|
||||
),
|
||||
permissions=PERMISSIONS,
|
||||
role_templates=ROLE_TEMPLATES,
|
||||
route_factory=_route_factory,
|
||||
frontend=FrontendModule(
|
||||
module_id=MODULE_ID,
|
||||
package_name="@govoplan/risk-compliance-webui",
|
||||
routes=(
|
||||
FrontendRoute(
|
||||
path="/risk-compliance",
|
||||
component="RiskCompliancePage",
|
||||
required_any=(SANCTIONS_READ_SCOPE,),
|
||||
order=115,
|
||||
surface_id="risk_compliance.workspace",
|
||||
),
|
||||
),
|
||||
nav_items=(
|
||||
NavItem(
|
||||
path="/risk-compliance",
|
||||
label="Risk Compliance",
|
||||
icon="shield-check",
|
||||
required_any=(SANCTIONS_READ_SCOPE,),
|
||||
order=115,
|
||||
surface_id="risk_compliance.navigation",
|
||||
),
|
||||
),
|
||||
view_surfaces=(
|
||||
ViewSurface(
|
||||
id="risk_compliance.sanctions.sources",
|
||||
module_id=MODULE_ID,
|
||||
kind="section",
|
||||
label="Sanctions source snapshots",
|
||||
order=20,
|
||||
),
|
||||
ViewSurface(
|
||||
id="risk_compliance.sanctions.screening",
|
||||
module_id=MODULE_ID,
|
||||
kind="section",
|
||||
label="Sanctions screening",
|
||||
order=30,
|
||||
),
|
||||
ViewSurface(
|
||||
id="risk_compliance.sanctions.review",
|
||||
module_id=MODULE_ID,
|
||||
kind="section",
|
||||
label="Sanctions review queue",
|
||||
order=40,
|
||||
),
|
||||
),
|
||||
),
|
||||
tenant_summary_providers=(_tenant_summary,),
|
||||
migration_spec=MigrationSpec(
|
||||
module_id=MODULE_ID,
|
||||
metadata=Base.metadata,
|
||||
script_location=str(
|
||||
Path(__file__).with_name("migrations") / "versions"
|
||||
),
|
||||
migration_after=("connectors",),
|
||||
retirement_supported=True,
|
||||
retirement_provider=drop_table_retirement_provider(
|
||||
*_PERSISTENT_MODELS,
|
||||
label="Risk Compliance",
|
||||
),
|
||||
retirement_notes=(
|
||||
"Destructive retirement removes immutable sanctions list, "
|
||||
"screening, and review evidence after a database snapshot."
|
||||
),
|
||||
),
|
||||
uninstall_guard_providers=(
|
||||
persistent_table_uninstall_guard(
|
||||
*_PERSISTENT_MODELS,
|
||||
label="Risk Compliance",
|
||||
),
|
||||
),
|
||||
documentation=DOCUMENTATION,
|
||||
)
|
||||
|
||||
|
||||
def get_manifest() -> ModuleManifest:
|
||||
return manifest
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ADMIN_SCOPE",
|
||||
"MODULE_ID",
|
||||
"MODULE_VERSION",
|
||||
"PERMISSIONS",
|
||||
"READ_SCOPE",
|
||||
"ROLE_TEMPLATES",
|
||||
"SANCTIONS_ADMIN_SCOPE",
|
||||
"SANCTIONS_READ_SCOPE",
|
||||
"SANCTIONS_REVIEW_SCOPE",
|
||||
"SANCTIONS_SCREEN_SCOPE",
|
||||
"WRITE_SCOPE",
|
||||
"get_manifest",
|
||||
"manifest",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user