Neu: eigene WAF-App-Profile (benannte, wiederverwendbare Rule-ID-Ausnahme-
Bündel) — zentrale Bibliothek im UI (eigener Tab), pro Domain zuweisbar,
Built-in-OWASP-Plugins bleiben read-only + als Vorlage klonbar. Nur reine
Rule-IDs/Ranges (keine SecLang-Ausführung, injektionssicher).
- Migration 0047: Tabelle waf_app_profiles (repliziert via reconcile) +
waf_configs.app_profiles.
- Service/Handler: CRUD (/waf/profiles), Built-ins geschützt (builtin=false-Gate).
- Agent-Loader: app_profiles → in effektive rule_exclusions gemerged; ihr
updated_at hebt das effektive updated_at der Domain → Engine-Rebuild bei
Profil-Edit.
- UI: Profile-Tab (Liste/Editor mit durchsuchbaren Rule-IDs) + Multi-Select im
Domain-Drawer.
FIX (wichtig): ListAllWithDomain — der EINZIGE Loader des laufenden WAF-Agents —
selektierte crs_plugins nie. Dadurch war cfg.CRSPlugins im Agent immer leer und
KEIN Built-in-CRS-Plugin (Nextcloud/WordPress/Drupal) wurde je in die Engine
inkludiert. Jetzt geladen (+ app_profiles). Die per-Domain-Plugin-Wahl wirkt
damit erstmals tatsächlich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Feedback: in der Regel-Ausnahmen-Sektion konnte man Ausnahmen nur SEHEN, nicht
hinzufügen (nur Hinweis auf den Alarme-Tab), und die Rule-ID war Freitext.
Jetzt: durchsuchbarer Select (aus CRS_RULES, filtert nach ID UND Beschreibung —
z.B. "941" oder "XSS") + optionale Notiz + Hinzufügen-Button direkt im Dialog.
Speichert sofort (wie der Entfernen-Button). Der Dropdown deckt alle 331
message-behafteten CRS-Regeln ab = genau die, die je in einem Alarm auftauchen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt manueller SecRuleRemoveById-IDs kann man pro Domain offizielle OWASP-CRS-
Exclusion-Plugins aktivieren — pfad-genaue, upstream-gepflegte App-Ausnahmen.
- Migration 0046: waf_configs.crs_plugins text[].
- Engine (engine.go): je gewähltem Plugin werden config/before VOR den CRS-Rules
und after DANACH inkludiert (exakt nach OWASP-CRS-Plugin-Spec); nur die für
DIESE Domain gewählten, nur wenn die Datei existiert. Whitelist KnownCRSPlugins.
- Handler: crs_plugins im Upsert-Body + Whitelist-Validierung (Include-Pfad-
Injection-Schutz).
- Packaging (postinst): lädt die Plugins (coreruleset/<name>-plugin) nach
<crs>/plugins/ — self-healing auf jedem configure, nur fehlende.
- UI: Multi-Select „App-Profile (CRS-Plugins)" im WAF-Config-Drawer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- crsRules.ts neu: 331 echte CRS v4.7.0 Regeln aus installierten Dateien
(v3-Nummernschema war falsch, v4 hat andere IDs — 949152 war skip-Regel)
- spoe.go: Regeln ohne Message nicht als Alert speichern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Migration 0039: exclusion_notes JSONB in waf_configs (rule_id → note)
- Model/Service/Handler: exclusion_notes in Upsert + GET durchgereicht
- Alerts-Tab: "Als Ausnahme"-Button öffnet Modal mit Notiz-Textarea;
Notiz wird in exclusion_notes gespeichert
- Config-Drawer: Ausnahmen als Liste (Rule-ID + Notiz + Entfernen-Button)
statt rohem Textfeld; Ausnahmen nur noch via Alert-Tab hinzufügbar
- i18n EN + DE
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Jede Alert-Zeile hat jetzt einen "Als Ausnahme"-Button. Klick:
1. Lädt aktuelle WAF-Config der betroffenen Domain
2. Fügt die Rule-ID zu rule_exclusions hinzu (dedupliziert)
3. Speichert via PUT /waf/configs/:domain_id → triggert HAProxy-Reload
4. Erfolgsmeldung + WAF-Config-Query invalidiert
Button disabled wenn domain_id fehlt (Domain nicht aufgelöst) oder Viewer-Rolle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pages/WAF/index.tsx: neue WAF-Seite mit Status-Strip,
Domänen-Tabelle (Toggle/Mode/PL) + Konfigurations-Drawer pro Domain
(enabled, mode, paranoia_level 1-4, rule_exclusions, trusted_proxies,
custom_rules). Quick-Toggle ohne Drawer; Hinweis: erst Detection, dann Blocking.
- App.tsx: /waf Route + lazy import
- Sidebar.tsx: WAF im Security-Bereich
- i18n EN + DE
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>