fix(server-utils): Always sanitize inline literals out of db.query.text - #24089
fix(server-utils): Always sanitize inline literals out of db.query.text#24089s1gr1d wants to merge 6 commits into
db.query.text#24089Conversation
…erals Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
size-limit report 📦
|
…ery-data # Conflicts: # packages/cloudflare/src/instrumentations/worker/instrumentD1.ts # packages/core/src/server.ts # packages/nuxt/src/runtime/utils/instrumentDatabase.ts # packages/server-utils/src/integrations/knex.ts # packages/server-utils/src/integrations/mysql.ts # packages/server-utils/src/integrations/mysql2/index.ts # packages/server-utils/src/integrations/postgres.ts # packages/server-utils/src/integrations/tedious.ts
Per OTel, query text may only be collected by default when literals are sanitized, and our docs say `databaseQueryData` does not control `db.query.text`. Sanitize unconditionally at every site that attached raw SQL and drop the `filterCollectedDbQueryText` gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dataCollection.databaseQueryData to inline SQL literalsdb.query.text
There was a problem hiding this comment.
Thanks for fixing this!
One observation from this PR, but totally out of scope for it: Looks like we have very few tests that check proper SQL queries, e.g. with filter conditions. Queries like SELECT 1 + 1 are not super representative here. I'm fine with them being sanitized as well although it's IMHO not as critically necessary as literals in filter clauses or insertion values WHERE col = ?.
That said, some of the tedious tests now show that literals in filter conditions are also sanitized, so all good!
Again, nothing to change for this PR but rather something we should tackle sometime to have more representative tests.
…ery-data # Conflicts: # dev-packages/e2e-tests/test-applications/astro-6-cf-workers/tests/db.test.ts # dev-packages/e2e-tests/test-applications/astro-7/tests/db.test.ts # dev-packages/e2e-tests/test-applications/node-express-esm-loader/tests/server.test.ts # dev-packages/e2e-tests/test-applications/node-express-v5/tests/mysql.test.ts
| function createStartSpanOptions(query: string, type: D1QueryType): StartSpanOptions { | ||
| const querySummary = query ? getSqlQuerySummary(sanitizeSqlQuery(query)) : undefined; | ||
| const queryText = sanitizeSqlQuery(query); | ||
| const querySummary = query ? getSqlQuerySummary(queryText) : undefined; |
There was a problem hiding this comment.
Bug: The D1 instrumentation sets db.query.text to 'Unknown SQL Query' for empty queries, unlike other integrations which omit the attribute, due to an unguarded call to sanitizeSqlQuery.
Severity: LOW
Suggested Fix
Add a guard before calling sanitizeSqlQuery to align with other database integrations. Change the line to const queryText = query ? sanitizeSqlQuery(query) : undefined;. This will ensure that for empty or falsy queries, the db.query.text attribute is omitted from the span.
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: packages/cloudflare/src/instrumentations/worker/instrumentD1.ts#L134-L136
Potential issue: In the D1 instrumentation, `sanitizeSqlQuery(query)` is called without
first checking if the `query` is a falsy value, such as an empty string. The
`sanitizeSqlQuery` function returns the string `'Unknown SQL Query'` for falsy inputs.
Consequently, if `D1PreparedStatement.prepare("")` is ever called, the resulting span
will have a `db.query.text` attribute set to `'Unknown SQL Query'`. This behavior is
inconsistent with other database integrations in the codebase, which use a guard to
ensure the attribute is omitted for empty or undefined queries. While this scenario is
unlikely in normal usage, it represents a deviation from the established pattern.
Also affects:
packages/cloudflare/src/instrumentations/worker/instrumentD1.ts:126~126
mysql, mysql2, pg, tedious, knex, the Nuxt DB helper and Cloudflare D1 wrote the raw statement to
db.query.text, so inline literals likeWHERE email = 'jane@example.com'shipped as span data. postgres-js and the mysql2 channel subscriber already sanitized; the rest did not.Per OTel, query text may be collected by default only when literals are sanitized to
?, and parameterized text passes through untouched ($nand?placeholders survive the sanitizer). Our own docs saydatabaseQueryDatadoes not controldb.query.text, so this is not gated on an option. Each site now sanitizes once and reuses the result for the attribute, the summary, and the non-streamed span name, which is less work than before (the summary path already sanitized). The D1 breadcrumb message gets the same treatment.An earlier revision of this PR gated the raw text on
databaseQueryDatainstead; that read the option as covering query text, which the docs explicitly carve out. Relay-side scrubbing for this attribute is being enabled separately in getsentry/sentry-conventions#625.This resolves the two
TODO: (fix)notes in the tedious integration test.Fixes #24084