feat(waf): ausgeschlossene Regeln grün + Bereits-Ausnahme-Tag — v1.2.84

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-06-03 13:52:03 +02:00
parent 134466293d
commit 025854150d
5 changed files with 32 additions and 8 deletions

View File

@@ -1 +1 @@
1.2.83 1.2.84

View File

@@ -1833,7 +1833,8 @@
"noDomain": "Domain nicht gefunden — Ausnahme manuell konfigurieren.", "noDomain": "Domain nicht gefunden — Ausnahme manuell konfigurieren.",
"exceptionModalTitle": "Ausnahme für Regel {{rule}} hinzufügen", "exceptionModalTitle": "Ausnahme für Regel {{rule}} hinzufügen",
"exceptionModalHint": "Optional: Begründung warum diese Regel ein False Positive für diese Domain ist.", "exceptionModalHint": "Optional: Begründung warum diese Regel ein False Positive für diese Domain ist.",
"exceptionNotePlaceholder": "z.B. Unsere API verwendet nicht-standardisierte Header die diese Regel auslösen." "exceptionNotePlaceholder": "z.B. Unsere API verwendet nicht-standardisierte Header die diese Regel auslösen.",
"alreadyExcluded": "Bereits Ausnahme"
} }
} }
} }

View File

@@ -1833,7 +1833,8 @@
"noDomain": "Domain not found — configure exception manually.", "noDomain": "Domain not found — configure exception manually.",
"exceptionModalTitle": "Add exception for rule {{rule}}", "exceptionModalTitle": "Add exception for rule {{rule}}",
"exceptionModalHint": "Optional: describe why this rule is a false positive for this domain.", "exceptionModalHint": "Optional: describe why this rule is a false positive for this domain.",
"exceptionNotePlaceholder": "e.g. Our custom API uses non-standard headers that trigger this rule." "exceptionNotePlaceholder": "e.g. Our custom API uses non-standard headers that trigger this rule.",
"alreadyExcluded": "Already excluded"
} }
} }
} }

View File

@@ -292,7 +292,7 @@ async function fetchAlerts(domainId?: number): Promise<WafAlert[]> {
return (r.data.data as { alerts?: WafAlert[] }).alerts ?? [] return (r.data.data as { alerts?: WafAlert[] }).alerts ?? []
} }
function AlertsTab({ domainId }: { domainId?: number }) { function AlertsTab({ domainId, configMap }: { domainId?: number; configMap: Map<number, WafConfig> }) {
const { t } = useTranslation() const { t } = useTranslation()
const qc = useQueryClient() const qc = useQueryClient()
const isViewer = useAuthStore((s) => s.user?.role) === 'viewer' const isViewer = useAuthStore((s) => s.user?.role) === 'viewer'
@@ -388,6 +388,15 @@ function AlertsTab({ domainId }: { domainId?: number }) {
key: 'exception', key: 'exception',
width: 130, width: 130,
render: (_: unknown, row: WafAlert) => { render: (_: unknown, row: WafAlert) => {
const isExcluded = !!row.domain_id &&
(configMap.get(row.domain_id)?.rule_exclusions ?? []).includes(String(row.rule_id))
if (isExcluded) {
return (
<Tag color="success" icon={<CheckCircleOutlined />}>
{t('waf.alerts.alreadyExcluded')}
</Tag>
)
}
const canExclude = !!row.domain_id && row.rule_id > 0 && !isViewer const canExclude = !!row.domain_id && row.rule_id > 0 && !isViewer
return ( return (
<Tooltip title={!row.domain_id ? t('waf.alerts.noDomain') : undefined}> <Tooltip title={!row.domain_id ? t('waf.alerts.noDomain') : undefined}>
@@ -432,9 +441,13 @@ function AlertsTab({ domainId }: { domainId?: number }) {
loading={isLoading} loading={isLoading}
dataSource={alerts ?? []} dataSource={alerts ?? []}
columns={columns} columns={columns}
rowClassName={(row: WafAlert) => rowClassName={(row: WafAlert) => {
row.action === 'blocked' ? 'fw-rule-row--zero-hit' : '' const isExcluded = !!row.domain_id &&
} (configMap.get(row.domain_id)?.rule_exclusions ?? []).includes(String(row.rule_id))
if (isExcluded) return 'waf-alert-row--excluded'
if (row.action === 'blocked') return 'fw-rule-row--zero-hit'
return ''
}}
/> />
)} )}
@@ -642,7 +655,7 @@ export default function WAFPage() {
{ {
key: 'alerts', key: 'alerts',
label: t('waf.tabs.alerts'), label: t('waf.tabs.alerts'),
children: <AlertsTab />, children: <AlertsTab configMap={configMap} />,
}, },
]} ]}
/> />

View File

@@ -3057,6 +3057,15 @@ h1, h2, h3, h4, h5, h6 {
border-radius: 0 !important; border-radius: 0 !important;
} }
/* ── WAF Alert rows ──────────────────────────────────────────────────── */
.waf-alert-row--excluded > td {
background: #F0FDF4 !important;
color: #15803D !important;
}
.waf-alert-row--excluded:hover > td {
background: #DCFCE7 !important;
}
/* ── Firewall Filter-Bar ─────────────────────────────────────────────── */ /* ── Firewall Filter-Bar ─────────────────────────────────────────────── */
.fw-filter-bar { .fw-filter-bar {
display: flex; display: flex;