Skip to content

Commit 085b2b6

Browse files
committed
test: restore missing runner tests
Restore tests that were removed during the runner package extraction: - TestDocker_Run_Networking: tests network isolation - TestDocker_Run_PrepareCommand: tests prepare_command option - TestExec_Optimization_SingleExecutable: tests single executable optimization - Expanded TestNewDockerOptions assertions for all fields - Expanded TestSandboxExec_Run with template and env variable tests
1 parent 10217e6 commit 085b2b6

3 files changed

Lines changed: 236 additions & 0 deletions

File tree

pkg/runner/docker_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package runner
22

33
import (
44
"context"
5+
"os"
56
"os/exec"
67
"runtime"
78
"strings"
@@ -159,6 +160,103 @@ func TestDocker_Run_EnvironmentVariables(t *testing.T) {
159160
}
160161
}
161162

163+
func TestDocker_Run_Networking(t *testing.T) {
164+
// Skip on Windows - Alpine Linux doesn't support Windows containers
165+
if runtime.GOOS == "windows" {
166+
t.Skip("Skipping Docker test on Windows - Alpine Linux image not compatible with Windows containers")
167+
}
168+
169+
// Skip if docker is not available or not running
170+
if !checkDockerRunning() {
171+
t.Skip("Docker not installed or not running, skipping test")
172+
}
173+
174+
// Check if running in GitHub Actions
175+
inGitHubActions := os.Getenv("GITHUB_ACTIONS") == "true"
176+
if inGitHubActions {
177+
t.Skip("Skipping network test in GitHub Actions environment")
178+
}
179+
180+
logger, _ := common.NewLogger("test-docker: ", "", common.LogLevelInfo, false)
181+
182+
testCases := []struct {
183+
name string
184+
allowNetworking bool
185+
expectSuccess bool
186+
}{
187+
{
188+
name: "With networking",
189+
allowNetworking: true,
190+
expectSuccess: true,
191+
},
192+
{
193+
name: "Without networking",
194+
allowNetworking: false,
195+
expectSuccess: false,
196+
},
197+
}
198+
199+
for _, tc := range testCases {
200+
t.Run(tc.name, func(t *testing.T) {
201+
// Create a runner with specified networking
202+
r, err := NewDocker(Options{
203+
"image": "alpine:latest",
204+
"allow_networking": tc.allowNetworking,
205+
}, logger)
206+
207+
if err != nil {
208+
t.Fatalf("Failed to create Docker runner: %v", err)
209+
}
210+
211+
// Try to ping google.com (will fail if networking is disabled)
212+
_, err = r.Run(context.Background(), "", "ping -c 1 -W 1 google.com", nil, nil, false)
213+
214+
if tc.expectSuccess && err != nil {
215+
t.Errorf("Expected network ping to succeed but got error: %v", err)
216+
}
217+
218+
if !tc.expectSuccess && err == nil {
219+
t.Errorf("Expected network ping to fail but it succeeded")
220+
}
221+
})
222+
}
223+
}
224+
225+
func TestDocker_Run_PrepareCommand(t *testing.T) {
226+
// Skip on Windows - Alpine Linux doesn't support Windows containers
227+
if runtime.GOOS == "windows" {
228+
t.Skip("Skipping Docker test on Windows - Alpine Linux image not compatible with Windows containers")
229+
}
230+
231+
// Skip if docker is not available or not running
232+
if !checkDockerRunning() {
233+
t.Skip("Docker not installed or not running, skipping test")
234+
}
235+
236+
logger, _ := common.NewLogger("test-docker: ", "", common.LogLevelInfo, false)
237+
238+
// Create a runner with alpine image and prepare command to install grep
239+
r, err := NewDocker(Options{
240+
"image": "alpine:latest",
241+
"prepare_command": "apk add --no-cache grep",
242+
}, logger)
243+
244+
if err != nil {
245+
t.Fatalf("Failed to create Docker runner: %v", err)
246+
}
247+
248+
// Run grep command that should only work if the prepare_command executed properly
249+
output, err := r.Run(context.Background(), "", "grep --version | head -n 1", nil, nil, false)
250+
if err != nil {
251+
t.Errorf("Failed to run command that requires prepare_command: %v", err)
252+
}
253+
254+
// Check the output contains grep version information
255+
if !strings.Contains(output, "grep") {
256+
t.Errorf("Expected output to contain grep version information, got: %q", output)
257+
}
258+
}
259+
162260
func TestDocker_Optimization_SingleExecutable(t *testing.T) {
163261
// Skip on Windows - Alpine Linux doesn't support Windows containers
164262
if runtime.GOOS == "windows" {
@@ -282,9 +380,41 @@ func TestNewDockerOptions(t *testing.T) {
282380
if result.Image != tc.expected.Image {
283381
t.Errorf("Image: expected %q, got %q", tc.expected.Image, result.Image)
284382
}
383+
if result.DockerRunOpts != tc.expected.DockerRunOpts {
384+
t.Errorf("DockerRunOpts: expected %q, got %q", tc.expected.DockerRunOpts, result.DockerRunOpts)
385+
}
285386
if result.AllowNetworking != tc.expected.AllowNetworking {
286387
t.Errorf("AllowNetworking: expected %v, got %v", tc.expected.AllowNetworking, result.AllowNetworking)
287388
}
389+
if result.Network != tc.expected.Network {
390+
t.Errorf("Network: expected %q, got %q", tc.expected.Network, result.Network)
391+
}
392+
if result.User != tc.expected.User {
393+
t.Errorf("User: expected %q, got %q", tc.expected.User, result.User)
394+
}
395+
if result.WorkDir != tc.expected.WorkDir {
396+
t.Errorf("WorkDir: expected %q, got %q", tc.expected.WorkDir, result.WorkDir)
397+
}
398+
if result.PrepareCommand != tc.expected.PrepareCommand {
399+
t.Errorf("PrepareCommand: expected %q, got %q", tc.expected.PrepareCommand, result.PrepareCommand)
400+
}
401+
402+
// Check slice fields
403+
if !compareStringSlices(result.Mounts, tc.expected.Mounts) {
404+
t.Errorf("Mounts: expected %v, got %v", tc.expected.Mounts, result.Mounts)
405+
}
406+
if !compareStringSlices(result.CapAdd, tc.expected.CapAdd) {
407+
t.Errorf("CapAdd: expected %v, got %v", tc.expected.CapAdd, result.CapAdd)
408+
}
409+
if !compareStringSlices(result.CapDrop, tc.expected.CapDrop) {
410+
t.Errorf("CapDrop: expected %v, got %v", tc.expected.CapDrop, result.CapDrop)
411+
}
412+
if !compareStringSlices(result.DNS, tc.expected.DNS) {
413+
t.Errorf("DNS: expected %v, got %v", tc.expected.DNS, result.DNS)
414+
}
415+
if !compareStringSlices(result.DNSSearch, tc.expected.DNSSearch) {
416+
t.Errorf("DNSSearch: expected %v, got %v", tc.expected.DNSSearch, result.DNSSearch)
417+
}
288418
})
289419
}
290420
}

