From daa898225e0594b9b4831da08c84f139cf842166 Mon Sep 17 00:00:00 2001 From: Tom de Bruijn Date: Fri, 3 Nov 2023 16:14:38 +0100 Subject: [PATCH] Add setSqlBody tracing helper (#957) Make it easier to set SQL queries as the span body attribute without danger of storing unsanitized SQL queries. When `setSqlBody` is used in combination with `setBody`, the `setSqlBody` call is leading. Related to https://github.com/appsignal/appsignal-python/issues/140 This change was made available in the agent in PR #955 Part of #956 --- .changesets/add-set_sql_body-tracing-helper.md | 18 ++++++++++++++++++ src/__tests__/helpers.test.ts | 13 +++++++++---- src/helpers.ts | 4 ++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 .changesets/add-set_sql_body-tracing-helper.md diff --git a/.changesets/add-set_sql_body-tracing-helper.md b/.changesets/add-set_sql_body-tracing-helper.md new file mode 100644 index 00000000..412c594b --- /dev/null +++ b/.changesets/add-set_sql_body-tracing-helper.md @@ -0,0 +1,18 @@ +--- +bump: "patch" +type: "add" +--- + +Add the `setSqlBody` tracing helper to set the body attribute on a span that contains a SQL query. When using this helper the given SQL query will be sanitized, reducing the chances of sending sensitive data to AppSignal. + +```js +import { setSqlBody } from "@appsignal/nodejs"; + +// Must be used in an instrumented context -- e.g. an Express route +setSqlBody("SELECT * FROM users WHERE 'password' = 'secret'"); +// Will be stored as: "SELECT * FROM users WHERE 'password' = ?" +``` + +When the `setBody` helper is also used, the `setSqlBody` overwrites the `setBody` attribute. + +More information about our [tracing helpers](https://docs.appsignal.com/nodejs/3.x/instrumentation/instrumentation.html) can be found in our documentation. diff --git a/src/__tests__/helpers.test.ts b/src/__tests__/helpers.test.ts index 55c11d24..f16a25e7 100644 --- a/src/__tests__/helpers.test.ts +++ b/src/__tests__/helpers.test.ts @@ -9,6 +9,7 @@ import { Client } from "../client" import { setBody, + setSqlBody, setCategory, setCustomData, setHeader, @@ -78,7 +79,8 @@ describe("Helpers", () => { it("set the attributes", () => { trace.getTracer("test").startActiveSpan("Some span", span => { - setBody("SELECT * FROM users") + setBody("Some body") + setSqlBody("SELECT * FROM users") setCategory("some.query") setName("Some query") setCustomData({ chunky: "bacon" }) @@ -94,7 +96,8 @@ describe("Helpers", () => { expect(spans.length).toEqual(1) expect(spans[0].attributes).toMatchObject({ - "appsignal.body": "SELECT * FROM users", + "appsignal.body": "Some body", + "appsignal.sql_body": "SELECT * FROM users", "appsignal.category": "some.query", "appsignal.name": "Some query", "appsignal.custom_data": '{"chunky":"bacon"}', @@ -235,7 +238,8 @@ describe("Helpers", () => { tracer.startActiveSpan("Active span", span => { const childSpan = tracer.startSpan("Child span") - setBody("SELECT * FROM users", childSpan) + setBody("Some body", childSpan) + setSqlBody("SELECT * FROM users", childSpan) setCategory("some.query", childSpan) setName("Some query", childSpan) setCustomData({ chunky: "bacon" }, childSpan) @@ -267,7 +271,8 @@ describe("Helpers", () => { expect(activeSpan.attributes).toEqual({}) expect(childSpan.attributes).toMatchObject({ - "appsignal.body": "SELECT * FROM users", + "appsignal.body": "Some body", + "appsignal.sql_body": "SELECT * FROM users", "appsignal.category": "some.query", "appsignal.name": "Some query", "appsignal.custom_data": '{"chunky":"bacon"}', diff --git a/src/helpers.ts b/src/helpers.ts index 9bf6d0ad..3a2a23f4 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -84,6 +84,10 @@ export function setBody(body: string, span?: Span) { setAttribute("appsignal.body", body, span) } +export function setSqlBody(body: string, span?: Span) { + setAttribute("appsignal.sql_body", body, span) +} + export function setNamespace(namespace: string, span?: Span) { setAttribute("appsignal.namespace", namespace, span) }