1package shell
2
3import (
4 "context"
5 "strings"
6 "testing"
7)
8
9func TestCommandBlocking(t *testing.T) {
10 tests := []struct {
11 name string
12 blockFuncs []BlockFunc
13 command string
14 shouldBlock bool
15 }{
16 {
17 name: "block simple command",
18 blockFuncs: []BlockFunc{
19 func(args []string) bool {
20 return len(args) > 0 && args[0] == "curl"
21 },
22 },
23 command: "curl https://example.com",
24 shouldBlock: true,
25 },
26 {
27 name: "allow non-blocked command",
28 blockFuncs: []BlockFunc{
29 func(args []string) bool {
30 return len(args) > 0 && args[0] == "curl"
31 },
32 },
33 command: "echo hello",
34 shouldBlock: false,
35 },
36 {
37 name: "block subcommand",
38 blockFuncs: []BlockFunc{
39 func(args []string) bool {
40 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
41 },
42 },
43 command: "brew install wget",
44 shouldBlock: true,
45 },
46 {
47 name: "allow different subcommand",
48 blockFuncs: []BlockFunc{
49 func(args []string) bool {
50 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
51 },
52 },
53 command: "brew list",
54 shouldBlock: false,
55 },
56 {
57 name: "block npm global install with -g",
58 blockFuncs: []BlockFunc{
59 ArgumentsBlocker([][]string{
60 {"npm", "install", "-g"},
61 {"npm", "install", "--global"},
62 }),
63 },
64 command: "npm install -g typescript",
65 shouldBlock: true,
66 },
67 {
68 name: "block npm global install with --global",
69 blockFuncs: []BlockFunc{
70 ArgumentsBlocker([][]string{
71 {"npm", "install", "-g"},
72 {"npm", "install", "--global"},
73 }),
74 },
75 command: "npm install --global typescript",
76 shouldBlock: true,
77 },
78 {
79 name: "allow npm local install",
80 blockFuncs: []BlockFunc{
81 ArgumentsBlocker([][]string{
82 {"npm", "install", "-g"},
83 {"npm", "install", "--global"},
84 }),
85 },
86 command: "npm install typescript",
87 shouldBlock: false,
88 },
89 }
90
91 for _, tt := range tests {
92 t.Run(tt.name, func(t *testing.T) {
93 // Create a temporary directory for each test
94 tmpDir := t.TempDir()
95
96 shell := NewShell(&Options{
97 WorkingDir: tmpDir,
98 BlockFuncs: tt.blockFuncs,
99 })
100
101 _, _, err := shell.Exec(context.Background(), tt.command)
102
103 if tt.shouldBlock {
104 if err == nil {
105 t.Errorf("Expected command to be blocked, but it was allowed")
106 } else if !strings.Contains(err.Error(), "not allowed for security reasons") {
107 t.Errorf("Expected security error, got: %v", err)
108 }
109 } else {
110 // For non-blocked commands, we might get other errors (like command not found)
111 // but we shouldn't get the security error
112 if err != nil && strings.Contains(err.Error(), "not allowed for security reasons") {
113 t.Errorf("Command was unexpectedly blocked: %v", err)
114 }
115 }
116 })
117 }
118}