import assert from 'node:assert/strict'; import { Writable } from 'node:stream'; import test from 'node:test'; import { loadConfig } from '../src/config.js'; import { diagnosticDurationMs, diagnosticError, diagnosticRequestPath, normalizeRequestId } from '../src/diagnostics.js'; import { buildServer, createControlPlaneLogger } from '../src/server.js'; import { TaskService, type TaskEvent } from '../src/task-service.js'; function testConfig(overrides: NodeJS.ProcessEnv = {}) { return loadConfig({ NODE_ENV: 'test', FIELD_ENCRYPTION_KEY: Buffer.alloc(32, 41).toString('base64'), DATABASE_URL: 'postgresql://invalid:invalid@127.0.0.1:1/invalid', ...overrides }); } function logCollector(): { destination: Writable; records: Array> } { const chunks: string[] = []; const records: Array> = []; const destination = new Writable({ write(chunk, _encoding, callback) { chunks.push(String(chunk)); const lines = chunks.join('').split('\n'); chunks.length = 0; const remainder = lines.pop() || ''; if (remainder) chunks.push(remainder); for (const line of lines) { if (line.trim()) records.push(JSON.parse(line) as Record); } callback(); } }); return { destination, records }; } test('diagnostic errors preserve code and stack location without leaking the error message', () => { const secret = 'customer-secret-value'; const error = new Error(`download https://user:password@example.test/list.xlsx?token=${secret}`) as Error & { code: string; errno: number; syscall: string; }; error.code = 'ECONNRESET'; error.errno = -54; error.syscall = 'read'; const metadata = diagnosticError(error, 'download_failed'); const serialized = JSON.stringify(metadata); assert.equal(metadata.error_code, 'ECONNRESET'); assert.equal(metadata.error_name, 'Error'); assert.match(String(metadata.error_fingerprint), /^[a-f0-9]{24}$/u); assert.equal(metadata.error_errno, -54); assert.equal(metadata.error_syscall, 'read'); assert.doesNotMatch(serialized, /customer-secret-value|password|example\.test|list\.xlsx/u); }); test('diagnostic request identifiers and paths are stable and query-safe', () => { assert.equal(normalizeRequestId('request:wechat:12345678'), 'request:wechat:12345678'); const generated = normalizeRequestId('token=must-not-be-used'); assert.match(generated, /^[a-f0-9-]{36}$/u); assert.doesNotMatch(generated, /token/u); assert.equal(diagnosticRequestPath('/api/tasks/TASK-1?token=secret#fragment'), '/api/tasks/TASK-1'); const startedAt = process.hrtime.bigint() - 2_000_000n; assert.ok(diagnosticDurationMs(startedAt) >= 1); }); test('control-plane logger redacts credentials and includes deployment identity', async () => { const { destination, records } = logCollector(); const logger = createControlPlaneLogger(testConfig({ DEPLOYMENT_REVISION: 'commit-2360506' }), destination); logger.info({ diagnostic_event: 'test.redaction', password: 'root-secret', nested: { token: 'nested-secret' }, safe_value: 'visible' }, 'diagnostic test'); await new Promise((resolve) => setImmediate(resolve)); assert.equal(records.length, 1); assert.equal(records[0].service, 'ltjt-control-plane'); assert.equal(records[0].deployment_revision, 'commit-2360506'); assert.equal(records[0].password, '[REDACTED]'); assert.deepEqual(records[0].nested, { token: '[REDACTED]' }); assert.equal(records[0].safe_value, 'visible'); }); test('HTTP diagnostics reuse one request ID and never log query values', async () => { const { destination, records } = logCollector(); const { app } = await buildServer({ config: testConfig(), startParserLoop: false, loggerDestination: destination, parser: { async parse() { return { blockers: ['test parser'] }; }, async checkConnection() { return { ok: false, configured: false }; } } }); const response = await app.inject({ method: 'GET', url: '/health/live?token=query-secret', headers: { 'x-request-id': 'request:test:12345678' } }); assert.equal(response.statusCode, 200); assert.equal(response.headers['x-request-id'], 'request:test:12345678'); await app.close(); await new Promise((resolve) => setImmediate(resolve)); const started = records.find((record) => record.diagnostic_event === 'http.request.started'); const completed = records.find((record) => record.diagnostic_event === 'http.request.completed'); assert.equal(started?.request_id, 'request:test:12345678'); assert.equal(completed?.request_id, 'request:test:12345678'); assert.equal(started?.path, '/health/live'); assert.equal(completed?.path, '/health/live'); assert.equal(completed?.status_code, 200); assert.doesNotMatch(JSON.stringify(records), /query-secret/u); }); test('task state and audit diagnostics record keys but never business values', async () => { const logs: Array> = []; const service = new TaskService( testConfig(), {} as never, { info(metadata) { logs.push(metadata); }, warn(metadata) { logs.push(metadata); }, error(metadata) { logs.push(metadata); } } ) as unknown as { notify(event: TaskEvent): void; audit( client: { query: (...args: unknown[]) => Promise<{ rowCount: number }> }, context: { organizationId: string; userId: string; requestId: string }, eventType: string, entityId: string, metadata: Record ): Promise; }; service.notify({ id: 8, organization_id: 'org-secret', task_id: 'TASK-DIAGNOSTIC-1', status: 'awaiting_attachment', stage: 'input', message: 'customer-secret-message', payload: { customer_name: 'customer-secret-value', row_count: 12 }, created_at: new Date().toISOString() }); await service.audit( { async query() { return { rowCount: 1 }; } }, { organizationId: 'org-secret', userId: 'user-secret', requestId: 'request:audit:12345678' }, 'task.passenger_roster_attachment_rejected', 'TASK-DIAGNOSTIC-1', { customer_name: 'customer-secret-value', error_code: 'roster_file_invalid' } ); assert.ok(logs.some((log) => log.diagnostic_event === 'task.state.emitted' && Array.isArray(log.payload_keys) && (log.payload_keys as string[]).includes('customer_name'))); assert.ok(logs.some((log) => log.diagnostic_event === 'audit.event.staged' && log.request_id === 'request:audit:12345678')); assert.doesNotMatch(JSON.stringify(logs), /customer-secret-value|customer-secret-message|org-secret|user-secret/u); }); test('production configuration rejects raw AgentBus payload logging', () => { assert.throws( () => testConfig({ NODE_ENV: 'production', AGENTBUS_LOG_PAYLOADS: 'true' }), /AGENTBUS_LOG_PAYLOADS must remain false in production/u ); assert.throws( () => testConfig({ LOG_LEVEL: 'verbose' }), /Invalid enum value/u ); });