diff --git a/pkg/tools/fs/filesystem.go b/pkg/tools/fs/filesystem.go index 661fd6ca..adc7fa99 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 1061f9ff..c30146f3 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) } }