pkg/runner/exec_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,33 @@ func TestExec_RunWithEnvExpansion(t *testing.T) {
163163
t.Errorf("Environment variable expansion failed: got %q, want %q", output, expected)
164164
}
165165
}
166+
167+
func TestExec_Optimization_SingleExecutable(t *testing.T) {
168+
logger, _ := common.NewLogger("test-runner-exec-opt: ", "", common.LogLevelInfo, false)
169+
r, err := NewExec(Options{}, logger)
170+
if err != nil {
171+
t.Fatalf("Failed to create Exec: %v", err)
172+
}
173+
174+
// This command should be a single executable and run directly
175+
command := "whoami"
176+
output, err := r.Run(context.Background(), "", command, nil, nil, false)
177+
if err != nil {
178+
t.Errorf("Expected '%s' to run without error, got: %v", command, err)
179+
}
180+
if len(strings.TrimSpace(output)) == 0 {
181+
t.Errorf("Expected output from '%s', got empty string", command)
182+
}
183+
184+
// This command has arguments and should be run via a shell, not directly.
185+
// isSingleExecutableCommand should return false.
186+
// The command itself should succeed when run through the shell.
187+
commandWithArgs := "echo hello"
188+
output, err = r.Run(context.Background(), "", commandWithArgs, nil, nil, false)
189+
if err != nil {
190+
t.Errorf("Expected '%s' to run without error, got: %v", commandWithArgs, err)
191+
}
192+
if strings.TrimSpace(output) != "hello" {
193+
t.Errorf("Expected output from '%s' to be 'hello', got %q", commandWithArgs, output)
194+
}
195+
}

