feat: v0.8.2 安全纵深补全 · 协议保真 · 断链修复 — 图片SSRF/根MEMORY.md保护根治 · Anthropic thinking回传+pause_turn续传 · 2523 用例全量回归 + E2E 扩充
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* v0.8.2 P1-5: 敏感值脱敏单源工具测试
|
||||
*
|
||||
* 锁定契约:
|
||||
* - 键名归一化匹配(api_key / authKey / Authorization 等形态均命中)
|
||||
* - 长值保留后 4 位、短值完全掩码
|
||||
* - 嵌套对象/数组递归;非敏感字段原样保留
|
||||
* - 循环引用与深度上限防护(防御恶意构造的工具参数)
|
||||
* - 原对象不被修改
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { deepMaskSensitive, maskSensitiveValue } from '../mask';
|
||||
|
||||
describe('maskSensitiveValue', () => {
|
||||
it('长值保留后 4 位', () => {
|
||||
expect(maskSensitiveValue('sk-abcdefgh12345678')).toBe('***5678');
|
||||
});
|
||||
it('短值(≤4)完全掩码', () => {
|
||||
expect(maskSensitiveValue('abc')).toBe('***');
|
||||
expect(maskSensitiveValue('abcd')).toBe('***');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deepMaskSensitive', () => {
|
||||
it('顶层与嵌套的敏感键均被掩码', () => {
|
||||
const input = {
|
||||
url: 'https://api.example.com',
|
||||
headers: {
|
||||
Authorization: 'Bearer sk-abcdefgh12345678',
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
api_key: 'sk-abcdefgh12345678',
|
||||
nested: { authToken: 'token-1234567890' },
|
||||
};
|
||||
const out = deepMaskSensitive(input) as typeof input;
|
||||
expect(out.url).toBe('https://api.example.com');
|
||||
expect(out['api_key']).toBe('***5678');
|
||||
expect((out.headers as Record<string, string>).Authorization).toBe('***5678');
|
||||
expect((out.headers as Record<string, string>)['content-type']).toBe('application/json');
|
||||
expect((out.nested as { authToken: string }).authToken).toBe('***7890');
|
||||
});
|
||||
|
||||
it('数组内对象同样脱敏', () => {
|
||||
const out = deepMaskSensitive([{ secret: 'supersecret-value-42' }, { ok: 1 }]) as Array<
|
||||
Record<string, unknown>
|
||||
>;
|
||||
expect(out[0].secret).toBe('***e-42');
|
||||
expect(out[1].ok).toBe(1);
|
||||
});
|
||||
|
||||
it('原对象不被修改', () => {
|
||||
const input = { api_key: 'sk-abcdefgh12345678' };
|
||||
deepMaskSensitive(input);
|
||||
expect(input.api_key).toBe('sk-abcdefgh12345678');
|
||||
});
|
||||
|
||||
it('循环引用与深度上限不抛错', () => {
|
||||
const a: Record<string, unknown> = { name: 'a' };
|
||||
a.self = a;
|
||||
const out = deepMaskSensitive(a) as Record<string, unknown>;
|
||||
expect(out.name).toBe('a');
|
||||
expect(out.self).toBe('[circular]');
|
||||
|
||||
const deep: Record<string, unknown> = { v: 0 };
|
||||
let cur = deep;
|
||||
for (let i = 0; i < 20; i++) {
|
||||
cur.next = { v: i + 1 };
|
||||
cur = cur.next as Record<string, unknown>;
|
||||
}
|
||||
const deepOut = deepMaskSensitive(deep) as Record<string, unknown>;
|
||||
expect(deepOut.v).toBe(0);
|
||||
expect(JSON.stringify(deepOut)).toContain('depth-limit');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user