kt-template-online-api/test/modules/qqbot/plugin-platform/plugin-package-source.spec.ts

91 lines
2.7 KiB
TypeScript

import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, sep } from 'node:path';
import { QqbotPluginPackagePathPolicyService } from '@/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-path-policy.service';
import { QqbotPluginPackageSourceService } from '@/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-source.service';
describe('QqbotPluginPackageSourceService', () => {
let tempRoot: string;
beforeEach(() => {
tempRoot = mkdtempSync(join(tmpdir(), 'qqbot-plugin-source-'));
});
afterEach(() => {
rmSync(tempRoot, { force: true, recursive: true });
});
it('discovers packages from plugin.json without importing package code', async () => {
const packageRoot = join(tempRoot, 'sample');
mkdirSync(join(packageRoot, 'src'), { recursive: true });
writeFileSync(
join(packageRoot, 'plugin.json'),
JSON.stringify({
key: 'sample',
name: 'Sample',
version: '1.0.0',
entry: 'src/index.ts',
runtime: {
workerType: 'thread',
timeoutMs: 5000,
memoryMb: 128,
maxConcurrency: 1,
configKeys: ['SAMPLE_TOKEN'],
},
operations: [],
}),
'utf8',
);
writeFileSync(
join(packageRoot, 'src', 'index.ts'),
'throw new Error("entry must not be imported during discovery");',
'utf8',
);
const source = new QqbotPluginPackageSourceService(
new QqbotPluginPackagePathPolicyService([tempRoot]),
);
await expect(source.discoverPackages()).resolves.toEqual([
expect.objectContaining({
entry: 'src/index.ts',
entryFile: join(packageRoot, 'src', 'index.ts'),
manifest: expect.objectContaining({ key: 'sample' }),
packageRoot,
pluginKey: 'sample',
}),
]);
});
it('rejects package entries that escape controlled roots', async () => {
const packageRoot = join(tempRoot, 'escape');
mkdirSync(packageRoot, { recursive: true });
writeFileSync(
join(packageRoot, 'plugin.json'),
JSON.stringify({
key: 'escape',
name: 'Escape',
version: '1.0.0',
entry: `..${sep}outside.ts`,
runtime: {
workerType: 'thread',
timeoutMs: 5000,
memoryMb: 128,
maxConcurrency: 1,
},
operations: [],
}),
'utf8',
);
const source = new QqbotPluginPackageSourceService(
new QqbotPluginPackagePathPolicyService([tempRoot]),
);
await expect(source.discoverPackages()).rejects.toThrow(
'Plugin entry must stay inside the package root',
);
});
});