start project

This commit is contained in:
Hemmat
2026-08-07 21:17:17 +03:30
commit ea1e1eead6
121 changed files with 8108 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
"""Severity scoring (Chapter 10): a simple, transparent rank-escalation
model — no ML, easy to explain to a non-expert user (Ch10's own requirement).
Chapter 07 assigns a PROVISIONAL severity per rule type at parse time.
This module computes an EFFECTIVE severity by escalating that base rank
for repeated/rapid hits from the same IP — the exact rule Ch10 names.
Escalation is rank-based and strictly non-decreasing: it starts at the
base severity's rank and only ever moves up (repeat-count / hit-rate
bonuses), clamped at "high". An earlier weighted-score-vs-fixed-threshold
version could silently *downgrade* an isolated high-severity event (e.g.
a single sqlmap hit) to "medium" purely because the thresholds weren't
calibrated to the base weights — caught by running the pipeline against
real sample data. A single dangerous event must never end up rated below
its own base severity; only repetition/rate should push it higher.
"""
from __future__ import annotations
from dataclasses import dataclass
_SEVERITY_RANKS = ["low", "medium", "high"]
_RANK_BY_SEVERITY = {name: rank for rank, name in enumerate(_SEVERITY_RANKS)}
_REPEAT_COUNT_HIGH = 20
_REPEAT_COUNT_MEDIUM = 5
_RAPID_AVG_INTERVAL_SECONDS = 60 # >1 event/minute from one IP suggests automation
@dataclass(frozen=True)
class SeverityInputs:
base_severity: str
ip_event_count: int
avg_interval_seconds: float | None # None if this IP has < 2 events in the window
def compute_effective_severity(inputs: SeverityInputs) -> str:
"""Two named, inspectable escalation rules: repeat-count and hit-rate."""
rank = _RANK_BY_SEVERITY.get(inputs.base_severity, 0)
if inputs.ip_event_count >= _REPEAT_COUNT_HIGH:
rank += 2
elif inputs.ip_event_count >= _REPEAT_COUNT_MEDIUM:
rank += 1
if inputs.avg_interval_seconds is not None and inputs.avg_interval_seconds < _RAPID_AVG_INTERVAL_SECONDS:
rank += 1
rank = min(rank, len(_SEVERITY_RANKS) - 1)
return _SEVERITY_RANKS[rank]