eeba3a704d
Send Telegram alerts for high/critical events and new Problems. Configurable via TELEGRAM_* env vars; ingest never fails on send errors.
69 lines
1.8 KiB
Python
69 lines
1.8 KiB
Python
"""Auto-create Problems from ingested events (MVP rules)."""
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models import Event, Problem, ProblemEvent
|
|
|
|
# event types that always open a problem
|
|
PROBLEM_TYPES = frozenset(
|
|
{
|
|
"ssh.ip.banned",
|
|
"ssh.bruteforce.mass",
|
|
}
|
|
)
|
|
|
|
HIGH_SEVERITIES = frozenset({"high", "critical"})
|
|
|
|
|
|
def maybe_create_problem(db: Session, event: Event) -> tuple[Problem | None, bool]:
|
|
if event.severity not in HIGH_SEVERITIES and event.type not in PROBLEM_TYPES:
|
|
return None, False
|
|
|
|
rule_id = "high_severity" if event.severity in HIGH_SEVERITIES else f"type:{event.type}"
|
|
|
|
existing = db.scalar(
|
|
select(Problem)
|
|
.join(ProblemEvent)
|
|
.where(
|
|
Problem.status == "open",
|
|
Problem.rule_id == rule_id,
|
|
Problem.host_id == event.host_id,
|
|
ProblemEvent.event_id == event.id,
|
|
)
|
|
.limit(1)
|
|
)
|
|
if existing:
|
|
return existing, False
|
|
|
|
# dedupe: one open problem per host+rule (append event link)
|
|
open_problem = db.scalar(
|
|
select(Problem)
|
|
.where(
|
|
Problem.status == "open",
|
|
Problem.rule_id == rule_id,
|
|
Problem.host_id == event.host_id,
|
|
)
|
|
.order_by(Problem.created_at.desc())
|
|
.limit(1)
|
|
)
|
|
if open_problem:
|
|
db.add(ProblemEvent(problem_id=open_problem.id, event_id=event.id))
|
|
open_problem.updated_at = event.received_at
|
|
db.flush()
|
|
return open_problem, False
|
|
|
|
problem = Problem(
|
|
host_id=event.host_id,
|
|
title=event.title,
|
|
summary=event.summary,
|
|
severity=event.severity,
|
|
status="open",
|
|
rule_id=rule_id,
|
|
)
|
|
db.add(problem)
|
|
db.flush()
|
|
db.add(ProblemEvent(problem_id=problem.id, event_id=event.id))
|
|
db.flush()
|
|
return problem, True
|