summaryrefslogtreecommitdiff
path: root/packages/core/src/tools/shell.test.ts
diff options
context:
space:
mode:
authorJerop Kipruto <[email protected]>2025-06-29 15:32:26 -0400
committerGitHub <[email protected]>2025-06-29 19:32:26 +0000
commitd8d78d73f9638d11ba8b6ba184b49d4dc7caa8f4 (patch)
treefd747168058eb730afc1766f5ad4712df335f6cf /packages/core/src/tools/shell.test.ts
parent19a0276142b61208e5d4b723e422e37bf005845a (diff)
feat: allow command-specific restrictions for ShellTool (#2605)
Diffstat (limited to 'packages/core/src/tools/shell.test.ts')
-rw-r--r--packages/core/src/tools/shell.test.ts171
1 files changed, 171 insertions, 0 deletions
diff --git a/packages/core/src/tools/shell.test.ts b/packages/core/src/tools/shell.test.ts
new file mode 100644
index 00000000..2cbd0ff4
--- /dev/null
+++ b/packages/core/src/tools/shell.test.ts
@@ -0,0 +1,171 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { expect, describe, it } from 'vitest';
+import { ShellTool } from './shell.js';
+import { Config } from '../config/config.js';
+
+describe('ShellTool', () => {
+ it('should allow a command if no restrictions are provided', async () => {
+ const config = {
+ getCoreTools: () => undefined,
+ getExcludeTools: () => undefined,
+ } as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('ls -l');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should allow a command if it is in the allowed list', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool(ls -l)'],
+ getExcludeTools: () => undefined,
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('ls -l');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should block a command if it is not in the allowed list', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool(ls -l)'],
+ getExcludeTools: () => undefined,
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('rm -rf /');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should block a command if it is in the blocked list', async () => {
+ const config = {
+ getCoreTools: () => undefined,
+ getExcludeTools: () => ['ShellTool(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('rm -rf /');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should allow a command if it is not in the blocked list', async () => {
+ const config = {
+ getCoreTools: () => undefined,
+ getExcludeTools: () => ['ShellTool(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('ls -l');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should block a command if it is in both the allowed and blocked lists', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool(rm -rf /)'],
+ getExcludeTools: () => ['ShellTool(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('rm -rf /');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should allow any command when ShellTool is in coreTools without specific commands', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool'],
+ getExcludeTools: () => [],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should block any command when ShellTool is in excludeTools without specific commands', async () => {
+ const config = {
+ getCoreTools: () => [],
+ getExcludeTools: () => ['ShellTool'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should allow a command if it is in the allowed list using the public-facing name', async () => {
+ const config = {
+ getCoreTools: () => ['run_shell_command(ls -l)'],
+ getExcludeTools: () => undefined,
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('ls -l');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should block a command if it is in the blocked list using the public-facing name', async () => {
+ const config = {
+ getCoreTools: () => undefined,
+ getExcludeTools: () => ['run_shell_command(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('rm -rf /');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should block any command when ShellTool is in excludeTools using the public-facing name', async () => {
+ const config = {
+ getCoreTools: () => [],
+ getExcludeTools: () => ['run_shell_command'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should block any command if coreTools contains an empty ShellTool command list using the public-facing name', async () => {
+ const config = {
+ getCoreTools: () => ['run_shell_command()'],
+ getExcludeTools: () => [],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should block any command if coreTools contains an empty ShellTool command list', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool()'],
+ getExcludeTools: () => [],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should block a command with extra whitespace if it is in the blocked list', async () => {
+ const config = {
+ getCoreTools: () => undefined,
+ getExcludeTools: () => ['ShellTool(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed(' rm -rf / ');
+ expect(isAllowed).toBe(false);
+ });
+
+ it('should allow any command when ShellTool is present with specific commands', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool', 'ShellTool(ls)'],
+ getExcludeTools: () => [],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('any command');
+ expect(isAllowed).toBe(true);
+ });
+
+ it('should block a command on the blocklist even with a wildcard allow', async () => {
+ const config = {
+ getCoreTools: () => ['ShellTool'],
+ getExcludeTools: () => ['ShellTool(rm -rf /)'],
+ } as unknown as Config;
+ const shellTool = new ShellTool(config);
+ const isAllowed = shellTool.isCommandAllowed('rm -rf /');
+ expect(isAllowed).toBe(false);
+ });
+});