From 2b5c155f575e675eab6ec75673d11914c100a11d Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 16 Jun 2026 18:38:58 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Mandanten-Suppression=20API-=C3=9Cberga?= =?UTF-8?q?be=20an=20Controls/CRA-Session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend (Suppression-API + Filter) ist live; Frontend-Mark/Unmark (Cyber-Risiko- Projekt + Workspace) wird übergeben. Endpunkte, Integration, offenes Mapping (Anzeige-Entität → control_uuid) dokumentiert. Co-Authored-By: Claude Opus 4.8 --- .../development/control-suppression-api.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs-src/development/control-suppression-api.md diff --git a/docs-src/development/control-suppression-api.md b/docs-src/development/control-suppression-api.md new file mode 100644 index 00000000..8cfb74ba --- /dev/null +++ b/docs-src/development/control-suppression-api.md @@ -0,0 +1,47 @@ +# Mandanten-Suppression — API-Übergabe (Backend fertig, UI offen) + +**Status (2026-06-16):** Backend **LIVE auf prod + macmini**. Frontend-UI +(Mark/Unmark) ist **offen** und an die Controls/CRA-Session übergeben. + +## Was es tut +Ein Mandant markiert ein Control als „nicht anwendbar / unbrauchbar" → es wird +in seinen Use-Case-Ansichten (und künftig Repo-Scans) **ausgeblendet**. +**Per-Tenant**, **reversibel** (nie gelöscht), **audit-geloggt** (wer/warum/wann). +Geteilte Schicht für **alle** Surfaces — jede UI ruft dieselbe API mit ihrem +`X-Tenant-ID`. + +## API (backend-compliance) +Alle Routen: Tenant über Header `X-Tenant-ID` (UUID). + +- `GET /v1/controls/suppressions[?include_reverted=true]` + → Liste der Suppressions des Mandanten (Audit: control_uuid, reason, actor, + active, created_at, reverted_at/by, control_id, title). +- `POST /v1/controls/suppressions` Body: `{"control_uuid": "...", "reason": "...", "actor": "..."}` + → markiert als nicht anwendbar (idempotent; reaktiviert eine zurückgenommene). +- `POST /v1/controls/suppressions/{control_uuid}/revert` Body: `{"reason": "...", "actor": "..."}` + → nimmt zurück (Zeile bleibt für Audit). + +## Integration in die Controls-Ansicht +`GET /v1/controls/use-cases/{use_case}/controls` (atom-grain) berücksichtigt die +Suppression **nur wenn `X-Tenant-ID` mitgeschickt wird** (Agenten/CRA ohne Tenant +unberührt): +- Default: suppressed Controls **ausgeblendet**. `?include_suppressed=true` zeigt sie. +- Response: `suppressed_count` (Anzahl ausgeblendet im aktuellen Scope) + pro + Control ein `suppressed`-Flag (true wenn eingeblendet). + +## Zu bauen (Übergabe) +1. **Cyber-Risikobeurteilungs-Projekt** (admin-compliance): „nicht anwendbar"-Button + pro Maßnahme/Control + „X ausgeblendet — anzeigen"-Toggle + Un-Mark. + **KLÄREN:** Tragen die dort angezeigten „Maßnahmen" eine `control_uuid` (dann + direkt `POST suppressions` mit dieser UUID)? Falls es CRA-M5xx / Findings sind, + braucht es ein Mapping Anzeige-Entität → `control_uuid` (oder eine Erweiterung + der Suppression auf diese Entität). +2. **Workspace-Cockpit** (breakpilot-workspace, Anwälte): gleiche API, eigenes Frontend. + +## Datenmodell +Tabelle `compliance.control_suppressions` (Migration 156, FK-los — prod +`canonical_controls` hatte nach dem DB-Swap keinen PK; mit Migration 157 +wiederhergestellt). PK `(tenant_id, control_uuid)`, `active` + `reverted_*` für +Reversibilität, `actor`/`reason`/`created_at` für Audit. Geteilter Filter-Helper: +`compliance.services.control_suppression.suppressed_control_uuids(db, tenant_id)` +— auch für Repo-Scans nutzbar.