From 36d3021aae2e140cba23a0f623ec034bef0257ff Mon Sep 17 00:00:00 2001 From: ollie Date: Sun, 3 May 2026 22:10:02 +0200 Subject: [PATCH] sandbox: require landrun, fail hard if unavailable WrapCommand now returns an error instead of silently falling back to unsandboxed execution when landrun is not in PATH. execute_code propagates this as a hard failure. --- internal/sandbox/sandbox_test.go | 58 +++++++++++++++++++------------- internal/sandbox/wrapper.go | 12 ++++--- pkg/tools/execute/server.go | 5 ++- 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/internal/sandbox/sandbox_test.go b/internal/sandbox/sandbox_test.go index e9648c0..1279174 100644 --- a/internal/sandbox/sandbox_test.go +++ b/internal/sandbox/sandbox_test.go @@ -115,7 +115,7 @@ func TestWrapCommand(t *testing.T) { t.Run("starts with landrun", func(t *testing.T) { cfg := &Config{General: GeneralConfig{}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"echo", "hi"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"echo", "hi"}, tmpDir) if len(got) == 0 || got[0] != "landrun" { t.Errorf("expected landrun as first arg, got %v", got) } @@ -123,7 +123,7 @@ func TestWrapCommand(t *testing.T) { t.Run("separator before original command", func(t *testing.T) { cfg := &Config{General: GeneralConfig{}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"echo", "test"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"echo", "test"}, tmpDir) sepIdx := indexOf(got, "--") if sepIdx == -1 { t.Fatal("missing -- separator") @@ -135,37 +135,37 @@ func TestWrapCommand(t *testing.T) { t.Run("log level flag", func(t *testing.T) { cfg := &Config{General: GeneralConfig{LogLevel: "debug"}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--log-level", "debug") }) t.Run("no log level when empty", func(t *testing.T) { cfg := &Config{General: GeneralConfig{LogLevel: ""}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertDoesNotContain(t, got, "--log-level") }) t.Run("best effort flag", func(t *testing.T) { cfg := &Config{General: GeneralConfig{BestEffort: true}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertContains(t, got, "--best-effort") }) t.Run("no best effort when false", func(t *testing.T) { cfg := &Config{General: GeneralConfig{BestEffort: false}, Advanced: AdvancedConfig{}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertDoesNotContain(t, got, "--best-effort") }) t.Run("ldd flag", func(t *testing.T) { cfg := &Config{General: GeneralConfig{}, Advanced: AdvancedConfig{LDD: true}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertContains(t, got, "--ldd") }) t.Run("add-exec flag", func(t *testing.T) { cfg := &Config{General: GeneralConfig{}, Advanced: AdvancedConfig{AddExec: true}, Network: NetworkConfig{}} - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertContains(t, got, "--add-exec") }) @@ -176,7 +176,7 @@ func TestWrapCommand(t *testing.T) { Filesystem: FilesystemConfig{RW: []string{rwDir}}, Network: NetworkConfig{}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--rw", rwDir) }) @@ -187,7 +187,7 @@ func TestWrapCommand(t *testing.T) { Filesystem: FilesystemConfig{RO: []string{roDir}}, Network: NetworkConfig{}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--ro", roDir) }) @@ -198,7 +198,7 @@ func TestWrapCommand(t *testing.T) { Filesystem: FilesystemConfig{RW: []string{"/nonexistent/path/that/does/not/exist/xyz"}}, Network: NetworkConfig{}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertDoesNotContain(t, got, "--rw") }) @@ -209,7 +209,7 @@ func TestWrapCommand(t *testing.T) { Filesystem: FilesystemConfig{RW: []string{"{CWD}"}}, Network: NetworkConfig{}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--rw", tmpDir) }) @@ -219,7 +219,7 @@ func TestWrapCommand(t *testing.T) { Advanced: AdvancedConfig{}, Network: NetworkConfig{Enabled: true, Unrestricted: true}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertContains(t, got, "--unrestricted-network") assertDoesNotContain(t, got, "--connect-tcp") assertDoesNotContain(t, got, "--bind-tcp") @@ -235,7 +235,7 @@ func TestWrapCommand(t *testing.T) { BindTCP: []string{"8080"}, }, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--connect-tcp", "443") assertFlagValue(t, got, "--connect-tcp", "80") assertFlagValue(t, got, "--bind-tcp", "8080") @@ -248,7 +248,7 @@ func TestWrapCommand(t *testing.T) { Advanced: AdvancedConfig{}, Network: NetworkConfig{Enabled: false, ConnectTCP: []string{"443"}}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertDoesNotContain(t, got, "--connect-tcp") assertDoesNotContain(t, got, "--unrestricted-network") }) @@ -260,7 +260,7 @@ func TestWrapCommand(t *testing.T) { Network: NetworkConfig{}, Env: []string{"HOME", "PATH"}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--env", "HOME") assertFlagValue(t, got, "--env", "PATH") }) @@ -277,7 +277,7 @@ func TestWrapCommand(t *testing.T) { Filesystem: FilesystemConfig{RW: []string{child, parent}}, // child listed first Network: NetworkConfig{}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) parentIdx := indexOf(got, parent) childIdx := indexOf(got, child) if parentIdx == -1 || childIdx == -1 { @@ -581,9 +581,12 @@ func TestWrapCommand_LandrunUnavailable(t *testing.T) { defer func() { isAvailableFn = old }() cfg := &Config{} - got := WrapCommand(cfg, []string{"echo", "hi"}, "/tmp") - if len(got) != 2 || got[0] != "echo" { - t.Errorf("should return original cmd when landrun unavailable; got %v", got) + _, err := WrapCommand(cfg, []string{"echo", "hi"}, "/tmp") + if err == nil { + t.Fatal("expected error when landrun unavailable") + } + if err != ErrNotAvailable { + t.Errorf("expected ErrNotAvailable, got %v", err) } } @@ -600,7 +603,7 @@ func TestWrapCommand_ROX_RWX(t *testing.T) { RWX: []string{rwxDir}, }, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) assertFlagValue(t, got, "--rox", roxDir) assertFlagValue(t, got, "--rwx", rwxDir) } @@ -616,7 +619,7 @@ func TestWrapCommand_SortTiebreaker(t *testing.T) { cfg := &Config{ Filesystem: FilesystemConfig{RW: []string{dirB, dirA}}, } - got := WrapCommand(cfg, []string{"sh"}, tmpDir) + got := mustWrapCommand(t, cfg, []string{"sh"}, tmpDir) idxA := indexOf(got, dirA) idxB := indexOf(got, dirB) if idxA == -1 || idxB == -1 { @@ -639,7 +642,7 @@ func TestWrapCommand_Superpowerd(t *testing.T) { defer func() { isSuperpowerdRunningFn = old }() cfg := &Config{} - got := WrapCommand(cfg, []string{"echo"}, "/tmp") + got := mustWrapCommand(t, cfg, []string{"echo"}, "/tmp") if got[0] != fakeSP { t.Errorf("expected superpowers as first arg; got %v", got) } @@ -691,6 +694,15 @@ func TestIsSuperpowerdRunning_SocketExists(t *testing.T) { // ---- helpers ---- +func mustWrapCommand(t *testing.T, cfg *Config, cmd []string, cwd string) []string { + t.Helper() + got, err := WrapCommand(cfg, cmd, cwd) + if err != nil { + t.Fatalf("WrapCommand failed: %v", err) + } + return got +} + func assertContains(t *testing.T, args []string, s string) { t.Helper() if indexOf(args, s) == -1 { diff --git a/internal/sandbox/wrapper.go b/internal/sandbox/wrapper.go index ab33bdb..ee1c4e0 100644 --- a/internal/sandbox/wrapper.go +++ b/internal/sandbox/wrapper.go @@ -1,6 +1,7 @@ package sandbox import ( + "fmt" "net" "os" "os/exec" @@ -20,11 +21,14 @@ var ( isSuperpowerdRunningFn = isSuperpowerdRunning ) +// ErrNotAvailable is returned when landrun is not found on the system. +var ErrNotAvailable = fmt.Errorf("SANDBOX FAILURE: landrun is not installed or not in PATH — execute_code CANNOT run without it") + // WrapCommand wraps a command with landrun based on the configuration. -// Returns the wrapped command args, or the original command if landrun is unavailable. -func WrapCommand(cfg *Config, originalCmd []string, cwd string) []string { +// Returns an error if landrun is not available. +func WrapCommand(cfg *Config, originalCmd []string, cwd string) ([]string, error) { if !isAvailableFn() { - return originalCmd + return nil, ErrNotAvailable } args := []string{"landrun"} @@ -108,7 +112,7 @@ func WrapCommand(cfg *Config, originalCmd []string, cwd string) []string { } } - return args + return args, nil } // isSuperpowerdRunning checks if superpowerd is running by testing socket connectivity diff --git a/pkg/tools/execute/server.go b/pkg/tools/execute/server.go index bb315d0..501f290 100644 --- a/pkg/tools/execute/server.go +++ b/pkg/tools/execute/server.go @@ -334,7 +334,10 @@ func (e *Server) executeWithStdin(ctx context.Context, code, language string, ti default: return "", fmt.Errorf("unsupported language: %s (supported: bash, python3, perl, awk, sed, ed, jq, expect, bc, lua)", language) } - wrapped := sandbox.WrapCommand(cfg, interpreter, workDir) + wrapped, wrapErr := sandbox.WrapCommand(cfg, interpreter, workDir) + if wrapErr != nil { + return "", wrapErr + } cmd = exec.CommandContext(ctx, wrapped[0], wrapped[1:]...) cmd.Dir = workDir switch {