feat(postbox): add governed DSAR coverage

This commit is contained in:
2026-08-21 00:46:06 +02:00
parent 8a21876634
commit e5da713d5f
5 changed files with 1868 additions and 1 deletions
File diff suppressed because it is too large Load Diff
+136
View File
@@ -18,6 +18,8 @@ from govoplan_core.core.module_guards import (
persistent_table_uninstall_guard,
)
from govoplan_core.core.modules import (
CapabilityDocumentation,
DocumentationCondition,
DocumentationLink,
DocumentationTopic,
FrontendModule,
@@ -53,6 +55,7 @@ from govoplan_core.core.tasks import WorkItemProviderRegistration
from govoplan_core.core.views import ViewSurface
from govoplan_core.db.base import Base
from govoplan_postbox.backend.db import models as postbox_models
from govoplan_postbox.backend.dsar_provider import POSTBOX_DSAR_CAPABILITY
from govoplan_postbox.backend.search_source import create_postbox_search_source
from govoplan_postbox.backend.permissions import (
ACKNOWLEDGE_SCOPE,
@@ -181,6 +184,13 @@ def _work_items(context: ModuleContext):
return PostboxWorkItemProvider(registry=context.registry)
def _postbox_dsar_provider(context: ModuleContext) -> object:
del context
from govoplan_postbox.backend.dsar_provider import PostboxDsarProvider
return PostboxDsarProvider()
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
return {
"postboxes": session.query(postbox_models.Postbox)
@@ -260,6 +270,7 @@ manifest = ModuleManifest(
CAPABILITY_POSTBOX_EVIDENCE,
CAPABILITY_POSTBOX_ROUTING,
CAPABILITY_POSTBOX_PORTAL,
POSTBOX_DSAR_CAPABILITY,
)
),
requires_interfaces=(
@@ -444,8 +455,133 @@ manifest = ModuleManifest(
"govoplan_postbox.backend.portal_projection",
fromlist=["create_portal_projection"],
).create_portal_projection(context),
POSTBOX_DSAR_CAPABILITY: _postbox_dsar_provider,
},
capability_documentation={
POSTBOX_DSAR_CAPABILITY: CapabilityDocumentation(
label="Postbox data-subject request provider",
summary=(
"Finds bounded personal Postbox communication, preference, access, "
"and governance metadata without exposing ciphertext, keys, tokens, "
"opaque metadata, or unrelated participants."
),
contract_version="0.1.0",
documentation_types=("admin",),
audience=("privacy_officer", "postbox_admin", "records_manager"),
),
},
documentation=(
DocumentationTopic(
id="postbox.privacy.data-subject-requests",
title="Review Postbox data in a data-subject request",
summary=(
"Collect tenant-scoped personal Postbox data while preserving "
"institutional communication, access, and protection evidence."
),
body=(
"Postbox searches corroborated account, identity, membership, email, "
"assignment, and namespaced Postbox references. Results include bounded "
"message content for privacy review, only matching participant data, "
"personal read and acknowledgement receipts, personal unified-inbox "
"groupings, attributed access events, and configuration or content-"
"protection authorship. Delivery, routing, receipt, access, template, and "
"protection-transition records retain explicit institutional evidence "
"reasons. Ciphertext, server envelopes, wrapped keys, external-recipient "
"tokens, opaque metadata, transition evidence payloads, and unrelated "
"participants are never exported by this provider. Personal groupings are "
"the only automated erasure action: execution rechecks tenant, owner, and "
"revision, then removes only the projection. Messages and other "
"institutional records require a separate authorized retention, third-party "
"privacy, and records review. Files, producer modules, Identity, and IDM "
"remain authoritative for their own data."
),
layer="configured",
documentation_types=("admin",),
audience=(
"privacy_officer",
"postbox_admin",
"records_manager",
"operator",
),
related_modules=(
"access",
"audit",
"files",
"identity",
"idm",
"records",
),
conditions=(
DocumentationCondition(
required_modules=("postbox", "access"),
any_scopes=(
"access:privacy:read",
"access:privacy:manage",
"access:privacy:erase",
),
),
),
links=(
DocumentationLink(
label="Data-subject requests",
href="/admin?section=tenant-data-subject-requests",
kind="runtime",
),
DocumentationLink(
label="Postbox concept",
href="docs/POSTBOX_CONCEPT.md",
kind="source",
),
),
translations={
"de": {
"title": "Postfachdaten in einem Betroffenenersuchen prüfen",
"summary": (
"Mandantenbezogene personenbezogene Postfachdaten erfassen "
"und institutionelle Kommunikations-, Zugriffs- und "
"Schutznachweise bewahren."
),
"body": (
"Postbox sucht nach bestätigten Konto-, Identitäts-, "
"Mitgliedschafts-, E-Mail-, Zuweisungs- und namensraumgebundenen "
"Postbox-Referenzen. Die Ergebnisse enthalten begrenzte "
"Nachrichteninhalte zur Datenschutzprüfung, ausschließlich passende "
"Beteiligtenangaben, persönliche Lese- und Bestätigungsbelege, "
"persönliche Sammelansichten, zugeordnete Zugriffsereignisse sowie "
"Urheberschaft an Konfigurationen und Inhaltsschutzwechseln. "
"Zustellung, Routing, Empfangsbelege, Zugriff, Vorlagen und "
"Schutzwechsel behalten ausdrückliche institutionelle "
"Aufbewahrungsgründe. Chiffrate, Server-Umschläge, umhüllte "
"Schlüssel, externe Empfänger-Token, undurchsichtige Metadaten, "
"Nachweisnutzdaten von Schutzwechseln und Angaben unbeteiligter "
"Personen werden niemals exportiert. Nur persönliche "
"Sammelansichten können automatisiert gelöscht werden: Die "
"Ausführung prüft Mandant, Eigentümer und Revision erneut und "
"entfernt weder Quellpostfächer noch Nachrichten. Nachrichten und "
"andere institutionelle Datensätze benötigen eine gesondert "
"autorisierte Aufbewahrungs-, Drittschutz- und Aktenprüfung. Files, "
"erzeugende Module, Identity und IDM bleiben für ihre Daten "
"zuständig."
),
}
},
metadata={
"kind": "workflow",
"route": "/admin?section=tenant-data-subject-requests",
"help_contexts": ["admin.privacy.data-subject-requests"],
"steps": [
"Run the Postbox provider and review message, participant, receipt, grouping, access, and governance dispositions.",
"Retain institutional delivery, routing, acknowledgement, access, and protection evidence with its reason.",
"Review plaintext content for third-party data and applicable records or hold policy before a separate lifecycle action.",
"Execute personal-grouping deletion only from a fresh plan; verify source Postboxes and messages remain unchanged.",
],
"limitations": [
"Encrypted content is reported by protection state but is not decrypted or exported by the provider.",
"Attachment payloads, producer records, identity records, and assignment records remain with their owning modules.",
],
},
order=31,
),
DocumentationTopic(
id="postbox.files.evidence-references",
title="Open permitted Files evidence from Postbox",