feat(compliance-check): exec-summary + voll-audit + TDM-respect + cookie-KB-extended + saving-scan-funnel
CI / detect-changes (push) Successful in 10s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 14s
CI / loc-budget (push) Failing after 15s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m43s
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 10s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 14s
CI / loc-budget (push) Failing after 15s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m43s
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
P1 — Exec-Summary oben im Email-Report (4 KPIs + 2 CTAs, dunkler Gradient)
P3 — no_direct_sales-Flag fuer OEM-Konfigurator-Sites; AGB/Widerruf/AGB als
"NICHT ANWENDBAR" (grau) statt "NICHT GEFUNDEN" (rot)
P5 — Voll-Audit Unification: alle Findings (MC + Pflichtangaben + Vendor +
Redundanz) in /data/compliance_audits.db.unified_findings; neuer
/api/compliance/agent/findings/<id> Endpoint + FindingsTab im Audit-UI
mit Filter + CSV-Export
P7 — Crawl-Hardening: TDM-Reservation-Check (robots.txt / ai.txt / Header /
Meta) vor jedem Run mit 24h-Cache; HeadlessChrome-UA (Firma noch nicht
gegruendet — Switch via BREAKPILOT_BRANDED_UA env); per-Domain
Rate-Limit 1 req/s + max 2 concurrent
P2 — Cookie-Knowledge-DB additiv erweitert (35 -> 74 Cookies): Adobe, Meta,
Microsoft, LinkedIn, TikTok, HubSpot, Marketo, Salesforce, Hotjar,
FullStory, Mouseflow, Intercom, Drift, Zendesk, Cloudflare, Stripe,
OneTrust/Cookiebot/Usercentrics, Matomo, Pinterest, Snapchat, X/Twitter,
YouTube, Vimeo, Klaviyo, Mailchimp, Mixpanel, Segment, Amplitude,
Optimizely, Datadog; Wire-in in cookie_function_classifier liefert
compliance_risk-Label (kritisch/hoch/mittel/gering) pro Vendor
A — k-Anonymitaets-Helper (benchmark_k_anonymity) fuer P6-Vorbereitung
B — Cross-Tenant-Domain-Assertion im /findings-Endpoint (expected_domain
Query-Param -> 403 bei Mismatch)
C — Saving-Scan-Funnel: /api/compliance/agent/saving-scan/start mit
Validierung + 24h-Rate-Limit pro Domain + Lead-Persistenz in
saving_scan_leads + Auto-Discovery via _run_compliance_check; 6 Tests
D — Risk-Badge im Email-Vendor-Row
Rechtliche Leitplanken (Memory feedback_oem_data_legal.md): nur eigene
Knapp-Bewertungen + Source-Pointer, keine 1:1-Kopien fremder CMP-Texte.
TDM-Opt-Out-Respect nach § 44b UrhG. KEINE Schema-Aenderungen — alles in
Sidecar-SQLite.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -134,7 +134,9 @@ def build_management_summary(results: list[DocCheckResult]) -> str:
|
||||
ok = [r for r in results if r.completeness_pct == 100 and not r.error]
|
||||
fixable = [r for r in results if 0 < r.completeness_pct < 100 and not r.error]
|
||||
critical = [r for r in results if r.completeness_pct == 0 and not r.error]
|
||||
errors = [r for r in results if r.error]
|
||||
not_applicable = [r for r in results if r.error
|
||||
and r.error.startswith("Nicht anwendbar")]
|
||||
errors = [r for r in results if r.error and r not in not_applicable]
|
||||
|
||||
html = [
|
||||
'<div style="font-family:-apple-system,BlinkMacSystemFont,sans-serif;'
|
||||
@@ -150,17 +152,24 @@ def build_management_summary(results: list[DocCheckResult]) -> str:
|
||||
html.append('<p>Keine Dokumente geprueft.</p></div>')
|
||||
return "\n".join(html)
|
||||
|
||||
na_note = (
|
||||
f' Zusaetzlich {len(not_applicable)} Dokument{"" if len(not_applicable) == 1 else "e"} '
|
||||
f'als NICHT ANWENDBAR markiert (kein Direkt-Vertrieb — '
|
||||
f'OEM-Konfigurator-Pattern).' if not_applicable else ""
|
||||
)
|
||||
if len(ok) == total:
|
||||
html.append(
|
||||
'<p style="color:#16a34a;font-weight:600;font-size:15px">'
|
||||
'Alle Dokumente sind vollstaendig. Keine dringenden Massnahmen noetig.</p>'
|
||||
f'<p style="color:#16a34a;font-weight:600;font-size:15px">'
|
||||
f'Alle Dokumente sind vollstaendig. Keine dringenden Massnahmen noetig.'
|
||||
f'{na_note}</p>'
|
||||
)
|
||||
else:
|
||||
html.append(
|
||||
f'<p style="font-size:14px;color:#475569">'
|
||||
f'{len(ok)} von {total} Dokumenten sind vollstaendig. '
|
||||
f'{len(fixable)} brauchen Korrekturen'
|
||||
f'{f", {len(critical)} fehlen oder sind unbrauchbar" if critical else ""}.</p>'
|
||||
f'{f", {len(critical)} fehlen oder sind unbrauchbar" if critical else ""}.'
|
||||
f'{na_note}</p>'
|
||||
)
|
||||
|
||||
# Concrete actions
|
||||
@@ -279,10 +288,13 @@ def _render_document(html: list[str], r: DocCheckResult, doc_text: str = "") ->
|
||||
r.error.startswith("Nicht eingereicht")
|
||||
or r.error.startswith("Auf der Website nicht gefunden")
|
||||
)
|
||||
is_not_applicable = bool(r.error) and r.error.startswith("Nicht anwendbar")
|
||||
if is_missing:
|
||||
status_label = ("NICHT GEFUNDEN"
|
||||
if r.error.startswith("Auf der Website")
|
||||
else "NICHT EINGEREICHT")
|
||||
elif is_not_applicable:
|
||||
status_label = "NICHT ANWENDBAR"
|
||||
elif r.error:
|
||||
status_label = "FEHLER"
|
||||
|
||||
@@ -330,6 +342,13 @@ def _render_document(html: list[str], r: DocCheckResult, doc_text: str = "") ->
|
||||
'background:#fafafa;border-top:1px solid #f3f4f6">'
|
||||
+ body_msg + '</div>'
|
||||
)
|
||||
elif is_not_applicable:
|
||||
html.append(
|
||||
'<div style="padding:12px 16px;color:#475569;font-size:12px;'
|
||||
'background:#f1f5f9;border-top:1px solid #cbd5e1;border-left:'
|
||||
'3px solid #94a3b8">'
|
||||
+ r.error + '</div>'
|
||||
)
|
||||
elif r.error:
|
||||
html.append(f'<div style="padding:12px 16px;color:#991b1b">{r.error}</div>')
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user