import { describe, expect, it } from 'vitest'; import { redact } from '../src/core/openai'; const KEY = 'sk-test-123'; describe('redact', () => { it('replaces every occurrence of the key', () => { expect(redact(`a ${KEY} b ${KEY}`, { apiKey: KEY })).toBe('a *** b ***'); }); it('masks any Bearer token', () => { expect(redact('Authorization: Bearer abc.def-1', { apiKey: KEY })).toBe('Authorization: Bearer ***'); }); it('leaves the message alone for an empty key', () => { expect(redact('HTTP 401: nope', { apiKey: '' })).toBe('HTTP 401: nope'); }); it('cuts at the multipart boundary and trims trailing ": "', () => { const b = '----voice-note-0000'; expect(redact(`HTTP 400: echo --${b}\r\nContent-Disposition: form-data`, { apiKey: KEY, boundary: b })).toBe( 'HTTP 400: echo', ); expect(redact(`HTTP 400: --${b}\r\n`, { apiKey: KEY, boundary: b })).toBe('HTTP 400'); }); it('cuts at Content-Disposition regardless of case', () => { expect(redact('HTTP 400: got content-disposition: form-data; name="file"', { apiKey: KEY })).toBe('HTTP 400: got'); }); it('caps the result at 300 chars', () => { expect(redact('x'.repeat(500), { apiKey: KEY })).toHaveLength(300); }); it('replaces the key before capping, so no key fragment survives the cut', () => { const out = redact(`${'y'.repeat(295)}${KEY}`, { apiKey: KEY }); expect(out).toBe(`${'y'.repeat(295)}***`); expect(out).not.toContain('sk-'); }); });