Files
Literature-Management/tests/unit/main/ipc/paths-no-path-leak.test.ts
2026-10-21 14:42:59 +08:00

69 lines
2.6 KiB
TypeScript

// tests/unit/main/ipc/paths-no-path-leak.test.ts
//
// 守 audit-r244「白名单拒绝消息不回显绝对路径」契约。
//
// 问题:ipc/wrap.ts 只对 **INTERNAL** 走 scrubInternal(把 rootPath **之内**
// 的路径替成占位符);已知 code(EPERM 等)是**原样透传**的。而
// `assertInsideAllowedRoot` 的 EPERM 消息里带着 `abs` —— 恰恰是
// rootPath **之外**的路径(scrubInternal 恰恰脱敏不到它)⇒ 家目录 /
// OneDrive 目录名随 IPC 错误回包进 renderer 与 telemetry。
//
// 口径已由 ipc/shell.ts(r229)、ipc/library.ts(r191)确立:消息不含路径,
// 完整路径只留 main 侧日志。paths.ts 是**源头**,之前靠三个调用点各自
// 改写文案才没漏 —— 属「运气」而非「设计」,新调用点一接就漏。
//
// 本测锁:白名单拒绝抛出的 AppError.message 里既没有越界路径,也没有
// 工作区根路径。
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { promises as fs } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { setRootPath } from '../../../../src/main/utils/safe-write';
import { assertInsideAllowedRoot } from '../../../../src/main/ipc/paths';
import { AppError } from '../../../../src/main/utils/error';
describe('audit-r244:白名单拒绝消息不含绝对路径', () => {
let root: string;
let outside: string;
beforeEach(async () => {
root = await fs.mkdtemp(join(tmpdir(), 'rkms-pathleak-root-'));
outside = await fs.mkdtemp(join(tmpdir(), 'rkms-pathleak-out-'));
setRootPath(root);
});
afterEach(async () => {
await fs.rm(root, { recursive: true, force: true });
await fs.rm(outside, { recursive: true, force: true });
});
it('工作区外的绝对路径 → EPERM,消息里既无越界路径也无根路径', () => {
const secret = join(outside, 'id_rsa');
let err: unknown;
try {
assertInsideAllowedRoot(secret);
} catch (e: unknown) {
err = e;
}
expect(err).toBeInstanceOf(AppError);
const appErr = err as AppError;
expect(appErr.code).toBe('EPERM');
expect(appErr.message).not.toContain(secret);
expect(appErr.message).not.toContain(outside);
expect(appErr.message).not.toContain(root);
});
it('工作区外的相对路径(基于 root 解析后越界)→ 同样不含路径', () => {
let err: unknown;
try {
assertInsideAllowedRoot('../escape-outside');
} catch (e: unknown) {
err = e;
}
expect(err).toBeInstanceOf(AppError);
expect((err as AppError).code).toBe('EPERM');
expect((err as AppError).message).not.toContain(root);
});
});