Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion sentry_sdk/integrations/_wsgi_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,14 @@ def extract_into_event(self, event: "Event") -> None:
content_length = self.content_length()
request_info = event.get("request", {})

if should_send_default_pii():
if has_data_collection_enabled(client.options):
cookies = _apply_key_value_collection_filtering(
items=dict(self.cookies()),
behaviour=client.options["data_collection"]["cookies"],
)
if cookies:
request_info["cookies"] = cookies
elif should_send_default_pii():
request_info["cookies"] = dict(self.cookies())

if not request_body_within_bounds(client, content_length):
Expand Down
3 changes: 1 addition & 2 deletions sentry_sdk/integrations/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import sentry_sdk
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations import DidNotEnable
from sentry_sdk.scope import should_send_default_pii
from sentry_sdk.traces import StreamedSpan, get_current_span
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
from sentry_sdk.tracing_utils import has_span_streaming_enabled
Expand Down Expand Up @@ -118,7 +117,7 @@ def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event":
# Extract information from request
request_info = event.get("request", {})
if info:
if "cookies" in info and should_send_default_pii():
if "cookies" in info:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the should_send_default_pii check here is no longer needed since this check happens within StarletteRequestExtractor

request_info["cookies"] = info["cookies"]
if "data" in info:
request_info["data"] = info["data"]
Expand Down
14 changes: 12 additions & 2 deletions sentry_sdk/integrations/litestar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import sentry_sdk
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.data_collection import _apply_key_value_collection_filtering
from sentry_sdk.integrations import (
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
DidNotEnable,
Expand All @@ -16,6 +17,7 @@
from sentry_sdk.utils import (
ensure_integration_enabled,
event_from_exception,
has_data_collection_enabled,
transaction_from_function,
)

Expand Down Expand Up @@ -273,7 +275,8 @@ def patch_http_route_handle() -> None:
async def handle_wrapper(
self: "HTTPRoute", scope: "HTTPScope", receive: "Receive", send: "Send"
) -> None:
if sentry_sdk.get_client().get_integration(LitestarIntegration) is None:
client = sentry_sdk.get_client()
if client.get_integration(LitestarIntegration) is None:
return await old_handle(self, scope, receive, send)

sentry_scope = sentry_sdk.get_isolation_scope()
Expand Down Expand Up @@ -312,7 +315,14 @@ async def handle_wrapper(
def event_processor(event: "Event", _: "Hint") -> "Event":
request_info = event.get("request", {})
request_info["content_length"] = len(scope.get("_body", b""))
if should_send_default_pii():
if has_data_collection_enabled(client.options):
cookies = _apply_key_value_collection_filtering(
items=extracted_request_data["cookies"],
behaviour=client.options["data_collection"]["cookies"],
)
if cookies:
request_info["cookies"] = cookies
elif should_send_default_pii():
request_info["cookies"] = extracted_request_data["cookies"]
if request_data is not None:
request_info["data"] = request_data
Expand Down
20 changes: 18 additions & 2 deletions sentry_sdk/integrations/starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import sentry_sdk
from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.data_collection import _apply_key_value_collection_filtering
from sentry_sdk.integrations import (
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
DidNotEnable,
Expand All @@ -35,6 +36,7 @@
capture_internal_exceptions,
ensure_integration_enabled,
event_from_exception,
has_data_collection_enabled,
parse_version,
transaction_from_function,
)
Expand Down Expand Up @@ -716,8 +718,15 @@ def __init__(self: "StarletteRequestExtractor", request: "Request") -> None:
def extract_cookies_from_request(
self: "StarletteRequestExtractor",
) -> "Optional[Dict[str, Any]]":
client_options = sentry_sdk.get_client().options
cookies: "Optional[Dict[str, Any]]" = None
if should_send_default_pii():
Comment thread
cursor[bot] marked this conversation as resolved.

if has_data_collection_enabled(client_options):
cookies = _apply_key_value_collection_filtering(
items=self.cookies(),
behaviour=client_options["data_collection"]["cookies"],
)
elif should_send_default_pii():
cookies = self.cookies()

return cookies
Expand All @@ -731,7 +740,14 @@ async def extract_request_info(

with capture_internal_exceptions():
# Add cookies
if should_send_default_pii():
if has_data_collection_enabled(client.options):
cookies = _apply_key_value_collection_filtering(
items=self.cookies(),
behaviour=client.options["data_collection"]["cookies"],
)
if cookies:
request_info["cookies"] = cookies
elif should_send_default_pii():
request_info["cookies"] = self.cookies()

# If there is no body, just return the cookies
Expand Down
14 changes: 12 additions & 2 deletions sentry_sdk/integrations/starlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import sentry_sdk
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.data_collection import _apply_key_value_collection_filtering
from sentry_sdk.integrations import DidNotEnable, Integration
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
from sentry_sdk.scope import should_send_default_pii
Expand All @@ -10,6 +11,7 @@
from sentry_sdk.utils import (
ensure_integration_enabled,
event_from_exception,
has_data_collection_enabled,
transaction_from_function,
)

Expand Down Expand Up @@ -224,7 +226,8 @@ def patch_http_route_handle() -> None:
async def handle_wrapper(
self: "HTTPRoute", scope: "HTTPScope", receive: "Receive", send: "Send"
) -> None:
if sentry_sdk.get_client().get_integration(StarliteIntegration) is None:
client = sentry_sdk.get_client()
if client.get_integration(StarliteIntegration) is None:
return await old_handle(self, scope, receive, send)

sentry_scope = sentry_sdk.get_isolation_scope()
Expand Down Expand Up @@ -262,7 +265,14 @@ async def handle_wrapper(
def event_processor(event: "Event", _: "Hint") -> "Event":
request_info = event.get("request", {})
request_info["content_length"] = len(scope.get("_body", b""))
if should_send_default_pii():
if has_data_collection_enabled(client.options):
cookies = _apply_key_value_collection_filtering(
items=extracted_request_data["cookies"],
behaviour=client.options["data_collection"]["cookies"],
)
if cookies:
request_info["cookies"] = cookies
elif should_send_default_pii():
request_info["cookies"] = extracted_request_data["cookies"]
if request_data is not None:
request_info["data"] = request_data
Expand Down
118 changes: 118 additions & 0 deletions tests/integrations/django/test_data_scrubbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from django.core.urlresolvers import reverse


NO_COOKIES = object()


@pytest.fixture
def client():
return Client(application)
Expand Down Expand Up @@ -99,3 +102,118 @@ def test_scrub_django_custom_session_cookies_filtered(
"csrf_secret": "[Filtered]",
"foo": "bar",
}


@pytest.mark.forked
@pytest_mark_django_db_decorator()
@pytest.mark.parametrize(
"cookies_to_set, data_collection, expected_cookies",
[
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar"},
{"cookies": {"mode": "off"}},
NO_COOKIES,
id="off",
),
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar"},
{"cookies": {"mode": "denylist"}},
{
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
},
id="denylist-default",
),
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar"},
{"cookies": {"mode": "denylist", "terms": ["foo"]}},
{
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "[Filtered]",
},
id="denylist-extra-terms",
),
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar", "bar": "baz"},
{"cookies": {"mode": "allowlist", "terms": ["foo"]}},
{
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
"bar": "[Filtered]",
},
id="allowlist",
),
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar", "bar": "baz"},
{"cookies": {"mode": "allowlist", "terms": ["sessionid", "foo"]}},
{
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
"bar": "[Filtered]",
},
id="allowlist-cannot-override-sensitive",
),
pytest.param(
{"sessionid": "123", "csrftoken": "456", "foo": "bar"},
{},
{
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
},
id="cookies-omitted-defaults-to-denylist",
),
],
)
def test_data_collection_cookies(
sentry_init,
client,
capture_items,
cookies_to_set,
data_collection,
expected_cookies,
):
sentry_init(
integrations=[DjangoIntegration()],
_experiments={"data_collection": data_collection},
)
items = capture_items("event")
for name, value in cookies_to_set.items():
werkzeug_set_cookie(client, "localhost", name, value)
client.get(reverse("view_exc"))

(event,) = (item.payload for item in items if item.type == "event")
if expected_cookies is NO_COOKIES:
assert "cookies" not in event["request"]
else:
assert event["request"]["cookies"] == expected_cookies


@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_data_collection_cookies_precedence_over_send_default_pii(
sentry_init, client, capture_items
):
# ``data_collection`` is the single source of truth: even with
# ``send_default_pii=False``, the configured cookie behaviour still applies.
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=False,
_experiments={"data_collection": {"cookies": {"mode": "denylist"}}},
)
items = capture_items("event")
werkzeug_set_cookie(client, "localhost", "sessionid", "123")
werkzeug_set_cookie(client, "localhost", "csrftoken", "456")
werkzeug_set_cookie(client, "localhost", "foo", "bar")
client.get(reverse("view_exc"))

(event,) = (item.payload for item in items if item.type == "event")
assert event["request"]["cookies"] == {
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
}
Loading
Loading