moving
This commit is contained in:
92
packages/worker/tests/execution-policy.test.ts
Normal file
92
packages/worker/tests/execution-policy.test.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { createWorkerExecutionContext } from '../src/execution-policy.js';
|
||||
|
||||
describe('worker execution policy', () => {
|
||||
let dataDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-worker-policy-'));
|
||||
vi.stubEnv('WAGGLE_DATA_DIR', dataDir);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
fs.rmSync(dataDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('derives a canonical tenant workspace from WAGGLE_DATA_DIR and teamId', () => {
|
||||
const context = createWorkerExecutionContext('team-123');
|
||||
const expected = fs.realpathSync.native(path.join(dataDir, 'teams', 'team-123', 'files'));
|
||||
|
||||
expect(context.workspaceDir).toBe(expected);
|
||||
expect(fs.statSync(context.workspaceDir).isDirectory()).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects a team directory link that aliases another tenant', () => {
|
||||
const teamsDir = path.join(dataDir, 'teams');
|
||||
const otherTeamDir = path.join(teamsDir, 'team-other');
|
||||
fs.mkdirSync(path.join(otherTeamDir, 'files'), { recursive: true });
|
||||
fs.symlinkSync(
|
||||
otherTeamDir,
|
||||
path.join(teamsDir, 'team-requested'),
|
||||
process.platform === 'win32' ? 'junction' : 'dir',
|
||||
);
|
||||
|
||||
expect(() => createWorkerExecutionContext('team-requested')).toThrow('link or junction');
|
||||
});
|
||||
|
||||
it('rejects a files directory link that widens the tenant root', () => {
|
||||
const teamDir = path.join(dataDir, 'teams', 'team-123');
|
||||
fs.mkdirSync(teamDir, { recursive: true });
|
||||
fs.symlinkSync(
|
||||
teamDir,
|
||||
path.join(teamDir, 'files'),
|
||||
process.platform === 'win32' ? 'junction' : 'dir',
|
||||
);
|
||||
|
||||
expect(() => createWorkerExecutionContext('team-123')).toThrow('link or junction');
|
||||
});
|
||||
|
||||
it('exposes exactly the read-only system tool pool', () => {
|
||||
const context = createWorkerExecutionContext('team-123');
|
||||
|
||||
expect(context.tools.map(tool => tool.name)).toEqual([
|
||||
'read_file',
|
||||
'search_files',
|
||||
'search_content',
|
||||
'web_search',
|
||||
'web_fetch',
|
||||
]);
|
||||
});
|
||||
|
||||
it('truthfully instructs the model to propose changes instead of mutating', () => {
|
||||
const context = createWorkerExecutionContext('team-123');
|
||||
|
||||
expect(context.systemPrompt).toContain('non-interactive read-only worker');
|
||||
expect(context.systemPrompt).toContain('cannot run shell commands, execute code, or write, edit, or delete files');
|
||||
expect(context.systemPrompt).toContain('proposed patch');
|
||||
});
|
||||
|
||||
it('fails closed without WAGGLE_DATA_DIR', () => {
|
||||
vi.stubEnv('WAGGLE_DATA_DIR', ' ');
|
||||
|
||||
expect(() => createWorkerExecutionContext('team-123')).toThrow('WAGGLE_DATA_DIR');
|
||||
});
|
||||
|
||||
it.each([
|
||||
['empty', ''],
|
||||
['current directory', '.'],
|
||||
['parent directory', '..'],
|
||||
['forward-slash traversal', '../outside'],
|
||||
['backslash traversal', '..\\outside'],
|
||||
['absolute Windows path', 'C:\\outside'],
|
||||
['overlong identifier', 'a'.repeat(129)],
|
||||
['missing runtime identifier', undefined as unknown as string],
|
||||
['null runtime identifier', null as unknown as string],
|
||||
])('rejects an unsafe %s teamId', (_label, teamId) => {
|
||||
expect(() => createWorkerExecutionContext(teamId)).toThrow('Invalid teamId');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user