From 3b5e8d034b9dcd12c7167491debdcae436c0f248 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 24 Sep 2026 16:40:43 +0200 Subject: [PATCH 1/2] ref(httpx): Remove support for `send_default_pii` --- sentry_sdk/integrations/httpx.py | 6 +-- tests/integrations/httpx/test_httpx.py | 67 +++++++++++++++++--------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/sentry_sdk/integrations/httpx.py b/sentry_sdk/integrations/httpx.py index 4286b84aa9..a3a79a67d5 100644 --- a/sentry_sdk/integrations/httpx.py +++ b/sentry_sdk/integrations/httpx.py @@ -7,7 +7,7 @@ from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_http_request_source, - get_url_attributes_legacy, + get_url_attributes, propagate_trace_headers, ) from sentry_sdk.utils import ( @@ -59,7 +59,7 @@ def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes = get_url_attributes_legacy(client, parsed_url) + url_attributes = get_url_attributes(client, parsed_url) if sentry_sdk.get_current_span() is None: span_ctx = nullcontext() @@ -148,7 +148,7 @@ async def send( }, ) - url_attributes = get_url_attributes_legacy(client, parsed_url) + url_attributes = get_url_attributes(client, parsed_url) with span_ctx as span: propagate_trace_headers(client, request) diff --git a/tests/integrations/httpx/test_httpx.py b/tests/integrations/httpx/test_httpx.py index 9c585fe8fe..624ea460aa 100644 --- a/tests/integrations/httpx/test_httpx.py +++ b/tests/integrations/httpx/test_httpx.py @@ -134,6 +134,7 @@ def test_crumb_capture_without_span_sync(sentry_init, capture_events, httpx_mock sentry_init( integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -169,6 +170,7 @@ async def test_crumb_capture_without_span_async( sentry_init( integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -383,6 +385,7 @@ def test_option_trace_propagation_targets_sync( trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, integrations=[HttpxIntegration()], + data_collection={}, ) httpx.Client().get(url) @@ -460,6 +463,7 @@ async def test_option_trace_propagation_targets_async( trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, integrations=[HttpxIntegration()], + data_collection={}, ) await httpx.AsyncClient().get(url) @@ -478,6 +482,7 @@ def test_outgoing_trace_headers_sync(sentry_init, capture_items, httpx_mock): sentry_init( traces_sample_rate=1.0, integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -507,6 +512,7 @@ async def test_outgoing_trace_headers_async(sentry_init, capture_items, httpx_mo sentry_init( traces_sample_rate=1.0, integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -530,9 +536,7 @@ async def test_outgoing_trace_headers_async(sentry_init, capture_items, httpx_mo def test_outgoing_trace_headers_append_to_baggage_sync( - sentry_init, - capture_items, - httpx_mock, + sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -540,6 +544,7 @@ def test_outgoing_trace_headers_append_to_baggage_sync( traces_sample_rate=1.0, integrations=[HttpxIntegration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", + data_collection={}, ) url = "http://example.com/" @@ -563,9 +568,7 @@ def test_outgoing_trace_headers_append_to_baggage_sync( @pytest.mark.asyncio async def test_outgoing_trace_headers_append_to_baggage_async( - sentry_init, - capture_items, - httpx_mock, + sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -573,6 +576,7 @@ async def test_outgoing_trace_headers_append_to_baggage_async( traces_sample_rate=1.0, integrations=[HttpxIntegration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", + data_collection={}, ) url = "http://example.com/" @@ -613,6 +617,7 @@ def test_outgoing_trace_headers_no_current_span(sentry_init, httpx_mock): traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -649,6 +654,7 @@ async def test_outgoing_trace_headers_no_current_span_async(sentry_init, httpx_m traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[HttpxIntegration()], + data_collection={}, ) url = "http://example.com/" @@ -680,6 +686,7 @@ def test_request_source_disabled_sync(sentry_init, capture_items, httpx_mock): traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -708,6 +715,7 @@ async def test_request_source_disabled_async(sentry_init, capture_items, httpx_m traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -736,15 +744,17 @@ def test_request_source_enabled_sync( ): httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } + kwargs = {} if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source + kwargs["enable_http_request_source"] = enable_http_request_source - sentry_init(**sentry_options) + sentry_init( + integrations=[HttpxIntegration()], + traces_sample_rate=1.0, + http_request_source_threshold_ms=0, + data_collection={}, + **kwargs, + ) items = capture_items("span") @@ -766,22 +776,21 @@ def test_request_source_enabled_sync( @pytest.mark.asyncio @pytest.mark.parametrize("enable_http_request_source", [None, True]) async def test_request_source_enabled_async( - sentry_init, - capture_items, - enable_http_request_source, - httpx_mock, + sentry_init, capture_items, enable_http_request_source, httpx_mock ): httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } + kwargs = {} if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source + kwargs["enable_http_request_source"] = enable_http_request_source - sentry_init(**sentry_options) + sentry_init( + integrations=[HttpxIntegration()], + traces_sample_rate=1.0, + http_request_source_threshold_ms=0, + data_collection={}, + **kwargs, + ) items = capture_items("span") @@ -808,6 +817,7 @@ def test_request_source_sync(sentry_init, capture_items, httpx_mock): traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -851,6 +861,7 @@ async def test_request_source_async(sentry_init, capture_items, httpx_mock): traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -900,6 +911,7 @@ def test_request_source_with_module_in_search_path_sync( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -945,6 +957,7 @@ async def test_request_source_with_module_in_search_path_async( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -990,6 +1003,7 @@ def test_no_request_source_if_duration_too_short_sync( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, + data_collection={}, ) items = capture_items("span") @@ -1021,6 +1035,7 @@ async def test_no_request_source_if_duration_too_short_async( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, + data_collection={}, ) items = capture_items("span") @@ -1051,6 +1066,7 @@ def test_request_source_if_duration_over_threshold_sync( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -1100,6 +1116,7 @@ async def test_request_source_if_duration_over_threshold_async( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, + data_collection={}, ) items = capture_items("span") @@ -1143,6 +1160,7 @@ def test_span_origin_sync(sentry_init, capture_items, httpx_mock): sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, + data_collection={}, ) items = capture_items("span") @@ -1166,6 +1184,7 @@ async def test_span_origin_async(sentry_init, capture_items, httpx_mock): sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, + data_collection={}, ) items = capture_items("span") From 1c95509669b5cb8eabe38e174b5a81090424177b Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 2 Oct 2026 12:04:31 +0200 Subject: [PATCH 2/2] ref(httpx): Drop support for `send_default_pii` --- tests/integrations/httpx/test_httpx.py | 659 +++++++------------------ 1 file changed, 182 insertions(+), 477 deletions(-) diff --git a/tests/integrations/httpx/test_httpx.py b/tests/integrations/httpx/test_httpx.py index 624ea460aa..d04dde1f9f 100644 --- a/tests/integrations/httpx/test_httpx.py +++ b/tests/integrations/httpx/test_httpx.py @@ -19,10 +19,7 @@ def _get_http_client_span(items): ) -@pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_and_hint_sync( - sentry_init, capture_events, httpx_mock, send_default_pii -): +def test_crumb_capture_and_hint_sync(sentry_init, capture_events, httpx_mock): httpx_mock.add_response() def before_breadcrumb(crumb, hint): @@ -32,7 +29,7 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[HttpxIntegration()], before_breadcrumb=before_breadcrumb, - send_default_pii=send_default_pii, + data_collection={}, ) url = "http://example.com/" @@ -50,35 +47,21 @@ def before_breadcrumb(crumb, hint): crumb = event["breadcrumbs"]["values"][0] assert crumb["type"] == "http" assert crumb["category"] == "httplib" - - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) + assert crumb["data"] == ApproxDict( + { + "url": url, + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.HTTP_QUERY: "", + SPANDATA.HTTP_STATUS_CODE: 200, + "reason": "OK", + "extra": "foo", + } + ) @pytest.mark.asyncio -@pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_crumb_capture_and_hint_async( - sentry_init, capture_events, httpx_mock, send_default_pii -): +async def test_crumb_capture_and_hint_async(sentry_init, capture_events, httpx_mock): httpx_mock.add_response() def before_breadcrumb(crumb, hint): @@ -88,7 +71,7 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[HttpxIntegration()], before_breadcrumb=before_breadcrumb, - send_default_pii=send_default_pii, + data_collection={}, ) url = "http://example.com/" @@ -106,27 +89,17 @@ def before_breadcrumb(crumb, hint): crumb = event["breadcrumbs"]["values"][0] assert crumb["type"] == "http" assert crumb["category"] == "httplib" - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) + assert crumb["data"] == ApproxDict( + { + "url": url, + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.HTTP_QUERY: "", + SPANDATA.HTTP_STATUS_CODE: 200, + "reason": "OK", + "extra": "foo", + } + ) def test_crumb_capture_without_span_sync(sentry_init, capture_events, httpx_mock): @@ -208,15 +181,14 @@ async def test_crumb_capture_without_span_async( (500, "error"), ], ) -@pytest.mark.parametrize("send_default_pii", [True, False]) def test_crumb_capture_client_error_sync( - sentry_init, capture_events, httpx_mock, status_code, level, send_default_pii + sentry_init, capture_events, httpx_mock, status_code, level ): httpx_mock.add_response(status_code=status_code) sentry_init( integrations=[HttpxIntegration()], - send_default_pii=send_default_pii, + data_collection={}, ) url = "http://example.com/" @@ -240,23 +212,15 @@ def test_crumb_capture_client_error_sync( else: assert crumb["level"] == level - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) + assert crumb["data"] == ApproxDict( + { + "url": url, + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.HTTP_QUERY: "", + SPANDATA.HTTP_STATUS_CODE: status_code, + } + ) @pytest.mark.asyncio @@ -270,15 +234,14 @@ def test_crumb_capture_client_error_sync( (500, "error"), ], ) -@pytest.mark.parametrize("send_default_pii", [True, False]) async def test_crumb_capture_client_error_async( - sentry_init, capture_events, httpx_mock, status_code, level, send_default_pii + sentry_init, capture_events, httpx_mock, status_code, level ): httpx_mock.add_response(status_code=status_code) sentry_init( integrations=[HttpxIntegration()], - send_default_pii=send_default_pii, + data_collection={}, ) url = "http://example.com/" @@ -302,23 +265,15 @@ async def test_crumb_capture_client_error_async( else: assert crumb["level"] == level - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) + assert crumb["data"] == ApproxDict( + { + "url": url, + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.HTTP_QUERY: "", + SPANDATA.HTTP_STATUS_CODE: status_code, + } + ) @pytest.mark.parametrize( @@ -1201,16 +1156,37 @@ async def test_span_origin_async(sentry_init, capture_items, httpx_mock): assert http_span["attributes"]["sentry.origin"] == "auto.http.httpx" -@pytest.mark.parametrize("send_default_pii", [True, False]) +@pytest.mark.parametrize( + "data_collection,expected_url_full,expected_query", + [ + pytest.param( + {}, + "http://example.com/?foo=bar#frag", + "foo=bar", + id="data_collection_defaults", + ), + pytest.param( + {"url_query_params": {"mode": "off"}}, + "http://example.com/#frag", + None, + id="data_collection_query_off", + ), + ], +) def test_http_url_attributes_sync( - sentry_init, capture_items, httpx_mock, send_default_pii + sentry_init, + capture_items, + httpx_mock, + data_collection, + expected_url_full, + expected_query, ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - send_default_pii=send_default_pii, + data_collection=data_collection, ) items = capture_items("span") @@ -1226,28 +1202,47 @@ def test_http_url_attributes_sync( assert http_span["attributes"]["http.request.method"] == "GET" assert http_span["attributes"]["http.response.status_code"] == 200 + assert http_span["attributes"]["url.full"] == expected_url_full + assert http_span["attributes"]["url.fragment"] == "frag" - if send_default_pii: - assert http_span["attributes"]["url.full"] == "http://example.com/?foo=bar#frag" - assert http_span["attributes"]["url.query"] == "foo=bar" - assert http_span["attributes"]["url.fragment"] == "frag" + if expected_query is not None: + assert http_span["attributes"]["url.query"] == expected_query else: - assert "url.full" not in http_span["attributes"] assert "url.query" not in http_span["attributes"] - assert "url.fragment" not in http_span["attributes"] @pytest.mark.asyncio -@pytest.mark.parametrize("send_default_pii", [True, False]) +@pytest.mark.parametrize( + "data_collection,expected_url_full,expected_query", + [ + pytest.param( + {}, + "http://example.com/?foo=bar#frag", + "foo=bar", + id="data_collection_defaults", + ), + pytest.param( + {"url_query_params": {"mode": "off"}}, + "http://example.com/#frag", + None, + id="data_collection_query_off", + ), + ], +) async def test_http_url_attributes_async( - sentry_init, capture_items, httpx_mock, send_default_pii + sentry_init, + capture_items, + httpx_mock, + data_collection, + expected_url_full, + expected_query, ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - send_default_pii=send_default_pii, + data_collection=data_collection, ) items = capture_items("span") @@ -1263,27 +1258,24 @@ async def test_http_url_attributes_async( assert http_span["attributes"]["http.request.method"] == "GET" assert http_span["attributes"]["http.response.status_code"] == 200 + assert http_span["attributes"]["url.full"] == expected_url_full + assert http_span["attributes"]["url.fragment"] == "frag" - if send_default_pii: - assert http_span["attributes"]["url.full"] == "http://example.com/?foo=bar#frag" - assert http_span["attributes"]["url.query"] == "foo=bar" - assert http_span["attributes"]["url.fragment"] == "frag" + if expected_query is not None: + assert http_span["attributes"]["url.query"] == expected_query else: - assert "url.full" not in http_span["attributes"] assert "url.query" not in http_span["attributes"] - assert "url.fragment" not in http_span["attributes"] -@pytest.mark.parametrize("send_default_pii", [True, False]) def test_http_url_attributes_no_query_or_fragment_sync( - sentry_init, capture_items, httpx_mock, send_default_pii + sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - send_default_pii=send_default_pii, + data_collection={}, ) items = capture_items("span") @@ -1299,26 +1291,21 @@ def test_http_url_attributes_no_query_or_fragment_sync( assert http_span["attributes"]["http.request.method"] == "GET" assert http_span["attributes"]["http.response.status_code"] == 200 + assert http_span["attributes"]["url.full"] == "http://example.com/" assert "url.query" not in http_span["attributes"] assert "url.fragment" not in http_span["attributes"] - if send_default_pii: - assert http_span["attributes"]["url.full"] == "http://example.com/" - else: - assert "url.full" not in http_span["attributes"] - @pytest.mark.asyncio -@pytest.mark.parametrize("send_default_pii", [True, False]) async def test_http_url_attributes_no_query_or_fragment_async( - sentry_init, capture_items, httpx_mock, send_default_pii + sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - send_default_pii=send_default_pii, + data_collection={}, ) items = capture_items("span") @@ -1334,89 +1321,60 @@ async def test_http_url_attributes_no_query_or_fragment_async( assert http_span["attributes"]["http.request.method"] == "GET" assert http_span["attributes"]["http.response.status_code"] == 200 + assert http_span["attributes"]["url.full"] == "http://example.com/" assert "url.query" not in http_span["attributes"] assert "url.fragment" not in http_span["attributes"] - if send_default_pii: - assert http_span["attributes"]["url.full"] == "http://example.com/" - else: - assert "url.full" not in http_span["attributes"] - @pytest.mark.parametrize( - "init_kwargs, expected_query", + "data_collection, expected_query, expected_url_full", [ - pytest.param( - {"send_default_pii": True}, - "toy=tennisball&color=red&auth=secret", - id="send_default_pii_true", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), pytest.param( {}, - None, - id="defaults", - ), - pytest.param( - {"data_collection": {}}, "toy=tennisball&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_default", + "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", + id="denylist_default", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "denylist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "denylist", "terms": ["toy"]}}, "toy=%5BFiltered%5D&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_custom_terms", + "http://example.com/?toy=%5BFiltered%5D&color=red&auth=%5BFiltered%5D#frag", + id="denylist_custom_terms", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["toy"]}}, "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist", + "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", + id="allowlist", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["auth"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["auth"]}}, "toy=%5BFiltered%5D&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist_sensitive_term", + "http://example.com/?toy=%5BFiltered%5D&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", + id="allowlist_sensitive_term", ), pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, + {"url_query_params": {"mode": "off"}}, None, - id="data_collection_off", - ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - None, - id="data_collection_wins_over_send_default_pii", + "http://example.com/#frag", + id="off", ), ], ) def test_url_query_data_collection_sync( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_query + sentry_init, + capture_items, + httpx_mock, + data_collection, + expected_query, + expected_url_full, ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - **init_kwargs, + data_collection=data_collection, ) items = capture_items("span") @@ -1430,6 +1388,8 @@ def test_url_query_data_collection_sync( http_span = _get_http_client_span(items) + assert http_span["attributes"]["url.full"] == expected_url_full + if expected_query is None: assert "url.query" not in http_span["attributes"] else: @@ -1438,79 +1398,54 @@ def test_url_query_data_collection_sync( @pytest.mark.asyncio @pytest.mark.parametrize( - "init_kwargs, expected_query", + "data_collection, expected_query, expected_url_full", [ - pytest.param( - {"send_default_pii": True}, - "toy=tennisball&color=red&auth=secret", - id="send_default_pii_true", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), pytest.param( {}, - None, - id="defaults", - ), - pytest.param( - {"data_collection": {}}, "toy=tennisball&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_default", + "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", + id="denylist_default", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "denylist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "denylist", "terms": ["toy"]}}, "toy=%5BFiltered%5D&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_custom_terms", + "http://example.com/?toy=%5BFiltered%5D&color=red&auth=%5BFiltered%5D#frag", + id="denylist_custom_terms", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["toy"]}}, "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist", + "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", + id="allowlist", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["auth"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["auth"]}}, "toy=%5BFiltered%5D&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist_sensitive_term", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - None, - id="data_collection_off", + "http://example.com/?toy=%5BFiltered%5D&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", + id="allowlist_sensitive_term", ), pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, + {"url_query_params": {"mode": "off"}}, None, - id="data_collection_wins_over_send_default_pii", + "http://example.com/#frag", + id="off", ), ], ) async def test_url_query_data_collection_async( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_query + sentry_init, + capture_items, + httpx_mock, + data_collection, + expected_query, + expected_url_full, ): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - **init_kwargs, + data_collection=data_collection, ) items = capture_items("span") @@ -1524,6 +1459,8 @@ async def test_url_query_data_collection_async( http_span = _get_http_client_span(items) + assert http_span["attributes"]["url.full"] == expected_url_full + if expected_query is None: assert "url.query" not in http_span["attributes"] else: @@ -1531,239 +1468,28 @@ async def test_url_query_data_collection_async( @pytest.mark.parametrize( - "init_kwargs, expected_url_full", + "data_collection, expected_url, expected_query, expected_fragment", [ pytest.param( - {"data_collection": {}}, - "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", - id="data_collection_denylist_default", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, - "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", - id="data_collection_allowlist", - ), - ], -) -def test_url_full_reassembly_sync( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - - items = capture_items("span") - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - with sentry_sdk.start_span(name="test"): - httpx.Client().get(url) - - sentry_sdk.flush() - - http_span = _get_http_client_span(items) - - assert http_span["attributes"]["url.full"] == expected_url_full - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs, expected_url_full", - [ - pytest.param( - {"data_collection": {}}, - "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", - id="data_collection_denylist_default", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, - "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", - id="data_collection_allowlist", - ), - ], -) -async def test_url_full_reassembly_async( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - - items = capture_items("span") - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - with sentry_sdk.start_span(name="test"): - await httpx.AsyncClient().get(url) - - sentry_sdk.flush() - - http_span = _get_http_client_span(items) - - assert http_span["attributes"]["url.full"] == expected_url_full - - -@pytest.mark.parametrize( - "init_kwargs, expected_url_full", - [ - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - "http://example.com/#frag", - id="data_collection_off", - ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - "http://example.com/#frag", - id="data_collection_wins_over_send_default_pii", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), - ], -) -def test_url_query_params_off_keeps_bare_url_sync( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - - items = capture_items("span") - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - with sentry_sdk.start_span(name="test"): - httpx.Client().get(url) - - sentry_sdk.flush() - - http_span = _get_http_client_span(items) - - assert "url.query" not in http_span["attributes"] - - if expected_url_full is None: - assert "url.full" not in http_span["attributes"] - assert "url.fragment" not in http_span["attributes"] - else: - assert http_span["attributes"]["url.full"] == expected_url_full - assert http_span["attributes"]["url.fragment"] == "frag" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs, expected_url_full", - [ - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - "http://example.com/#frag", - id="data_collection_off", - ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - "http://example.com/#frag", - id="data_collection_wins_over_send_default_pii", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), - ], -) -async def test_url_query_params_off_keeps_bare_url_async( - sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - - items = capture_items("span") - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - with sentry_sdk.start_span(name="test"): - await httpx.AsyncClient().get(url) - - sentry_sdk.flush() - - http_span = _get_http_client_span(items) - - assert "url.query" not in http_span["attributes"] - - if expected_url_full is None: - assert "url.full" not in http_span["attributes"] - assert "url.fragment" not in http_span["attributes"] - else: - assert http_span["attributes"]["url.full"] == expected_url_full - assert http_span["attributes"]["url.fragment"] == "frag" - - -@pytest.mark.parametrize( - "init_kwargs, expected_url, expected_query, expected_fragment", - [ - pytest.param( - {"data_collection": {}}, + {}, "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", "toy=tennisball&color=red&auth=%5BFiltered%5D", "frag", - id="data_collection_denylist_default", + id="denylist_default", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["toy"]}}, "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", "frag", - id="data_collection_allowlist", + id="allowlist", ), pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, + {"url_query_params": {"mode": "off"}}, "http://example.com/#frag", "", "frag", - id="data_collection_off", - ), - pytest.param( - {"send_default_pii": False}, - None, - None, - None, - id="send_default_pii_false", + id="off", ), ], ) @@ -1771,7 +1497,7 @@ def test_crumb_url_query_data_collection_sync( sentry_init, capture_events, httpx_mock, - init_kwargs, + data_collection, expected_url, expected_query, expected_fragment, @@ -1780,7 +1506,7 @@ def test_crumb_url_query_data_collection_sync( sentry_init( integrations=[HttpxIntegration()], - **init_kwargs, + data_collection=data_collection, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" @@ -1795,51 +1521,35 @@ def test_crumb_url_query_data_collection_sync( crumb = event["breadcrumbs"]["values"][0] - if expected_url is None: - assert "url" not in crumb["data"] - assert SPANDATA.HTTP_QUERY not in crumb["data"] - assert SPANDATA.HTTP_FRAGMENT not in crumb["data"] - else: - assert crumb["data"]["url"] == expected_url - assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment + assert crumb["data"]["url"] == expected_url + assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query + assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment @pytest.mark.asyncio @pytest.mark.parametrize( - "init_kwargs, expected_url, expected_query, expected_fragment", + "data_collection, expected_url, expected_query, expected_fragment", [ pytest.param( - {"data_collection": {}}, + {}, "http://example.com/?toy=tennisball&color=red&auth=%5BFiltered%5D#frag", "toy=tennisball&color=red&auth=%5BFiltered%5D", "frag", - id="data_collection_denylist_default", + id="denylist_default", ), pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, + {"url_query_params": {"mode": "allowlist", "terms": ["toy"]}}, "http://example.com/?toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D#frag", "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", "frag", - id="data_collection_allowlist", + id="allowlist", ), pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, + {"url_query_params": {"mode": "off"}}, "http://example.com/#frag", "", "frag", - id="data_collection_off", - ), - pytest.param( - {"send_default_pii": False}, - None, - None, - None, - id="send_default_pii_false", + id="off", ), ], ) @@ -1847,7 +1557,7 @@ async def test_crumb_url_query_data_collection_async( sentry_init, capture_events, httpx_mock, - init_kwargs, + data_collection, expected_url, expected_query, expected_fragment, @@ -1856,7 +1566,7 @@ async def test_crumb_url_query_data_collection_async( sentry_init( integrations=[HttpxIntegration()], - **init_kwargs, + data_collection=data_collection, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" @@ -1871,14 +1581,9 @@ async def test_crumb_url_query_data_collection_async( crumb = event["breadcrumbs"]["values"][0] - if expected_url is None: - assert "url" not in crumb["data"] - assert SPANDATA.HTTP_QUERY not in crumb["data"] - assert SPANDATA.HTTP_FRAGMENT not in crumb["data"] - else: - assert crumb["data"]["url"] == expected_url - assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment + assert crumb["data"]["url"] == expected_url + assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query + assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment @pytest.mark.tests_internal_exceptions