/** * GATE 1 — Debug facility unit tests. * Must pass before Phase 2. */ import { describe, it, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; import { parseDebugVeraeEnv, loadDebugConfig, shouldLog, createDebugger, setDebugTestSink, redact, withTrace, getTraceId, generateTraceId, } from '../../src/debug/index.js'; describe('parseDebugVeraeEnv', () => { it('disables when unset or empty', () => { assert.equal(parseDebugVeraeEnv(undefined).enabled, false); assert.equal(parseDebugVeraeEnv('').enabled, false); assert.equal(parseDebugVeraeEnv('off').enabled, false); }); it('enables all namespaces for 1 or *', () => { const a = parseDebugVeraeEnv('1'); assert.equal(a.enabled, true); assert.equal(a.namespaces, null); const b = parseDebugVeraeEnv('*'); assert.equal(b.enabled, true); assert.equal(b.namespaces, null); }); it('parses comma-separated namespaces', () => { const { enabled, namespaces } = parseDebugVeraeEnv('auth, NATS, jobs'); assert.equal(enabled, true); assert.ok(namespaces.has('auth')); assert.ok(namespaces.has('nats')); assert.ok(namespaces.has('jobs')); assert.equal(namespaces.has('webhooks'), false); }); }); describe('shouldLog', () => { it('respects level thresholds', () => { const config = { enabled: true, namespaces: null, level: 'warn', filePath: null, }; assert.equal(shouldLog(config, 'app', 'debug'), false); assert.equal(shouldLog(config, 'app', 'warn'), true); assert.equal(shouldLog(config, 'app', 'error'), true); }); it('filters by namespace', () => { const config = { enabled: true, namespaces: new Set(['auth']), level: 'debug', filePath: null, }; assert.equal(shouldLog(config, 'auth', 'debug'), true); assert.equal(shouldLog(config, 'nats', 'debug'), false); }); }); describe('redact', () => { it('redacts sensitive keys and token-like strings', () => { const out = redact({ password: 'secret', apiKey: 'zmw_abc123def456ghi789jkl', jobId: 'keep-me', authorization: 'Bearer eyJhbGciOiJIUzI1NiJ9.aaa.bbb', nested: { veraeToken: 'zmt_payload.sig' }, }); assert.equal(out.password, '[REDACTED]'); assert.equal(out.apiKey, '[REDACTED]'); assert.equal(out.jobId, 'keep-me'); assert.equal(out.authorization, '[REDACTED]'); assert.equal(out.nested.veraeToken, '[REDACTED]'); }); }); describe('createDebugger', () => { /** @type {string[]} */ let lines; const prev = { ...process.env }; beforeEach(() => { lines = []; setDebugTestSink((line) => lines.push(line)); }); afterEach(() => { setDebugTestSink(null); for (const key of Object.keys(process.env)) { if (!(key in prev)) delete process.env[key]; } Object.assign(process.env, prev); }); it('is silent when DEBUG_VERAE is unset', () => { delete process.env.DEBUG_VERAE; const log = createDebugger('auth'); log.debug('should not appear', { x: 1 }); assert.equal(lines.length, 0); }); it('emits only selected namespaces', () => { process.env.DEBUG_VERAE = 'auth'; createDebugger('auth').debug('auth-line'); createDebugger('nats').debug('nats-line'); assert.equal(lines.length, 1); assert.match(lines[0], /auth-line/); assert.doesNotMatch(lines[0], /nats-line/); }); it('redacts secrets in meta', () => { process.env.DEBUG_VERAE = 'auth'; createDebugger('auth').debug('login', { password: 'hunter2', token: 'zmw_supersecretvaluehere12', }); assert.equal(lines.length, 1); assert.doesNotMatch(lines[0], /hunter2/); assert.doesNotMatch(lines[0], /zmw_supersecret/); assert.match(lines[0], /REDACTED/); }); }); describe('withTrace', () => { it('propagates traceId to nested async work', async () => { const outerId = generateTraceId(); let innerId = null; await withTrace({ traceId: outerId, span: 'outer' }, async () => { assert.equal(getTraceId(), outerId); await withTrace({ span: 'inner' }, async () => { innerId = getTraceId(); }); }); assert.equal(innerId, outerId); assert.equal(getTraceId(), null); }); }); describe('loadDebugConfig', () => { it('reads level and file from env', () => { process.env.DEBUG_VERAE = '1'; process.env.DEBUG_VERAE_LEVEL = 'error'; process.env.DEBUG_VERAE_FILE = '/tmp/verae-debug.log'; const cfg = loadDebugConfig(process.env); assert.equal(cfg.enabled, true); assert.equal(cfg.level, 'error'); assert.equal(cfg.filePath, '/tmp/verae-debug.log'); }); });