aps-agent/scripts/check-cross-database.test.mjs

54 lines
2.1 KiB
JavaScript
Raw Normal View History

/** 跨库访问检查的用例(任务 A1.6):负例必须真的失败。 */
import assert from 'node:assert/strict';
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import { test } from 'node:test';
import { fileURLToPath } from 'node:url';
import { findCrossDatabaseAccess } from './check-cross-database.mjs';
const ROOT = fileURLToPath(new URL('..', import.meta.url));
async function withFixture(files, run) {
const dir = await mkdtemp(join(tmpdir(), 'crossdb-'));
try {
for (const [rel, content] of Object.entries(files)) {
const file = join(dir, rel);
await mkdir(dirname(file), { recursive: true });
await writeFile(file, content, 'utf8');
}
return await run(dir);
} finally {
await rm(dir, { recursive: true, force: true });
}
}
test('正例:当前仓库无跨库访问', async () => {
assert.deepEqual(await findCrossDatabaseAccess(ROOT), []);
});
test('负例:平台代码里出现 APS 表名被拦下', async () => {
await withFixture(
{ 'server/core/query.ts': 'const sql = "select * from routing_templates";\nexport const q = sql;\n' },
async (dir) => {
const violations = await findCrossDatabaseAccess(dir);
assert.ok(violations.some((v) => v.reason.includes('routing_templates')), JSON.stringify(violations));
},
);
});
test('正例:平台自己的 APS_DB_PATH 变量不算越界', async () => {
await withFixture({ 'server/config.ts': 'const path = process.env.APS_DB_PATH ?? "~/.aps/aps.sqlite";\nexport const p = path;\n' }, async (dir) => {
assert.deepEqual(await findCrossDatabaseAccess(dir), [], '平台自己的库配置不应被当成访问 APS 业务库');
});
});
test('负例:平台代码里出现 APS 库连接串被拦下', async () => {
await withFixture(
{ 'server/app/config.ts': 'export const url = "postgres://user:pw@db/aps_db";\n' },
async (dir) => {
const violations = await findCrossDatabaseAccess(dir);
assert.ok(violations.length > 0, JSON.stringify(violations));
},
);
});