feat: Add experimental async transport (port of PR #4572) #5646
4 issues
find-bugs: Found 4 issues (2 medium, 2 low)
Medium
SOCKS proxy failure silently bypasses proxy and connects directly - `sentry_sdk/transport.py:952-956`
When a SOCKS proxy is configured but httpcore.AsyncSOCKSProxy raises RuntimeError (e.g., socksio not installed), the code logs a warning but then falls through to return httpcore.AsyncConnectionPool(**opts) on line 960, silently establishing a direct connection without any proxy. Users who configure a SOCKS proxy typically expect all traffic to go through it (e.g., for privacy, corporate firewall compliance, or security reasons). Silently bypassing the proxy could result in unintended data exposure or security policy violations.
Test will fail: isinstance() check on Mock object returns False - `tests/integrations/asyncio/test_asyncio.py:665-673`
The test test_loop_close_flushes_async_transport uses Mock(spec=AsyncHttpTransport) for the transport. However, the _flush() function in patch_loop_close() uses isinstance(client.transport, AsyncHttpTransport) to check the transport type. Since a Mock with spec is not an actual instance of AsyncHttpTransport, isinstance() returns False, causing the function to return early without calling client.close_async(). The subsequent assertions mock_client.close_async.assert_called_once() and mock_client.close_async.assert_awaited_once() will fail because close_async is never called.
Low
Race condition in close_async() can cause AttributeError - `sentry_sdk/client.py:1076`
In close_async(), between the await of flush_async() (line 1074) and the call to self.transport.kill() (line 1076), another concurrent call to close_async() could set self.transport to None. This would cause an AttributeError when trying to call kill() on None. While this requires unusual concurrent usage of close_async(), it violates the principle of defensive coding.
Missing test finalizer causes test pollution - `tests/test_transport.py:1074`
The test test_async_transport_concurrent_requests sets the client on the global scope via sentry_sdk.get_global_scope().set_client(client) at line 1074, but unlike similar tests (e.g., lines 125-126, 971-972, 1097-1098), it does not register a finalizer to clean up the global scope. This can cause test pollution where subsequent tests may inherit a client with a closed transport.
Duration: 17m 46s · Tokens: 11.5M in / 69.0k out · Cost: $15.49 (+extraction: $0.01, +merge: $0.00, +fix_gate: $0.01)
Annotations
Check warning on line 956 in sentry_sdk/transport.py
sentry-warden / warden: find-bugs
SOCKS proxy failure silently bypasses proxy and connects directly
When a SOCKS proxy is configured but `httpcore.AsyncSOCKSProxy` raises `RuntimeError` (e.g., socksio not installed), the code logs a warning but then falls through to `return httpcore.AsyncConnectionPool(**opts)` on line 960, silently establishing a direct connection without any proxy. Users who configure a SOCKS proxy typically expect all traffic to go through it (e.g., for privacy, corporate firewall compliance, or security reasons). Silently bypassing the proxy could result in unintended data exposure or security policy violations.
Check warning on line 673 in tests/integrations/asyncio/test_asyncio.py
sentry-warden / warden: find-bugs
Test will fail: isinstance() check on Mock object returns False
The test `test_loop_close_flushes_async_transport` uses `Mock(spec=AsyncHttpTransport)` for the transport. However, the `_flush()` function in `patch_loop_close()` uses `isinstance(client.transport, AsyncHttpTransport)` to check the transport type. Since a Mock with spec is not an actual instance of AsyncHttpTransport, `isinstance()` returns False, causing the function to return early without calling `client.close_async()`. The subsequent assertions `mock_client.close_async.assert_called_once()` and `mock_client.close_async.assert_awaited_once()` will fail because `close_async` is never called.