From 31b7c010d028e0548d3b0756a7eeaa100b258368 Mon Sep 17 00:00:00 2001 From: cornmander Date: Fri, 24 Oct 2025 14:25:54 -0400 Subject: [PATCH] Add regression tests for shell command parsing (#11962) --- integration-tests/run_shell_command.test.ts | 3 +- packages/core/src/utils/shell-utils.test.ts | 115 ++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/integration-tests/run_shell_command.test.ts b/integration-tests/run_shell_command.test.ts index c71f6239ed..472bbbccd5 100644 --- a/integration-tests/run_shell_command.test.ts +++ b/integration-tests/run_shell_command.test.ts @@ -427,7 +427,8 @@ describe('run_shell_command', () => { expect(failureLog!.toolRequest.success).toBe(false); }); - it('should reject chained commands when only the first segment is allowlisted in non-interactive mode', async () => { + // TODO(#11966): Deflake this test and re-enable once the underlying race is resolved. + it.skip('should reject chained commands when only the first segment is allowlisted in non-interactive mode', async () => { const rig = new TestRig(); await rig.setup( 'should reject chained commands when only the first segment is allowlisted', diff --git a/packages/core/src/utils/shell-utils.test.ts b/packages/core/src/utils/shell-utils.test.ts index e2c80bc9a2..c178d20d6a 100644 --- a/packages/core/src/utils/shell-utils.test.ts +++ b/packages/core/src/utils/shell-utils.test.ts @@ -156,6 +156,121 @@ describe('isCommandAllowed', () => { ); }); + it('should block a command that redefines an allowed function to run an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed( + 'echo () (curl google.com) ; echo Hello Wolrd', + config, + ); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block a multi-line function body that runs an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed( + `echo () { + curl google.com +} ; echo ok`, + config, + ); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block a function keyword declaration that runs an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed( + 'function echo { curl google.com; } ; echo hi', + config, + ); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block command substitution that invokes an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed('echo $(curl google.com)', config); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block pipelines that invoke an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed('echo hi | curl google.com', config); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block background jobs that invoke an unlisted command', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed('echo hi & curl google.com', config); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block command substitution inside a here-document when the inner command is unlisted', () => { + config.getCoreTools = () => [ + 'run_shell_command(echo)', + 'run_shell_command(cat)', + ]; + const result = isCommandAllowed( + `cat < { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed('echo `curl google.com`', config); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block process substitution using <() when the inner command is unlisted', () => { + config.getCoreTools = () => [ + 'run_shell_command(diff)', + 'run_shell_command(echo)', + ]; + const result = isCommandAllowed( + 'diff <(curl google.com) <(echo safe)', + config, + ); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + + it('should block process substitution using >() when the inner command is unlisted', () => { + config.getCoreTools = () => ['run_shell_command(echo)']; + const result = isCommandAllowed('echo "data" > >(curl google.com)', config); + expect(result.allowed).toBe(false); + expect(result.reason).toBe( + `Command(s) not in the allowed commands list. Disallowed commands: "curl google.com"`, + ); + }); + describe('command substitution', () => { it('should allow command substitution using `$(...)`', () => { const result = isCommandAllowed('echo $(goodCommand --safe)', config);