正しくREDACTEDにされるかのテストを追加

This commit is contained in:
samunohito
2026-08-01 09:33:15 +09:00
parent adc1ec2319
commit 1d9fa528e9
@@ -3,9 +3,15 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { createRequire } from 'node:module';
import { context, propagation, trace } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { describe, expect, test, vi } from 'vitest';
import type { Span as SdkSpan, SpanProcessor } from '@opentelemetry/sdk-trace-base';
import { installDatabaseInstrumentation, installInstrumentation } from '@/core/telemetry/database-instrumentation.js';
const backendRequire = createRequire(import.meta.url);
describe('database-instrumentation', () => {
test('does not install PostgreSQL instrumentation when disabled', async () => {
const uninstall = await installDatabaseInstrumentation({} as any, {
@@ -55,6 +61,76 @@ describe('database-instrumentation', () => {
expect(pg.disable).toHaveBeenCalledOnce();
});
test('redacts SQL attributes after pg instrumentation records the statement', async () => {
const statement = 'SELECT very_secret_literal';
const attributeWrites: Array<{ key: string; value: unknown }> = [];
let attributesAtStart: Record<string, unknown> | undefined;
let pgSpan: SdkSpan | undefined;
const spanProcessor: SpanProcessor = {
forceFlush: async () => {},
onStart: span => {
if (span.instrumentationScope.name !== '@opentelemetry/instrumentation-pg') return;
pgSpan = span;
attributesAtStart = { ...span.attributes };
const setAttribute = span.setAttribute.bind(span);
span.setAttribute = (key, value) => {
attributeWrites.push({ key, value });
return setAttribute(key, value);
};
},
onEnd: () => {},
shutdown: async () => {},
};
const provider = new NodeTracerProvider({ spanProcessors: [spanProcessor] });
provider.register();
let uninstall: (() => void) | undefined;
try {
uninstall = await installDatabaseInstrumentation(provider, {
capturePgSpans: true,
capturePgStatement: false,
capturePgConnectionSpans: false,
});
const { Client } = backendRequire('pg') as typeof import('pg');
const tracer = provider.getTracer('database-instrumentation-test');
tracer.startActiveSpan('parent', parentSpan => {
try {
// pg instrumentation runs before an unconnected client queues the query,
// so no database is required.
new Client().query(statement, () => {});
} finally {
parentSpan.end();
}
});
const recordedPgSpan = pgSpan;
expect(recordedPgSpan).toBeDefined();
if (recordedPgSpan == null) throw new Error('PostgreSQL span was not started.');
expect(attributesAtStart).not.toHaveProperty('db.statement');
expect(attributesAtStart).not.toHaveProperty('db.query.text');
const rawSqlIndex = attributeWrites.findIndex(({ key, value }) =>
(key === 'db.statement' || key === 'db.query.text') && value === statement);
expect(rawSqlIndex).toBeGreaterThanOrEqual(0);
const rawSqlKey = attributeWrites[rawSqlIndex].key;
expect(attributeWrites.findIndex(({ key, value }, index) =>
index > rawSqlIndex && key === rawSqlKey && value === '[REDACTED]')).toBeGreaterThan(rawSqlIndex);
expect(recordedPgSpan.attributes['db.statement']).toBe('[REDACTED]');
expect(recordedPgSpan.attributes['db.query.text']).toBe('[REDACTED]');
expect(Object.values(recordedPgSpan.attributes)).not.toContain(statement);
} finally {
pgSpan?.end();
uninstall?.();
await provider.shutdown();
trace.disable();
context.disable();
propagation.disable();
}
});
test('keeps SQL statement attributes when explicitly enabled', () => {
const pg = { setTracerProvider: vi.fn(), enable: vi.fn(), disable: vi.fn() };
const config = vi.fn();