All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 32s
CI/CD / test-python-backend-compliance (push) Successful in 29s
CI/CD / test-python-document-crawler (push) Successful in 21s
CI/CD / test-python-dsms-gateway (push) Successful in 16s
CI/CD / validate-canonical-controls (push) Successful in 10s
CI/CD / Deploy (push) Successful in 2s
- Delve-Vorfall als Motivation mit konkreten Haftungsrisiken - 6 Guardrails als Mermaid-Diagramm mit Zusammenspiel - Verbindung zu evidence_type (code/process/hybrid) - Sicherheitsarchitektur: Warum E0-E4, warum Four-Eyes nur GOV/PRIV - Same-Person-Schutz Erklaerung (Backend-Level, kein Admin-Bypass) - Hard Blocks: SQL-Beispiele fuer Audit-Sperren - Vollstaendiges DB-Schema (Enums, alle Tabellen, alle Spalten) - Vollstaendige API-Referenz (Evidence, Assertions, Audit-Trail, LLM-Audit) - FAQ-Sektion (E0 loeschen, Four-Eyes Timeout, Assertion-Extraktion) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
814 lines
28 KiB
Markdown
814 lines
28 KiB
Markdown
# Anti-Fake-Evidence Architektur
|
||
|
||
**Status:** Phase 3 (aktiv seit 2026-03-23)
|
||
**Prefix:** CP-AFE
|
||
**Motivation:** Delve-Vorfall (Maerz 2026) — Compliance-Theater verhindern
|
||
|
||
---
|
||
|
||
## Warum dieses System existiert
|
||
|
||
### Das Delve-Problem
|
||
|
||
Im Maerz 2026 wurde bekannt, wie die Compliance-Plattform Delve ein Compliance-Audit
|
||
bestand — ohne dass die Firma tatsaechlich compliant war:
|
||
|
||
1. **LLM-generierte Nachweise** wurden 1:1 als Evidence akzeptiert. Ein GPT-generierter
|
||
Text "Die Organisation hat ein ISMS implementiert" wurde als Nachweis fuer ISO 27001
|
||
Kontrolle A.5 eingesetzt — ohne dass ein ISMS existierte.
|
||
|
||
2. **Controls ohne Evidence** standen auf "pass". Das System erlaubte es, jeden Control-Status
|
||
manuell auf "pass" zu setzen, ohne dass ein einziger Nachweis hochgeladen wurde.
|
||
|
||
3. **100%-Compliance-Dashboards** ohne Validierung. Das Management sah eine gruene 100%-Anzeige
|
||
und glaubte, das Audit sei bestanden — bis der externe Auditor nach Dokumenten fragte.
|
||
|
||
### Haftungsrisiko
|
||
|
||
Wenn eine Compliance-Plattform falsche Compliance suggeriert, haftet:
|
||
|
||
- **Die Firma** — Aufsichtsbehoerden (z.B. BfDI, BaFin) akzeptieren "die Software hat gesagt
|
||
wir sind compliant" nicht als Entschuldigung
|
||
- **Die Geschaeftsfuehrung** — persoenliche Haftung bei DSGVO/NIS2-Verstoessen
|
||
- **Der Plattform-Anbieter** — wenn die Software den Eindruck erweckt, Compliance sei
|
||
nachgewiesen, obwohl sie nur Platzhalter anzeigt
|
||
|
||
### Die 6 Guardrails
|
||
|
||
Die Anti-Fake-Evidence Architektur implementiert 6 Schutzmechanismen:
|
||
|
||
```mermaid
|
||
graph TB
|
||
G1["1. Evidence Confidence Levels<br/>(E0-E4)"]
|
||
G2["2. Truth-Status Lifecycle<br/>(generated → validated)"]
|
||
G3["3. Control Status Machine<br/>(pass erfordert Evidence ≥ E2)"]
|
||
G4["4. Four-Eyes-Prinzip<br/>(GOV/PRIV: 2 unabhaengige Reviewer)"]
|
||
G5["5. LLM Truth Labels<br/>(may_be_used_as_evidence = false)"]
|
||
G6["6. Verbotene Formulierungen<br/>(keine Claims ohne Nachweis)"]
|
||
|
||
G1 --> G3
|
||
G2 --> G3
|
||
G4 --> G3
|
||
G5 --> G1
|
||
G3 --> G6
|
||
|
||
style G1 fill:#fee2e2,stroke:#dc2626
|
||
style G2 fill:#fef3c7,stroke:#d97706
|
||
style G3 fill:#dbeafe,stroke:#2563eb
|
||
style G4 fill:#d1fae5,stroke:#059669
|
||
style G5 fill:#e0e7ff,stroke:#4f46e5
|
||
style G6 fill:#fce7f3,stroke:#db2777
|
||
```
|
||
|
||
**Zusammenspiel:** Ein Control kann nur auf "pass" stehen, wenn mindestens ein Evidence
|
||
mit Confidence >= E2 vorliegt, dessen Truth-Status validiert ist. Bei GOV/PRIV-Controls
|
||
muessen zwei verschiedene Personen den Evidence reviewt haben (Four-Eyes). LLM-generierte
|
||
Inhalte koennen nie als Evidence zaehlen.
|
||
|
||
---
|
||
|
||
## Zusammenspiel mit evidence_type
|
||
|
||
Das [evidence_type Feld](evidence-type.md) (code/process/hybrid) bestimmt,
|
||
**wie** Evidence gesammelt wird. Das Anti-Fake-Evidence System bestimmt,
|
||
**ob** die gesammelte Evidence valide ist:
|
||
|
||
| evidence_type | Typische Evidence-Quelle | Confidence | Automatisierbar? |
|
||
|---|---|---|---|
|
||
| `code` | SAST-Report, CI/CD-Pipeline, IaC-Scan | E3 (observed) | Ja — System-beobachtet |
|
||
| `process` | Policy-Dokument, Schulungsnachweis, Vertrag | E1 (uploaded) → E2 (reviewed) | Nein — Review noetig |
|
||
| `hybrid` | Code-Scan + Prozess-Doku | E1-E3 gemischt | Teilweise |
|
||
|
||
!!! warning "Code Controls sind nicht automatisch valide"
|
||
Auch ein SAST-Report (E3) muss einen validen Truth-Status haben.
|
||
Ein veralteter Scan (> 90 Tage) wird als "stale" markiert und reduziert
|
||
die Evidence Freshness im Dashboard-Score.
|
||
|
||
---
|
||
|
||
## Evidence Confidence Levels (E0–E4)
|
||
|
||
| Level | Bezeichnung | Beschreibung | Beispiel |
|
||
|-------|-------------|--------------|----------|
|
||
| **E0** | Generated | LLM-Output, Platzhalter | KI-generierter Nachweis-Entwurf |
|
||
| **E1** | Uploaded | Manuell hochgeladen, ungeprüft | PDF ohne Reviewer |
|
||
| **E2** | Reviewed | Intern geprüft, Hash verifiziert | Dokument von Compliance-Beauftragtem bestätigt |
|
||
| **E3** | Observed | System-beobachtet (CI/CD, API) | Automatischer SAST-Report mit SHA-256 |
|
||
| **E4** | Auditor-validated | Extern validiert | Wirtschaftsprüfer hat akzeptiert |
|
||
|
||
### Auto-Klassifikation
|
||
|
||
| Source | Confidence | Truth Status |
|
||
|--------|-----------|--------------|
|
||
| `ci_pipeline` | E3 | observed |
|
||
| `api` (mit Hash) | E3 | observed |
|
||
| `manual` / `upload` | E1 | uploaded |
|
||
| `generated` | E0 | generated |
|
||
|
||
---
|
||
|
||
## Evidence Truth-Status Lifecycle
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> generated : LLM erzeugt
|
||
[*] --> uploaded : Manuell hochgeladen
|
||
[*] --> observed : CI/CD Pipeline
|
||
|
||
generated --> rejected : Review abgelehnt
|
||
uploaded --> validated_internal : Intern geprueft
|
||
uploaded --> rejected : Review abgelehnt
|
||
observed --> validated_internal : Intern bestaetigt
|
||
|
||
validated_internal --> provided_to_auditor : An Auditor uebergeben
|
||
provided_to_auditor --> accepted_by_auditor : Auditor akzeptiert
|
||
provided_to_auditor --> rejected : Auditor lehnt ab
|
||
```
|
||
|
||
---
|
||
|
||
## Control Status-Transition State Machine
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
planned --> in_progress : immer erlaubt
|
||
in_progress --> pass : Evidence >= E2 + truth_status valid
|
||
in_progress --> partial : min 1 Evidence (beliebig)
|
||
in_progress --> fail : immer erlaubt
|
||
pass --> fail : Degradation (immer)
|
||
partial --> pass : Evidence >= E2 + truth_status valid
|
||
|
||
note right of pass
|
||
Voraussetzung: min 1 Evidence
|
||
mit confidence >= E2 UND
|
||
truth_status in (uploaded,
|
||
observed, validated_internal,
|
||
accepted_by_auditor)
|
||
end note
|
||
```
|
||
|
||
### Transition-Regeln
|
||
|
||
| Von | Nach | Voraussetzung |
|
||
|-----|------|---------------|
|
||
| planned | in_progress | keine |
|
||
| in_progress | pass | min 1 Evidence mit confidence >= E2, truth_status valide |
|
||
| in_progress | partial | min 1 Evidence (beliebig) |
|
||
| in_progress | fail | immer erlaubt |
|
||
| pass | fail | immer erlaubt (Degradation) |
|
||
| * | n/a | erfordert `status_justification` |
|
||
| * | planned | immer erlaubt (Reset) |
|
||
|
||
Bei Verstoß: **HTTP 409 Conflict** mit Liste der Violations.
|
||
|
||
---
|
||
|
||
## LLM Truth-Labels
|
||
|
||
Jeder LLM-generierte Inhalt wird mit einem Truth-Label versehen:
|
||
|
||
```json
|
||
{
|
||
"generation_mode": "draft_assistance",
|
||
"truth_status": "generated",
|
||
"may_be_used_as_evidence": false,
|
||
"generated_by": "system"
|
||
}
|
||
```
|
||
|
||
### Audit-Trail
|
||
|
||
Tabelle `compliance_llm_generation_audit`:
|
||
|
||
| Feld | Typ | Beschreibung |
|
||
|------|-----|--------------|
|
||
| entity_type | VARCHAR(50) | 'evidence', 'control', 'document' |
|
||
| entity_id | VARCHAR(36) | FK zur generierten Entitaet |
|
||
| generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' |
|
||
| truth_status | ENUM | generated, uploaded, ... |
|
||
| may_be_used_as_evidence | BOOLEAN | Default: FALSE |
|
||
| llm_model | VARCHAR(100) | z.B. 'qwen2.5vl:32b' |
|
||
| llm_provider | VARCHAR(50) | 'ollama', 'anthropic' |
|
||
| prompt_hash | VARCHAR(64) | SHA-256 des Prompts |
|
||
|
||
---
|
||
|
||
## Multi-dimensionaler Compliance-Score
|
||
|
||
Statt einer einzelnen Prozentzahl zeigt der Score 6 Dimensionen:
|
||
|
||
| Dimension | Gewicht | Beschreibung |
|
||
|-----------|---------|--------------|
|
||
| requirement_coverage | 20% | % Requirements mit verlinktem Control |
|
||
| evidence_strength | 25% | Gewichteter Durchschnitt der Evidence-Confidence |
|
||
| validation_quality | 20% | % Evidence mit truth_status >= validated_internal |
|
||
| evidence_freshness | 10% | % Evidence nicht expired + reviewed < 90 Tage |
|
||
| control_effectiveness | 25% | Bestehende Formel (pass + partial*0.5) |
|
||
| **overall_readiness** | — | Gewichteter Composite der 5 Dimensionen |
|
||
|
||
### Hard Blocks
|
||
|
||
Zusaetzlich werden **Sperrgründe** angezeigt, die eine Audit-Readiness verhindern:
|
||
|
||
- Controls auf 'pass' ohne jegliche Evidence
|
||
- Controls auf 'pass' mit nur E0/E1-Evidence (keine Validierung)
|
||
|
||
---
|
||
|
||
## Verbotene Formulierungen
|
||
|
||
Der Drafting-Engine Validator prueft auf Formulierungen, die **ohne ausreichenden Nachweis** nicht verwendet werden duerfen:
|
||
|
||
| Verboten | Sicher stattdessen |
|
||
|----------|--------------------|
|
||
| "ist compliant" | "soll compliant sein" |
|
||
| "erfuellt vollstaendig" | "soll vollstaendig erfuellt werden" |
|
||
| "wurde geprueft" | "soll geprueft werden" |
|
||
| "wurde umgesetzt" | "ist zur Umsetzung vorgesehen" |
|
||
| "ist auditiert" | "soll auditiert werden" |
|
||
| "vollstaendig implementiert" | "Implementierung ist vorgesehen" |
|
||
| "nachweislich konform" | "Konformitaet ist nachzuweisen" |
|
||
|
||
**Erlaubt nur wenn:** control_status = pass AND confidence >= E2 AND truth_status in (validated_internal, accepted_by_auditor).
|
||
|
||
---
|
||
|
||
## API-Aenderungen
|
||
|
||
### Neue Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---------|------|--------------|
|
||
| PATCH | `/evidence/{id}/review` | Evidence reviewen (Confidence upgraden) |
|
||
| POST | `/llm-audit` | LLM-Generierungs-Audit erstellen |
|
||
| GET | `/llm-audit` | LLM-Audit-Eintraege auflisten |
|
||
|
||
### Erweiterte Responses
|
||
|
||
**EvidenceResponse** — 6 neue Felder:
|
||
|
||
```json
|
||
{
|
||
"confidence_level": "E3",
|
||
"truth_status": "observed",
|
||
"generation_mode": null,
|
||
"may_be_used_as_evidence": true,
|
||
"reviewed_by": null,
|
||
"reviewed_at": null
|
||
}
|
||
```
|
||
|
||
**DashboardResponse** — neues Feld `multi_score`:
|
||
|
||
```json
|
||
{
|
||
"multi_score": {
|
||
"requirement_coverage": 85.0,
|
||
"evidence_strength": 60.0,
|
||
"validation_quality": 40.0,
|
||
"evidence_freshness": 90.0,
|
||
"control_effectiveness": 70.0,
|
||
"overall_readiness": 65.0,
|
||
"hard_blocks": ["3 Controls auf 'pass' haben nur E0/E1-Evidence"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**ControlResponse** — neues Feld `status_justification`.
|
||
|
||
**ControlUpdate** — neues Feld `status_justification` (Pflicht fuer n/a-Transitions).
|
||
|
||
### Status-Transition Fehler (409)
|
||
|
||
```json
|
||
{
|
||
"detail": {
|
||
"error": "Status transition not allowed",
|
||
"current_status": "in_progress",
|
||
"requested_status": "pass",
|
||
"violations": [
|
||
"Transition to 'pass' requires at least 1 evidence with confidence >= E2..."
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Migration
|
||
|
||
### Phase 1
|
||
**Datei:** `backend-compliance/migrations/076_anti_fake_evidence.sql`
|
||
|
||
- Neue ENUM-Typen: `evidence_confidence_level`, `evidence_truth_status`
|
||
- 6 neue Spalten auf `compliance_evidence`
|
||
- `in_progress` Wert fuer `controlstatusenum`
|
||
- `status_justification` auf `compliance_controls`
|
||
- Neue Tabelle `compliance_llm_generation_audit`
|
||
- Backfill bestehender Evidence nach Source
|
||
- Indizes auf neue Spalten
|
||
|
||
### Phase 2
|
||
**Datei:** `backend-compliance/migrations/077_anti_fake_evidence_phase2.sql`
|
||
|
||
- Neue Tabelle `compliance_assertions` (Assertion Engine)
|
||
- 6 neue Spalten auf `compliance_evidence` (Four-Eyes: approval_status, first_reviewer, etc.)
|
||
- Performance-Index auf `compliance_audit_trail (entity_type, action, performed_at)`
|
||
|
||
---
|
||
|
||
## Phase 2: UI-Badges
|
||
|
||
Badges werden auf Evidence-Cards angezeigt und zeigen den Vertrauensstatus auf einen Blick:
|
||
|
||
| Badge | Farben | Anzeige |
|
||
|-------|--------|---------|
|
||
| **ConfidenceLevelBadge** | E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald | Immer |
|
||
| **TruthStatusBadge** | generated=violet, uploaded=grau, observed=blau, validated=gruen, rejected=rot | Immer |
|
||
| **GenerationModeBadge** | violet + Sparkles-Icon | Wenn LLM-generiert |
|
||
| **ApprovalStatusBadge** | pending=gelb, first_approved=blau, approved=gruen, rejected=rot | Nur bei Four-Eyes |
|
||
|
||
---
|
||
|
||
## Phase 2: Assertion Engine
|
||
|
||
Die Assertion Engine trennt **Behauptungen** von **Fakten** in Compliance-Texten.
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Text[Freitext] --> Split[Satz-Splitting]
|
||
Split --> Classify{Normativ?}
|
||
Classify -->|Pflicht| A[Assertion pflicht]
|
||
Classify -->|Empfehlung| B[Assertion empfehlung]
|
||
Classify -->|Kann| C[Assertion kann]
|
||
Classify -->|Begruendung| D[Rationale]
|
||
Classify -->|Evidence-Keywords| E[Fact tentativ]
|
||
E --> Verify[Manuell verifizieren]
|
||
Verify --> Fact[Verified Fact]
|
||
```
|
||
|
||
### Assertion-Typen
|
||
|
||
| Typ | Bedeutung | Beispiel |
|
||
|-----|-----------|----------|
|
||
| **assertion** | Normative Aussage (unbewiesen) | "Die Organisation muss ein ISMS implementieren" |
|
||
| **fact** | Verifizierte Tatsache | "ISO-Zertifikat Nr. 12345 liegt vor" |
|
||
| **rationale** | Begruendung | "Dies ist notwendig, weil..." |
|
||
|
||
### Normative Tiers
|
||
|
||
| Tier | Signal-Woerter |
|
||
|------|---------------|
|
||
| **pflicht** | muss, hat sicherzustellen, ist verpflichtet, shall, must, required |
|
||
| **empfehlung** | soll, sollte, gewaehrleisten, should, ensure |
|
||
| **kann** | kann, darf, may, optional |
|
||
|
||
---
|
||
|
||
## Phase 2: Four-Eyes-Prinzip
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> pending_first : Evidence erstellt (Gov/Priv Domain)
|
||
pending_first --> first_approved : 1. Reviewer OK
|
||
first_approved --> approved : 2. Reviewer OK (andere Person!)
|
||
first_approved --> rejected : 2. Reviewer lehnt ab
|
||
pending_first --> rejected : 1. Reviewer lehnt ab
|
||
|
||
note right of first_approved
|
||
Zweiter Reviewer MUSS
|
||
eine andere Person sein
|
||
als der erste Reviewer
|
||
end note
|
||
```
|
||
|
||
### Domains mit Four-Eyes-Pflicht
|
||
|
||
| Domain | Four-Eyes? | Begruendung |
|
||
|--------|-----------|-------------|
|
||
| `gov` | Ja | Governance-Controls sind audit-kritisch |
|
||
| `priv` | Ja | Datenschutz erfordert unabhaengige Pruefung |
|
||
| `ops`, `sdlc`, `ai`, ... | Nein | Operationale Controls mit Single-Review |
|
||
|
||
---
|
||
|
||
## Phase 2: Audit-Trail-Erweiterung
|
||
|
||
Neue Audit-Trail-Eintraege:
|
||
|
||
| Entity | Action | Wann |
|
||
|--------|--------|------|
|
||
| evidence | create | Bei Evidence-Erstellung |
|
||
| evidence | review | Bei Confidence/Truth-Status-Aenderung |
|
||
| evidence | reject | Bei Evidence-Ablehnung |
|
||
| control | status_change | Bei Control-Status-Aenderung |
|
||
|
||
Jeder Eintrag enthaelt `old_value`, `new_value` und einen SHA-256 `checksum`.
|
||
|
||
Neuer Query-Endpoint: `GET /audit-trail?entity_type=evidence&entity_id={id}`
|
||
|
||
---
|
||
|
||
## Phase 2: Neue API-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---------|------|--------------|
|
||
| PATCH | `/evidence/{id}/reject` | Evidence ablehnen |
|
||
| GET | `/audit-trail` | Audit-Trail abfragen (Filter: entity_type, entity_id, action) |
|
||
| POST | `/assertions` | Assertion manuell erstellen |
|
||
| GET | `/assertions` | Assertions auflisten (Filter: entity_type, entity_id, assertion_type) |
|
||
| GET | `/assertions/{id}` | Assertion Detail |
|
||
| PUT | `/assertions/{id}` | Assertion aktualisieren |
|
||
| POST | `/assertions/{id}/verify` | Als Fakt markieren |
|
||
| POST | `/assertions/extract` | Automatische Extraktion aus Freitext |
|
||
| GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) |
|
||
|
||
### Erweiterte EvidenceResponse (Phase 2)
|
||
|
||
```json
|
||
{
|
||
"approval_status": "first_approved",
|
||
"first_reviewer": "reviewer1@example.com",
|
||
"first_reviewed_at": "2026-03-23T14:00:00Z",
|
||
"second_reviewer": null,
|
||
"second_reviewed_at": null,
|
||
"requires_four_eyes": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 3: Durchsetzung (UI + Dashboard)
|
||
|
||
Phase 3 macht das Anti-Fake-Evidence-System **benutzbar und durchsetzbar** im Frontend.
|
||
|
||
### Evidence Review/Reject UI
|
||
|
||
Die Evidence-Seite bietet jetzt direkte Buttons fuer Review und Ablehnung:
|
||
|
||
- **Reviewen-Button**: Sichtbar wenn `approvalStatus` nicht `approved` oder `rejected`
|
||
- **Ablehnen-Button**: Sichtbar bei Four-Eyes-Evidence die noch nicht abgeschlossen ist
|
||
|
||
**ReviewModal** erlaubt:
|
||
- Confidence-Level aendern (E0-E4 Dropdown)
|
||
- Truth-Status aendern (Dropdown)
|
||
- Reviewer E-Mail angeben
|
||
- Four-Eyes-Warnung wenn noch ein weiterer Review noetig ist
|
||
|
||
**RejectModal** erlaubt:
|
||
- Ablehnungsgrund als Freitext
|
||
- Reviewer E-Mail angeben
|
||
|
||
Bei Four-Eyes Same-Person-Fehler (HTTP 400) wird eine Fehlermeldung angezeigt.
|
||
|
||
### Control Status-Transition Fehlerbehandlung
|
||
|
||
Die Controls-Seite zeigt jetzt detaillierte Fehler bei blockierten Status-Transitionen:
|
||
|
||
- **Optimistic Update mit Rollback**: UI aktualisiert sofort, rollt bei Fehler zurueck
|
||
- **TransitionErrorBanner**: Zeigt Violations-Liste bei HTTP 409 Conflict
|
||
- z.B. "Transition to 'pass' requires at least 1 evidence with confidence >= E2"
|
||
- **Link zur Evidence-Seite**: "Evidence hinzufuegen" direkt im Fehler-Banner
|
||
|
||
### Evidence Audit-Trail Anzeige
|
||
|
||
Neuer "Historie"-Button auf jeder Evidence-Card zeigt den vollstaendigen Audit-Trail:
|
||
|
||
- Timeline mit Zeitstempel, Aktion und Akteur
|
||
- Details zu Feldaenderungen (old_value → new_value)
|
||
- Lazy-Loading: Erst beim Aufklappen wird `GET /audit-trail` abgerufen
|
||
|
||
### Evidence Confidence-Filter
|
||
|
||
Neue Filter-Pills auf der Evidence-Seite:
|
||
|
||
```
|
||
[Alle] [Gueltig] [Abgelaufen] [Ausstehend] | [E0] [E1] [E2] [E3] [E4]
|
||
```
|
||
|
||
Farbcodierung: E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald (passend zu den Badges)
|
||
|
||
### Evidence Confidence-Verteilung (Dashboard)
|
||
|
||
Neuer Endpoint und Dashboard-Bereich:
|
||
|
||
**Endpoint:** `GET /dashboard/evidence-distribution`
|
||
|
||
```json
|
||
{
|
||
"by_confidence": {"E0": 2, "E1": 5, "E2": 3, "E3": 8, "E4": 1},
|
||
"four_eyes_pending": 3,
|
||
"total": 19
|
||
}
|
||
```
|
||
|
||
**Compliance Hub** zeigt:
|
||
- Horizontal gestapelter Balken der Confidence-Verteilung (E0 rot → E4 emerald)
|
||
- Multi-Score Dimensionen als Fortschrittsbalken (5 Dimensionen + Audit-Readiness)
|
||
- Four-Eyes-Warteschlange (Anzahl pending)
|
||
- Hard-Blocks-Liste oder "Keine Hard Blocks" Status
|
||
|
||
### Assertions-Seite
|
||
|
||
Neue Seite unter `/sdk/assertions` mit 3 Tabs:
|
||
|
||
| Tab | Inhalt |
|
||
|-----|--------|
|
||
| **Uebersicht** | Summary-Stats (Assertions, Facts, Rationale, Unverified) |
|
||
| **Assertion-Liste** | Filterbarer Tabelle (entity_type, assertion_type) mit AssertionCards |
|
||
| **Extraktion** | Textfeld + Button → `POST /assertions/extract` |
|
||
|
||
**AssertionCard** zeigt:
|
||
- Normative-Tier als farbiger Badge (Pflicht=rot, Empfehlung=gelb, Kann=blau)
|
||
- Typ-Badge (Assertion/Fact/Rationale)
|
||
- "Als Fakt pruefen"-Button → `POST /assertions/{id}/verify`
|
||
|
||
### Phase 3: Neue API-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---------|------|--------------|
|
||
| GET | `/dashboard/evidence-distribution` | Evidence-Verteilung nach Confidence + Four-Eyes-Status |
|
||
|
||
---
|
||
|
||
## Sicherheitsarchitektur im Detail
|
||
|
||
### Warum E0-E4 und nicht einfach "valide/invalide"?
|
||
|
||
Ein binaeres System ("valide" vs. "invalide") haette ein fundamentales Problem:
|
||
Wo zieht man die Grenze? Ein manuell hochgeladenes PDF ist "besser" als ein
|
||
LLM-Entwurf, aber "schlechter" als ein automatischer SAST-Report.
|
||
|
||
Die 5-stufige Skala erlaubt:
|
||
|
||
1. **Graduelle Verbesserung**: Ein Kunde kann mit E1-Evidence starten und
|
||
schrittweise auf E3/E4 aufruesten
|
||
2. **Risiko-basierte Entscheidungen**: Ein Auditor sieht sofort, welche
|
||
Controls nur auf schwacher Evidence basieren
|
||
3. **Automatische Schwellwerte**: Das System blockiert "pass" unterhalb E2,
|
||
aber zeigt auch E1-Evidence (mit Warnung)
|
||
|
||
```mermaid
|
||
graph LR
|
||
E0["E0<br/>Generated<br/>❌ Kein Nachweis"]
|
||
E1["E1<br/>Uploaded<br/>⚠️ Ungeprüft"]
|
||
E2["E2<br/>Reviewed<br/>✓ Intern geprüft"]
|
||
E3["E3<br/>Observed<br/>✓✓ System-beobachtet"]
|
||
E4["E4<br/>Auditor<br/>✓✓✓ Extern validiert"]
|
||
|
||
E0 --> E1 --> E2 --> E3 --> E4
|
||
|
||
style E0 fill:#fee2e2,stroke:#dc2626
|
||
style E1 fill:#fef3c7,stroke:#d97706
|
||
style E2 fill:#dbeafe,stroke:#2563eb
|
||
style E3 fill:#d1fae5,stroke:#059669
|
||
style E4 fill:#d1fae5,stroke:#047857
|
||
```
|
||
|
||
### Confidence-Gewichtung im Score
|
||
|
||
| Level | Gewicht | Bedeutung |
|
||
|---|---|---|
|
||
| E0 | 0.00 | Zaehlt nicht als Evidence |
|
||
| E1 | 0.25 | Minimal — ungepruefte Uploads |
|
||
| E2 | 0.50 | Schwelle fuer "pass"-Status |
|
||
| E3 | 0.75 | Stark — system-verifiziert |
|
||
| E4 | 1.00 | Perfekt — extern validiert |
|
||
|
||
### Warum Four-Eyes nur fuer GOV und PRIV?
|
||
|
||
Das Four-Eyes-Prinzip erhoert den Aufwand erheblich (jedes Evidence braucht
|
||
zwei verschiedene Reviewer). Deshalb wird es gezielt nur fuer Domains eingesetzt,
|
||
bei denen Manipulation besonders gefaehrlich ist:
|
||
|
||
| Domain | Four-Eyes | Begruendung |
|
||
|---|---|---|
|
||
| **GOV** (Governance) | Ja | Governance-Controls definieren das Compliance-Framework selbst. Wenn hier manipuliert wird, ist alles darunter wertlos. |
|
||
| **PRIV** (Datenschutz) | Ja | DSGVO-Nachweise sind rechtlich bindend. Falsche Nachweise koennen zu Bussgeldern fuehren. |
|
||
| SEC, AUTH, NET, ... | Nein | Technische Controls sind oft automatisch pruefbar (E3). Der Aufwand von Four-Eyes waere unverhältnismäßig. |
|
||
|
||
### Same-Person-Schutz
|
||
|
||
```python
|
||
# Der zweite Reviewer MUSS eine andere Person sein:
|
||
if review.reviewed_by == evidence.first_reviewer:
|
||
raise HTTPException(
|
||
status_code=400,
|
||
detail="Four-Eyes: second reviewer must be different from first reviewer"
|
||
)
|
||
```
|
||
|
||
Dies verhindert, dass eine einzelne Person ein Evidence "durchwinkt". Der Schutz
|
||
ist auf DB-Ebene durchgesetzt — nicht nur im Frontend.
|
||
|
||
---
|
||
|
||
## Hard Blocks — Audit-Sperren
|
||
|
||
Hard Blocks sind **absolute Sperren**, die eine Audit-Readiness verhindern.
|
||
Sie werden im Dashboard prominent rot angezeigt.
|
||
|
||
### Block 1: Controls auf "pass" ohne Evidence
|
||
|
||
```sql
|
||
-- Controls die "pass" oder "partial" sind, aber keine Evidence haben
|
||
SELECT control_id FROM compliance_controls
|
||
WHERE status IN ('pass', 'partial')
|
||
AND id NOT IN (SELECT control_id FROM compliance_evidence)
|
||
```
|
||
|
||
**Warum kritisch:** Ein Control auf "pass" ohne jeden Nachweis ist die Definition
|
||
von Compliance-Theater. Der Auditor wird sofort fragen: "Wo ist der Nachweis?"
|
||
|
||
### Block 2: Controls auf "pass" mit nur E0/E1-Evidence
|
||
|
||
```sql
|
||
-- Controls auf "pass" deren beste Evidence nur E0 oder E1 ist
|
||
SELECT c.control_id FROM compliance_controls c
|
||
JOIN compliance_evidence e ON e.control_id = c.id
|
||
WHERE c.status = 'pass'
|
||
GROUP BY c.control_id
|
||
HAVING MAX(CASE
|
||
WHEN e.confidence_level = 'E4' THEN 4
|
||
WHEN e.confidence_level = 'E3' THEN 3
|
||
WHEN e.confidence_level = 'E2' THEN 2
|
||
WHEN e.confidence_level = 'E1' THEN 1
|
||
ELSE 0
|
||
END) < 2 -- Nur E0 oder E1
|
||
```
|
||
|
||
**Warum kritisch:** Ein LLM-generierter Text (E0) oder ein ungeprüeftes Upload (E1)
|
||
reicht nicht aus, um Compliance zu behaupten. Mindestens ein intern geprüeftes
|
||
Dokument (E2) ist erforderlich.
|
||
|
||
---
|
||
|
||
## Datenbank-Schema (Komplett)
|
||
|
||
### ENUM-Typen
|
||
|
||
```sql
|
||
CREATE TYPE evidence_confidence_level AS ENUM (
|
||
'E0', -- Generated / kein echter Nachweis
|
||
'E1', -- Hochgeladen, ungeprüeft
|
||
'E2', -- Intern geprüeft, Hash verifiziert
|
||
'E3', -- System-beobachtet (CI/CD, API mit Hash)
|
||
'E4' -- Extern validiert (Auditor)
|
||
);
|
||
|
||
CREATE TYPE evidence_truth_status AS ENUM (
|
||
'generated', -- LLM/System-generiert
|
||
'uploaded', -- Manuell hochgeladen
|
||
'observed', -- Automatisch beobachtet
|
||
'validated_internal', -- Intern geprüeft + bestätigt
|
||
'rejected', -- Abgelehnt
|
||
'provided_to_auditor', -- An Auditor üebergeben
|
||
'accepted_by_auditor' -- Auditor hat akzeptiert
|
||
);
|
||
```
|
||
|
||
### compliance_evidence — Erweiterte Spalten
|
||
|
||
| Spalte | Typ | Default | Beschreibung |
|
||
|---|---|---|---|
|
||
| confidence_level | ENUM | E1 | Vertrauensstufe (E0-E4) |
|
||
| truth_status | ENUM | uploaded | Wahrheitsstatus |
|
||
| generation_mode | VARCHAR(100) | NULL | 'draft_assistance', 'auto_generation' |
|
||
| may_be_used_as_evidence | BOOLEAN | TRUE | FALSE fuer LLM-Output |
|
||
| reviewed_by | VARCHAR(200) | NULL | Reviewer E-Mail |
|
||
| reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt des Reviews |
|
||
| approval_status | VARCHAR(30) | 'none' | Four-Eyes Status |
|
||
| first_reviewer | VARCHAR(200) | NULL | Erster Reviewer |
|
||
| first_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt erster Review |
|
||
| second_reviewer | VARCHAR(200) | NULL | Zweiter Reviewer (muss anders sein!) |
|
||
| second_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt zweiter Review |
|
||
| requires_four_eyes | BOOLEAN | FALSE | Ob Four-Eyes-Pflicht besteht |
|
||
|
||
### compliance_llm_generation_audit
|
||
|
||
Jeder LLM-generierte Inhalt wird in dieser Tabelle protokolliert:
|
||
|
||
| Spalte | Typ | Beschreibung |
|
||
|---|---|---|
|
||
| id | VARCHAR(36) | PK |
|
||
| tenant_id | VARCHAR(36) | Mandant |
|
||
| entity_type | VARCHAR(50) | 'evidence', 'control', 'document' |
|
||
| entity_id | VARCHAR(36) | FK zur generierten Entitaet |
|
||
| generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' |
|
||
| truth_status | ENUM | Default: 'generated' |
|
||
| may_be_used_as_evidence | BOOLEAN | Default: FALSE |
|
||
| llm_model | VARCHAR(100) | z.B. 'qwen3:30b-a3b' |
|
||
| llm_provider | VARCHAR(50) | 'ollama', 'anthropic' |
|
||
| prompt_hash | VARCHAR(64) | SHA-256 des Prompts |
|
||
| input_summary | TEXT | Zusammenfassung des Inputs |
|
||
| output_summary | TEXT | Zusammenfassung des Outputs |
|
||
|
||
### compliance_assertions
|
||
|
||
Die Assertion Engine trennt Behauptungen von Fakten:
|
||
|
||
| Spalte | Typ | Beschreibung |
|
||
|---|---|---|
|
||
| id | VARCHAR(36) | PK |
|
||
| tenant_id | VARCHAR(36) | Mandant |
|
||
| entity_type | VARCHAR(50) | 'control', 'evidence', 'document', 'obligation' |
|
||
| entity_id | VARCHAR(36) | FK zur Entitaet |
|
||
| sentence_text | TEXT | Originalsatz |
|
||
| sentence_index | INTEGER | Position im Text |
|
||
| assertion_type | VARCHAR(20) | 'assertion', 'fact', 'rationale' |
|
||
| evidence_ids | JSONB | Verlinkte Evidence-IDs |
|
||
| confidence | FLOAT | 0.0-1.0 Konfidenz |
|
||
| normative_tier | VARCHAR(20) | 'pflicht', 'empfehlung', 'kann' |
|
||
| verified_by | VARCHAR(200) | Verifizierer |
|
||
| verified_at | TIMESTAMPTZ | Zeitpunkt der Verifikation |
|
||
|
||
---
|
||
|
||
## Vollstaendige API-Referenz
|
||
|
||
### Evidence-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung | Auth |
|
||
|---|---|---|---|
|
||
| GET | `/evidence` | Evidence auflisten (mit Filtern) | Tenant |
|
||
| POST | `/evidence` | Neues Evidence erstellen | Tenant |
|
||
| DELETE | `/evidence/{id}` | Evidence loeschen | Tenant |
|
||
| POST | `/evidence/upload` | Evidence-Datei hochladen | Tenant |
|
||
| POST | `/evidence/collect` | CI/CD Evidence sammeln (automatisch) | API-Key |
|
||
| GET | `/evidence/ci-status` | CI/CD Evidence Statusuebersicht | Tenant |
|
||
| **PATCH** | **`/evidence/{id}/review`** | **Evidence reviewen (Four-Eyes)** | Tenant |
|
||
| **PATCH** | **`/evidence/{id}/reject`** | **Evidence ablehnen** | Tenant |
|
||
|
||
### Audit-Trail-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---|---|---|
|
||
| GET | `/audit-trail` | Audit-Trail abfragen (entity_type, entity_id, action) |
|
||
|
||
### Assertion-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---|---|---|
|
||
| POST | `/assertions` | Assertion manuell erstellen |
|
||
| GET | `/assertions` | Assertions auflisten |
|
||
| GET | `/assertions/{id}` | Assertion Detail |
|
||
| PUT | `/assertions/{id}` | Assertion aktualisieren |
|
||
| POST | `/assertions/{id}/verify` | Als Fakt markieren |
|
||
| POST | `/assertions/extract` | Automatische Extraktion aus Freitext |
|
||
| GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) |
|
||
|
||
### LLM-Audit-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---|---|---|
|
||
| POST | `/llm-audit` | LLM-Generierungs-Audit erstellen |
|
||
| GET | `/llm-audit` | LLM-Audit-Eintraege auflisten |
|
||
|
||
### Dashboard-Endpoints
|
||
|
||
| Methode | Pfad | Beschreibung |
|
||
|---|---|---|
|
||
| GET | `/dashboard/evidence-distribution` | Confidence-Verteilung + Four-Eyes-Status |
|
||
|
||
---
|
||
|
||
## Haeufige Fragen
|
||
|
||
### Kann ich E0-Evidence loeschen?
|
||
|
||
Ja, aber es bleibt ein Eintrag in `compliance_llm_generation_audit`. Das stellt sicher,
|
||
dass die Generierung nachvollziehbar ist, auch wenn der LLM-Output geloescht wurde.
|
||
|
||
### Was passiert, wenn der erste Reviewer nicht verfuegbar ist?
|
||
|
||
Das Four-Eyes-System hat keinen Timeout. Der erste Review bleibt als `first_approved`
|
||
gespeichert, bis ein zweiter Reviewer die Evidence prueft. Das ist bewusst so —
|
||
Compliance-Nachweise sollten nicht durch Zeitdruck kompromittiert werden.
|
||
|
||
### Kann ein Admin das Four-Eyes-Prinzip umgehen?
|
||
|
||
Nein. Der Same-Person-Check ist auf Backend-Ebene implementiert (HTTP 400 bei
|
||
gleichem Reviewer). Es gibt keine Admin-Bypass-Option. Dies ist ein bewusstes
|
||
Design-Prinzip: Wenn selbst der Admin das System umgehen koennte, waere die
|
||
gesamte Integritaet gefaehrdet.
|
||
|
||
### Wie funktioniert die Assertion-Extraktion?
|
||
|
||
Der Endpoint `POST /assertions/extract` nimmt einen Freitext und:
|
||
|
||
1. **Satz-Splitting**: Teilt den Text an `.!?` gefolgt von Grossbuchstaben
|
||
2. **Klassifikation**: Prueft jeden Satz auf normative Signal-Woerter
|
||
3. **Normative Tiers**: "muss/shall/must" → pflicht, "soll/should" → empfehlung, "kann/may" → kann
|
||
4. **Evidence-Keywords**: Woerter wie "liegt vor", "wurde geprueft" → als tentative Fakten markiert
|
||
5. **Ergebnis**: Liste von Assertions mit Typ und Normative-Tier
|
||
|
||
### Was ist der Unterschied zwischen Truth-Status und Confidence?
|
||
|
||
- **Confidence** (E0-E4) sagt: Wie vertrauenswuerdig ist die **Quelle**?
|
||
(LLM < Upload < Review < CI/CD < Auditor)
|
||
- **Truth-Status** sagt: In welchem **Lifecycle-Zustand** ist der Nachweis?
|
||
(generated → uploaded → validated → accepted_by_auditor)
|
||
|
||
Ein E3-Evidence (CI/CD) kann Truth-Status "observed" haben und ist damit sofort
|
||
verwendbar. Ein E1-Evidence (Upload) muss erst "validated_internal" werden.
|