@@ -13,6 +13,75 @@ import (
1313 "sigs.k8s.io/yaml"
1414)
1515
16+ // TestSymlinkWithIncludePaths verifies that a sync with includePaths succeeds even when
17+ // the filtered content contains symlinks pointing to paths that are excluded by includePaths.
18+ // The dangling symlinks must be silently removed rather than causing an error.
19+ func TestSymlinkWithIncludePaths (t * testing.T ) {
20+ env := BuildEnv (t )
21+ vendir := Vendir {t , env .BinaryPath , Logger {}}
22+
23+ tmpDir , err := os .MkdirTemp ("" , "vendir-test" )
24+ require .NoError (t , err )
25+ defer os .RemoveAll (tmpDir )
26+
27+ tmpDir , err = filepath .EvalSymlinks (tmpDir )
28+ require .NoError (t , err )
29+
30+ // Source layout:
31+ // src/
32+ // dir1/
33+ // kept.txt <- included by includePaths
34+ // link_to_other -> ../dir2/other.txt (will dangle after filtering)
35+ // dir2/
36+ // other.txt <- NOT included by includePaths
37+ srcDir := filepath .Join (tmpDir , "src" )
38+ dir1 := filepath .Join (srcDir , "dir1" )
39+ dir2 := filepath .Join (srcDir , "dir2" )
40+ require .NoError (t , os .MkdirAll (dir1 , os .ModePerm ))
41+ require .NoError (t , os .MkdirAll (dir2 , os .ModePerm ))
42+
43+ keptFile , err := os .Create (filepath .Join (dir1 , "kept.txt" ))
44+ require .NoError (t , err )
45+ keptFile .Close ()
46+
47+ otherFile , err := os .Create (filepath .Join (dir2 , "other.txt" ))
48+ require .NoError (t , err )
49+ otherFile .Close ()
50+
51+ // Symlink uses a relative path (../dir2/other.txt) so it is internal to the bundle
52+ require .NoError (t , os .Symlink ("../dir2/other.txt" , filepath .Join (dir1 , "link_to_other" )))
53+
54+ cfg := config.Config {
55+ APIVersion : "vendir.k14s.io/v1alpha1" ,
56+ Kind : "Config" ,
57+ Directories : []config.Directory {{
58+ Path : "result" ,
59+ Contents : []config.DirectoryContents {{
60+ Path : "out" ,
61+ Directory : & config.DirectoryContentsDirectory {
62+ Path : "src" ,
63+ },
64+ IncludePaths : []string {"dir1/**" },
65+ }},
66+ }},
67+ }
68+
69+ cfgBytes , err := yaml .Marshal (cfg )
70+ require .NoError (t , err )
71+ require .NoError (t , os .WriteFile (filepath .Join (tmpDir , "vendir.yml" ), cfgBytes , 0666 ))
72+
73+ _ , err = vendir .RunWithOpts ([]string {"sync" }, RunOpts {Dir : tmpDir , AllowError : true })
74+ require .NoError (t , err , "sync should succeed even though includePaths causes a dangling symlink" )
75+
76+ // The dangling symlink must have been removed
77+ _ , err = os .Lstat (filepath .Join (tmpDir , "result" , "out" , "dir1" , "link_to_other" ))
78+ require .True (t , os .IsNotExist (err ), "dangling symlink should have been removed after filtering" )
79+
80+ // The kept file must still be present
81+ _ , err = os .Stat (filepath .Join (tmpDir , "result" , "out" , "dir1" , "kept.txt" ))
82+ require .NoError (t , err , "kept.txt should be present after filtering" )
83+ }
84+
1685func TestInvalidSymlink (t * testing.T ) {
1786 env := BuildEnv (t )
1887 vendir := Vendir {t , env .BinaryPath , Logger {}}
0 commit comments