feat(waf): Regel direkt aus Alert als Ausnahme hinzufügen — v1.2.78
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>
This commit is contained in:
@@ -1823,7 +1823,11 @@
|
|||||||
"ruleId": "Regel-ID",
|
"ruleId": "Regel-ID",
|
||||||
"severity": "Schwere",
|
"severity": "Schwere",
|
||||||
"msg": "Meldung"
|
"msg": "Meldung"
|
||||||
}
|
},
|
||||||
|
"addException": "Als Ausnahme",
|
||||||
|
"exceptionAdded": "Regel als Ausnahme für diese Domain hinzugefügt.",
|
||||||
|
"exceptionFailed": "Ausnahme konnte nicht gespeichert werden.",
|
||||||
|
"noDomain": "Domain nicht gefunden — Ausnahme manuell konfigurieren."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1823,7 +1823,11 @@
|
|||||||
"ruleId": "Rule ID",
|
"ruleId": "Rule ID",
|
||||||
"severity": "Severity",
|
"severity": "Severity",
|
||||||
"msg": "Message"
|
"msg": "Message"
|
||||||
}
|
},
|
||||||
|
"addException": "Add exception",
|
||||||
|
"exceptionAdded": "Rule added as exception for this domain.",
|
||||||
|
"exceptionFailed": "Failed to add exception.",
|
||||||
|
"noDomain": "Domain not found — configure exception manually."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,6 +272,25 @@ function AlertsTab({ domainId }: { domainId?: number }) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const addException = useMutation({
|
||||||
|
mutationFn: async ({ domainId, ruleId }: { domainId: number; ruleId: number }) => {
|
||||||
|
// Fetch current config (returns default if none exists yet)
|
||||||
|
const r = await apiClient.get(`/waf/configs/${domainId}`)
|
||||||
|
const cfg: WafConfig = isEnvelope(r.data)
|
||||||
|
? (r.data.data as { config: WafConfig }).config
|
||||||
|
: defaultConfig(domainId)
|
||||||
|
const exclusions = [...(cfg.rule_exclusions ?? [])]
|
||||||
|
const ruleStr = String(ruleId)
|
||||||
|
if (!exclusions.includes(ruleStr)) exclusions.push(ruleStr)
|
||||||
|
return apiClient.put(`/waf/configs/${domainId}`, { ...cfg, rule_exclusions: exclusions })
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
message.success(t('waf.alerts.exceptionAdded'))
|
||||||
|
void qc.invalidateQueries({ queryKey: ['waf'] })
|
||||||
|
},
|
||||||
|
onError: () => message.error(t('waf.alerts.exceptionFailed')),
|
||||||
|
})
|
||||||
|
|
||||||
const severityColor = (s: string) => {
|
const severityColor = (s: string) => {
|
||||||
switch (s?.toLowerCase()) {
|
switch (s?.toLowerCase()) {
|
||||||
case 'critical': return 'red'
|
case 'critical': return 'red'
|
||||||
@@ -316,6 +335,32 @@ function AlertsTab({ domainId }: { domainId?: number }) {
|
|||||||
render: (v: string) => <Tag color={severityColor(v)}>{v || '—'}</Tag> },
|
render: (v: string) => <Tag color={severityColor(v)}>{v || '—'}</Tag> },
|
||||||
{ title: t('waf.alerts.col.msg'), dataIndex: 'rule_msg', key: 'rule_msg', ellipsis: true,
|
{ title: t('waf.alerts.col.msg'), dataIndex: 'rule_msg', key: 'rule_msg', ellipsis: true,
|
||||||
render: (v: string) => <Text style={{ fontSize: 11, color: '#64748B' }}>{v || '—'}</Text> },
|
render: (v: string) => <Text style={{ fontSize: 11, color: '#64748B' }}>{v || '—'}</Text> },
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
key: 'exception',
|
||||||
|
width: 130,
|
||||||
|
render: (_: unknown, row: WafAlert) => {
|
||||||
|
const canExclude = !!row.domain_id && row.rule_id > 0 && !isViewer
|
||||||
|
const isPending = addException.isPending &&
|
||||||
|
addException.variables?.domainId === row.domain_id &&
|
||||||
|
addException.variables?.ruleId === row.rule_id
|
||||||
|
return (
|
||||||
|
<Tooltip title={!row.domain_id ? t('waf.alerts.noDomain') : t('waf.alerts.addException')}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
disabled={!canExclude}
|
||||||
|
loading={isPending}
|
||||||
|
onClick={() => row.domain_id && addException.mutate({
|
||||||
|
domainId: row.domain_id,
|
||||||
|
ruleId: row.rule_id,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{t('waf.alerts.addException')}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user