From 27ba44617508a8ba71091986fc07cb1c361cea6d Mon Sep 17 00:00:00 2001 From: Erica Pisani Date: Thu, 1 Oct 2026 14:23:32 -0400 Subject: [PATCH 1/2] ref(redis)!: Drop `send_default_pii` support Redis command arguments are now gated solely on `data_collection["database_query_data"]`. The `send_default_pii` fallback in `_get_safe_command` is removed. Tests that exercised `send_default_pii` (including the precedence test) are removed, and the remaining ones use `data_collection` instead. Fixes PY-2837 Fixes #7608 --- sentry_sdk/integrations/redis/utils.py | 9 +- tests/integrations/redis/test_redis.py | 168 +------------------------ 2 files changed, 4 insertions(+), 173 deletions(-) diff --git a/sentry_sdk/integrations/redis/utils.py b/sentry_sdk/integrations/redis/utils.py index a8c782018d..a2be8a53e8 100644 --- a/sentry_sdk/integrations/redis/utils.py +++ b/sentry_sdk/integrations/redis/utils.py @@ -8,9 +8,8 @@ _MULTI_KEY_COMMANDS, _SINGLE_KEY_COMMANDS, ) -from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import Span -from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE, has_data_collection_enabled +from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE if TYPE_CHECKING: from typing import Any, Optional, Sequence @@ -20,7 +19,6 @@ def _get_safe_command(name: str, args: "Sequence[Any]") -> str: command_parts = [name] name_low = name.lower() - send_default_pii = should_send_default_pii() client_options = sentry_sdk.get_client().options for i, arg in enumerate(args): @@ -35,10 +33,7 @@ def _get_safe_command(name: str, args: "Sequence[Any]") -> str: if arg_is_the_key: command_parts.append(repr(arg)) else: - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["database_query_data"]: - command_parts.append(repr(arg)) - elif send_default_pii: + if client_options["data_collection"]["database_query_data"]: command_parts.append(repr(arg)) else: command_parts.append(SENSITIVE_DATA_SUBSTITUTE) diff --git a/tests/integrations/redis/test_redis.py b/tests/integrations/redis/test_redis.py index 7d3bcf3378..6d33ab2021 100644 --- a/tests/integrations/redis/test_redis.py +++ b/tests/integrations/redis/test_redis.py @@ -41,53 +41,6 @@ def test_basic(sentry_init, capture_events): "type": "redis", } - -@pytest.mark.parametrize( - "is_transaction, send_default_pii, expected_first_ten", - [ - (False, False, ["GET 'foo'", "SET 'bar' [Filtered]", "SET 'baz' [Filtered]"]), - (True, True, ["GET 'foo'", "SET 'bar' 1", "SET 'baz' 2"]), - ], -) -def test_redis_pipeline( - sentry_init, - capture_events, - capture_items, - is_transaction, - send_default_pii, - expected_first_ten, -): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - ) - - connection = FakeRedis() - - items = capture_items("span") - - with sentry_sdk.start_span(name="custom parent"): - pipeline = connection.pipeline(transaction=is_transaction) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - sentry_sdk.flush() - - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload - - assert parent_span["name"] == "custom parent" - assert parent_span["is_segment"] is True - - assert pipeline_span["name"] == "redis.pipeline.execute" - assert pipeline_span["attributes"]["sentry.op"] == "db.redis" - assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" - assert pipeline_span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "redis" - - @pytest.mark.parametrize( "data_collection, expected_first_ten", [ @@ -134,39 +87,6 @@ def test_redis_pipeline_data_collection( assert pipeline_span["name"] == "redis.pipeline.execute" assert pipeline_span["attributes"]["sentry.op"] == "db.redis" - -def test_sensitive_data( - sentry_init, - capture_events, - capture_items, -): - # fakeredis does not support the AUTH command, so we need to mock it - with mock.patch( - "sentry_sdk.integrations.redis.utils._COMMANDS_INCLUDING_SENSITIVE_DATA", - ["get"], - ): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - ) - - connection = FakeRedis() - - items = capture_items("span") - with sentry_sdk.start_span(name="custom parent"): - connection.get("this is super secret") - sentry_sdk.flush() - - assert len(items) == 2 - redis_span, parent_span = items[0].payload, items[1].payload - - assert parent_span["name"] == "custom parent" - assert redis_span["name"] == "GET [Filtered]" - assert redis_span["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET [Filtered]" - assert redis_span["attributes"]["sentry.op"] == "db.redis" - - def test_pii_data_redacted( sentry_init, capture_events, @@ -245,95 +165,11 @@ def test_data_collection_database_query_data( assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description assert set_span["attributes"]["sentry.op"] == "db.redis" - -@pytest.mark.parametrize( - "data_collection, send_default_pii, expected_description", - [ - ({"database_query_data": False}, True, "SET 'somekey1'"), - ( - {"database_query_data": True}, - False, - "SET 'somekey1' 'my secret string1'", - ), - ], -) -@pytest.mark.filterwarnings("ignore::DeprecationWarning") -def test_database_query_data_takes_precedence_over_send_default_pii( - sentry_init, - capture_events, - capture_items, - data_collection, - send_default_pii, - expected_description, -): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - data_collection=data_collection, - ) - - connection = FakeRedis() - - items = capture_items("span") - - with sentry_sdk.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - - sentry_sdk.flush() - - assert len(items) == 2 - set_span, parent = [item.payload for item in items] - - assert parent["name"] == "custom parent" - assert set_span["name"] == expected_description - assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description - assert set_span["attributes"]["sentry.op"] == "db.redis" - - -def test_pii_data_sent(sentry_init, capture_items): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - ) - - connection = FakeRedis() - - items = capture_items("span") - - with sentry_sdk.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - connection.set("somekey2", "my secret string2") - connection.get("somekey2") - connection.delete("somekey1", "somekey2") - - sentry_sdk.flush() - - assert len(items) == 5 - set1, set2, get, delete, parent = [item.payload for item in items] - - assert parent["name"] == "custom parent" - assert set1["name"] == "SET 'somekey1' 'my secret string1'" - assert ( - set1["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SET 'somekey1' 'my secret string1'" - ) - assert set1["attributes"]["sentry.op"] == "db.redis" - assert set2["name"] == "SET 'somekey2' 'my secret string2'" - assert ( - set2["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SET 'somekey2' 'my secret string2'" - ) - assert get["name"] == "GET 'somekey2'" - assert delete["name"] == "DEL 'somekey1' 'somekey2'" - - def test_no_data_truncation_by_default(sentry_init, capture_items): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - send_default_pii=True, + data_collection={"database_query_data": True}, ) connection = FakeRedis() @@ -366,7 +202,7 @@ def test_no_data_truncation_by_default(sentry_init, capture_items): def test_breadcrumbs(sentry_init, capture_events): sentry_init( integrations=[RedisIntegration()], - send_default_pii=True, + data_collection={"database_query_data": True}, ) events = capture_events() From c67f0144d053be04e6be3300c93b448a07a2e8df Mon Sep 17 00:00:00 2001 From: Erica Pisani Date: Thu, 1 Oct 2026 14:34:17 -0400 Subject: [PATCH 2/2] update assertion --- tests/integrations/redis/test_redis.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/integrations/redis/test_redis.py b/tests/integrations/redis/test_redis.py index 6d33ab2021..db0fa77410 100644 --- a/tests/integrations/redis/test_redis.py +++ b/tests/integrations/redis/test_redis.py @@ -41,6 +41,7 @@ def test_basic(sentry_init, capture_events): "type": "redis", } + @pytest.mark.parametrize( "data_collection, expected_first_ten", [ @@ -87,6 +88,7 @@ def test_redis_pipeline_data_collection( assert pipeline_span["name"] == "redis.pipeline.execute" assert pipeline_span["attributes"]["sentry.op"] == "db.redis" + def test_pii_data_redacted( sentry_init, capture_events, @@ -125,7 +127,7 @@ def test_pii_data_redacted( @pytest.mark.parametrize( "data_collection, expected_description", [ - ({"database_query_data": False}, "SET 'somekey1'"), + ({"database_query_data": False}, "SET 'somekey1' [Filtered]"), ({"database_query_data": True}, "SET 'somekey1' 'my secret string1'"), ({}, "SET 'somekey1' 'my secret string1'"), ], @@ -165,6 +167,7 @@ def test_data_collection_database_query_data( assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description assert set_span["attributes"]["sentry.op"] == "db.redis" + def test_no_data_truncation_by_default(sentry_init, capture_items): sentry_init( integrations=[RedisIntegration()],