feat: Dreistufenmodell normative Verbindlichkeit + Duplikat-Filter + Auto-Deploy

- 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>
This commit is contained in:
Benjamin Admin
2026-03-25 08:18:00 +01:00
parent 6d3bdf8e74
commit 230fbeb490
8 changed files with 796 additions and 4 deletions

View File

@@ -0,0 +1,102 @@
"""Tests for source_type_classification module."""
import sys
sys.path.insert(0, ".")
from compliance.data.source_type_classification import (
classify_source_regulation,
cap_normative_strength,
get_highest_source_type,
SOURCE_TYPE_LAW,
SOURCE_TYPE_GUIDELINE,
SOURCE_TYPE_FRAMEWORK,
)
class TestClassifySourceRegulation:
"""Tests for classify_source_regulation()."""
def test_eu_regulation(self):
assert classify_source_regulation("DSGVO (EU) 2016/679") == SOURCE_TYPE_LAW
def test_eu_directive(self):
assert classify_source_regulation("NIS2-Richtlinie (EU) 2022/2555") == SOURCE_TYPE_LAW
def test_national_law(self):
assert classify_source_regulation("Bundesdatenschutzgesetz (BDSG)") == SOURCE_TYPE_LAW
def test_edpb_guideline(self):
assert classify_source_regulation("EDPB Leitlinien 01/2020 (Datentransfers)") == SOURCE_TYPE_GUIDELINE
def test_bsi_standard(self):
assert classify_source_regulation("BSI-TR-03161-1") == SOURCE_TYPE_GUIDELINE
def test_wp29_guideline(self):
assert classify_source_regulation("WP260 Leitlinien (Transparenz)") == SOURCE_TYPE_GUIDELINE
def test_enisa_framework(self):
assert classify_source_regulation("ENISA Supply Chain Good Practices") == SOURCE_TYPE_FRAMEWORK
def test_nist_framework(self):
assert classify_source_regulation("NIST Cybersecurity Framework 2.0") == SOURCE_TYPE_FRAMEWORK
def test_owasp_framework(self):
assert classify_source_regulation("OWASP Top 10 (2021)") == SOURCE_TYPE_FRAMEWORK
def test_unknown_defaults_to_framework(self):
assert classify_source_regulation("Some Unknown Source") == SOURCE_TYPE_FRAMEWORK
def test_empty_string(self):
assert classify_source_regulation("") == SOURCE_TYPE_FRAMEWORK
def test_heuristic_verordnung(self):
assert classify_source_regulation("Neue Verordnung 2027") == SOURCE_TYPE_LAW
def test_heuristic_nist(self):
assert classify_source_regulation("NIST Future Standard") == SOURCE_TYPE_FRAMEWORK
class TestCapNormativeStrength:
"""Tests for cap_normative_strength()."""
def test_must_from_law_stays(self):
assert cap_normative_strength("must", SOURCE_TYPE_LAW) == "must"
def test_should_from_law_stays(self):
assert cap_normative_strength("should", SOURCE_TYPE_LAW) == "should"
def test_must_from_guideline_capped(self):
assert cap_normative_strength("must", SOURCE_TYPE_GUIDELINE) == "should"
def test_should_from_guideline_stays(self):
assert cap_normative_strength("should", SOURCE_TYPE_GUIDELINE) == "should"
def test_must_from_framework_capped(self):
assert cap_normative_strength("must", SOURCE_TYPE_FRAMEWORK) == "can"
def test_should_from_framework_capped(self):
assert cap_normative_strength("should", SOURCE_TYPE_FRAMEWORK) == "can"
def test_can_from_framework_stays(self):
assert cap_normative_strength("can", SOURCE_TYPE_FRAMEWORK) == "can"
def test_can_from_law_stays(self):
assert cap_normative_strength("can", SOURCE_TYPE_LAW) == "can"
class TestGetHighestSourceType:
"""Tests for get_highest_source_type()."""
def test_law_wins(self):
assert get_highest_source_type(["framework", "law"]) == "law"
def test_guideline_over_framework(self):
assert get_highest_source_type(["framework", "guideline"]) == "guideline"
def test_single_framework(self):
assert get_highest_source_type(["framework"]) == "framework"
def test_empty_defaults_to_framework(self):
assert get_highest_source_type([]) == "framework"
def test_all_three(self):
assert get_highest_source_type(["framework", "guideline", "law"]) == "law"