feat: 6 améliorations SOC — synthèse IP, baseline, sophistication, chasse proactive, badge ASN, 2 nouveaux onglets rotation
- investigation_summary.py: nouveau endpoint GET /api/investigation/{ip}/summary
agrège 6 sources (ML, bruteforce, TCP spoofing, JA4 rotation, persistance, timeline 24h)
en un score de risque 0-100 avec signaux détaillés
- InvestigationView.tsx: widget IPActivitySummary avec jauge Risk Score SVG,
badges multi-sources et mini-timeline 24h barres
- metrics.py: endpoint GET /api/metrics/baseline — comparaison 24h vs hier
(total détections, IPs uniques, alertes CRITICAL) avec % de variation
- IncidentsView.tsx: widget baseline avec ▲▼ sur le dashboard principal
- rotation.py: endpoints /sophistication et /proactive-hunt
Score sophistication = JOIN 3 tables (rotation×10 + récurrence×20 + log(bf+1)×5)
Chasse proactive = IPs récurrentes sous le seuil ML (abs(score) < 0.5)
- RotationView.tsx: onglets 🏆 Sophistication et 🕵️ Chasse proactive
avec tier APT-like/Advanced/Automated/Basic et boutons investigation
- detections.py: LEFT JOIN asn_reputation, badge coloré rouge/orange/vert
selon label (bot/scanner → score 0.05, human → 0.9)
- models.py: ajout champs asn_score et asn_rep_label dans Detection
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -30,10 +30,22 @@ interface MetricsSummary {
|
||||
unique_ips: number;
|
||||
}
|
||||
|
||||
interface BaselineMetric {
|
||||
today: number;
|
||||
yesterday: number;
|
||||
pct_change: number;
|
||||
}
|
||||
interface BaselineData {
|
||||
total_detections: BaselineMetric;
|
||||
unique_ips: BaselineMetric;
|
||||
critical_alerts: BaselineMetric;
|
||||
}
|
||||
|
||||
export function IncidentsView() {
|
||||
const navigate = useNavigate();
|
||||
const [clusters, setClusters] = useState<IncidentCluster[]>([]);
|
||||
const [metrics, setMetrics] = useState<MetricsSummary | null>(null);
|
||||
const [baseline, setBaseline] = useState<BaselineData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedClusters, setSelectedClusters] = useState<Set<string>>(new Set());
|
||||
|
||||
@ -47,6 +59,11 @@ export function IncidentsView() {
|
||||
setMetrics(metricsData.summary);
|
||||
}
|
||||
|
||||
const baselineResponse = await fetch('/api/metrics/baseline');
|
||||
if (baselineResponse.ok) {
|
||||
setBaseline(await baselineResponse.json());
|
||||
}
|
||||
|
||||
const clustersResponse = await fetch('/api/incidents/clusters');
|
||||
if (clustersResponse.ok) {
|
||||
const clustersData = await clustersResponse.json();
|
||||
@ -126,6 +143,38 @@ export function IncidentsView() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Baseline comparison */}
|
||||
{baseline && (
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{([
|
||||
{ key: 'total_detections', label: 'Détections 24h', icon: '📊' },
|
||||
{ key: 'unique_ips', label: 'IPs uniques', icon: '🖥️' },
|
||||
{ key: 'critical_alerts', label: 'Alertes CRITICAL', icon: '🔴' },
|
||||
] as { key: keyof BaselineData; label: string; icon: string }[]).map(({ key, label, icon }) => {
|
||||
const m = baseline[key];
|
||||
const up = m.pct_change > 0;
|
||||
const neutral = m.pct_change === 0;
|
||||
return (
|
||||
<div key={key} className="bg-background-card border border-border rounded-lg px-4 py-3 flex items-center gap-3">
|
||||
<span className="text-xl">{icon}</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-xs text-text-disabled uppercase tracking-wide">{label}</div>
|
||||
<div className="text-xl font-bold text-text-primary">{m.today.toLocaleString('fr-FR')}</div>
|
||||
<div className="text-xs text-text-secondary">hier: {m.yesterday.toLocaleString('fr-FR')}</div>
|
||||
</div>
|
||||
<div className={`text-sm font-bold px-2 py-1 rounded ${
|
||||
neutral ? 'text-text-disabled' :
|
||||
up ? 'text-threat-critical bg-threat-critical/10' :
|
||||
'text-threat-low bg-threat-low/10'
|
||||
}`}>
|
||||
{neutral ? '=' : up ? `▲ +${m.pct_change}%` : `▼ ${m.pct_change}%`}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Critical Metrics */}
|
||||
{metrics && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user