File size: 2,763 Bytes
dcedb25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { describe, it, expect } from 'vitest';
import { sanitizeProviderErrorMessage, summarizeAttemptError } from '../../lib/error-redaction.js';

describe('sanitizeProviderErrorMessage', () => {
  it('redacts Bearer tokens', () => {
    expect(sanitizeProviderErrorMessage('auth failed: Bearer abc.def-123')).toBe(
      'auth failed: Bearer [redacted]',
    );
  });

  it('redacts labeled secrets in plain form', () => {
    expect(sanitizeProviderErrorMessage('api_key=supersecretvalue rejected')).toBe(
      'api_key=[redacted] rejected',
    );
  });

  it('redacts JSON-quoted secret labels', () => {
    const out = sanitizeProviderErrorMessage('upstream said {"api_key": "supersecretvalue123"}');
    expect(out).not.toContain('supersecretvalue123');
    expect(out).toContain('"api_key": "[redacted]');
  });

  it('redacts bare high-entropy tokens with no known prefix', () => {
    const out = sanitizeProviderErrorMessage('key co-A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8 was rejected');
    expect(out).not.toContain('A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8');
    expect(out).toContain('[redacted-token]');
  });

  it('redacts URLs including key-bearing query strings', () => {
    const out = sanitizeProviderErrorMessage('GET https://api.example.com/v1?key=sk-abc123 failed');
    expect(out).not.toContain('api.example.com');
    expect(out).toContain('[redacted-url]');
  });

  it('leaves ordinary provider prose and model ids intact', () => {
    const msg = 'model llama-3.3-70b-versatile is over capacity, retry after 30s (HTTP 429)';
    expect(sanitizeProviderErrorMessage(msg)).toBe(msg);
  });

  it('caps message length', () => {
    const out = sanitizeProviderErrorMessage('x '.repeat(400));
    expect(out.length).toBeLessThanOrEqual(240);
  });
});

// The short per-attempt error summary stored in request_attempts.error_summary:
// same redactions as sanitizeProviderErrorMessage, tighter cap (200 chars).
describe('summarizeAttemptError', () => {
  it('applies the same secret redactions', () => {
    const out = summarizeAttemptError('401 rejected: Bearer sk-abc.def-12345 for key gsk_A1b2C3d4E5f6G7h8');
    expect(out).not.toContain('sk-abc.def-12345');
    expect(out).not.toContain('gsk_A1b2C3d4E5f6G7h8');
    expect(out).toContain('Bearer [redacted]');
  });

  it('caps the summary at 200 characters with an ellipsis', () => {
    const out = summarizeAttemptError('upstream exploded because ' + 'y '.repeat(300));
    expect(out.length).toBeLessThanOrEqual(200);
    expect(out.endsWith('...')).toBe(true);
  });

  it('leaves ordinary provider prose intact', () => {
    const msg = '429 Too Many Requests: rate limit reached for llama-3.3-70b, retry in 7m12s';
    expect(summarizeAttemptError(msg)).toBe(msg);
  });
});