pkg/runner/sandbox_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package runner
22

33
import (
44
"context"
5+
"os"
56
"reflect"
67
"runtime"
78
"strings"
@@ -84,6 +85,20 @@ func TestSandboxExec_Run(t *testing.T) {
8485
t.Skip("skipping test in short mode")
8586
}
8687

88+
// Set environment variables for the test
89+
if err := os.Setenv("ALLOWED_FROM_ENV", "/tmp"); err != nil {
90+
t.Fatalf("Failed to set environment variable: %v", err)
91+
}
92+
if err := os.Setenv("USR_DIR", "/usr"); err != nil {
93+
t.Fatalf("Failed to set environment variable: %v", err)
94+
}
95+
96+
// Ensure cleanup
97+
defer func() {
98+
_ = os.Unsetenv("ALLOWED_FROM_ENV")
99+
_ = os.Unsetenv("USR_DIR")
100+
}()
101+
87102
// Create a logger for the test
88103
logger, _ := common.NewLogger("test-runner-sandbox: ", "", common.LogLevelInfo, false)
89104
ctx := context.Background()
@@ -127,6 +142,67 @@ func TestSandboxExec_Run(t *testing.T) {
127142
shouldSucceed: true,
128143
expectedOut: "Restricted",
129144
},
145+
{
146+
name: "read /tmp with folder restrictions",
147+
command: "ls -la /tmp | grep -q . && echo 'success'",
148+
options: Options{
149+
"allow_networking": false,
150+
"allow_user_folders": false,
151+
},
152+
shouldSucceed: true,
153+
expectedOut: "success",
154+
},
155+
{
156+
name: "custom profile allowing only /tmp",
157+
command: "ls -la /tmp | grep -q . && echo 'success'",
158+
options: Options{
159+
"custom_profile": `(version 1)
160+
(allow default)
161+
(deny file-read* (subpath "/Users"))
162+
(allow file-read* (regex "^/tmp"))`,
163+
},
164+
shouldSucceed: true,
165+
expectedOut: "success",
166+
},
167+
{
168+
name: "read from allowed folder using env variable",
169+
command: "ls -la /tmp > /dev/null && echo 'can read /tmp'",
170+
options: Options{
171+
"allow_networking": false,
172+
"allow_user_folders": false,
173+
"allow_read_folders": []string{"{{ env ALLOWED_FROM_ENV }}"},
174+
"custom_profile": "",
175+
},
176+
shouldSucceed: true,
177+
expectedOut: "can read /tmp",
178+
},
179+
{
180+
name: "template variables in allow_read_folders",
181+
command: "ls -la /var > /dev/null && echo 'can read templated folder'",
182+
options: Options{
183+
"allow_networking": false,
184+
"allow_user_folders": false,
185+
"allow_read_folders": []string{"{{.test_folder}}"},
186+
"custom_profile": "",
187+
},
188+
params: map[string]interface{}{
189+
"test_folder": "/var",
190+
},
191+
shouldSucceed: true,
192+
expectedOut: "can read templated folder",
193+
},
194+
{
195+
name: "complex env variable template in allow_read_folders",
196+
command: "ls -la /usr/bin > /dev/null && echo 'can read /usr/bin'",
197+
options: Options{
198+
"allow_networking": false,
199+
"allow_user_folders": false,
200+
"allow_read_folders": []string{"{{ env USR_DIR }}/bin"},
201+
"custom_profile": "",
202+
},
203+
shouldSucceed: true,
204+
expectedOut: "can read /usr/bin",
205+
},
130206
}
131207

132208
for _, tt := range tests {

0 commit comments

Comments
 (0)