From 10e3d9cae6a5eeaa0e0ce87d76e555e75c96a949 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 14 Nov 2024 14:06:45 -0800 Subject: [PATCH] fix: include_tracing_fields arg to control unvetted data in rust_tracing integration --- sentry_sdk/integrations/rust_tracing.py | 34 ++++++++----- .../rust_tracing/test_rust_tracing.py | 49 ++++++++++++++----- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/sentry_sdk/integrations/rust_tracing.py b/sentry_sdk/integrations/rust_tracing.py index 121bf082b8..ae52c850c3 100644 --- a/sentry_sdk/integrations/rust_tracing.py +++ b/sentry_sdk/integrations/rust_tracing.py @@ -151,12 +151,25 @@ def __init__( [Dict[str, Any]], EventTypeMapping ] = default_event_type_mapping, span_filter: Callable[[Dict[str, Any]], bool] = default_span_filter, - send_sensitive_data: Optional[bool] = None, + include_tracing_fields: Optional[bool] = None, ): self.origin = origin self.event_type_mapping = event_type_mapping self.span_filter = span_filter - self.send_sensitive_data = send_sensitive_data + self.include_tracing_fields = include_tracing_fields + + def _include_tracing_fields(self) -> bool: + """ + By default, the values of tracing fields are not included in case they + contain PII. A user may override that by passing `True` for the + `include_tracing_fields` keyword argument of this integration or by + setting `send_default_pii` to `True` in their Sentry client options. + """ + return ( + should_send_default_pii() + if self.include_tracing_fields is None + else self.include_tracing_fields + ) def on_event(self, event: str, _span_state: TraceState) -> None: deserialized_event = json.loads(event) @@ -207,7 +220,10 @@ def on_new_span(self, attrs: str, span_id: str) -> TraceState: fields = metadata.get("fields", []) for field in fields: - sentry_span.set_data(field, attrs.get(field)) + if self._include_tracing_fields(): + sentry_span.set_data(field, attrs.get(field)) + else: + sentry_span.set_data(field, SENSITIVE_DATA_SUBSTITUTE) scope.span = sentry_span return (parent_sentry_span, sentry_span) @@ -225,15 +241,9 @@ def on_record(self, span_id: str, values: str, span_state: TraceState) -> None: return _parent_sentry_span, sentry_span = span_state - send_sensitive_data = ( - should_send_default_pii() - if self.send_sensitive_data is None - else self.send_sensitive_data - ) - deserialized_values = json.loads(values) for key, value in deserialized_values.items(): - if send_sensitive_data: + if self._include_tracing_fields(): sentry_span.set_data(key, value) else: sentry_span.set_data(key, SENSITIVE_DATA_SUBSTITUTE) @@ -259,12 +269,12 @@ def __init__( [Dict[str, Any]], EventTypeMapping ] = default_event_type_mapping, span_filter: Callable[[Dict[str, Any]], bool] = default_span_filter, - send_sensitive_data: Optional[bool] = None, + include_tracing_fields: Optional[bool] = None, ): self.identifier = identifier origin = f"auto.function.rust_tracing.{identifier}" self.tracing_layer = RustTracingLayer( - origin, event_type_mapping, span_filter, send_sensitive_data + origin, event_type_mapping, span_filter, include_tracing_fields ) initializer(self.tracing_layer) diff --git a/tests/integrations/rust_tracing/test_rust_tracing.py b/tests/integrations/rust_tracing/test_rust_tracing.py index b1fad1a7f7..893fc86966 100644 --- a/tests/integrations/rust_tracing/test_rust_tracing.py +++ b/tests/integrations/rust_tracing/test_rust_tracing.py @@ -1,3 +1,4 @@ +from unittest import mock import pytest from string import Template @@ -66,7 +67,9 @@ def record(self, span_id: int): def test_on_new_span_on_close(sentry_init, capture_events): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( - "test_on_new_span_on_close", rust_tracing.set_layer_impl + "test_on_new_span_on_close", + initializer=rust_tracing.set_layer_impl, + include_tracing_fields=True, ) sentry_init(integrations=[integration], traces_sample_rate=1.0) @@ -105,7 +108,9 @@ def test_on_new_span_on_close(sentry_init, capture_events): def test_nested_on_new_span_on_close(sentry_init, capture_events): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( - "test_nested_on_new_span_on_close", rust_tracing.set_layer_impl + "test_nested_on_new_span_on_close", + initializer=rust_tracing.set_layer_impl, + include_tracing_fields=True, ) sentry_init(integrations=[integration], traces_sample_rate=1.0) @@ -331,7 +336,10 @@ def span_filter(metadata: Dict[str, object]) -> bool: rust_tracing = FakeRustTracing() integration = RustTracingIntegration( - "test_span_filter", rust_tracing.set_layer_impl, span_filter=span_filter + "test_span_filter", + initializer=rust_tracing.set_layer_impl, + span_filter=span_filter, + include_tracing_fields=True, ) sentry_init(integrations=[integration], traces_sample_rate=1.0) @@ -365,7 +373,7 @@ def test_record(sentry_init): integration = RustTracingIntegration( "test_record", initializer=rust_tracing.set_layer_impl, - send_sensitive_data=True, + include_tracing_fields=True, ) sentry_init(integrations=[integration], traces_sample_rate=1.0) @@ -391,6 +399,7 @@ def span_filter(metadata: Dict[str, object]) -> bool: "test_record_in_ignored_span", rust_tracing.set_layer_impl, span_filter=span_filter, + include_tracing_fields=True, ) sentry_init(integrations=[integration], traces_sample_rate=1.0) @@ -409,7 +418,7 @@ def span_filter(metadata: Dict[str, object]) -> bool: @pytest.mark.parametrize( - "send_default_pii, send_sensitive_data, sensitive_data_expected", + "send_default_pii, include_tracing_fields, tracing_fields_expected", [ (True, True, True), (True, False, False), @@ -419,14 +428,14 @@ def span_filter(metadata: Dict[str, object]) -> bool: (False, None, False), ], ) -def test_sensitive_data( - sentry_init, send_default_pii, send_sensitive_data, sensitive_data_expected +def test_include_tracing_fields( + sentry_init, send_default_pii, include_tracing_fields, tracing_fields_expected ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( "test_record", initializer=rust_tracing.set_layer_impl, - send_sensitive_data=send_sensitive_data, + include_tracing_fields=include_tracing_fields, ) sentry_init( @@ -438,13 +447,29 @@ def test_sensitive_data( rust_tracing.new_span(RustTracingLevel.Info, 3) span_before_record = sentry_sdk.get_current_span().to_json() - assert span_before_record["data"]["version"] is None + if tracing_fields_expected: + assert span_before_record["data"]["version"] is None + else: + assert span_before_record["data"]["version"] == "[Filtered]" rust_tracing.record(3) span_after_record = sentry_sdk.get_current_span().to_json() - if sensitive_data_expected: - assert span_after_record["data"]["version"] == "memoized" + if tracing_fields_expected: + assert span_after_record["data"] == { + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "use_memoized": True, + "version": "memoized", + "index": 10, + } + else: - assert span_after_record["data"]["version"] == "[Filtered]" + assert span_after_record["data"] == { + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "use_memoized": "[Filtered]", + "version": "[Filtered]", + "index": "[Filtered]", + }