feat(asgi): Gate client IP/user info behind data_collection config#6841
feat(asgi): Gate client IP/user info behind data_collection config#6841ericapisani wants to merge 2 commits into
Conversation
Apply data_collection.user_info filtering to REMOTE_ADDR/client.address, falling back to send_default_pii when data_collection is not configured. Also convert earlier query parameter data collection tests to end-to-end assertions via a real ASGI app. Ref PY-2586 Ref #6746
| if has_data_collection_enabled(client_options): | ||
| if client_options["data_collection"]["user_info"]: |
There was a problem hiding this comment.
client_options may be unbound when scope type is not http/websocket
In both _get_request_data and _get_request_attributes, client_options = sentry_sdk.get_client().options is assigned only inside the if ty in ("http", "websocket") block, but is later referenced unconditionally when client/asgi_scope_client is truthy. If a scope with ty other than http/websocket carries a client entry, has_data_collection_enabled(client_options) raises NameError. In practice only http/websocket ASGI scopes carry a client key (lifespan scopes do not), so this path is largely unreachable with spec-compliant servers, but it is a latent regression: the prior code branched on should_send_default_pii() and did not depend on client_options.
Evidence
client_optionsis assigned at line 128 (and 181) insideif ty in ("http", "websocket").- Lines 151-156 (
_get_request_data) and 234-239 (_get_request_attributes) referencehas_data_collection_enabled(client_options)at the outer indent, guarded only byif client:/if asgi_scope_client:, not by scope type. - Per ASGI, only http/websocket scopes include a
clientkey, soclientbeing truthy whiletyis neither is not expected from compliant servers, making the NameError path hard to reach in practice. - The regression is that the old branch used
should_send_default_pii(), which needed noclient_options, so a malformed/non-standard scope with aclientvalue would now raise instead of behaving gracefully.
Also found at 1 additional location
sentry_sdk/integrations/_asgi_common.py:233-235
Identified by Warden code-review · DVQ-38F
There was a problem hiding this comment.
Fix attempt detected (commit 8c9f43d)
The fix moved client_options above the http/websocket block in _get_request_data (line 153 resolved), but the identical bug at the additional reported location (_get_request_attributes, lines 233-235) still has client_options assigned only inside the http/websocket block, so the NameError path persists there.
The original issue appears unresolved. Please review and try again.
Evaluated by Warden
Codecov Results 📊✅ 94263 passed | ⏭️ 6338 skipped | Total: 100601 | Pass Rate: 93.7% | Execution Time: 331m 19s 📊 Comparison with Base Branch
All tests are passing successfully. ✅ Patch coverage is 100.00%. Project has 2513 uncovered lines. Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 89.68% 89.62% -0.06%
==========================================
Files 193 193 —
Lines 24007 24218 +211
Branches 8342 8504 +162
==========================================
+ Hits 21530 21705 +175
- Misses 2477 2513 +36
- Partials 1386 1396 +10Generated by Codecov Action |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8c9f43d. Configure here.
| attributes["client.address"] = ip | ||
| elif should_send_default_pii(): | ||
| ip = _get_ip(asgi_scope) | ||
| attributes["client.address"] = ip |
There was a problem hiding this comment.
Unbound client_options outside type check
Medium Severity
In _get_request_attributes, client_options is assigned only inside the http/websocket branch, but the new user_info gating reads it afterward. For a non-http/websocket scope with a truthy client, that path raises UnboundLocalError. The matching move of client_options outside the type check was applied in _get_request_data but missed here.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 8c9f43d. Configure here.
| trace_lifecycle="stream", | ||
| _experiments={ | ||
| **init_kwargs.pop("_experiments", {}), | ||
| }, |
There was a problem hiding this comment.
Shared param dict mutated by pop
Medium Severity
test_user_info_data_collection_with_streamed_spans calls init_kwargs.pop("_experiments", {}) on the shared USER_INFO_CASES dicts. That permanently removes _experiments for later uses of the same cases, including test_user_info_data_collection, so data-collection expectations can silently diverge depending on collection order.
Reviewed by Cursor Bugbot for commit 8c9f43d. Configure here.
| if has_data_collection_enabled(client_options): | ||
| if client_options["data_collection"]["user_info"]: |
There was a problem hiding this comment.
Bug: The variable client_options is used outside the conditional block where it is defined, which can cause an UnboundLocalError.
Severity: LOW
Suggested Fix
Move the initialization of client_options to a higher scope, before the if ty in ("http", "websocket"): conditional block, to ensure it is always defined before being accessed.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: sentry_sdk/integrations/_asgi_common.py#L235-L236
Potential issue: In the function `_get_request_attributes`, the variable
`client_options` is initialized within a conditional block that checks if the scope type
`ty` is `"http"` or `"websocket"`. However, `client_options` is later accessed outside
of this conditional block. If the function is called with a scope type other than "http"
or "websocket" (e.g., `"lifespan"`) and `asgi_scope.get("client")` is truthy, an
`UnboundLocalError` will be raised because `client_options` was never assigned.
Also affects:
sentry_sdk/integrations/_asgi_common.py:235~237
Did we get this right? 👍 / 👎 to inform future reviews.


Apply data_collection.user_info filtering to REMOTE_ADDR/client.address,
falling back to send_default_pii when data_collection is not configured.
Also convert earlier query parameter data collection tests to end-to-end assertions via a real ASGI app.
Ref PY-2586
Ref #6746