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}