Skip to content
Merged
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
30 changes: 11 additions & 19 deletions sentry_sdk/integrations/_wsgi_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import sentry_sdk
from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE
from sentry_sdk.data_collection import _apply_key_value_collection_filtering
from sentry_sdk.scope import should_send_default_pii
Comment thread
cursor[bot] marked this conversation as resolved.
from sentry_sdk.utils import AnnotatedValue, has_data_collection_enabled
from sentry_sdk.utils import AnnotatedValue

try:
from django.http.request import RawPostDataException
Expand Down Expand Up @@ -89,23 +88,16 @@ def extract_into_event(self, event: "Event") -> None:
content_length = self.content_length()
request_info = event.get("request", {})

# Prior to data collection being implemented we unconditionally attached
# the request body, which is why we default to True here.
attach_request_body = True

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

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

attach_request_body = (
"incoming_request" in client.options["data_collection"]["http_bodies"]
)

if attach_request_body:
if not request_body_within_bounds(client, content_length):
Expand Down
67 changes: 6 additions & 61 deletions tests/integrations/django/asgi/test_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ async def test_basic(
# to be installed manually (see myapp/asgi.py)
assert event["transaction"] == "/view-exc"
assert event["request"] == {
"cookies": {},
"headers": {},
"method": "GET",
"query_string": "test=query",
Expand All @@ -113,7 +112,7 @@ async def test_async_views(
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
data_collection={},
)

comm = HttpCommunicator(application, "GET", "/async_message")
Expand All @@ -128,10 +127,8 @@ async def test_async_views(

assert event["transaction"] == "/async_message"
assert event["request"] == {
"cookies": {},
"headers": {},
"method": "GET",
"query_string": None,
"url": "/async_message",
}

Expand Down Expand Up @@ -456,115 +453,63 @@ async def test_trace_from_headers_if_performance_disabled(

@pytest.mark.parametrize("application", APPS)
@pytest.mark.parametrize(
"send_default_pii,method,headers,url_name,body,expected_data",
"method,headers,url_name,body,expected_data",
[
(
True,
"POST",
[(b"content-type", b"text/plain")],
"post_echo_async",
b"",
None,
),
(
True,
"POST",
[(b"content-type", b"text/plain")],
"post_echo_async",
b"some raw text body",
"",
),
(
True,
"POST",
[(b"content-type", b"application/json")],
"post_echo_async",
b'{"username":"xyz","password":"xyz"}',
{"username": "xyz", "password": "[Filtered]"},
),
(
True,
"POST",
[(b"content-type", b"application/xml")],
"post_echo_async",
b'<?xml version="1.0" encoding="UTF-8"?><root></root>',
"",
),
(
True,
"POST",
[
(b"content-type", b"multipart/form-data; boundary=fd721ef49ea403a6"),
(b"content-length", BODY_FORM_CONTENT_LENGTH),
],
"post_echo_async",
BODY_FORM,
{"password": "[Filtered]", "photo": "", "username": "Jane"},
),
(
False,
"POST",
[(b"content-type", b"text/plain")],
"post_echo_async",
b"",
None,
),
(
False,
"POST",
[(b"content-type", b"text/plain")],
"post_echo_async",
b"some raw text body",
"",
),
(
False,
"POST",
[(b"content-type", b"application/json")],
"post_echo_async",
b'{"username":"xyz","password":"xyz"}',
{"username": "xyz", "password": "[Filtered]"},
{"username": "xyz", "password": "xyz"},
),
(
False,
"POST",
[(b"content-type", b"application/xml")],
"post_echo_async",
b'<?xml version="1.0" encoding="UTF-8"?><root></root>',
"",
),
(
False,
"POST",
[
(b"content-type", b"multipart/form-data; boundary=fd721ef49ea403a6"),
(b"content-length", BODY_FORM_CONTENT_LENGTH),
],
"post_echo_async",
BODY_FORM,
{"password": "[Filtered]", "photo": "", "username": "Jane"},
{"password": "hello123", "photo": "", "username": "Jane"},
),
],
)
@pytest.mark.asyncio
@pytest.mark.skipif(
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
)
async def test_asgi_request_body_send_default_pii(
async def test_asgi_request_body(
sentry_init,
capture_items,
application,
send_default_pii,
method,
headers,
url_name,
body,
expected_data,
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=send_default_pii,
)
sentry_init(integrations=[DjangoIntegration()], data_collection={})

comm = HttpCommunicator(
application,
Expand Down
4 changes: 1 addition & 3 deletions tests/integrations/django/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_request_captured(
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
data_collection={},
)
items = capture_items("event")
content, status, headers = unpack_werkzeug_response(client.get(reverse("message")))
Expand All @@ -151,11 +151,9 @@ def test_request_captured(

assert event["transaction"] == "/message"
assert event["request"] == {
"cookies": {},
"env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"},
"headers": {"Host": "localhost"},
"method": "GET",
"query_string": "",
"url": "http://localhost/message",
}

Expand Down
101 changes: 0 additions & 101 deletions tests/integrations/django/test_data_scrubbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,81 +20,6 @@ def client():
return Client(application)


@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_scrub_django_session_cookies_removed(
sentry_init,
client,
capture_items,
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=False,
)
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)
assert "cookies" not in event["request"]


@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_scrub_django_session_cookies_filtered(
sentry_init,
client,
capture_items,
):
sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)
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)
assert event["request"]["cookies"] == {
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
}


@pytest.mark.forked
@pytest_mark_django_db_decorator()
def test_scrub_django_custom_session_cookies_filtered(
sentry_init,
client,
capture_items,
settings,
):
settings.SESSION_COOKIE_NAME = "my_sess"
settings.CSRF_COOKIE_NAME = "csrf_secret"

sentry_init(
integrations=[DjangoIntegration()],
send_default_pii=True,
)
items = capture_items("event")
werkzeug_set_cookie(client, "localhost", "my_sess", "123")
werkzeug_set_cookie(client, "localhost", "csrf_secret", "456")
werkzeug_set_cookie(client, "localhost", "foo", "bar")
client.get(reverse("view_exc"))

(event,) = (item.payload for item in items)
assert event["request"]["cookies"] == {
"my_sess": "[Filtered]",
"csrf_secret": "[Filtered]",
"foo": "bar",
}


@pytest.mark.forked
@pytest_mark_django_db_decorator()
@pytest.mark.parametrize(
Expand Down Expand Up @@ -184,32 +109,6 @@ def test_data_collection_cookies(
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,
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)
assert event["request"]["cookies"] == {
"sessionid": "[Filtered]",
"csrftoken": "[Filtered]",
"foo": "bar",
}


# Query string used across the query-param filtering tests below. ``auth`` is a
# built-in sensitive term, so it is redacted by the default denylist.
QUERY_STRING = "toy=tennisball&color=red&auth=secret"
Expand Down
Loading