Files
security-alert-center/backend/tests/test_notify_dispatch.py
T
PapaTramp 563b836acc feat: Seaca mobile API, enrollment, FCM push and admin UI (0.9.0)
Adds mobile device registration by admin codes, refresh tokens, push channel
in notification policy, and Settings section for managing Seaca clients.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 13:19:14 +10:00

297 lines
11 KiB
Python

"""notify_dispatch respects global policy."""
from datetime import datetime, timezone
from unittest.mock import patch
from app.models import Event
from app.services import notify_dispatch
from app.services.notification_policy import NotificationPolicyConfig
def test_notify_event_calls_selected_channels():
event = Event(
event_id="00000000-0000-4000-8000-000000000401",
host_id=1,
occurred_at=datetime(2026, 5, 29, 15, 0, tzinfo=timezone.utc),
category="auth",
type="rdp.login.success",
severity="info",
title="ok",
summary="skip",
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=False,
use_email=False,
use_mobile=False,
source="db",
)
with patch.object(notify_dispatch, "get_effective_notification_policy", return_value=policy):
with patch.object(notify_dispatch, "telegram_notify") as mock_tg:
notify_dispatch.notify_event(event)
mock_tg.notify_event.assert_not_called()
def test_notify_event_calls_selected_channels():
event = Event(
event_id="00000000-0000-4000-8000-000000000402",
host_id=1,
occurred_at=datetime(2026, 5, 29, 15, 0, tzinfo=timezone.utc),
category="auth",
type="rdp.login.failed",
severity="warning",
title="fail",
summary="send",
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=True,
use_email=False,
use_mobile=False,
source="db",
)
with patch.object(notify_dispatch, "get_effective_notification_policy", return_value=policy):
with patch.object(notify_dispatch, "telegram_notify") as mock_tg:
with patch.object(notify_dispatch, "webhook_notify") as mock_wh:
with patch.object(notify_dispatch, "email_notify") as mock_em:
notify_dispatch.notify_event(event)
mock_tg.notify_event.assert_called_once()
mock_wh.notify_event.assert_called_once()
mock_em.notify_event.assert_not_called()
def test_notify_event_skipped_by_cooldown():
event = Event(
event_id="00000000-0000-4000-8000-000000000403",
host_id=1,
occurred_at=datetime(2026, 5, 29, 15, 0, tzinfo=timezone.utc),
category="auth",
type="rdp.login.failed",
severity="warning",
title="fail",
summary="send",
dedup_key="same-key",
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=False,
use_email=False,
use_mobile=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=False):
with patch.object(notify_dispatch, "telegram_notify") as mock_tg:
notify_dispatch.notify_event(event)
mock_tg.notify_event.assert_not_called()
def test_notify_auth_login_bypasses_min_severity():
event = Event(
event_id="00000000-0000-4000-8000-000000000601",
host_id=1,
occurred_at=datetime(2026, 5, 31, 18, 36, tzinfo=timezone.utc),
category="auth",
type="rdp.login.success",
severity="info",
title="RDP login event 4624",
summary="papatramp from 192.168.160.3",
details={"telegram_via": "sac"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=False,
use_email=False,
use_mobile=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_auth_login(event)
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,
use_mobile=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():
event = Event(
event_id="00000000-0000-4000-8000-000000000602",
host_id=1,
occurred_at=datetime(2026, 5, 31, 18, 36, tzinfo=timezone.utc),
category="auth",
type="ssh.login.success",
severity="info",
title="SSH login",
summary="user from 10.0.0.1",
details={"telegram_via": "agent"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=True,
use_email=False,
use_mobile=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:
with patch.object(notify_dispatch, "webhook_notify") as mock_wh:
notify_dispatch.notify_auth_login(event)
mock_tg.notify_event.assert_not_called()
mock_wh.notify_event.assert_called_once()
def test_notify_lifecycle_bypasses_min_severity():
event = Event(
event_id="00000000-0000-4000-8000-000000000501",
host_id=1,
occurred_at=datetime(2026, 5, 29, 15, 0, tzinfo=timezone.utc),
category="agent",
type="agent.lifecycle",
severity="info",
title="started",
summary="agent started",
details={"lifecycle": "started", "telegram_via": "sac"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=False,
use_email=False,
use_mobile=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_lifecycle(event)
mock_tg.notify_event.assert_called_once()
def test_notify_lifecycle_skips_telegram_when_via_agent():
event = Event(
event_id="00000000-0000-4000-8000-000000000502",
host_id=1,
occurred_at=datetime(2026, 5, 29, 15, 0, tzinfo=timezone.utc),
category="agent",
type="agent.lifecycle",
severity="info",
title="started",
summary="agent started",
details={"lifecycle": "started", "telegram_via": "agent"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=True,
use_email=False,
use_mobile=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:
with patch.object(notify_dispatch, "webhook_notify") as mock_wh:
notify_dispatch.notify_lifecycle(event)
mock_tg.notify_event.assert_not_called()
mock_wh.notify_event.assert_called_once()
def test_notify_daily_report_skips_telegram_when_via_agent():
event = Event(
event_id="00000000-0000-4000-8000-000000000604",
host_id=1,
occurred_at=datetime(2026, 6, 3, 9, 0, tzinfo=timezone.utc),
category="report",
type="report.daily.rdp",
severity="info",
title="Ежедневный отчёт Windows",
summary="RDP 24ч: успех 0, неудач 0, банов 0",
details={"telegram_via": "agent", "report_body": "📊 body"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=True,
use_email=False,
use_mobile=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:
with patch.object(notify_dispatch, "webhook_notify") as mock_wh:
notify_dispatch.notify_daily_report(event)
mock_tg.notify_event.assert_not_called()
mock_wh.notify_event.assert_called_once()
def test_notify_daily_report_skips_telegram_when_via_agent():
event = Event(
event_id="00000000-0000-4000-8000-000000000604",
host_id=1,
occurred_at=datetime(2026, 6, 3, 9, 0, tzinfo=timezone.utc),
category="report",
type="report.daily.rdp",
severity="info",
title="Ежедневный отчёт Windows",
summary="RDP 24ч: успех 0, неудач 0, банов 0",
details={"telegram_via": "agent", "report_body": "📊 body"},
payload={},
)
policy = NotificationPolicyConfig(
min_severity="warning",
use_telegram=True,
use_webhook=True,
use_email=False,
use_mobile=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:
with patch.object(notify_dispatch, "webhook_notify") as mock_wh:
notify_dispatch.notify_daily_report(event)
mock_tg.notify_event.assert_not_called()
mock_wh.notify_event.assert_called_once()