@@ -2,6 +2,7 @@ package fileutil
22
33import (
44 "os/user"
5+ "path/filepath"
56 "testing"
67
78 "github.com/stretchr/testify/require"
@@ -74,6 +75,52 @@ func TestExpandHome(t *testing.T) {
7475 }
7576}
7677
78+ func TestResolveLocalPath (t * testing.T ) {
79+ sep := string (filepath .Separator )
80+ root := filepath .Clean ("/data/proj123" )
81+
82+ variations := []struct {
83+ Name string
84+ Path string
85+ Root string
86+ AllowHostAccess bool
87+ Expected string
88+ ExpectErr bool
89+ }{
90+ // Relative paths within the root are joined and cleaned.
91+ {"relative within root" , "sub/file.csv" , root , false , filepath .Join (root , "sub" , "file.csv" ), false },
92+ {"relative to root itself" , "." , root , false , root , false },
93+
94+ // Absolute paths within the root are allowed.
95+ {"absolute within root" , filepath .Join (root , "file.csv" ), root , false , filepath .Join (root , "file.csv" ), false },
96+
97+ // Absolute path traversal must be rejected once cleaned.
98+ {"absolute traversal" , root + sep + ".." + sep + ".." + sep + "etc" + sep + "passwd" , root , false , "" , true },
99+
100+ // Relative traversal escaping the root must be rejected.
101+ {"relative traversal" , ".." + sep + ".." + sep + "etc" + sep + "passwd" , root , false , "" , true },
102+
103+ // Sibling directory sharing the root's prefix must not pass the check.
104+ {"sibling prefix collision" , "/data/proj123-x/secret" , root , false , "" , true },
105+ {"relative sibling prefix collision" , ".." + sep + "proj123-x" + sep + "secret" , root , false , "" , true },
106+
107+ // With host access enabled, any path is allowed (but still cleaned).
108+ {"host access bypasses sandbox" , root + sep + ".." + sep + "etc" + sep + "passwd" , root , true , filepath .Clean ("/data/etc/passwd" ), false },
109+ }
110+
111+ for _ , tt := range variations {
112+ t .Run (tt .Name , func (t * testing.T ) {
113+ got , err := ResolveLocalPath (tt .Path , tt .Root , tt .AllowHostAccess )
114+ if tt .ExpectErr {
115+ require .Error (t , err )
116+ return
117+ }
118+ require .NoError (t , err )
119+ require .Equal (t , tt .Expected , got )
120+ })
121+ }
122+ }
123+
77124func TestIsGlob (t * testing.T ) {
78125 variations := []struct {
79126 Path string
0 commit comments