worked poc

This commit is contained in:
Mateusz Gruszczyński
2026-08-14 11:33:01 +02:00
parent adfdb0b86c
commit fc3a2944b2
94 changed files with 2931 additions and 3412 deletions
+74
View File
@@ -0,0 +1,74 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class TuningDecision:
keep: bool
reason: str
class AlertTuner:
"""Small second-stage noise filter for the dashboard/incident database.
It intentionally does not replace Suricata threshold.config. The latter is
the right place for sensor-level suppressions and thresholds. This filter
is a final guardrail so low-priority or explicitly ignored alerts do not
flood SQLite and the UI.
"""
def __init__(
self,
max_severity: int,
ignore_sids: str = "",
ignore_categories: str = "",
) -> None:
self.max_severity = max(0, int(max_severity))
self.ignore_sids = _parse_int_set(ignore_sids)
self.ignore_categories = {
value.strip().casefold()
for value in (ignore_categories or "").split(",")
if value.strip()
}
def evaluate(self, event: dict[str, Any]) -> TuningDecision:
alert = event.get("alert") or {}
sid = _as_int(alert.get("signature_id"))
severity = _as_int(alert.get("severity"))
category = str(alert.get("category") or "").strip()
if sid is not None and sid in self.ignore_sids:
return TuningDecision(False, "ignored_sid")
if category and category.casefold() in self.ignore_categories:
return TuningDecision(False, "ignored_category")
if self.max_severity > 0:
if severity is None:
return TuningDecision(False, "invalid_severity")
if severity > self.max_severity:
return TuningDecision(False, "low_priority")
return TuningDecision(True, "accepted")
def _parse_int_set(value: str) -> set[int]:
result: set[int] = set()
for item in (value or "").split(","):
item = item.strip()
if not item:
continue
try:
result.add(int(item))
except ValueError:
continue
return result
def _as_int(value: Any) -> int | None:
try:
return int(value)
except (TypeError, ValueError):
return None