feat: add alert correlation & normalization engine with tRPC router

Implement the cross-service alert correlation and normalization engine:

- correlation router with 6 procedures: getAlerts, getAlertDetails,
  getGroups, getGroupDetails, resolveAlert, getStats
- correlation service with normalizeAlert, correlateAlerts,
  getAlertTimeline, resolveAlert, getThreatScore, getAlertStats
- correlation engine with findRelatedAlerts, createCorrelationGroup,
  updateGroupSeverity, deduplicateAlerts
- alert normalizer with service-specific converters for DarkWatch,
  SpamShield, VoicePrint, HomeTitle, and RemoveBrokers
- Entity extraction (emails, phones, SSNs) and threat scoring
  with severity-weighted decay over 30-day window
- 52 unit tests across engine, service, normalizer, and router
This commit is contained in:
2026-05-25 16:55:31 -04:00
parent d84595bf72
commit 4f7882a10d
10 changed files with 1662 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
import { object, string, minLength, optional, number, picklist } from "valibot";
export const AlertFilterSchema = object({
source: optional(
picklist(["DARKWATCH", "SPAMSHIELD", "VOICEPRINT", "CALL_ANALYSIS", "HOME_TITLE", "INFO_BROKER"]),
),
severity: optional(
picklist(["LOW", "INFO", "MEDIUM", "WARNING", "HIGH", "CRITICAL"]),
),
status: optional(
picklist(["ACTIVE", "RESOLVED", "FALSE_POSITIVE"]),
),
page: optional(number(), 1),
limit: optional(number(), 20),
});
export const AlertDetailsSchema = object({
alertId: string([minLength(1)]),
});
export const GroupFilterSchema = object({
status: optional(
picklist(["ACTIVE", "RESOLVED", "FALSE_POSITIVE"]),
),
page: optional(number(), 1),
limit: optional(number(), 20),
});
export const GroupDetailsSchema = object({
groupId: string([minLength(1)]),
});
export const ResolveAlertSchema = object({
alertId: string([minLength(1)]),
resolution: picklist(["RESOLVED", "FALSE_POSITIVE"]),
});