command_block_test.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package shell
  2. import (
  3. "context"
  4. "strings"
  5. "testing"
  6. )
  7. func TestCommandBlocking(t *testing.T) {
  8. tests := []struct {
  9. name string
  10. blockFuncs []BlockFunc
  11. command string
  12. shouldBlock bool
  13. }{
  14. {
  15. name: "block simple command",
  16. blockFuncs: []BlockFunc{
  17. func(args []string) bool {
  18. return len(args) > 0 && args[0] == "curl"
  19. },
  20. },
  21. command: "curl https://example.com",
  22. shouldBlock: true,
  23. },
  24. {
  25. name: "allow non-blocked command",
  26. blockFuncs: []BlockFunc{
  27. func(args []string) bool {
  28. return len(args) > 0 && args[0] == "curl"
  29. },
  30. },
  31. command: "echo hello",
  32. shouldBlock: false,
  33. },
  34. {
  35. name: "block subcommand",
  36. blockFuncs: []BlockFunc{
  37. func(args []string) bool {
  38. return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
  39. },
  40. },
  41. command: "brew install wget",
  42. shouldBlock: true,
  43. },
  44. {
  45. name: "allow different subcommand",
  46. blockFuncs: []BlockFunc{
  47. func(args []string) bool {
  48. return len(args) >= 2 && args[0] == "brew" && args[1] == "install"
  49. },
  50. },
  51. command: "brew list",
  52. shouldBlock: false,
  53. },
  54. {
  55. name: "block npm global install with -g",
  56. blockFuncs: []BlockFunc{
  57. ArgumentsBlocker([][]string{
  58. {"npm", "install", "-g"},
  59. {"npm", "install", "--global"},
  60. }),
  61. },
  62. command: "npm install -g typescript",
  63. shouldBlock: true,
  64. },
  65. {
  66. name: "block npm global install with --global",
  67. blockFuncs: []BlockFunc{
  68. ArgumentsBlocker([][]string{
  69. {"npm", "install", "-g"},
  70. {"npm", "install", "--global"},
  71. }),
  72. },
  73. command: "npm install --global typescript",
  74. shouldBlock: true,
  75. },
  76. {
  77. name: "allow npm local install",
  78. blockFuncs: []BlockFunc{
  79. ArgumentsBlocker([][]string{
  80. {"npm", "install", "-g"},
  81. {"npm", "install", "--global"},
  82. }),
  83. },
  84. command: "npm install typescript",
  85. shouldBlock: false,
  86. },
  87. }
  88. for _, tt := range tests {
  89. t.Run(tt.name, func(t *testing.T) {
  90. // Create a temporary directory for each test
  91. tmpDir := t.TempDir()
  92. shell := NewShell(&Options{
  93. WorkingDir: tmpDir,
  94. BlockFuncs: tt.blockFuncs,
  95. })
  96. _, _, err := shell.Exec(context.Background(), tt.command)
  97. if tt.shouldBlock {
  98. if err == nil {
  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)
  102. }
  103. } else {
  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)
  108. }
  109. }
  110. })
  111. }
  112. }