feat: ZeroClaw compliance agent — document analysis + role assignment + email

Add autonomous compliance agent that fetches web documents (cookie banners,
privacy policies), classifies them via Qwen/Ollama, assesses DSGVO compliance,
assigns to the responsible role, and sends notification emails.

Components:
- ZeroClaw SOP (6-step workflow: fetch, classify, assess, summarize, assign, notify)
- Backend: /api/compliance/agent/analyze (combined endpoint)
- Backend: /api/compliance/agent/notify (standalone email)
- Frontend: /sdk/agent page (Manager UI with URL input + results)
- Helper scripts + E2E test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-27 23:27:25 +02:00
parent f528b8e7a9
commit 0c0dd4e3a6
16 changed files with 1095 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bash
#
# test_sop_workflow.sh — End-to-end test for the compliance-analyst SOP.
#
# Prerequisites:
# - Compliance SDK running on localhost:8093
# - Backend running on localhost:8002
# - Ollama running on localhost:11434 with qwen model
# - Mailpit running (SMTP on 1025, Web on 8025)
# - ZeroClaw installed
set -euo pipefail
SDK="http://localhost:8093"
BACKEND="http://localhost:8002"
OLLAMA="http://localhost:11434"
MAILPIT="http://localhost:8025"
TENANT="9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
USER_ID="00000000-0000-0000-0000-000000000001"
red() { printf '\033[31m✗ %s\033[0m\n' "$*"; }
green() { printf '\033[32m✓ %s\033[0m\n' "$*"; }
echo "═══ Compliance Agent SOP — E2E Test ═══"
echo ""
# Step 1: Health checks
echo "── Step 1: Service Health ──"
curl -sf "$SDK/health" >/dev/null && green "SDK healthy" || red "SDK unreachable"
curl -sf "$BACKEND/health" >/dev/null && green "Backend healthy" || red "Backend unreachable"
curl -sf "$OLLAMA/api/tags" >/dev/null && green "Ollama running" || red "Ollama unreachable"
# Step 2: Test document fetch
echo ""
echo "── Step 2: Document Fetch ──"
TEXT=$(bash "$(dirname "$0")/../scripts/fetch-and-analyze.sh" "https://www.google.com/intl/de/policies/privacy/" 2000)
CHARS=${#TEXT}
if [ "$CHARS" -gt 100 ]; then
green "Fetched $CHARS chars from Google Privacy Policy"
else
red "Fetch returned too little text ($CHARS chars)"
exit 1
fi
# Step 3: Test LLM classification
echo ""
echo "── Step 3: LLM Classification ──"
CLASSIFY_RESULT=$(curl -sf -X POST "$SDK/sdk/v1/llm/chat" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: $TENANT" \
-H "X-User-ID: $USER_ID" \
-d "{
\"messages\": [
{\"role\": \"system\", \"content\": \"Klassifiziere: privacy_policy, cookie_banner, terms_of_service, imprint, dpa, other. Antworte NUR mit dem Kategorienamen.\"},
{\"role\": \"user\", \"content\": $(echo "$TEXT" | head -c 1000 | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}
]
}" 2>&1) || true
if echo "$CLASSIFY_RESULT" | grep -qi "privacy_policy\|cookie\|terms\|imprint\|dpa"; then
green "Classification: $(echo "$CLASSIFY_RESULT" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("response","").strip()[:50])' 2>/dev/null || echo "$CLASSIFY_RESULT" | head -c 50)"
else
echo " Classification result: $(echo "$CLASSIFY_RESULT" | head -c 100)"
red "Classification did not return expected category (may still be valid)"
fi
# Step 4: Test notification endpoint
echo ""
echo "── Step 4: Agent Notification ──"
NOTIFY_RESULT=$(curl -sf -X POST "$BACKEND/api/compliance/agent/notify" \
-H "Content-Type: application/json" \
-d '{
"recipient": "dsb@breakpilot.local",
"subject": "E2E Test: Compliance-Finding",
"body_html": "<h2>Test-Benachrichtigung</h2><p>Automatischer E2E-Test des Compliance-Agent SOP.</p>",
"role": "Datenschutzbeauftragter"
}' 2>&1) || true
if echo "$NOTIFY_RESULT" | grep -qi "sent\|success\|ok"; then
green "Notification sent"
else
echo " Notify result: $(echo "$NOTIFY_RESULT" | head -c 100)"
red "Notification endpoint returned unexpected result"
fi
# Step 5: Check Mailpit
echo ""
echo "── Step 5: Mailpit Check ──"
MAIL_COUNT=$(curl -sf "$MAILPIT/api/v1/messages" 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("total",0))' 2>/dev/null || echo "0")
if [ "$MAIL_COUNT" -gt 0 ]; then
green "Mailpit has $MAIL_COUNT message(s)"
else
red "No messages in Mailpit (check SMTP connectivity)"
fi
echo ""
echo "═══ E2E Test Complete ═══"