feat(asgi): Make integration fully span first compatible #5920
6 issues
High
Inverted filter logic causes all items to be skipped when types=None - `tests/conftest.py:341-342`
The condition if types is None or item.type not in types: continue has inverted logic. When types is None (intended to mean 'capture all types'), the first condition types is None evaluates to True, causing continue to execute and skip ALL items. This defeats the purpose of having a default behavior that captures everything.
Medium
AnnotatedValue objects from sensitive headers not properly handled in attributes - `sentry_sdk/integrations/_asgi_common.py:123-124`
When should_send_default_pii() returns False, _filter_headers() returns AnnotatedValue objects for sensitive headers (like authorization, cookie, etc.). The new _get_request_attributes() function directly assigns these values to attributes. When set_attribute() processes these, format_attribute() will fall back to safe_repr(), producing unhelpful string representations like <AnnotatedValue object at 0x...> instead of properly filtered values. While no actual PII leaks (the original sensitive data is already stripped), the resulting attribute values are not meaningful.
KeyError when span has no attributes - `tests/conftest.py:1272-1274`
The envelopes_to_spans helper accesses span_json["attributes"] directly, but in _span_batcher.py:116-119, the attributes key is only added to the span JSON when item._attributes is truthy. If a span has no attributes, this will raise a KeyError. This would cause tests to fail when processing spans without attributes.
Sensitive headers are improperly serialized as AnnotatedValue string representation instead of filtered values - `sentry_sdk/integrations/_asgi_common.py:123-124`
When should_send_default_pii() returns False, _filter_headers() replaces sensitive headers (like authorization, cookies, x-forwarded-for) with AnnotatedValue objects. In _get_request_attributes(), these AnnotatedValue objects are passed directly to attributes. When scope.set_attribute() processes them via format_attribute(), they fall through to safe_repr(), resulting in string representations like "{'value': '[Filtered]', 'metadata': ...}" instead of the intended filtered value. This causes ugly, confusing attribute values and may leak metadata information.
Filter logic in capture_items fixture skips all items when types is None - `tests/conftest.py:341-342`
The condition if types is None or item.type not in types is inverted. When types=None, all items should be captured (no filtering), but the current code skips ALL items because types is None evaluates to True. The correct logic should be if types is not None and item.type not in types. While the current tests always pass a types argument, any future test calling capture_items() without arguments will get an empty list.
Low
KeyError when span has no attributes in envelopes_to_spans - `tests/conftest.py:1272-1274`
The envelopes_to_spans function accesses span_json["attributes"] directly without checking if the key exists. According to _span_batcher.py lines 116-119, the attributes key is only included in the transport format when item._attributes is truthy (non-empty). If a span with empty attributes is processed, this will raise a KeyError. While current code paths typically ensure attributes are populated, the batcher explicitly handles this edge case, so the test utility should as well.
4 skills analyzed
| Skill | Findings | Duration | Cost |
|---|---|---|---|
| code-review | 3 | 2m 26s | $1.99 |
| find-bugs | 3 | 5m 21s | $4.95 |
| skill-scanner | 0 | 4m 15s | $0.42 |
| security-review | 0 | 3m 16s | $0.46 |
Duration: 15m 18s · Tokens: 5.3M in / 49.9k out · Cost: $7.85 (+extraction: $0.02, +merge: $0.00, +fix_gate: $0.01, +dedup: $0.01)