feat(b15): AI-Act Rechtsgrundlage-Check (GT AI-ACT-RISK-001)
Erkennt: LLM/GPAI-System (Vertex AI, OpenAI/GPT, Claude) wird in
DSE oder Cookie-Doc auf Art. 6 Abs. 1 lit. f (berechtigtes Interesse)
gestützt — statt auf lit. a (Einwilligung).
GT-Anker (Elli AI-ACT-RISK-001): Vertex-AI-Chatbot mit lit. f
deklariert. Bei LLM-Prompt/Output-Logging + US-Transfer +
Profiling-Ähnlichkeit ist Interessenabwägung fragwürdig.
Heuristik:
- KB-basiert (chat_providers.json filter: ai_capable + LLM-Type-Hint)
- LLM-Vendor-Aliases inkl. Marken-Familien (PaLM, Gemini, GPT-4,
ChatGPT, Claude 3, Azure OpenAI)
- Absatz-Boundary-Scope: Provider + lit. f im selben Absatz
- Negativ-Filter: wenn lit. a / Einwilligung ebenfalls im Absatz →
kein Finding (Side-Purpose-Erwähnung)
- Dedup pro (doc_type, provider_id)
Severity: MEDIUM.
Norm: DSGVO Art. 6 Abs. 1 lit. a vs lit. f + AI Act Art. 50 + 51.
Tests: 17/17 grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""B15 wiring — AI-Act Rechtsgrundlage-Check für LLM-Vendors.
|
||||
|
||||
Hängt sich an `state["extra_findings"]` an und rendert einen V2-Block
|
||||
(`ai_legal_basis_html`).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import html
|
||||
import logging
|
||||
|
||||
from compliance.services.ai_legal_basis_check import check_ai_legal_basis
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_b15(state: dict) -> None:
|
||||
new = check_ai_legal_basis(state)
|
||||
if not new:
|
||||
return
|
||||
extras = state.get("extra_findings") or []
|
||||
extras.extend(new)
|
||||
state["extra_findings"] = extras
|
||||
state["ai_legal_basis_html"] = _render(new)
|
||||
logger.info("B15 ai-legal-basis: %d finding(s)", len(new))
|
||||
|
||||
|
||||
def _render(findings: list[dict]) -> str:
|
||||
cards = []
|
||||
for f in findings:
|
||||
sev = (f.get("severity") or "").upper()
|
||||
color = "#dc2626" if sev == "HIGH" else "#f59e0b"
|
||||
meta = (
|
||||
"<div style='font-size:12px;color:#475569;margin-top:6px;'>"
|
||||
f"<em>Provider: {html.escape(f.get('provider') or '?')} · "
|
||||
f"Doc: {html.escape(f.get('doc_type') or '?')}</em></div>"
|
||||
)
|
||||
cards.append(
|
||||
f"<div style='margin:12px 0;padding:14px;background:#fff;"
|
||||
f"border-left:3px solid {color};border-radius:4px;'>"
|
||||
f"<div style='font-weight:600;color:{color};font-size:14px;'>"
|
||||
f"{sev} · {html.escape(f.get('check_id') or '')}</div>"
|
||||
f"<div style='font-size:14px;margin-top:4px;'>"
|
||||
f"<strong>{html.escape(f.get('title') or '')}</strong></div>"
|
||||
f"<div style='font-size:12px;color:#64748b;margin-top:2px;'>"
|
||||
f"{html.escape(f.get('norm') or '')}</div>"
|
||||
f"{meta}"
|
||||
f"<div style='font-size:12px;color:#475569;margin-top:6px;'>"
|
||||
f"<em>{html.escape(f.get('evidence') or '')}</em></div>"
|
||||
f"<div style='font-size:13px;margin-top:8px;background:#dcfce7;"
|
||||
f"padding:8px 10px;border-radius:4px;'>"
|
||||
f"<strong>→ Empfehlung:</strong> "
|
||||
f"{html.escape(f.get('action') or '')}</div>"
|
||||
"</div>"
|
||||
)
|
||||
return (
|
||||
"<div style='margin:24px 0;padding:16px;border-left:4px solid #f59e0b;"
|
||||
"background:#fffbeb;border-radius:4px;'>"
|
||||
"<h2 style='margin:0 0 8px;color:#92400e;font-size:16px;'>"
|
||||
"🤖 AI-Act Rechtsgrundlage (LLM-Vendor auf berechtigtem Interesse)"
|
||||
"</h2>"
|
||||
+ "".join(cards) +
|
||||
"</div>"
|
||||
)
|
||||
@@ -25,6 +25,7 @@ from ._b9b10_wiring import run_b9b10
|
||||
from ._b12_wiring import run_b12
|
||||
from ._b13_wiring import run_b13
|
||||
from ._b14_wiring import run_b14
|
||||
from ._b15_wiring import run_b15
|
||||
from ._constants import _compliance_check_jobs
|
||||
from ._phase_a_resolve import run_phase_a
|
||||
from ._phase_b_profile_check import run_phase_b
|
||||
@@ -74,6 +75,7 @@ async def run_compliance_check(check_id: str, req) -> None:
|
||||
run_b12(state) # Chatbot-Cookie-Klassifikation (B11 ist in B9B10)
|
||||
run_b13(state) # Widerrufsbelehrung-Reachability (B2C-Pflicht)
|
||||
run_b14(state) # Widersprüchliche Speicherdauer im selben Doc
|
||||
run_b15(state) # AI-Act Rechtsgrundlage (LLM-Vendor auf lit. f)
|
||||
# Phase D-3 top/mid/bot: Step 5 HTML blocks
|
||||
await run_phase_d3_top(state)
|
||||
await run_phase_d3_mid(state)
|
||||
|
||||
Reference in New Issue
Block a user