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
4 changes: 2 additions & 2 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class DataCollectionUserOptions(TypedDict, total=False):
gen_ai: "GenAICollectionUserOptions"
database_query_data: bool
queues: bool
stack_frame_variables: bool
stack_frame_variables: "Union[bool, KeyValueCollectionBehaviour]"
frame_context_lines: int

class DataCollection(TypedDict):
Expand All @@ -202,7 +202,7 @@ class DataCollection(TypedDict):
gen_ai: "GenAICollectionBehaviour"
database_query_data: bool
queues: bool
stack_frame_variables: bool
stack_frame_variables: "Union[bool, KeyValueCollectionBehaviour]"
frame_context_lines: int

# "critical" is an alias of "fatal" recognized by Relay
Expand Down
21 changes: 13 additions & 8 deletions sentry_sdk/data_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@
"""

import warnings
from typing import TYPE_CHECKING, List, Mapping, Optional, Union, cast
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Union, cast
from urllib.parse import parse_qs, urlencode

from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE

if TYPE_CHECKING:
from typing import Any, Dict

from sentry_sdk._types import (
DataCollection,
GenAICollectionBehaviour,
Expand Down Expand Up @@ -190,7 +188,6 @@

def _resolve_explicit(
d: "dict[str, Any]",
include_local_variables: bool,
) -> "DataCollection":
"""
Build a fully-resolved ``DataCollection`` from a user-supplied
Expand All @@ -205,10 +202,19 @@
frame_context_lines = _DEFAULT_FRAME_CONTEXT_LINES
elif isinstance(frame_context_lines, bool):
frame_context_lines = _DEFAULT_FRAME_CONTEXT_LINES if frame_context_lines else 0
else:
if not isinstance(frame_context_lines, int) or frame_context_lines < 0:
raise ValueError(
"Invalid `frame_context_lines` value: Must be 0 or greater."
)

raw_stack_frame_variables = d.get("stack_frame_variables", True)
stack_frame_variables: "Union[bool, KeyValueCollectionBehaviour]"

stack_frame_variables = d.get("stack_frame_variables")
if stack_frame_variables is None:
stack_frame_variables = include_local_variables
if isinstance(raw_stack_frame_variables, dict):
stack_frame_variables = _kvcb_from_value(raw_stack_frame_variables)
else:
stack_frame_variables = bool(raw_stack_frame_variables)

Check failure on line 217 in sentry_sdk/data_collection.py

View check run for this annotation

@sentry/warden / warden: code-review

stack_frame_variables allowlist/denylist is stored but never applied

Resolved `stack_frame_variables` (bool or KVCB) is never read at collection time; `serialize_frame` / callers still gate on legacy `include_local_variables`, so allowlist/denylist and even `False` have no effect. Wire frame vars through `data_collection["stack_frame_variables"]` (and apply `_apply_key_value_collection_filtering`) like `frame_context_lines`.

Check failure on line 217 in sentry_sdk/data_collection.py

View check run for this annotation

@sentry/warden / warden: find-bugs

Explicit stack_frame_variables collection behavior is ignored during frame serialization

The resolved `data_collection["stack_frame_variables"]` value is never used when serializing stack frames. `serialize_frame()` continues to gate locals solely on the legacy `include_local_variables` option and serializes all `frame.f_locals` without applying the configured allowlist, denylist, or off behavior. Because an explicit `data_collection` configuration disables `EventScrubber`, sensitive local variables can be sent despite an explicit restriction.
Comment thread
cursor[bot] marked this conversation as resolved.

# http_bodies: omitted means "all valid types"; [] is the explicit opt-out.
http_bodies = d.get("http_bodies")
Expand Down Expand Up @@ -317,11 +323,10 @@
DeprecationWarning,
stacklevel=2,
)
return _resolve_explicit(
user_dc,
include_local_variables,
)

Check failure on line 328 in sentry_sdk/data_collection.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[3UM-NU2] Explicit stack_frame_variables collection behavior is ignored during frame serialization (additional location)

