first add

This commit is contained in:
larssand
2026-06-18 21:03:07 +02:00
parent 191ac4cf55
commit 05038c6ad7
22 changed files with 701 additions and 0 deletions

119
src/fgai/logs.py Normal file
View File

@@ -0,0 +1,119 @@
from __future__ import annotations
import json
import shlex
from collections.abc import Iterable
from pathlib import Path
from .models import LogEvent
UTM_SUBTYPES = {
"ips",
"virus",
"av",
"anomaly",
"ddos",
"dos",
"webfilter",
"app-ctrl",
"application",
"waf",
"dns",
}
THREAT_ACTIONS = {
"blocked",
"block",
"dropped",
"drop",
"reset",
"reset-client",
"reset-server",
"detected",
"deny",
"quarantine",
}
SEVERITY_SCORE = {
"emergency": 6,
"alert": 6,
"critical": 5,
"high": 4,
"warning": 3,
"medium": 3,
"notice": 2,
"low": 1,
"information": 1,
"info": 1,
}
def parse_log_line(line: str) -> LogEvent:
stripped = line.strip()
if not stripped:
return LogEvent(raw=line, fields={})
if stripped.startswith("{"):
try:
data = json.loads(stripped)
except json.JSONDecodeError:
data = {}
else:
return LogEvent(raw=line, fields={str(k).lower(): str(v) for k, v in data.items()})
fields: dict[str, str] = {}
try:
parts = shlex.split(stripped)
except ValueError:
parts = stripped.split()
for part in parts:
if "=" not in part:
continue
key, value = part.split("=", 1)
fields[key.strip().lower()] = value.strip().strip('"')
return LogEvent(raw=line, fields=fields)
def read_events(path: str | Path) -> list[LogEvent]:
with Path(path).open("r", encoding="utf-8", errors="replace") as handle:
return [event for line in handle if (event := parse_log_line(line)).fields]
def is_utm_event(event: LogEvent) -> bool:
subtype = event.subtype
event_type = event.fields.get("type", "").lower()
return event_type == "utm" or subtype in UTM_SUBTYPES
def event_score(event: LogEvent) -> int:
score = SEVERITY_SCORE.get(event.severity, 0)
if is_utm_event(event):
score += 2
if event.action in THREAT_ACTIONS:
score += 2
if event.fields.get("attack") or event.fields.get("attackid") or event.fields.get("signature"):
score += 1
return score
def summarize_events(events: Iterable[LogEvent]) -> dict[str, int]:
summary = {
"total": 0,
"utm": 0,
"threat_actions": 0,
"with_src_ip": 0,
"critical_or_high": 0,
}
for event in events:
summary["total"] += 1
if is_utm_event(event):
summary["utm"] += 1
if event.action in THREAT_ACTIONS:
summary["threat_actions"] += 1
if event.src_ip:
summary["with_src_ip"] += 1
if event.severity in {"critical", "high", "alert", "emergency"}:
summary["critical_or_high"] += 1
return summary