Skip to content
Open
43 changes: 38 additions & 5 deletions sentry_sdk/integrations/clickhouse_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# from: https://stackoverflow.com/a/71944042/300572
if TYPE_CHECKING:
from collections.abc import Iterator
from typing import Any, Callable, ParamSpec, Union
from typing import Any, Callable, Optional, ParamSpec, Union

Check failure on line 18 in sentry_sdk/integrations/clickhouse_driver.py

View check run for this annotation

@sentry/warden / warden: code-review

Streaming ClickHouse breadcrumbs include query results when database query data is disabled

In `_wrap_end`, the streaming breadcrumb always passes `{"db.result": res, **breadcrumb_data}`. This bypasses the preceding `database_query_data`/`send_default_pii` check, causing ClickHouse query results to be attached to breadcrumbs even when database query data collection is disabled. Pass only `breadcrumb_data` after the conditional merge.
else:
# Fake ParamSpec
class ParamSpec:
Expand Down Expand Up @@ -79,7 +79,7 @@
if client.get_integration(ClickhouseDriverIntegration) is None:
return f(*args, **kwargs)

connection = args[0]
connection: "Connection" = args[0]
query = args[1]
query_id = args[2] if len(args) > 2 else kwargs.get("query_id")
params = args[3] if len(args) > 3 else kwargs.get("params")
Expand All @@ -95,6 +95,16 @@
SPANDATA.DB_QUERY_TEXT: str(query),
},
)

connection._query = query
connection._breadcrumb_data = {
SPANDATA.DB_SYSTEM: "clickhouse",
SPANDATA.DB_NAME: connection.database,
SPANDATA.DB_DRIVER_NAME: "clickhouse-driver",
SPANDATA.SERVER_ADDRESS: connection.host,
SPANDATA.SERVER_PORT: connection.port,
SPANDATA.DB_USER: connection.user,
}
else:
span = sentry_sdk.start_span(
op=OP.DB,
Expand All @@ -114,24 +124,47 @@
elif should_send_default_pii():
span.set_data("db.params", params)

connection._sentry_span = span # type: ignore[attr-defined]
connection._sentry_span = span
Comment thread
alexander-alderman-webb marked this conversation as resolved.

if span is not None:
_set_db_data(span, connection)

# run the original code
ret = f(*args, **kwargs)

return ret

return _inner


def _wrap_end(f: "Callable[P, T]") -> "Callable[P, T]":
def _inner_end(*args: "P.args", **kwargs: "P.kwargs") -> "T":
res = f(*args, **kwargs)
instance = args[0]
span = getattr(instance.connection, "_sentry_span", None) # type: ignore[attr-defined]
instance: "Client" = args[0]

query = getattr(instance.connection, "_query", None)
breadcrumb_data: "Optional[dict[str, Any]]" = getattr(
instance.connection, "_breadcrumb_data", None
)

if query is not None and breadcrumb_data is not None:
client_options = sentry_sdk.get_client().options
if (
has_data_collection_enabled(client_options)
and client_options["data_collection"]["database_query_data"]
) or (
not has_data_collection_enabled(client_options)
and should_send_default_pii()
):
breadcrumb_data = {"db.result": res, **breadcrumb_data}

sentry_sdk.get_isolation_scope().add_breadcrumb(
message=query,
category="query",
data={"db.result": res, **breadcrumb_data},
)

Check warning on line 165 in sentry_sdk/integrations/clickhouse_driver.py

View check run for this annotation

@sentry/warden / warden: security-review

ClickHouse breadcrumbs always include db.result despite PII/data-collection guards

In the streaming breadcrumb path, `db.result` is unconditionally merged into breadcrumb data after the PII/data-collection check, so query results are always sent to Sentry. Gate the `add_breadcrumb` data the same way the non-streaming span path gates `span.set_data("db.result", res)`.

Check failure on line 165 in sentry_sdk/integrations/clickhouse_driver.py

View check run for this annotation

@sentry/warden / warden: code-review

[VEU-T9U] Streaming ClickHouse breadcrumbs include query results when database query data is disabled (additional location)

In `_wrap_end`, the streaming breadcrumb always passes `{"db.result": res, **breadcrumb_data}`. This bypasses the preceding `database_query_data`/`send_default_pii` check, causing ClickHouse query results to be attached to breadcrumbs even when database query data collection is disabled. Pass only `breadcrumb_data` after the conditional merge.

Check failure on line 165 in sentry_sdk/integrations/clickhouse_driver.py

View check run for this annotation

@sentry/warden / warden: find-bugs

Streaming breadcrumbs always attach db.result, bypassing PII guards

In `_wrap_end`, `db.result` is always merged into breadcrumb data even when the PII/`database_query_data` check fails; pass `data=breadcrumb_data` instead so results are only included when that guard succeeds.

span = getattr(instance.connection, "_sentry_span", None)

if span is None:
return res
Expand Down
Loading
Loading