8 "github.com/stretchr/testify/require"
11func TestCommandBlocking(t *testing.T) {
14 blockFuncs []BlockFunc
19 name: "block simple command",
20 blockFuncs: []BlockFunc{
21 func(args []string) bool {
22 return len(args) > 0 && args[0] == "curl"
25 command: "curl https://example.com",
29 name: "allow non-blocked command",
30 blockFuncs: []BlockFunc{
31 func(args []string) bool {
32 return len(args) > 0 && args[0] == "curl"
35 command: "echo hello",
39 name: "block subcommand",
40 blockFuncs: []BlockFunc{
41 func(args []string) bool {
42 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
45 command: "brew install wget",
49 name: "allow different subcommand",
50 blockFuncs: []BlockFunc{
51 func(args []string) bool {
52 return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
59 name: "block npm global install with -g",
60 blockFuncs: []BlockFunc{
61 ArgumentsBlocker("npm", []string{"install"}, []string{"-g"}),
63 command: "npm install -g typescript",
67 name: "block npm global install with --global",
68 blockFuncs: []BlockFunc{
69 ArgumentsBlocker("npm", []string{"install"}, []string{"--global"}),
71 command: "npm install --global typescript",
75 name: "allow npm local install",
76 blockFuncs: []BlockFunc{
77 ArgumentsBlocker("npm", []string{"install"}, []string{"-g"}),
78 ArgumentsBlocker("npm", []string{"install"}, []string{"--global"}),
80 command: "npm install typescript",
85 for _, tt := range tests {
86 t.Run(tt.name, func(t *testing.T) {
87 // Create a temporary directory for each test
90 shell := NewShell(&Options{
92 BlockFuncs: tt.blockFuncs,
95 _, _, err := shell.Exec(context.Background(), tt.command)
99 t.Errorf("Expected command to be blocked, but it was allowed")
100 } else if !strings.Contains(err.Error(), "not allowed for security reasons") {
101 t.Errorf("Expected security error, got: %v", err)
104 // For non-blocked commands, we might get other errors (like command not found)
105 // but we shouldn't get the security error
106 if err != nil && strings.Contains(err.Error(), "not allowed for security reasons") {
107 t.Errorf("Command was unexpectedly blocked: %v", err)
114func TestArgumentsBlocker(t *testing.T) {
123 // Basic command blocking
125 name: "block exact command match",
127 args: []string{"install"},
129 input: []string{"npm", "install", "package"},
133 name: "allow different command",
135 args: []string{"install"},
137 input: []string{"yarn", "install", "package"},
141 name: "allow different subcommand",
143 args: []string{"install"},
145 input: []string{"npm", "list"},
149 // Flag-based blocking
151 name: "block with single flag",
153 args: []string{"install"},
154 flags: []string{"-g"},
155 input: []string{"npm", "install", "-g", "typescript"},
159 name: "block with flag in different position",
161 args: []string{"install"},
162 flags: []string{"-g"},
163 input: []string{"npm", "install", "typescript", "-g"},
167 name: "allow without required flag",
169 args: []string{"install"},
170 flags: []string{"-g"},
171 input: []string{"npm", "install", "typescript"},
175 name: "block with multiple flags",
177 args: []string{"install"},
178 flags: []string{"--user"},
179 input: []string{"pip", "install", "--user", "--upgrade", "package"},
183 // Complex argument patterns
185 name: "block multi-arg subcommand",
187 args: []string{"global", "add"},
189 input: []string{"yarn", "global", "add", "typescript"},
193 name: "allow partial multi-arg match",
195 args: []string{"global", "add"},
197 input: []string{"yarn", "global", "list"},
203 name: "handle empty input",
205 args: []string{"install"},
211 name: "handle command only",
213 args: []string{"install"},
215 input: []string{"npm"},
219 name: "block pacman with -S flag",
222 flags: []string{"-S"},
223 input: []string{"pacman", "-S", "package"},
227 name: "allow pacman without -S flag",
230 flags: []string{"-S"},
231 input: []string{"pacman", "-Q", "package"},
237 name: "go test exec",
239 args: []string{"test"},
240 flags: []string{"-exec"},
241 input: []string{"go", "test", "-exec", "bash -c 'echo hello'"},
245 name: "go test exec",
247 args: []string{"test"},
248 flags: []string{"-exec"},
249 input: []string{"go", "test", `-exec="bash -c 'echo hello'"`},
254 for _, tt := range tests {
255 t.Run(tt.name, func(t *testing.T) {
256 blocker := ArgumentsBlocker(tt.cmd, tt.args, tt.flags)
257 result := blocker(tt.input)
258 require.Equal(t, tt.shouldBlock, result,
259 "Expected block=%v for input %v", tt.shouldBlock, tt.input)
264func TestCommandsBlocker(t *testing.T) {
272 name: "block single banned command",
273 banned: []string{"curl"},
274 input: []string{"curl", "https://example.com"},
278 name: "allow non-banned command",
279 banned: []string{"curl", "wget"},
280 input: []string{"echo", "hello"},
284 name: "block from multiple banned",
285 banned: []string{"curl", "wget", "nc"},
286 input: []string{"wget", "https://example.com"},
290 name: "handle empty input",
291 banned: []string{"curl"},
296 name: "case sensitive matching",
297 banned: []string{"curl"},
298 input: []string{"CURL", "https://example.com"},
303 for _, tt := range tests {
304 t.Run(tt.name, func(t *testing.T) {
305 blocker := CommandsBlocker(tt.banned)
306 result := blocker(tt.input)
307 require.Equal(t, tt.shouldBlock, result,
308 "Expected block=%v for input %v", tt.shouldBlock, tt.input)
313func TestSplitArgsFlags(t *testing.T) {
322 input: []string{"install", "package", "another"},
323 wantArgs: []string{"install", "package", "another"},
324 wantFlags: []string{},
328 input: []string{"-g", "--verbose", "-f"},
329 wantArgs: []string{},
330 wantFlags: []string{"-g", "--verbose", "-f"},
333 name: "mixed args and flags",
334 input: []string{"install", "-g", "package", "--verbose"},
335 wantArgs: []string{"install", "package"},
336 wantFlags: []string{"-g", "--verbose"},
341 wantArgs: []string{},
342 wantFlags: []string{},
345 name: "single dash flag",
346 input: []string{"-S", "package"},
347 wantArgs: []string{"package"},
348 wantFlags: []string{"-S"},
351 name: "flag with equals sign",
352 input: []string{"-exec=bash", "package"},
353 wantArgs: []string{"package"},
354 wantFlags: []string{"-exec"},
357 name: "long flag with equals sign",
358 input: []string{"--config=/path/to/config", "run"},
359 wantArgs: []string{"run"},
360 wantFlags: []string{"--config"},
363 name: "flag with complex value",
364 input: []string{`-exec="bash -c 'echo hello'"`, "test"},
365 wantArgs: []string{"test"},
366 wantFlags: []string{"-exec"},
370 for _, tt := range tests {
371 t.Run(tt.name, func(t *testing.T) {
372 args, flags := splitArgsFlags(tt.input)
373 require.Equal(t, tt.wantArgs, args, "args mismatch")
374 require.Equal(t, tt.wantFlags, flags, "flags mismatch")
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list