The resolved `data_collection["stack_frame_variables"]` value is never used when serializing stack frames. `serialize_frame()` continues to gate locals solely on the legacy `include_local_variables` option and serializes all `frame.f_locals` without applying the configured allowlist, denylist, or off behavior. Because an explicit `data_collection` configuration disables `EventScrubber`, sensitive local variables can be sent despite an explicit restriction.

Check failure on line 329 in sentry_sdk/data_collection.py

View check run for this annotation

@sentry/warden / warden: code-review

[N63-A7T] stack_frame_variables allowlist/denylist is stored but never applied (additional location)

Resolved `stack_frame_variables` (bool or KVCB) is never read at collection time; `serialize_frame` / callers still gate on legacy `include_local_variables`, so allowlist/denylist and even `False` have no effect. Wire frame vars through `data_collection["stack_frame_variables"]` (and apply `_apply_key_value_collection_filtering`) like `frame_context_lines`.
return _map_from_send_default_pii(
send_default_pii=bool(send_default_pii),
include_local_variables=include_local_variables,
Expand Down
109 changes: 107 additions & 2 deletions tests/test_data_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@
sentry_sdk.init(_experiments={"data_collection": {"cookies": {"mode": "nope"}}}) # type: ignore Purposely ignoring to test invalid option


def test_stack_frame_variables_invalid_mode():
with pytest.raises(ValueError):
sentry_sdk.init(
_experiments={
"data_collection": {"stack_frame_variables": {"mode": "nope"}}
}
)

Check failure on line 21 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: code-review

[N63-A7T] stack_frame_variables allowlist/denylist is stored but never applied (additional location)

Resolved `stack_frame_variables` (bool or KVCB) is never read at collection time; `serialize_frame` / callers still gate on legacy `include_local_variables`, so allowlist/denylist and even `False` have no effect. Wire frame vars through `data_collection["stack_frame_variables"]` (and apply `_apply_key_value_collection_filtering`) like `frame_context_lines`.

Check failure on line 21 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[3UM-NU2] Explicit stack_frame_variables collection behavior is ignored during frame serialization (additional location)

The resolved `data_collection["stack_frame_variables"]` value is never used when serializing stack frames. `serialize_frame()` continues to gate locals solely on the legacy `include_local_variables` option and serializes all `frame.f_locals` without applying the configured allowlist, denylist, or off behavior. Because an explicit `data_collection` configuration disables `EventScrubber`, sensitive local variables can be sent despite an explicit restriction.


@pytest.mark.parametrize(
"value",
["3", -1, [1], 2.5],
ids=[
"frame_context_lines_string",
"frame_context_lines_negative",
"frame_context_lines_list",
"frame_context_lines_float",
],
)
def test_frame_context_lines_invalid_value(value):
with pytest.raises(ValueError):
sentry_sdk.init(
_experiments={"data_collection": {"frame_context_lines": value}}
)


def test_kvcb_from_dict_defaults_mode():
sentry_sdk.init(
_experiments={
Expand Down Expand Up @@ -147,8 +173,8 @@
"include_local_variables": False,
"include_source_context": False,
},
{"stack_frame_variables": False, "frame_context_lines": 5},
id="explicit_stack_frame_variables_falls_back_to_legacy_option",
{"stack_frame_variables": True, "frame_context_lines": 5},
id="explicit_data_collection_ignores_legacy_include_local_variables",

Check failure on line 177 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[3UM-NU2] Explicit stack_frame_variables collection behavior is ignored during frame serialization (additional location)

The resolved `data_collection["stack_frame_variables"]` value is never used when serializing stack frames. `serialize_frame()` continues to gate locals solely on the legacy `include_local_variables` option and serializes all `frame.f_locals` without applying the configured allowlist, denylist, or off behavior. Because an explicit `data_collection` configuration disables `EventScrubber`, sensitive local variables can be sent despite an explicit restriction.
),
pytest.param(
{
Expand Down Expand Up @@ -248,6 +274,85 @@
{"frame_context_lines": 0},
id="frame_context_lines_bool_fallback_0",
),
pytest.param(
{"_experiments": {"data_collection": {"stack_frame_variables": True}}},
{"stack_frame_variables": True},
id="stack_frame_variables_explicit_true",
),
pytest.param(
{"_experiments": {"data_collection": {"stack_frame_variables": False}}},
{"stack_frame_variables": False},
id="stack_frame_variables_explicit_false",
),
pytest.param(
{
"_experiments": {
"data_collection": {
"stack_frame_variables": {
"mode": "allowlist",
"terms": ["order_id"],
}
}
}
},
{
"stack_frame_variables": {
"mode": "allowlist",
"terms": ["order_id"],
}
},
id="stack_frame_variables_allowlist_dict",

Check failure on line 304 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: code-review

[N63-A7T] stack_frame_variables allowlist/denylist is stored but never applied (additional location)

Resolved `stack_frame_variables` (bool or KVCB) is never read at collection time; `serialize_frame` / callers still gate on legacy `include_local_variables`, so allowlist/denylist and even `False` have no effect. Wire frame vars through `data_collection["stack_frame_variables"]` (and apply `_apply_key_value_collection_filtering`) like `frame_context_lines`.

Check failure on line 304 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: find-bugs

[3UM-NU2] Explicit stack_frame_variables collection behavior is ignored during frame serialization (additional location)

The resolved `data_collection["stack_frame_variables"]` value is never used when serializing stack frames. `serialize_frame()` continues to gate locals solely on the legacy `include_local_variables` option and serializes all `frame.f_locals` without applying the configured allowlist, denylist, or off behavior. Because an explicit `data_collection` configuration disables `EventScrubber`, sensitive local variables can be sent despite an explicit restriction.
),
pytest.param(
{
"_experiments": {
"data_collection": {
"stack_frame_variables": {"terms": ["order_id"]}
}
}
},
{
"stack_frame_variables": {
"mode": "denylist",
"terms": ["order_id"],
}
},
id="stack_frame_variables_dict_defaults_mode_to_denylist",
),
pytest.param(
{
"_experiments": {
"data_collection": {"stack_frame_variables": {"mode": "off"}}
}
},
{"stack_frame_variables": {"mode": "off"}},
id="stack_frame_variables_off_dict_omits_terms",

Check failure on line 329 in tests/test_data_collection.py

View check run for this annotation

@sentry/warden / warden: code-review

[N63-A7T] stack_frame_variables allowlist/denylist is stored but never applied (additional location)

Resolved `stack_frame_variables` (bool or KVCB) is never read at collection time; `serialize_frame` / callers still gate on legacy `include_local_variables`, so allowlist/denylist and even `False` have no effect. Wire frame vars through `data_collection["stack_frame_variables"]` (and apply `_apply_key_value_collection_filtering`) like `frame_context_lines`.
),
pytest.param(
{"_experiments": {"data_collection": {"stack_frame_variables": "yes"}}},
{"stack_frame_variables": True},
id="stack_frame_variables_non_bool_truthy_coerces_to_true",
),
pytest.param(
{"_experiments": {"data_collection": {"stack_frame_variables": ""}}},
{"stack_frame_variables": False},
id="stack_frame_variables_non_bool_falsy_coerces_to_false",
),
pytest.param(
{"_experiments": {"data_collection": {"frame_context_lines": None}}},
{"frame_context_lines": 5},
id="frame_context_lines_none_falls_back_to_spec_default",
),
pytest.param(
{"include_local_variables": False, "include_source_context": False},
{"stack_frame_variables": False, "frame_context_lines": 0},
id="legacy_include_local_variables_off_disables_stack_frame_variables",
),
pytest.param(
{"include_local_variables": True, "include_source_context": True},
{"stack_frame_variables": True, "frame_context_lines": 5},
id="legacy_include_local_variables_on_enables_stack_frame_variables",
),
],
)
def test_initialize_client_data_collection(options, expected):
Expand Down
Loading