Skip to content

Commit 54f5e8b

Browse files
authored
test(magician): add interceptingRunner to reroute sandbox executions (#17961)
1 parent 8491e25 commit 54f5e8b

2 files changed

Lines changed: 115 additions & 9 deletions

File tree

.ci/magician/cmd/sandbox_sanity_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package cmd
1717

1818
import (
1919
"os"
20+
"path/filepath"
2021
"strings"
2122
"testing"
2223
)
@@ -28,6 +29,7 @@ func TestSandboxInitialization(t *testing.T) {
2829
t.Fatalf("Sandbox directory %s does not exist", sb.Dir)
2930
}
3031

32+
sb.AllowPassthrough("git")
3133
output, err := sb.Runner.Run("git", []string{"status"}, nil)
3234
if err != nil {
3335
t.Fatalf("Sandbox is not a valid git repository: %v\nOutput: %s", err, output)
@@ -37,3 +39,39 @@ func TestSandboxInitialization(t *testing.T) {
3739
t.Errorf("Expected 'On branch main' in git status output, got: %s", output)
3840
}
3941
}
42+
43+
func TestSandboxInterceptor_AllowedCommand(t *testing.T) {
44+
sb := newSandbox(t)
45+
sb.RequireWhitelist()
46+
_, err := sb.Runner.Run("touch", []string{"test_file.txt"}, nil)
47+
if err != nil {
48+
t.Fatalf("Expected whitelisted command to succeed, got: %v", err)
49+
}
50+
}
51+
52+
func TestSandboxInterceptor_MockOverridesAllowed(t *testing.T) {
53+
sb := newSandbox(t)
54+
sb.RequireWhitelist()
55+
sb.Runner.WriteFile("echo", "#!/bin/bash\necho 'intercepted echo'")
56+
os.Chmod(filepath.Join(sb.Dir, "echo"), 0755)
57+
58+
output, err := sb.Runner.Run("echo", []string{"hello"}, nil)
59+
if err != nil {
60+
t.Fatalf("Expected mocked command to succeed, got: %v", err)
61+
}
62+
if !strings.Contains(output, "intercepted echo") {
63+
t.Errorf("Expected sandbox mock to override whitelist, got: %s", output)
64+
}
65+
}
66+
67+
func TestSandboxInterceptor_UnhandledCommandPanics(t *testing.T) {
68+
sb := newSandbox(t)
69+
sb.RequireWhitelist()
70+
_, err := sb.Runner.Run("curl", []string{"http://example.com"}, nil)
71+
if err == nil {
72+
t.Fatalf("Expected unhandled command to return error, but it succeeded")
73+
}
74+
if !strings.Contains(err.Error(), "not in the passthrough list") {
75+
t.Errorf("Expected strict interceptor error, got: %v", err)
76+
}
77+
}

.ci/magician/cmd/sandbox_test.go

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
package cmd
1717

1818
import (
19+
"fmt"
20+
"os"
21+
"path/filepath"
22+
"strings"
1923
"testing"
2024

2125
"magician/exec"
@@ -26,29 +30,93 @@ type sandbox struct {
2630
Runner ExecRunner
2731
}
2832

33+
// Routes some commands to fake sandbox scripts, bypassing $PATH.
34+
type interceptingRunner struct {
35+
*exec.Runner
36+
sbDir string
37+
allowedPassthrough map[string]bool
38+
strictMode bool
39+
}
40+
41+
func (s *interceptingRunner) Run(name string, args []string, env map[string]string) (string, error) {
42+
if !s.strictMode {
43+
if !strings.Contains(name, string(filepath.Separator)) {
44+
sandboxBin := filepath.Join(s.sbDir, name)
45+
if _, err := os.Stat(sandboxBin); err == nil {
46+
name = sandboxBin
47+
}
48+
}
49+
return s.Runner.Run(name, args, env)
50+
}
51+
52+
baseName := filepath.Base(name)
53+
54+
sandboxBin := filepath.Join(s.sbDir, baseName)
55+
if _, err := os.Stat(sandboxBin); err == nil {
56+
return s.Runner.Run(sandboxBin, args, env)
57+
}
58+
59+
if s.allowedPassthrough[baseName] {
60+
return s.Runner.Run(name, args, env)
61+
}
62+
63+
return "", fmt.Errorf("command %q is not in the passthrough list and no sandbox mock was found. Please mock it or add it to the passthrough list", baseName)
64+
}
65+
2966
func newSandbox(t *testing.T) *sandbox {
3067
dir := t.TempDir()
3168

32-
runner, err := exec.NewRunner()
69+
realRunner, err := exec.NewRunner()
3370
if err != nil {
3471
t.Fatalf("Failed to create runner: %v", err)
3572
}
3673

37-
if err := runner.PushDir(dir); err != nil {
74+
if err := realRunner.PushDir(dir); err != nil {
3875
t.Fatalf("Failed to push dir: %v", err)
3976
}
4077

41-
runner.MustRun("git", []string{"init", "-b", "main"}, nil)
78+
realRunner.MustRun("git", []string{"init", "-b", "main"}, nil)
79+
80+
realRunner.MustRun("touch", []string{"README.md"}, nil)
81+
realRunner.MustRun("git", []string{"add", "."}, nil)
82+
realRunner.MustRun("git", []string{"config", "user.email", "test@example.com"}, nil)
83+
realRunner.MustRun("git", []string{"config", "user.name", "Test Sandbox"}, nil)
84+
realRunner.MustRun("git", []string{"config", "commit.gpgsign", "false"}, nil)
85+
realRunner.MustRun("git", []string{"commit", "-m", "Initial sandbox commit"}, nil)
4286

43-
runner.MustRun("touch", []string{"README.md"}, nil)
44-
runner.MustRun("git", []string{"add", "."}, nil)
45-
runner.MustRun("git", []string{"config", "user.email", "test@example.com"}, nil)
46-
runner.MustRun("git", []string{"config", "user.name", "Test Sandbox"}, nil)
47-
runner.MustRun("git", []string{"config", "commit.gpgsign", "false"}, nil)
48-
runner.MustRun("git", []string{"commit", "-m", "Initial sandbox commit"}, nil)
87+
runner := &interceptingRunner{
88+
Runner: realRunner,
89+
sbDir: dir,
90+
allowedPassthrough: map[string]bool{
91+
"chmod": true,
92+
"rm": true,
93+
"mkdir": true,
94+
"touch": true,
95+
"cp": true,
96+
"mv": true,
97+
"ls": true,
98+
"echo": true,
99+
"cat": true,
100+
"grep": true,
101+
},
102+
}
49103

50104
return &sandbox{
51105
Dir: dir,
52106
Runner: runner,
53107
}
54108
}
109+
110+
func (s *sandbox) AllowPassthrough(commands ...string) {
111+
if runner, ok := s.Runner.(*interceptingRunner); ok {
112+
for _, cmd := range commands {
113+
runner.allowedPassthrough[cmd] = true
114+
}
115+
}
116+
}
117+
118+
func (s *sandbox) RequireWhitelist() {
119+
if runner, ok := s.Runner.(*interceptingRunner); ok {
120+
runner.strictMode = true
121+
}
122+
}

0 commit comments

Comments
 (0)