""" 🚨 Тесты интеграции OAuth безопасности с GlitchTip Проверяем отправку алертов безопасности в GlitchTip при критических событиях. """ import pytest from unittest.mock import MagicMock, patch, call from auth.oauth_security import ( send_rate_limit_alert, send_open_redirect_alert, log_oauth_security_event, _send_security_alert_to_glitchtip, ) class TestGlitchTipSecurityAlerts: """🚨 Тесты отправки алертов безопасности в GlitchTip""" @patch('sentry_sdk.capture_message') @patch('sentry_sdk.configure_scope') def test_critical_security_event_sent_as_error(self, mock_configure_scope, mock_capture_message): """🚨 Критические события отправляются как ERROR в GlitchTip""" mock_scope = MagicMock() mock_configure_scope.return_value.__enter__.return_value = mock_scope # Критическое событие _send_security_alert_to_glitchtip("rate_limit_exceeded", { "ip": "192.168.1.100", "attempts": 15, "severity": "high" }) # Проверяем настройку scope mock_scope.set_tag.assert_any_call("security_event", "rate_limit_exceeded") mock_scope.set_tag.assert_any_call("component", "oauth") mock_scope.set_tag.assert_any_call("client_ip", "192.168.1.100") mock_scope.set_context.assert_called_once() # Проверяем отправку как ERROR mock_capture_message.assert_called_once_with( "🚨 CRITICAL OAuth Security Event: rate_limit_exceeded", level="error" ) @patch('sentry_sdk.capture_message') @patch('sentry_sdk.configure_scope') def test_normal_security_event_sent_as_warning(self, mock_configure_scope, mock_capture_message): """⚠️ Обычные события отправляются как WARNING в GlitchTip""" mock_scope = MagicMock() mock_configure_scope.return_value.__enter__.return_value = mock_scope # Обычное событие _send_security_alert_to_glitchtip("oauth_login_attempt", { "provider": "github", "ip": "192.168.1.100" }) # Проверяем настройку scope mock_scope.set_tag.assert_any_call("security_event", "oauth_login_attempt") mock_scope.set_tag.assert_any_call("oauth_provider", "github") # Проверяем отправку как WARNING mock_capture_message.assert_called_once_with( "⚠️ OAuth Security Event: oauth_login_attempt", level="warning" ) @patch('sentry_sdk.capture_message') @patch('sentry_sdk.configure_scope') def test_open_redirect_alert_integration(self, mock_configure_scope, mock_capture_message): """🚨 Тест интеграции алерта open redirect атаки""" mock_scope = MagicMock() mock_configure_scope.return_value.__enter__.return_value = mock_scope # Отправляем алерт о попытке open redirect send_open_redirect_alert("https://evil.com/steal", "192.168.1.100") # Проверяем что событие отправлено как критическое mock_scope.set_tag.assert_any_call("security_event", "open_redirect_attempt") mock_scope.set_tag.assert_any_call("client_ip", "192.168.1.100") mock_capture_message.assert_called_once_with( "🚨 CRITICAL OAuth Security Event: open_redirect_attempt", level="error" ) @patch('sentry_sdk.capture_message') @patch('sentry_sdk.configure_scope') def test_rate_limit_alert_integration(self, mock_configure_scope, mock_capture_message): """🚨 Тест интеграции алерта превышения rate limit""" mock_scope = MagicMock() mock_configure_scope.return_value.__enter__.return_value = mock_scope # Отправляем алерт о превышении rate limit send_rate_limit_alert("192.168.1.100", 15) # Проверяем что событие отправлено как критическое mock_scope.set_tag.assert_any_call("security_event", "rate_limit_exceeded") mock_scope.set_tag.assert_any_call("client_ip", "192.168.1.100") mock_capture_message.assert_called_once_with( "🚨 CRITICAL OAuth Security Event: rate_limit_exceeded", level="error" ) @patch('sentry_sdk.configure_scope') def test_glitchtip_failure_handling(self, mock_configure_scope): """❌ Тест обработки ошибок GlitchTip (не ломает основную логику)""" # Симулируем ошибку GlitchTip mock_configure_scope.side_effect = Exception("GlitchTip unavailable") # Функция не должна упасть try: _send_security_alert_to_glitchtip("test_event", {"test": "data"}) # Если дошли сюда - хорошо, ошибка обработана except Exception as e: pytest.fail(f"GlitchTip error should be handled gracefully: {e}") @patch('sentry_sdk.capture_message') @patch('sentry_sdk.configure_scope') def test_security_context_tags(self, mock_configure_scope, mock_capture_message): """🏷️ Тест правильной установки тегов и контекста""" mock_scope = MagicMock() mock_configure_scope.return_value.__enter__.return_value = mock_scope details = { "ip": "192.168.1.100", "provider": "github", "redirect_uri": "https://evil.com", "attempts": 15, "severity": "critical" } _send_security_alert_to_glitchtip("rate_limit_exceeded", details) # Проверяем все теги expected_calls = [ call("security_event", "rate_limit_exceeded"), call("component", "oauth"), call("client_ip", "192.168.1.100"), call("oauth_provider", "github"), call("has_redirect_uri", "true") ] for expected_call in expected_calls: assert expected_call in mock_scope.set_tag.call_args_list # Проверяем контекст mock_scope.set_context.assert_called_once_with("security_details", details) @patch('auth.oauth_security._send_security_alert_to_glitchtip') def test_log_oauth_security_event_calls_glitchtip(self, mock_glitchtip): """🔗 Тест что log_oauth_security_event вызывает GlitchTip""" event_type = "test_event" details = {"test": "data"} log_oauth_security_event(event_type, details) # Проверяем что GlitchTip функция была вызвана mock_glitchtip.assert_called_once_with(event_type, details) def test_critical_events_list(self): """📋 Тест что критические события правильно определены""" # Эти события должны отправляться как ERROR critical_events = [ "open_redirect_attempt", "rate_limit_exceeded", "invalid_provider", "suspicious_redirect_uri", "brute_force_detected" ] # Проверяем что список не пустой и содержит ожидаемые события assert len(critical_events) > 0 assert "open_redirect_attempt" in critical_events assert "rate_limit_exceeded" in critical_events