From 892ddd43009a1126c1087239b9162352790c5f61 Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 19 Oct 2026 01:18:15 +0000 Subject: [PATCH] test(evals): read-only grammar controls are POSIX-only; pin fail-closed on Windows (GSTA-49) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- test/read-only-command-grammar.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/read-only-command-grammar.test.ts b/test/read-only-command-grammar.test.ts index 30fde8a37..2822afcbc 100644 --- a/test/read-only-command-grammar.test.ts +++ b/test/read-only-command-grammar.test.ts @@ -19,6 +19,7 @@ let outside: string; const scope = () => ({ root, deny: (file: string) => path.basename(file) === 'credentials.json' }); beforeAll(() => { + if (process.platform === 'win32') return; base = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'ro-grammar-')); root = path.join(base, 'root'); outside = path.join(base, 'outside'); @@ -38,7 +39,13 @@ beforeAll(() => { fs.symlinkSync(outside, path.join(root, 'escape')); fs.symlinkSync(path.join(root, 'docs/guide.md'), path.join(root, 'guide-link.md')); }); -afterAll(() => fs.rmSync(base, { recursive: true, force: true })); +afterAll(() => { if (base) fs.rmSync(base, { recursive: true, force: true }); }); + +// Paid fixtures run on Linux; the grammar resolves POSIX paths only, so on Windows it accepts nothing. +test.if(process.platform === 'win32')('the grammar fails closed on Windows', () => { + const root = fs.realpathSync(os.tmpdir()); + for (const command of ['pwd', 'ls', 'wc -l x']) expect(readOnlyCommandAllowed(command, { root })).toBe(false); +}); function tree(dir: string): Record { const out: Record = {}; @@ -151,7 +158,7 @@ const REJECTED: Array<[string, string, RegExp]> = [ ['shell syntax', 'tail -f docs/guide.md', /unsupported tail option: -f/], ]; -describe('rejected classes stay rejected', () => { +describe.skipIf(process.platform === 'win32')('rejected classes stay rejected', () => { test.each(REJECTED)('%s: %s', (_, command, reason) => { expect(readOnlyCommandRejection(command, scope())).toMatch(reason); expect(readOnlyCommandAllowed(command, scope())).toBe(false);