feat: provide access DSAR integration

This commit is contained in:
2026-08-07 14:53:24 +02:00
parent e04671034f
commit 0b9e3751c2
3 changed files with 819 additions and 0 deletions
+79
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
from pathlib import Path
from govoplan_access.backend.configuration_provider import ACCESS_CONFIGURATION_CAPABILITY
from govoplan_access.backend.dsar_provider import ACCESS_DSAR_CAPABILITY
from govoplan_access.backend.db.base import AccessBase
from govoplan_access.backend.db import models as access_models # noqa: F401 - populate access metadata
from govoplan_core.core.access import (
@@ -105,6 +106,10 @@ ACCESS_PERMISSIONS: tuple[PermissionDefinition, ...] = (
_permission("access:credential:manage_own", "Manage own credentials", "Manage reusable credentials owned by the current membership.", "Tenant access", "tenant"),
_permission("access:policy:read", "View tenant policies", "Read tenant policy and governance settings.", "Tenant access", "tenant"),
_permission("access:policy:write", "Manage tenant policies", "Change tenant policy and governance settings where system policy permits it.", "Tenant access", "tenant"),
_permission("access:privacy:read", "View data-subject requests", "Inspect tenant data-subject requests, provider coverage, and retained evidence decisions.", "Privacy", "tenant"),
_permission("access:privacy:manage", "Manage data-subject requests", "Create requests and run provider searches and erasure planning.", "Privacy", "tenant"),
_permission("access:privacy:export", "Export data-subject requests", "Export the collected personal-data package and its coverage manifest.", "Privacy", "tenant"),
_permission("access:privacy:erase", "Execute data erasure", "Execute explicitly selected, provider-owned erasure and anonymization actions.", "Privacy", "tenant"),
_permission("access:governance:read", "View governance", "Inspect managed role and group templates.", "Access", "system"),
_permission("access:governance:write", "Manage governance", "Create and assign managed role and group templates.", "Access", "system"),
)
@@ -244,6 +249,20 @@ ACCESS_ROLE_TEMPLATES: tuple[RoleTemplate, ...] = (
managed=True,
protected=False,
),
RoleTemplate(
slug="privacy_officer",
name="Privacy officer",
description="Search, export, plan, and execute governed data-subject requests.",
permissions=(
"access:privacy:read",
"access:privacy:manage",
"access:privacy:export",
"access:privacy:erase",
),
level="tenant",
managed=True,
protected=False,
),
)
ADMIN_READ_SCOPES = (
@@ -263,6 +282,7 @@ ADMIN_READ_SCOPES = (
"access:account:read",
"access:governance:read",
"access:function:read",
"access:privacy:read",
"views:definition:read",
"views:assignment:read",
"views:system_definition:read",
@@ -573,6 +593,56 @@ ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
],
},
),
DocumentationTopic(
id="access.workflow.data-subject-request",
title="Process a data-subject request",
summary="Privacy officers search provider-owned data, export a coverage manifest, and execute only reviewed erasure actions while retaining required institutional evidence.",
body=(
"Create a request with at least one stable subject selector, run the cross-module search, and inspect provider coverage before treating the result as complete. "
"For erasure requests, generate a plan and review every provider-owned action. Immutable role, function, and audit evidence remains present with its retention reason; global accounts and identities require system-level review because they may serve more than one tenant. "
"Execution requires the dedicated erasure permission, the current resource revision, selected executable actions, and an exact confirmation phrase. Access anonymizes the tenant membership and revokes active API keys and sessions without deleting stable evidence identifiers."
),
layer="configured",
documentation_types=("admin", "user"),
audience=("privacy_officer", "tenant_owner", "operator"),
order=34,
conditions=(
DocumentationCondition(
required_modules=("access", "admin"),
any_scopes=(
"access:privacy:read",
"access:privacy:manage",
"access:privacy:export",
"access:privacy:erase",
),
),
),
links=(
DocumentationLink(label="Data-subject requests", href="/admin?section=tenant-data-subject-requests", kind="runtime"),
DocumentationLink(label="Data-subject request API", href="/api/v1/admin/privacy/data-subject-requests", kind="api"),
),
translations={
"de": {
"title": "Betroffenenanfrage bearbeiten",
"summary": "Datenschutzbeauftragte suchen modulspezifische Daten, exportieren einen Abdeckungsnachweis und führen nur geprüfte Löschaktionen aus; erforderliche institutionelle Nachweise bleiben erhalten.",
"body": "Legen Sie eine Anfrage mit mindestens einem stabilen Merkmal der betroffenen Person an, führen Sie die modulübergreifende Suche aus und prüfen Sie die Anbieterabdeckung. Erstellen Sie bei Löschanfragen anschließend einen Plan und prüfen Sie jede Aktion. Unveränderliche Rollen-, Funktions- und Auditnachweise bleiben mit Begründung erhalten. Die Ausführung erfordert ein eigenes Recht, die aktuelle Revision, ausgewählte Aktionen und die exakte Bestätigung.",
}
},
metadata={
"kind": "workflow",
"help_contexts": ["admin.privacy.data-subject-requests"],
"permission_scopes": [
"access:privacy:read",
"access:privacy:manage",
"access:privacy:export",
"access:privacy:erase",
],
"limitations": [
"Modules without a DSAR provider are reported as coverage gaps.",
"Global accounts and identities are not erased automatically.",
],
},
),
)
@@ -732,6 +802,13 @@ def _configuration_provider(context: ModuleContext) -> object:
return SqlAccessConfigurationProvider()
def _dsar_provider(context: ModuleContext) -> object:
del context
from govoplan_access.backend.dsar_provider import AccessDsarProvider
return AccessDsarProvider()
def _route_factory(context: ModuleContext):
from fastapi import APIRouter
@@ -773,6 +850,7 @@ manifest = ModuleManifest(
name="auth.automation_principal",
version="0.2.0",
),
ModuleInterfaceProvider(name=ACCESS_DSAR_CAPABILITY, version="0.1.0"),
),
permissions=ACCESS_PERMISSIONS,
role_templates=ACCESS_ROLE_TEMPLATES,
@@ -848,6 +926,7 @@ manifest = ModuleManifest(
CAPABILITY_ACCESS_PEOPLE_SEARCH: _people_search,
CAPABILITY_ACCESS_REFERENCE_OPTIONS: _access_reference_options,
ACCESS_CONFIGURATION_CAPABILITY: _configuration_provider,
ACCESS_DSAR_CAPABILITY: _dsar_provider,
},
documentation=ACCESS_DOCUMENTATION,
architecture=declared_module_architecture(