on main help sign in
chore: better naming
commit2fdbcac0290e1aa977de0139c335210ce35b0faf authorKujtim Hoxha <kujtimii.h@gmail.com> dateFri 11 Jul 2025, 17:55 (1 year ago) parent931029e
3 files changed+118−32
internal/llm/tools/bash.go+93−8 internal/shell/command_block_test.go+12−12 internal/shell/shell.go+13−12
internal/llm/tools/bash.go+93−8
@@ -42,9 +42,74 @@ const (
4242)
4343
4444var bannedCommands = []string{
45− "alias", "curl", "curlie", "wget", "axel", "aria2c",
46− "nc", "telnet", "lynx", "w3m", "links", "httpie", "xh",
47− "http-prompt", "chrome", "firefox", "safari", "sudo",
45+ // Network/Download tools
46+ "alias",
47+ "aria2c",
48+ "axel",
49+ "chrome",
50+ "curl",
51+ "curlie",
52+ "firefox",
53+ "http-prompt",
54+ "httpie",
55+ "links",
56+ "lynx",
57+ "nc",
58+ "safari",
59+ "telnet",
60+ "w3m",
61+ "wget",
62+ "xh",
63+
64+ // System administration
65+ "doas",
66+ "su",
67+ "sudo",
68+
69+ // Package managers
70+ "apk",
71+ "apt",
72+ "apt-cache",
73+ "apt-get",
74+ "dnf",
75+ "dpkg",
76+ "emerge",
77+ "home-manager",
78+ "makepkg",
79+ "opkg",
80+ "pacman",
81+ "paru",
82+ "pkg",
83+ "pkg_add",
84+ "pkg_delete",
85+ "portage",
86+ "rpm",
87+ "yay",
88+ "yum",
89+ "zypper",
90+
91+ // System modification
92+ "at",
93+ "batch",
94+ "chkconfig",
95+ "crontab",
96+ "fdisk",
97+ "mkfs",
98+ "mount",
99+ "parted",
100+ "service",
101+ "systemctl",
102+ "umount",
103+
104+ // Network configuration
105+ "firewall-cmd",
106+ "ifconfig",
107+ "ip",
108+ "iptables",
109+ "netstat",
110+ "pfctl",
111+ "route",
112+ "ufw",
48113}
49114
50115// getSafeReadOnlyCommands returns platform-appropriate safe commands
@@ -245,13 +310,33 @@ Important:
245310- Never update git config`, bannedCommandsStr, MaxOutputLength)
246311}
247312
248−func createCommandBlockFuncs() []shell.CommandBlockFunc {
249− return []shell.CommandBlockFunc{
250− shell.CreateSimpleCommandBlocker(bannedCommands),
251− shell.CreateSubCommandBlocker([][]string{
313+func blockFuncs() []shell.BlockFunc {
314+ return []shell.BlockFunc{
315+ shell.CommandsBlocker(bannedCommands),
316+ shell.ArgumentsBlocker([][]string{
317+ // System package managers
318+ {"apk", "add"},
319+ {"apt", "install"},
320+ {"apt-get", "install"},
321+ {"dnf", "install"},
322+ {"emerge"},
323+ {"pacman", "-S"},
324+ {"pkg", "install"},
325+ {"yum", "install"},
326+ {"zypper", "install"},
327+
328+ // Language-specific package managers
252329 {"brew", "install"},
330+ {"cargo", "install"},
331+ {"gem", "install"},
332+ {"go", "install"},
253333 {"npm", "install", "-g"},
254334 {"npm", "install", "--global"},
335+ {"pip", "install", "--user"},
336+ {"pip3", "install", "--user"},
337+ {"pnpm", "add", "-g"},
338+ {"pnpm", "add", "--global"},
339+ {"yarn", "global", "add"},
255340 }),
256341 }
257342}
@@ -259,7 +344,7 @@ func createCommandBlockFuncs() []shell.CommandBlockFunc {
259344func NewBashTool(permission permission.Service, workingDir string) BaseTool {
260345 // Set up command blocking on the persistent shell
261346 persistentShell := shell.GetPersistentShell(workingDir)
262− persistentShell.SetBlockFuncs(createCommandBlockFuncs())
347+ persistentShell.SetBlockFuncs(blockFuncs())
263348
264349 return &bashTool{
265350 permissions: permission,
internal/shell/command_block_test.go+12−12
@@ -10,13 +10,13 @@ import (
1010func TestCommandBlocking(t *testing.T) {
1111 tests := []struct {
1212 name string
13− blockFuncs []CommandBlockFunc
13+ blockFuncs []BlockFunc
1414 command string
1515 shouldBlock bool
1616 }{
1717 {
1818 name: "block simple command",
19− blockFuncs: []CommandBlockFunc{
19+ blockFuncs: []BlockFunc{
2020 func(args []string) bool {
2121 return len(args) > 0 && args[0] == "curl"
2222 },
@@ -26,7 +26,7 @@ func TestCommandBlocking(t *testing.T) {
2626 },
2727 {
2828 name: "allow non-blocked command",
29− blockFuncs: []CommandBlockFunc{
29+ blockFuncs: []BlockFunc{
3030 func(args []string) bool {
3131 return len(args) > 0 && args[0] == "curl"
3232 },
@@ -36,7 +36,7 @@ func TestCommandBlocking(t *testing.T) {
3636 },
3737 {
3838 name: "block subcommand",
39− blockFuncs: []CommandBlockFunc{
39+ blockFuncs: []BlockFunc{
4040 func(args []string) bool {
4141 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
4242 },
@@ -46,7 +46,7 @@ func TestCommandBlocking(t *testing.T) {
4646 },
4747 {
4848 name: "allow different subcommand",
49− blockFuncs: []CommandBlockFunc{
49+ blockFuncs: []BlockFunc{
5050 func(args []string) bool {
5151 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
5252 },
@@ -56,8 +56,8 @@ func TestCommandBlocking(t *testing.T) {
5656 },
5757 {
5858 name: "block npm global install with -g",
59− blockFuncs: []CommandBlockFunc{
60− CreateSubCommandBlocker([][]string{
59+ blockFuncs: []BlockFunc{
60+ ArgumentsBlocker([][]string{
6161 {"npm", "install", "-g"},
6262 {"npm", "install", "--global"},
6363 }),
@@ -67,8 +67,8 @@ func TestCommandBlocking(t *testing.T) {
6767 },
6868 {
6969 name: "block npm global install with --global",
70− blockFuncs: []CommandBlockFunc{
71− CreateSubCommandBlocker([][]string{
70+ blockFuncs: []BlockFunc{
71+ ArgumentsBlocker([][]string{
7272 {"npm", "install", "-g"},
7373 {"npm", "install", "--global"},
7474 }),
@@ -78,8 +78,8 @@ func TestCommandBlocking(t *testing.T) {
7878 },
7979 {
8080 name: "allow npm local install",
81− blockFuncs: []CommandBlockFunc{
82− CreateSubCommandBlocker([][]string{
81+ blockFuncs: []BlockFunc{
82+ ArgumentsBlocker([][]string{
8383 {"npm", "install", "-g"},
8484 {"npm", "install", "--global"},
8585 }),
@@ -120,4 +120,4 @@ func TestCommandBlocking(t *testing.T) {
120120 }
121121 })
122122 }
123−}
123+}
internal/shell/shell.go+13−12
@@ -44,8 +44,8 @@ type noopLogger struct{}
4444
4545func (noopLogger) InfoPersist(msg string, keysAndValues ...interface{}) {}
4646
47−// CommandBlockFunc is a function that determines if a command should be blocked
48−type CommandBlockFunc func(args []string) bool
47+// BlockFunc is a function that determines if a command should be blocked
48+type BlockFunc func(args []string) bool
4949
5050// Shell provides cross-platform shell execution with optional state persistence
5151type Shell struct {
@@ -53,7 +53,7 @@ type Shell struct {
5353 cwd string
5454 mu sync.Mutex
5555 logger Logger
56− blockFuncs []CommandBlockFunc
56+ blockFuncs []BlockFunc
5757}
5858
5959// Options for creating a new shell
@@ -61,7 +61,7 @@ type Options struct {
6161 WorkingDir string
6262 Env []string
6363 Logger Logger
64− BlockFuncs []CommandBlockFunc
64+ BlockFuncs []BlockFunc
6565}
6666
6767// NewShell creates a new shell instance with the given options
@@ -159,7 +159,7 @@ func (s *Shell) SetEnv(key, value string) {
159159}
160160
161161// SetBlockFuncs sets the command block functions for the shell
162−func (s *Shell) SetBlockFuncs(blockFuncs []CommandBlockFunc) {
162+func (s *Shell) SetBlockFuncs(blockFuncs []BlockFunc) {
163163 s.mu.Lock()
164164 defer s.mu.Unlock()
165165 s.blockFuncs = blockFuncs
@@ -216,13 +216,13 @@ func (s *Shell) determineShellType(command string) ShellType {
216216 return ShellTypePOSIX
217217}
218218
219−// CreateSimpleCommandBlocker creates a CommandBlockFunc that blocks exact command matches
220−func CreateSimpleCommandBlocker(bannedCommands []string) CommandBlockFunc {
219+// CommandsBlocker creates a BlockFunc that blocks exact command matches
220+func CommandsBlocker(bannedCommands []string) BlockFunc {
221221 bannedSet := make(map[string]bool)
222222 for _, cmd := range bannedCommands {
223223 bannedSet[cmd] = true
224224 }
225−
225+
226226 return func(args []string) bool {
227227 if len(args) == 0 {
228228 return false
@@ -231,8 +231,8 @@ func CreateSimpleCommandBlocker(bannedCommands []string) CommandBlockFunc {
231231 }
232232}
233233
234−// CreateSubCommandBlocker creates a CommandBlockFunc that blocks specific subcommands
235−func CreateSubCommandBlocker(blockedSubCommands [][]string) CommandBlockFunc {
234+// ArgumentsBlocker creates a BlockFunc that blocks specific subcommands
235+func ArgumentsBlocker(blockedSubCommands [][]string) BlockFunc {
236236 return func(args []string) bool {
237237 for _, blocked := range blockedSubCommands {
238238 if len(args) >= len(blocked) {
@@ -251,7 +251,8 @@ func CreateSubCommandBlocker(blockedSubCommands [][]string) CommandBlockFunc {
251251 return false
252252 }
253253}
254−func (s *Shell) createCommandBlockHandler() func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
254+
255+func (s *Shell) blockHandler() func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
255256 return func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
256257 return func(ctx context.Context, args []string) error {
257258 if len(args) == 0 {
@@ -357,7 +358,7 @@ func (s *Shell) execPOSIX(ctx context.Context, command string) (string, string,
357358 interp.Interactive(false),
358359 interp.Env(expand.ListEnviron(s.env...)),
359360 interp.Dir(s.cwd),
360− interp.ExecHandlers(s.createCommandBlockHandler()),
361+ interp.ExecHandlers(s.blockHandler()),
361362 )
362363 if err != nil {
363364 return "", "", fmt.Errorf("could not run command: %w", err)