feat(audit): Phase 1 Quick-Wins (P81 + P85 + P70 + P83) + TCF DELETE/INSERT-Fix
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 / detect-changes (push) Successful in 11s
CI / branch-name (push) Has been skipped
CI / loc-budget (push) Failing after 16s
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) Has been skipped
CI / validate-canonical-controls (push) Successful in 15s
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 38s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / test-go (push) Has been skipped

P81 — tests/fixtures/golden_truth/vw_de.json:
GT-Fixture mit must_find_cookies (47 VW-Cookies) + expected_vendors
(Google, Adobe, Trade Desk, ...). Basis fuer kuenftige Regression-Tests.

P85 — banner_screenshot_block.py + consent_scanner.py + main.py:
consent-tester macht beim Banner-Detect einen base64-PNG-Screenshot
(< 1.5MB). Backend rendert ihn als <img src="data:..."> direkt nach
dem GF-1-Pager. Visueller Beweis 'so sah das Banner aus' fuer Dispute
mit Marketing/DSB.

P70 — rag_provenance.py:
classify_finding_provenance() klassifiziert ein Finding als 'rag'
(Norm + Quelle), 'mixed' (Norm ohne Quelle) oder 'heuristic' (eigene
Interpretation). provenance_badge_html() rendert kleine Badges
(✓ RAG / NORM / ⚠ HEURISTIK). Modul ist generisch, kann bei jedem
Finding-Renderer einklinkt werden.

P83 — scripts/check-rebuild-needed.sh:
Prueft ob die im Container deployten BUILD_SHA mit local HEAD
uebereinstimmen. Bei Mismatch exit 1 mit 'REBUILD REQUIRED'-Hinweis.
Verhindert das 'alter Code im Container'-Problem das uns mehrfach
erwischt hat (Frontend-Tabs sichtbar, Backend ohne neuen Service).

TCF-Fix — tcf_vendor_authority.py:
cookie_library hat keinen UNIQUE-Index auf cookie_name → ON CONFLICT
war unmoeglich. Loesung: vor Insert DELETE WHERE source_name='iab_tcf_v2'.
Idempotent. + per-Vendor-Commit damit ein Fail die naechsten nicht blockt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-22 08:24:46 +02:00
parent 6c35bcf116
commit 8cbb513e2c
8 changed files with 269 additions and 7 deletions
@@ -81,6 +81,12 @@ async def fetch_and_ingest_tcf_vendors(db: Session) -> dict:
if not vendors:
return {"error": "no vendors in TCF response", "n_vendors": 0}
# Erst alte TCF-Eintraege weg (kein UNIQUE-Index auf cookie_name,
# daher kein ON CONFLICT moeglich → idempotent via DELETE+INSERT).
db.execute(sa_text(
"DELETE FROM compliance.cookie_library WHERE source_name='iab_tcf_v2'"
))
db.commit()
inserted = 0
skipped = 0
for vid, v in vendors.items():
@@ -106,13 +112,6 @@ async def fetch_and_ingest_tcf_vendors(db: Session) -> dict:
VALUES (:n, :dp, :v, :pu, :cat, :purp, 'iab_tcf_v2',
'https://vendor-list.consensu.org/v3/vendor-list.json',
0.99)
ON CONFLICT (cookie_name) DO UPDATE
SET actual_category = EXCLUDED.actual_category,
vendor_name = EXCLUDED.vendor_name,
vendor_privacy_url = EXCLUDED.vendor_privacy_url,
purpose_en = EXCLUDED.purpose_en,
source_name = EXCLUDED.source_name,
confidence = EXCLUDED.confidence
"""
), {"n": marker, "dp": "*",
"v": f"[TCF-{vid}] {name}",