96 lines
3.0 KiB
TypeScript
96 lines
3.0 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { createIsolatedEnv, type IsolatedEnv, updateIsolatedConfig } from '../helpers/isolated-env';
|
|
import { createLocalRepo, type LocalRepo } from '../helpers/test-repo';
|
|
import { runTakt } from '../helpers/takt-runner';
|
|
|
|
const provider = process.env.TAKT_E2E_PROVIDER;
|
|
const codexIt = provider === 'codex' ? it : it.skip;
|
|
|
|
describe('E2E: Codex permission mode readonly/full', () => {
|
|
let isolatedEnv: IsolatedEnv;
|
|
let repo: LocalRepo;
|
|
let piecePath: string;
|
|
|
|
beforeEach(() => {
|
|
isolatedEnv = createIsolatedEnv();
|
|
repo = createLocalRepo();
|
|
piecePath = join(repo.path, 'permission-mode-e2e-piece.yaml');
|
|
|
|
writeFileSync(
|
|
piecePath,
|
|
[
|
|
'name: permission-mode-e2e',
|
|
'description: Verify readonly/full behavior in codex sandbox',
|
|
'max_movements: 3',
|
|
'initial_movement: write_check',
|
|
'movements:',
|
|
' - name: write_check',
|
|
' agent: codex',
|
|
' allowed_tools:',
|
|
' - Bash',
|
|
' required_permission_mode: readonly',
|
|
' instruction_template: |',
|
|
' Run this exact command in repository root:',
|
|
' /bin/sh -lc \'printf "ok\\n" > epperm-check.txt\'',
|
|
' If file creation succeeds, reply exactly: COMPLETE',
|
|
' rules:',
|
|
' - condition: COMPLETE',
|
|
' next: COMPLETE',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
});
|
|
|
|
afterEach(() => {
|
|
try { repo.cleanup(); } catch { /* best-effort */ }
|
|
try { isolatedEnv.cleanup(); } catch { /* best-effort */ }
|
|
});
|
|
|
|
codexIt('readonly で失敗し full で成功する', () => {
|
|
updateIsolatedConfig(isolatedEnv.taktDir, {
|
|
provider_profiles: {
|
|
codex: { default_permission_mode: 'readonly' },
|
|
},
|
|
});
|
|
|
|
const readonlyResult = runTakt({
|
|
args: ['--task', 'Run write permission check', '--piece', piecePath],
|
|
cwd: repo.path,
|
|
env: isolatedEnv.env,
|
|
timeout: 240_000,
|
|
});
|
|
|
|
const readonlyOutput = `${readonlyResult.stdout}\n${readonlyResult.stderr}`;
|
|
expect(existsSync(join(repo.path, 'epperm-check.txt'))).toBe(false);
|
|
expect(
|
|
[
|
|
'EPERM',
|
|
'permission denied',
|
|
'Permission denied',
|
|
'Operation not permitted',
|
|
'read-only',
|
|
'Read-only',
|
|
].some((marker) => readonlyOutput.includes(marker)),
|
|
).toBe(true);
|
|
|
|
updateIsolatedConfig(isolatedEnv.taktDir, {
|
|
provider_profiles: {
|
|
codex: { default_permission_mode: 'full' },
|
|
},
|
|
});
|
|
|
|
const fullResult = runTakt({
|
|
args: ['--task', 'Run write permission check', '--piece', piecePath],
|
|
cwd: repo.path,
|
|
env: isolatedEnv.env,
|
|
timeout: 240_000,
|
|
});
|
|
|
|
expect(fullResult.exitCode).toBe(0);
|
|
expect(existsSync(join(repo.path, 'epperm-check.txt'))).toBe(true);
|
|
expect(readFileSync(join(repo.path, 'epperm-check.txt'), 'utf-8')).toContain('ok');
|
|
}, 300_000);
|
|
});
|