feat: notify RD Gateway events in Telegram outside min_severity
Route rdg.connection.* through notify_rdg_connection and add disconnected type. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,11 +21,13 @@ from app.services.notify_dispatch import (
|
|||||||
AUTH_LOGIN_SUCCESS_TYPES,
|
AUTH_LOGIN_SUCCESS_TYPES,
|
||||||
DAILY_REPORT_EVENT_TYPES,
|
DAILY_REPORT_EVENT_TYPES,
|
||||||
LIFECYCLE_EVENT_TYPE,
|
LIFECYCLE_EVENT_TYPE,
|
||||||
|
RDG_CONNECTION_TYPES,
|
||||||
notify_auth_login,
|
notify_auth_login,
|
||||||
notify_daily_report,
|
notify_daily_report,
|
||||||
notify_event,
|
notify_event,
|
||||||
notify_lifecycle,
|
notify_lifecycle,
|
||||||
notify_problem,
|
notify_problem,
|
||||||
|
notify_rdg_connection,
|
||||||
)
|
)
|
||||||
|
|
||||||
router = APIRouter(prefix="/events", tags=["events"])
|
router = APIRouter(prefix="/events", tags=["events"])
|
||||||
@@ -79,6 +81,8 @@ def post_event(
|
|||||||
notify_lifecycle(event, db=db)
|
notify_lifecycle(event, db=db)
|
||||||
elif event.type in AUTH_LOGIN_SUCCESS_TYPES:
|
elif event.type in AUTH_LOGIN_SUCCESS_TYPES:
|
||||||
notify_auth_login(event, db=db)
|
notify_auth_login(event, db=db)
|
||||||
|
elif event.type in RDG_CONNECTION_TYPES:
|
||||||
|
notify_rdg_connection(event, db=db)
|
||||||
else:
|
else:
|
||||||
notify_event(event, db=db)
|
notify_event(event, db=db)
|
||||||
if problem is not None and problem_created:
|
if problem is not None and problem_created:
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ logger = logging.getLogger(__name__)
|
|||||||
LIFECYCLE_EVENT_TYPE = "agent.lifecycle"
|
LIFECYCLE_EVENT_TYPE = "agent.lifecycle"
|
||||||
DAILY_REPORT_EVENT_TYPES = frozenset({"report.daily.ssh", "report.daily.rdp"})
|
DAILY_REPORT_EVENT_TYPES = frozenset({"report.daily.ssh", "report.daily.rdp"})
|
||||||
AUTH_LOGIN_SUCCESS_TYPES = frozenset({"rdp.login.success", "ssh.login.success"})
|
AUTH_LOGIN_SUCCESS_TYPES = frozenset({"rdp.login.success", "ssh.login.success"})
|
||||||
|
RDG_CONNECTION_TYPES = frozenset({
|
||||||
|
"rdg.connection.success",
|
||||||
|
"rdg.connection.disconnected",
|
||||||
|
"rdg.connection.failed",
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def _event_telegram_via_agent(event: Event) -> bool:
|
def _event_telegram_via_agent(event: Event) -> bool:
|
||||||
@@ -94,3 +99,11 @@ def notify_auth_login(event: Event, *, db: Session | None = None) -> None:
|
|||||||
if not should_notify_event(event, db):
|
if not should_notify_event(event, db):
|
||||||
return
|
return
|
||||||
_dispatch_lifecycle_channels(event, db=db, policy=policy)
|
_dispatch_lifecycle_channels(event, db=db, policy=policy)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_rdg_connection(event: Event, *, db: Session | None = None) -> None:
|
||||||
|
"""RD Gateway 302/303 — ingest всегда; Telegram SAC вне min_severity (как auth login)."""
|
||||||
|
policy = get_effective_notification_policy(db)
|
||||||
|
if not should_notify_event(event, db):
|
||||||
|
return
|
||||||
|
_dispatch_lifecycle_channels(event, db=db, policy=policy)
|
||||||
|
|||||||
@@ -428,8 +428,12 @@ def format_event_telegram_html(event: Event) -> str:
|
|||||||
|
|
||||||
def _format_rdg_html(event: Event) -> str:
|
def _format_rdg_html(event: Event) -> str:
|
||||||
details = _details_dict(event)
|
details = _details_dict(event)
|
||||||
ok = event.type.endswith(".success")
|
if event.type.endswith(".success"):
|
||||||
header = "✅ RD Gateway: подключение" if ok else "❌ RD Gateway: ошибка"
|
header = "✅ RD Gateway: подключение"
|
||||||
|
elif event.type.endswith(".disconnected"):
|
||||||
|
header = "ℹ️ RD Gateway: отключение"
|
||||||
|
else:
|
||||||
|
header = "❌ RD Gateway: ошибка"
|
||||||
msg = f"<b>{header}</b>\n"
|
msg = f"<b>{header}</b>\n"
|
||||||
msg += _line("👤", "Пользователь", html_escape(_detail(details, "user", "username")))
|
msg += _line("👤", "Пользователь", html_escape(_detail(details, "user", "username")))
|
||||||
msg += _line("🏢", "Хост", host_label(event.host))
|
msg += _line("🏢", "Хост", host_label(event.host))
|
||||||
|
|||||||
@@ -116,6 +116,33 @@ def test_notify_auth_login_bypasses_min_severity():
|
|||||||
mock_tg.notify_event.assert_called_once()
|
mock_tg.notify_event.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_notify_rdg_connection_bypasses_min_severity():
|
||||||
|
event = Event(
|
||||||
|
event_id="00000000-0000-4000-8000-000000000603",
|
||||||
|
host_id=1,
|
||||||
|
occurred_at=datetime(2026, 5, 31, 18, 36, tzinfo=timezone.utc),
|
||||||
|
category="auth",
|
||||||
|
type="rdg.connection.success",
|
||||||
|
severity="info",
|
||||||
|
title="RD Gateway event 302",
|
||||||
|
summary="RDG 302 papatramp -> 192.168.160.3",
|
||||||
|
details={"telegram_via": "sac"},
|
||||||
|
payload={},
|
||||||
|
)
|
||||||
|
policy = NotificationPolicyConfig(
|
||||||
|
min_severity="warning",
|
||||||
|
use_telegram=True,
|
||||||
|
use_webhook=False,
|
||||||
|
use_email=False,
|
||||||
|
source="db",
|
||||||
|
)
|
||||||
|
with patch.object(notify_dispatch, "get_effective_notification_policy", return_value=policy):
|
||||||
|
with patch.object(notify_dispatch, "should_notify_event", return_value=True):
|
||||||
|
with patch.object(notify_dispatch, "telegram_notify") as mock_tg:
|
||||||
|
notify_dispatch.notify_rdg_connection(event)
|
||||||
|
mock_tg.notify_event.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
def test_notify_auth_login_skips_telegram_when_via_agent():
|
def test_notify_auth_login_skips_telegram_when_via_agent():
|
||||||
event = Event(
|
event = Event(
|
||||||
event_id="00000000-0000-4000-8000-000000000602",
|
event_id="00000000-0000-4000-8000-000000000602",
|
||||||
|
|||||||
@@ -99,6 +99,8 @@
|
|||||||
"rdp.shadow.control.permission",
|
"rdp.shadow.control.permission",
|
||||||
"winrm.session.started",
|
"winrm.session.started",
|
||||||
"rdg.connection.success",
|
"rdg.connection.success",
|
||||||
|
"rdg.connection.disconnected",
|
||||||
|
"rdg.connection.failed",
|
||||||
"report.daily.ssh",
|
"report.daily.ssh",
|
||||||
"agent.heartbeat",
|
"agent.heartbeat",
|
||||||
"agent.test"
|
"agent.test"
|
||||||
|
|||||||
Reference in New Issue
Block a user