- Source-Type-Klassifikation (58 Regulierungen: law/guideline/framework) - Backfill-Endpoint POST /controls/backfill-normative-strength - exclude_duplicates Filter fuer Control-Library (Backend + Proxy + UI-Toggle) - MkDocs-Kapitel: Normative Verbindlichkeit mit Mermaid-Diagrammen - scripts/deploy.sh: Auto-Push + Mac Mini rebuild + Coolify health monitoring - 26 Unit Tests fuer Klassifikations-Logik Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.2 KiB
Normative Verbindlichkeit — Dreistufenmodell
Uebersicht
Nicht jede Quelle, aus der Controls abgeleitet werden, hat die gleiche rechtliche Verbindlichkeit. Ein Control, das aus einem EU-Gesetz stammt, hat ein anderes Gewicht als eines aus einem freiwilligen Framework.
Das Dreistufenmodell klassifiziert jede Quell-Regulierung und leitet daraus die effektive normative Staerke der daraus erzeugten Obligations ab.
Die drei Stufen
graph TB
subgraph "Stufe 1 — GESETZ (law)"
direction LR
A1["DSGVO, NIS2, AI Act, CRA..."]
A2["Rechtlich bindend"]
A3["Bussgeld bei Verstoss"]
A4["normative_strength: must/should/may"]
end
subgraph "Stufe 2 — LEITLINIE (guideline)"
direction LR
B1["EDPB-Leitlinien, BSI-TR, WP29"]
B2["Offizielle Auslegungshilfe"]
B3["Beweislastumkehr"]
B4["max normative_strength: should"]
end
subgraph "Stufe 3 — FRAMEWORK (framework)"
direction LR
C1["ENISA, NIST, OWASP, OECD"]
C2["Freiwillige Best Practice"]
C3["Stand der Technik"]
C4["max normative_strength: can"]
end
A1 --> A2 --> A3 --> A4
B1 --> B2 --> B3 --> B4
C1 --> C2 --> C3 --> C4
Stufe 1: Gesetz (law)
| Eigenschaft | Beschreibung |
|---|---|
| Verbindlichkeit | Rechtlich bindend, Bussgeld bei Verstoss |
| normative_strength | Bleibt wie im Gesetzestext: must, should oder may |
| Beispiele | DSGVO (EU) 2016/679, NIS2-Richtlinie, KI-Verordnung, CRA, BDSG |
| Warum relevant | "Sie MUESSEN angemessene technische Massnahmen ergreifen" (Art. 32 DSGVO) |
!!! warning "Wichtig" Gesetze formulieren Pflichten abstrakt. Art. 32 DSGVO sagt: "dem Stand der Technik entsprechende Massnahmen" — aber NICHT "verwende AES-256". Das WAS ist Pflicht, das WIE bleibt offen.
Stufe 2: Leitlinie (guideline)
| Eigenschaft | Beschreibung |
|---|---|
| Verbindlichkeit | Nicht direkt bindend, aber Beweislastumkehr |
| normative_strength | Maximal should — auch wenn die Leitlinie intern "must" schreibt |
| Beispiele | EDPB-Leitlinien, BSI Technische Richtlinien, WP29-Dokumente |
| Warum relevant | "Daten at rest muessen verschluesselt werden" (BSI-TR) → should |
!!! info "Beweislastumkehr" Wenn eine Aufsichtsbehoerde fragt "Warum verschluesselt ihr nicht?", muss die Firma begruenden, warum sie von der Leitlinie abweicht. Die Firma muss aber nicht genau so verschluesseln wie die BSI vorschlaegt.
Stufe 3: Framework (framework)
| Eigenschaft | Beschreibung |
|---|---|
| Verbindlichkeit | Freiwillig, nicht rechtsverbindlich |
| normative_strength | Maximal can — unabhaengig von interner Sprache |
| Beispiele | ENISA CCM, NIST CSF, OWASP Top 10, OECD KI-Empfehlung |
| Warum relevant | "Organizations SHALL implement..." (ENISA) → can fuer den Anwender |
!!! tip "Stand der Technik"
NIS2 Art. 21 verweist auf ENISA-Leitlinien als Referenz fuer den
"Stand der Technik". Das hebt ENISA-Controls faktisch auf Stufe 2 (should)
— aber nur im Kontext von NIS2-pflichtigen Unternehmen, nicht generell.
Ableitungskette
Die vollstaendige Kette von der Rechtsquelle zum atomaren Control:
graph LR
R["Regulierung<br/>(DSGVO Art. 32)"] -->|"MUSS"| O["Obligation<br/>(Daten schuetzen)"]
O -->|decomposition| RC["Rich Control<br/>(Verschluesselung)"]
RC -->|pass0b| AC["Atomares Control<br/>(AES-256 at rest)"]
R2["Framework<br/>(ENISA CCM)"] -->|"KANN"| AC
style R fill:#fee2e2,stroke:#dc2626
style R2 fill:#dbeafe,stroke:#2563eb
style O fill:#fef3c7,stroke:#d97706
style RC fill:#e0e7ff,stroke:#4f46e5
style AC fill:#d1fae5,stroke:#059669
Beispiel: Das atomare Control "AES-256 Verschluesselung at rest"
- Aus DSGVO Art. 32 abgeleitet → Obligation "must secure data" → MUSS (die Pflicht zu schuetzen)
- Aus ENISA CCM konkretisiert → KANN (AES-256 ist eine moegliche Umsetzung)
- Resultat: Die Firma MUSS verschluesseln, KANN aber waehlen wie
Multi-Parent-Links
Ein atomares Control kann aus mehreren Quellen stammen:
| Control | Parent 1 | Parent 2 | Parent 3 | Effektive Staerke |
|---|---|---|---|---|
| SEC-042 (Encrypt at rest) | DSGVO Art. 32 (law) | NIS2 Art. 21 (law) | ENISA CCM (framework) | must (Gesetz uebertrumpft) |
| NET-015 (Zero Trust) | NIST SP 800-207 (framework) | CISA (framework) | — | can (nur Frameworks) |
| AUTH-003 (MFA) | DSGVO Art. 32 (law) | BSI-TR (guideline) | OWASP ASVS (framework) | must (Gesetz vorhanden) |
Regel: Der hoechste source_type bestimmt, ob die normative_strength begrenzt wird. Wenn mindestens ein Parent-Link ein Gesetz ist, bleibt die Staerke wie extrahiert.
Technische Umsetzung
Klassifikations-Map
Datei: backend-compliance/compliance/data/source_type_classification.py
Jeder source_regulation-Wert aus control_parent_links wird klassifiziert:
SOURCE_REGULATION_CLASSIFICATION = {
"DSGVO (EU) 2016/679": "law",
"EDPB Leitlinien 01/2020 (Datentransfers)": "guideline",
"NIST Cybersecurity Framework 2.0": "framework",
# ... 55+ Eintraege
}
Backfill-Endpoint
POST /api/compliance/v1/canonical/controls/backfill-normative-strength?dry_run=true
Ablauf:
- Alle aktiven
obligation_candidatesladen - Fuer jede Obligation den Parent-Control finden
- Ueber
control_parent_linksdie source_regulations ermitteln - Hoechsten source_type bestimmen
normative_strengthbegrenzen falls noetig- Bei
dry_run=false: Aenderungen in die DB schreiben
Cap-Funktion
def cap_normative_strength(original: str, source_type: str) -> str:
"""
cap_normative_strength("must", "framework") → "can"
cap_normative_strength("should", "law") → "should"
cap_normative_strength("must", "guideline") → "should"
"""
Frontend-Anzeige
In der Control-Detail-Ansicht werden Obligations mit farbcodierten Badges angezeigt:
| normative_strength | Badge | Farbe | Bedeutung |
|---|---|---|---|
must |
MUSS | Rot | Gesetzliche Pflicht |
should |
SOLL | Gelb/Amber | Empfohlen, Begruendungspflicht bei Abweichung |
can / may |
KANN | Gruen | Freiwillige Best Practice |
Haeufige Fragen
Warum steht bei einem ENISA-Control "MUSS"?
Vor dem Backfill: Das System uebernahm die Sprache des Quelldokuments 1:1. ENISA schreibt intern "shall/must" weil es innerhalb seines Frameworks verbindlich formuliert. Fuer den Anwender ist das ENISA-Dokument aber nicht rechtsverbindlich.
Nach dem Backfill: ENISA-Controls zeigen maximal "KANN", es sei denn ein Gesetz (z.B. NIS2) referenziert dasselbe Control — dann gilt die gesetzliche Verbindlichkeit.
Was bedeutet "Stand der Technik"?
NIS2 und DSGVO verweisen auf den "Stand der Technik", ohne ihn zu definieren. In der Praxis werden ENISA- und BSI-Dokumente als Referenz herangezogen. Das macht ihre Empfehlungen relevant ("SOLL"), aber nicht zu Gesetzen ("MUSS").
Wie gehe ich mit unbekannten Quellen um?
Neue Regulierungen muessen in der SOURCE_REGULATION_CLASSIFICATION Map
eingetragen werden. Der Fallback fuer unbekannte Quellen ist framework
(konservativstes Ergebnis — geringste Verbindlichkeit zugewiesen).