Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7541460
ref(integrations): route HTTP header filtering through data collectio…
ericapisani Jul 8, 2026
5e9f610
Merge branch 'master' into py-2584-update-wsgi-filter-headers
ericapisani Jul 9, 2026
a590c8e
Make changes to adjust to the data collection option being within the…
ericapisani Jul 9, 2026
16ed0c8
fix test
ericapisani Jul 9, 2026
486f0bc
make sure host header is not filtered when being added to the url
ericapisani Jul 9, 2026
7d14a81
add test coverage for edge case around host header being dropped but …
ericapisani Jul 9, 2026
bb98334
add aws lambda test coverage
ericapisani Jul 9, 2026
61d1618
fix(aws-lambda): Remove vendored deps from new embedded-sdk test fixt…
ericapisani Jul 9, 2026
951c408
add test coverage within the wsgi test file
ericapisani Jul 9, 2026
a19be39
feat(integrations): apply data_collection cookie filtering to wsgi, s…
ericapisani Jul 10, 2026
620e222
fix(integrations): omit cookies field when data_collection cookies mo…
ericapisani Jul 10, 2026
ec6f520
update tornado test
ericapisani Jul 10, 2026
4dd3ba6
ref(integrations): route HTTP header filtering through data collectio…
ericapisani Jul 8, 2026
d0bae90
Make changes to adjust to the data collection option being within the…
ericapisani Jul 9, 2026
a6c4688
fix test
ericapisani Jul 9, 2026
d7b378b
make sure host header is not filtered when being added to the url
ericapisani Jul 9, 2026
52c2da1
add test coverage for edge case around host header being dropped but …
ericapisani Jul 9, 2026
aa645d7
add aws lambda test coverage
ericapisani Jul 9, 2026
8b6e3ad
fix(aws-lambda): Remove vendored deps from new embedded-sdk test fixt…
ericapisani Jul 9, 2026
d717172
add test coverage within the wsgi test file
ericapisani Jul 9, 2026
c7f590f
Merge branch 'py-2584-update-wsgi-filter-headers' of github.com:getse…
ericapisani Jul 14, 2026
293a291
feat(integrations): apply data_collection cookie filtering to wsgi, s…
ericapisani Jul 10, 2026
530e83c
fix(integrations): omit cookies field when data_collection cookies mo…
ericapisani Jul 10, 2026
326d796
update tornado test
ericapisani Jul 10, 2026
e9f0e20
Merge branch 'master' into py-2584-update-wsgi-filter-headers
ericapisani Jul 15, 2026
48f7c7b
Merge branch 'py-2581-cookies' of github.com:getsentry/sentry-python …
ericapisani Jul 15, 2026
621d79b
Merge branch 'py-2584-update-wsgi-filter-headers' into py-2581-cookies
ericapisani Jul 15, 2026
3d7bddb
test(aiohttp): Expect single span in streaming passthrough test
ericapisani Jul 15, 2026
fad2292
Merge branch 'py-2584-update-wsgi-filter-headers' into py-2581-cookies
ericapisani Jul 15, 2026
19d0b12
test(integrations): Replace NO_COOKIES sentinel with None
ericapisani Jul 22, 2026
45c77f9
Merge branch 'master' into py-2581-cookies
ericapisani Jul 22, 2026
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 @@ -89,7 +89,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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Been some time since I last looked at the extractor code -- so the Starlette extractor runs after this and overwrites the cookies?

Just wanted to double-check that we have the precedence right (and that the cookies are really missing if should_send_default_pii=False after this change)

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.

Been some time since I last looked at the extractor code -- so the Starlette extractor runs after this and overwrites the cookies?

It runs before this, and then, yes, overwrites the cookies.

If should_send_default_pii is false or if the data collection configuration filters out cookies, then the cookies key/value doesn't get set on info within the Starlette extractor's extract_request_info (and line 121 doesn't run).

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 @@ -279,7 +281,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 @@ -318,7 +321,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,
nullcontext,
parse_version,
transaction_from_function,
Expand Down Expand Up @@ -719,8 +721,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 @@ -734,7 +743,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,
nullcontext,
transaction_from_function,
)
Expand Down Expand Up @@ -227,7 +229,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 @@ -265,7 +268,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
115 changes: 115 additions & 0 deletions tests/integrations/django/test_data_scrubbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,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"}},
None,
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 None:
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