meal-order-manager/tests/test_sentry_init.py

221 lines
7.4 KiB
Python
Raw Normal View History

"""sentry_init: DSN no-op, FlaskIntegration, and before_send scrub."""
from unittest.mock import patch
from botocore.exceptions import ClientError
from sentry_sdk.integrations.flask import FlaskIntegration
import server.sentry_init as sentry_mod
_FAKE_DSN = "https://key@o1.ingest.sentry.io/1"
def _parameter_not_found():
return ClientError(
{"Error": {"Code": "ParameterNotFound", "Message": "not found"}},
"GetParameter",
)
def test_unset_dsn_does_not_init():
with (
patch.dict("os.environ", {}, clear=False),
patch("sentry_sdk.init") as mocked,
):
# Ensure both sources are absent even if a prior test set them.
import os
os.environ.pop("SENTRY_DSN", None)
os.environ.pop("SENTRY_DSN_PARAM", None)
sentry_mod.init_sentry()
mocked.assert_not_called()
def test_empty_dsn_does_not_init(monkeypatch):
monkeypatch.setenv("SENTRY_DSN", "")
monkeypatch.delenv("SENTRY_DSN_PARAM", raising=False)
with patch("sentry_sdk.init") as mocked:
sentry_mod.init_sentry()
mocked.assert_not_called()
def test_literal_unset_dsn_does_not_init(monkeypatch):
monkeypatch.setenv("SENTRY_DSN", "unset")
with patch("sentry_sdk.init") as mocked:
sentry_mod.init_sentry()
mocked.assert_not_called()
def test_set_dsn_inits_flask_integration(monkeypatch):
monkeypatch.setenv("SENTRY_DSN", _FAKE_DSN)
monkeypatch.setenv("STAGE", "dev")
monkeypatch.setenv("GIT_SHA", "abc123def")
with patch("sentry_sdk.init") as mocked:
sentry_mod.init_sentry()
mocked.assert_called_once()
kwargs = mocked.call_args.kwargs
assert kwargs["dsn"] == _FAKE_DSN
assert kwargs["send_default_pii"] is False
assert kwargs["include_local_variables"] is False
assert kwargs["enable_logs"] is False
assert kwargs["traces_sample_rate"] == 0.0
assert kwargs["before_send"] is sentry_mod._before_send
assert kwargs["environment"] == "dev"
assert kwargs["release"] == "abc123def"
integrations = kwargs["integrations"]
assert len(integrations) == 1
assert isinstance(integrations[0], FlaskIntegration)
def test_missing_stage_defaults_environment_to_local(monkeypatch):
monkeypatch.setenv("SENTRY_DSN", _FAKE_DSN)
monkeypatch.delenv("STAGE", raising=False)
monkeypatch.delenv("GIT_SHA", raising=False)
with patch("sentry_sdk.init") as mocked:
sentry_mod.init_sentry()
kwargs = mocked.call_args.kwargs
assert kwargs["environment"] == "local"
assert "release" not in kwargs
def test_sentry_dsn_param_fetches_from_ssm(monkeypatch):
monkeypatch.delenv("SENTRY_DSN", raising=False)
monkeypatch.setenv("SENTRY_DSN_PARAM", "/meal-order-manager/sentry-dsn")
monkeypatch.setenv("STAGE", "dev")
monkeypatch.setenv("GIT_SHA", "deadbeef")
with (
patch("shared.secrets.get_parameter", return_value=_FAKE_DSN) as mock_get,
patch("sentry_sdk.init") as mocked,
):
sentry_mod.init_sentry()
mock_get.assert_called_once_with("/meal-order-manager/sentry-dsn", decrypt=True)
mocked.assert_called_once()
assert mocked.call_args.kwargs["dsn"] == _FAKE_DSN
assert isinstance(mocked.call_args.kwargs["integrations"][0], FlaskIntegration)
def test_sentry_dsn_param_unset_value_does_not_init(monkeypatch):
monkeypatch.delenv("SENTRY_DSN", raising=False)
monkeypatch.setenv("SENTRY_DSN_PARAM", "/meal-order-manager/sentry-dsn")
with (
patch("shared.secrets.get_parameter", return_value="unset"),
patch("sentry_sdk.init") as mocked,
):
sentry_mod.init_sentry()
mocked.assert_not_called()
def test_sentry_dsn_param_not_found_does_not_init(monkeypatch):
monkeypatch.delenv("SENTRY_DSN", raising=False)
monkeypatch.setenv("SENTRY_DSN_PARAM", "/meal-order-manager/sentry-dsn")
with (
patch("shared.secrets.get_parameter", side_effect=_parameter_not_found()),
patch("sentry_sdk.init") as mocked,
):
sentry_mod.init_sentry()
mocked.assert_not_called()
def test_before_send_strips_auth_and_publish_key_headers():
event = {
"request": {
"headers": {
"Authorization": "Bearer secret",
"X-Meals-Publish-Key": "hmac-secret",
"X-Auth-Token": "tok",
"Cookie": "session=abc",
"X-Amz-Date": "20260101T000000Z",
"Content-Type": "application/json",
},
"url": "https://example.invalid/api/submit-order",
}
}
out = sentry_mod._before_send(event, {})
assert out["request"]["headers"] == {"Content-Type": "application/json"}
assert out["request"]["url"] == "https://example.invalid/api/submit-order"
def test_before_send_strips_list_headers():
event = {
"request": {
"headers": [
("Authorization", "Bearer secret"),
("X-Meals-Publish-Key", "hmac-secret"),
("Content-Type", "application/json"),
]
}
}
out = sentry_mod._before_send(event, {})
assert out["request"]["headers"] == [("Content-Type", "application/json")]
def test_before_send_drops_body_and_secret_keys():
event = {
"request": {
"body": '{"google_id_token":"ya29.secret"}',
"data": {"google_id_token": "ya29.secret"},
"method": "POST",
},
"extra": {
"google_id_token": "ya29.secret",
"publish_hmac": "aabbcc",
"bot_token": "xoxb-secret",
"week": "2026-W38",
},
}
out = sentry_mod._before_send(event, {})
assert "body" not in out["request"]
assert "data" not in out["request"]
assert out["request"]["method"] == "POST"
assert "google_id_token" not in out["extra"]
assert "publish_hmac" not in out["extra"]
assert "bot_token" not in out["extra"]
assert out["extra"]["week"] == "2026-W38"
def test_before_send_drops_exception_and_thread_frame_locals():
event = {
"exception": {
"values": [
{
"stacktrace": {
"frames": [
{
"function": "handler",
"vars": {
"google_id_token": "ya29.secret",
"SecretString": "aabbcc",
},
}
]
}
}
]
},
"threads": {
"values": [
{
"stacktrace": {
"frames": [
{
"function": "_require_publish_key",
"vars": {"provided": "hmac-secret"},
}
]
}
}
]
},
"stacktrace": {
"frames": [{"function": "get_secret", "vars": {"item": {"token": "x"}}}]
},
}
out = sentry_mod._before_send(event, {})
assert "vars" not in out["exception"]["values"][0]["stacktrace"]["frames"][0]
assert "vars" not in out["threads"]["values"][0]["stacktrace"]["frames"][0]
assert "vars" not in out["stacktrace"]["frames"][0]
assert (
out["exception"]["values"][0]["stacktrace"]["frames"][0]["function"]
== "handler"
)