mirror of
https://github.com/ParrotXray/Mantis.git
synced 2026-08-24 18:50:28 +09:00
fix: correct AlertSource/AlertSeverity casing to match serde snake_case
Root cause: AlertSource and AlertSeverity use #[serde(rename_all = "snake_case")],
so the JSON values are "ml"/"rule"/"fusion" and "high"/"critical" — not PascalCase.
SOURCE_CONFIG and SEVERITY_CONFIG keys were PascalCase, causing undefined lookups.
Changes:
- Type aliases: 'Ml'|'Rule'|'Fusion' -> 'ml'|'rule'|'fusion'
'High'|'Critical' -> 'high'|'critical'
- SOURCE_CONFIG keys: Ml/Rule/Fusion -> ml/rule/fusion
- SEVERITY_CONFIG keys: Critical/High -> critical/high
- All source/severity comparisons updated to lowercase
- Stats filter predicates updated to lowercase
- Filter button arrays updated to lowercase
https://claude.ai/code/session_01Wen51749mAnwBEfh7XmvUw
This commit is contained in:
parent
a163d88f15
commit
7fe77d235b
@ -26,8 +26,8 @@ import LoadingSpinner from '../components/LoadingSpinner'
|
||||
|
||||
// --- Types (mirrors backend UnifiedAlert) ---
|
||||
|
||||
type AlertSource = 'Ml' | 'Rule' | 'Fusion'
|
||||
type AlertSeverity = 'High' | 'Critical'
|
||||
type AlertSource = 'ml' | 'rule' | 'fusion'
|
||||
type AlertSeverity = 'high' | 'critical'
|
||||
|
||||
interface UnifiedAlert {
|
||||
timestamp: number
|
||||
@ -50,19 +50,19 @@ interface UnifiedAlert {
|
||||
// --- Display config ---
|
||||
|
||||
const SOURCE_CONFIG = {
|
||||
Ml: {
|
||||
label: 'AI',
|
||||
ml: {
|
||||
label: 'ML',
|
||||
color: '#7c3aed',
|
||||
bgColor: 'rgba(124,58,237,0.10)',
|
||||
icon: faBrain,
|
||||
},
|
||||
Rule: {
|
||||
rule: {
|
||||
label: 'Rule',
|
||||
color: '#2563eb',
|
||||
bgColor: 'rgba(37,99,235,0.10)',
|
||||
icon: faScroll,
|
||||
},
|
||||
Fusion: {
|
||||
fusion: {
|
||||
label: 'Fusion',
|
||||
color: '#dc2626',
|
||||
bgColor: 'rgba(220,38,38,0.10)',
|
||||
@ -71,13 +71,13 @@ const SOURCE_CONFIG = {
|
||||
} as const
|
||||
|
||||
const SEVERITY_CONFIG = {
|
||||
Critical: {
|
||||
critical: {
|
||||
label: 'Critical',
|
||||
color: '#dc2626',
|
||||
bgColor: 'rgba(220,38,38,0.10)',
|
||||
icon: faExclamationTriangle,
|
||||
},
|
||||
High: {
|
||||
high: {
|
||||
label: 'High',
|
||||
color: '#d97706',
|
||||
bgColor: 'rgba(217,119,6,0.10)',
|
||||
@ -383,7 +383,7 @@ const AlertDetails: React.FC<AlertDetailsProps> = ({ alert, onClose, showNotific
|
||||
{(alert.attack_type || alert.rule_msg) && (
|
||||
<div className="mb-6">
|
||||
<span className="text-sm font-medium text-gray-600">
|
||||
{alert.source === 'Ml' ? 'Attack Type' : 'Rule Message'}:
|
||||
{alert.source === 'ml' ? 'Attack Type' : 'Rule Message'}:
|
||||
</span>
|
||||
<div className="mt-1 p-3 bg-gray-50 rounded-lg">
|
||||
<p className="text-sm text-gray-900">{alert.attack_type ?? alert.rule_msg}</p>
|
||||
@ -392,7 +392,7 @@ const AlertDetails: React.FC<AlertDetailsProps> = ({ alert, onClose, showNotific
|
||||
)}
|
||||
|
||||
{/* ML inference metrics */}
|
||||
{(alert.source === 'Ml' || alert.source === 'Fusion') && (
|
||||
{(alert.source === 'ml' || alert.source === 'fusion') && (
|
||||
<div className="mb-6 space-y-3">
|
||||
<h4 className="text-sm font-semibold text-gray-700">ML Inference Metrics</h4>
|
||||
<div className="flex justify-between items-center">
|
||||
@ -420,7 +420,7 @@ const AlertDetails: React.FC<AlertDetailsProps> = ({ alert, onClose, showNotific
|
||||
)}
|
||||
|
||||
{/* Rule SID */}
|
||||
{(alert.source === 'Rule' || alert.source === 'Fusion') && alert.rule_sid !== null && (
|
||||
{(alert.source === 'rule' || alert.source === 'fusion') && alert.rule_sid !== null && (
|
||||
<div className="mb-6">
|
||||
<h4 className="text-sm font-semibold text-gray-700 mb-2">Rule Info</h4>
|
||||
<div className="flex justify-between items-center">
|
||||
@ -530,11 +530,11 @@ const Detection: React.FC = () => {
|
||||
const stats = useMemo(
|
||||
() => ({
|
||||
total: alerts.length,
|
||||
critical: alerts.filter(a => a.severity === 'Critical').length,
|
||||
high: alerts.filter(a => a.severity === 'High').length,
|
||||
ml: alerts.filter(a => a.source === 'Ml').length,
|
||||
rule: alerts.filter(a => a.source === 'Rule').length,
|
||||
fusion: alerts.filter(a => a.source === 'Fusion').length,
|
||||
critical: alerts.filter(a => a.severity === 'critical').length,
|
||||
high: alerts.filter(a => a.severity === 'high').length,
|
||||
ml: alerts.filter(a => a.source === 'ml').length,
|
||||
rule: alerts.filter(a => a.source === 'rule').length,
|
||||
fusion: alerts.filter(a => a.source === 'fusion').length,
|
||||
uniqueIPs: new Set([...alerts.map(a => a.src_ip), ...alerts.map(a => a.dst_ip)]).size,
|
||||
}),
|
||||
[alerts]
|
||||
@ -652,15 +652,15 @@ const Detection: React.FC = () => {
|
||||
{/* Source filter */}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-xs text-gray-500">Source:</span>
|
||||
{(['all', 'Ml', 'Rule', 'Fusion'] as const).map(s => (
|
||||
{(['all', 'ml', 'rule', 'fusion'] as const).map(s => (
|
||||
<FilterButton
|
||||
key={s}
|
||||
isActive={sourceFilter === s}
|
||||
onClick={() => setSourceFilter(s)}
|
||||
activeColor={
|
||||
s === 'all' ? '#374151'
|
||||
: s === 'Ml' ? '#7c3aed'
|
||||
: s === 'Rule' ? '#2563eb'
|
||||
: s === 'ml' ? '#7c3aed'
|
||||
: s === 'rule' ? '#2563eb'
|
||||
: '#dc2626'
|
||||
}
|
||||
>
|
||||
@ -674,13 +674,13 @@ const Detection: React.FC = () => {
|
||||
{/* Severity filter */}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-xs text-gray-500">Severity:</span>
|
||||
{(['all', 'Critical', 'High'] as const).map(s => (
|
||||
{(['all', 'critical', 'high'] as const).map(s => (
|
||||
<FilterButton
|
||||
key={s}
|
||||
isActive={severityFilter === s}
|
||||
onClick={() => setSeverityFilter(s)}
|
||||
activeColor={
|
||||
s === 'all' ? '#374151' : s === 'Critical' ? '#dc2626' : '#d97706'
|
||||
s === 'all' ? '#374151' : s === 'critical' ? '#dc2626' : '#d97706'
|
||||
}
|
||||
>
|
||||
{s === 'all' ? 'All' : SEVERITY_CONFIG[s].label}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user