From 29e019ec663fecb8512c61ad740a98eeb4b39aa8 Mon Sep 17 00:00:00 2001 From: danmobot Date: Mon, 22 Jun 2026 23:01:20 +0100 Subject: [PATCH 1/3] test: cover sandbox fs Windows path handling --- pkg/tools/fs/filesystem_windows_path_test.go | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 pkg/tools/fs/filesystem_windows_path_test.go diff --git a/pkg/tools/fs/filesystem_windows_path_test.go b/pkg/tools/fs/filesystem_windows_path_test.go new file mode 100644 index 000000000..1061f9ff2 --- /dev/null +++ b/pkg/tools/fs/filesystem_windows_path_test.go @@ -0,0 +1,57 @@ +package fstools + +import ( + "io" + "os" + "path/filepath" + "testing" +) + +func TestSandboxFsReadDirAcceptsOSSpecificRelativePaths(t *testing.T) { + workspace := t.TempDir() + if err := os.MkdirAll(filepath.Join(workspace, "aaa", "bbb", "ccc"), 0o755); err != nil { + t.Fatalf("create nested directory: %v", err) + } + if err := os.WriteFile(filepath.Join(workspace, "aaa", "bbb", "file.txt"), []byte("hello"), 0o600); err != nil { + t.Fatalf("create nested file: %v", err) + } + + fsys := &sandboxFs{workspace: workspace} + entries, err := fsys.ReadDir(filepath.Join("aaa", "bbb")) + if err != nil { + t.Fatalf("ReadDir with OS-specific relative path returned error: %v", err) + } + + seen := map[string]bool{} + for _, entry := range entries { + seen[entry.Name()] = true + } + if !seen["ccc"] || !seen["file.txt"] { + t.Fatalf("ReadDir entries = %v, want ccc and file.txt", seen) + } +} + +func TestSandboxFsOpenAcceptsOSSpecificRelativePaths(t *testing.T) { + workspace := t.TempDir() + if err := os.MkdirAll(filepath.Join(workspace, "aaa", "bbb"), 0o755); err != nil { + t.Fatalf("create nested directory: %v", err) + } + if err := os.WriteFile(filepath.Join(workspace, "aaa", "bbb", "file.txt"), []byte("hello"), 0o600); err != nil { + t.Fatalf("create nested file: %v", err) + } + + fsys := &sandboxFs{workspace: workspace} + file, err := fsys.Open(filepath.Join("aaa", "bbb", "file.txt")) + if err != nil { + t.Fatalf("Open with OS-specific relative path returned error: %v", err) + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + t.Fatalf("read opened file: %v", err) + } + if string(data) != "hello" { + t.Fatalf("file content = %q, want %q", string(data), "hello") + } +} From 46ffda264f7a37caa97acf7e5873695cc5067337 Mon Sep 17 00:00:00 2001 From: danmobot <270805001+danmobot@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:42:27 +0100 Subject: [PATCH 2/3] fix: import log in openai compat provider --- pkg/providers/openai_compat/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index c12a8348f..6a1b73d8a 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io" + "log" "maps" "net/http" "net/url" From acc2c5c6aad4296aadcdae4777727a67688dedfc Mon Sep 17 00:00:00 2001 From: danmobot <270805001+danmobot@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:57:42 +0100 Subject: [PATCH 3/3] test(fs): cover root path separator normalization --- pkg/tools/fs/filesystem.go | 15 ++++- pkg/tools/fs/filesystem_windows_path_test.go | 58 ++++---------------- 2 files changed, 24 insertions(+), 49 deletions(-) diff --git a/pkg/tools/fs/filesystem.go b/pkg/tools/fs/filesystem.go index 661fd6caf..adc7fa998 100644 --- a/pkg/tools/fs/filesystem.go +++ b/pkg/tools/fs/filesystem.go @@ -1064,8 +1064,8 @@ func (r *sandboxFs) execute(path string, fn func(root *os.Root, relPath string) return err } - // os.Root api on windows only accept forward slashes (/) - relPath = filepath.ToSlash(relPath) + // os.Root API on Windows only accepts forward slashes (/). + relPath = normalizeRootRelPath(relPath) return fn(root, relPath) } @@ -1230,6 +1230,17 @@ func buildFs(workspace string, restrict bool, patterns []*regexp.Regexp) fileSys return sandbox } +func normalizeRootRelPath(relPath string) string { + return normalizeRootRelPathForSeparator(relPath, os.PathSeparator) +} + +func normalizeRootRelPathForSeparator(relPath string, sep rune) string { + if sep == '\\' { + return strings.ReplaceAll(relPath, `\`, `/`) + } + return relPath +} + // Helper to get a safe relative path for os.Root usage func getSafeRelPath(workspace, path string) (string, error) { if workspace == "" { diff --git a/pkg/tools/fs/filesystem_windows_path_test.go b/pkg/tools/fs/filesystem_windows_path_test.go index 1061f9ff2..c30146f35 100644 --- a/pkg/tools/fs/filesystem_windows_path_test.go +++ b/pkg/tools/fs/filesystem_windows_path_test.go @@ -1,57 +1,21 @@ package fstools -import ( - "io" - "os" - "path/filepath" - "testing" -) +import "testing" -func TestSandboxFsReadDirAcceptsOSSpecificRelativePaths(t *testing.T) { - workspace := t.TempDir() - if err := os.MkdirAll(filepath.Join(workspace, "aaa", "bbb", "ccc"), 0o755); err != nil { - t.Fatalf("create nested directory: %v", err) - } - if err := os.WriteFile(filepath.Join(workspace, "aaa", "bbb", "file.txt"), []byte("hello"), 0o600); err != nil { - t.Fatalf("create nested file: %v", err) - } +func TestNormalizeRootRelPathForWindowsSeparator(t *testing.T) { + got := normalizeRootRelPathForSeparator(`aaa\bbb\file.txt`, '\\') + want := "aaa/bbb/file.txt" - fsys := &sandboxFs{workspace: workspace} - entries, err := fsys.ReadDir(filepath.Join("aaa", "bbb")) - if err != nil { - t.Fatalf("ReadDir with OS-specific relative path returned error: %v", err) - } - - seen := map[string]bool{} - for _, entry := range entries { - seen[entry.Name()] = true - } - if !seen["ccc"] || !seen["file.txt"] { - t.Fatalf("ReadDir entries = %v, want ccc and file.txt", seen) + if got != want { + t.Fatalf("normalizeRootRelPathForSeparator() = %q, want %q", got, want) } } -func TestSandboxFsOpenAcceptsOSSpecificRelativePaths(t *testing.T) { - workspace := t.TempDir() - if err := os.MkdirAll(filepath.Join(workspace, "aaa", "bbb"), 0o755); err != nil { - t.Fatalf("create nested directory: %v", err) - } - if err := os.WriteFile(filepath.Join(workspace, "aaa", "bbb", "file.txt"), []byte("hello"), 0o600); err != nil { - t.Fatalf("create nested file: %v", err) - } +func TestNormalizeRootRelPathForUnixSeparatorLeavesBackslashUnchanged(t *testing.T) { + input := `aaa\bbb\file.txt` + got := normalizeRootRelPathForSeparator(input, '/') - fsys := &sandboxFs{workspace: workspace} - file, err := fsys.Open(filepath.Join("aaa", "bbb", "file.txt")) - if err != nil { - t.Fatalf("Open with OS-specific relative path returned error: %v", err) - } - defer file.Close() - - data, err := io.ReadAll(file) - if err != nil { - t.Fatalf("read opened file: %v", err) - } - if string(data) != "hello" { - t.Fatalf("file content = %q, want %q", string(data), "hello") + if got != input { + t.Fatalf("normalizeRootRelPathForSeparator() = %q, want %q", got, input) } }