diff --git a/apps/backend/core/sentry.py b/apps/backend/core/sentry.py index 0634f4ad..50bab867 100644 --- a/apps/backend/core/sentry.py +++ b/apps/backend/core/sentry.py @@ -257,17 +257,28 @@ def init_sentry( event_level=logging.ERROR, # Send ERROR and above as events ) - # Initialize Sentry - sentry_sdk.init( - dsn=dsn, - environment=environment, - release=f"auto-claude@{version}", - traces_sample_rate=traces_sample_rate, - before_send=_before_send, - integrations=[logging_integration], - # Don't send PII - send_default_pii=False, - ) + # Initialize Sentry with exception handling for malformed DSN + try: + sentry_sdk.init( + dsn=dsn, + environment=environment, + release=f"auto-claude@{version}", + traces_sample_rate=traces_sample_rate, + before_send=_before_send, + integrations=[logging_integration], + # Don't send PII + send_default_pii=False, + ) + except Exception as e: + # Handle malformed DSN (e.g., missing public key) gracefully + # This prevents crashes when SENTRY_DSN is misconfigured + logger.warning( + f"[Sentry] Failed to initialize - invalid DSN configuration: {e}" + ) + logger.debug( + "[Sentry] DSN should be in format: https://PUBLIC_KEY@o123.ingest.sentry.io/PROJECT_ID" + ) + return False # Set component tag sentry_sdk.set_tag("component", component) diff --git a/tests/test_auth.py b/tests/test_auth.py index d5a41288..fe840ed8 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -67,8 +67,10 @@ class TestEnvVarTokenResolution: token = get_auth_token() assert token == claude_token - def test_no_token_returns_none(self): + def test_no_token_returns_none(self, mocker): """Returns None when no auth token is configured.""" + # Mock keychain to return None (env vars already cleared by fixture) + mocker.patch("core.auth.get_token_from_keychain", return_value=None) token = get_auth_token() assert token is None @@ -367,10 +369,12 @@ class TestRequireAuthToken: """Tests for require_auth_token function.""" @pytest.fixture(autouse=True) - def clear_env(self): - """Clear auth environment variables before each test.""" + def clear_env(self, mocker): + """Clear auth environment variables and mock keychain before each test.""" for var in AUTH_TOKEN_ENV_VARS: os.environ.pop(var, None) + # Mock keychain to return None (tests that need a token will set env var) + mocker.patch("core.auth.get_token_from_keychain", return_value=None) yield # Cleanup after test for var in AUTH_TOKEN_ENV_VARS: @@ -552,8 +556,10 @@ class TestTokenSourceDetection: source = get_auth_token_source() assert source == "Linux Secret Service" - def test_source_none_when_not_found(self): + def test_source_none_when_not_found(self, mocker): """Returns None when no token source is found.""" + # Mock keychain to return None (env vars already cleared by fixture) + mocker.patch("core.auth.get_token_from_keychain", return_value=None) source = get_auth_token_source() assert source is None