@@ -41,42 +41,84 @@ func MirrorToTempFileIfPathIsDescriptor(file string) (string, bool) {
4141}
4242
4343// DiscoverContainerfile tries to find a Containerfile or a Dockerfile within the provided `path`.
44+ // The path may be a directory (in which case Containerfile/Dockerfile is searched inside it)
45+ // or a direct path to a container file.
46+ //
47+ // Symlinked Containerfile/Dockerfile entries are only used when their real
48+ // target stays inside the build context directory. Symlinks that resolve
49+ // outside the context or are dangling are skipped.
4450func DiscoverContainerfile (path string ) (foundCtrFile string , err error ) {
45- // Test for existence of the file
46- target , err := os .Stat (path )
51+ path , err = filepath .Abs (path )
4752 if err != nil {
4853 return "" , fmt .Errorf ("discovering Containerfile: %w" , err )
4954 }
5055
51- switch mode := target .Mode (); {
52- case mode .IsDir ():
53- // If the path is a real directory, we assume a Containerfile or a Dockerfile within it
54- ctrfile := filepath .Join (path , "Containerfile" )
55-
56- // Test for existence of the Containerfile file
57- file , err := os .Stat (ctrfile )
58- if err != nil {
59- // See if we have a Dockerfile within it
60- ctrfile = filepath .Join (path , "Dockerfile" )
56+ target , err := os .Lstat (path )
57+ if err != nil {
58+ return "" , fmt .Errorf ("discovering Containerfile: %w" , err )
59+ }
6160
62- // Test for existence of the Dockerfile file
63- file , err = os .Stat (ctrfile )
64- if err != nil {
65- return "" , fmt .Errorf ("cannot find Containerfile or Dockerfile in context directory: %w" , err )
61+ switch {
62+ case target .IsDir ():
63+ for _ , name := range []string {"Containerfile" , "Dockerfile" } {
64+ ctrfile := filepath .Join (path , name )
65+ if isRegularFileInContext (path , ctrfile ) {
66+ return ctrfile , nil
6667 }
6768 }
69+ return "" , fmt .Errorf ("cannot find Containerfile or Dockerfile in context directory" )
70+
71+ case target .Mode ().IsRegular ():
72+ return path , nil
6873
69- // The file exists, now verify the correct mode
70- if mode := file .Mode (); mode .IsRegular () {
71- foundCtrFile = ctrfile
72- } else {
73- return "" , fmt .Errorf ("assumed Containerfile %q is not a file" , ctrfile )
74+ case target .Mode ()& os .ModeSymlink != 0 :
75+ if isRegularFileInContext (filepath .Dir (path ), path ) {
76+ return path , nil
7477 }
78+ return "" , fmt .Errorf ("assumed Containerfile %q is not a file" , path )
7579
76- case mode .IsRegular ():
77- // If the context dir is a file, we assume this as Containerfile
78- foundCtrFile = path
80+ default :
81+ return "" , fmt .Errorf ("assumed Containerfile %q is not a file" , path )
7982 }
83+ }
8084
81- return foundCtrFile , nil
85+ // isRegularFileInContext returns true if path is a regular file (or a symlink
86+ // to one) whose real target is inside contextDir. Symlinks whose raw target
87+ // traverses outside the context at any intermediate step are rejected, even if
88+ // the final resolved path lands back inside.
89+ func isRegularFileInContext (contextDir , path string ) bool {
90+ cleanContext , err := filepath .EvalSymlinks (contextDir )
91+ if err != nil {
92+ return false
93+ }
94+ info , err := os .Lstat (path )
95+ if err != nil {
96+ return false
97+ }
98+ if info .Mode ()& os .ModeSymlink != 0 {
99+ target , err := os .Readlink (path )
100+ if err != nil {
101+ return false
102+ }
103+ clean := filepath .Clean (target )
104+ if ! filepath .IsAbs (target ) && (clean == ".." || strings .HasPrefix (clean , ".." + string (filepath .Separator ))) {
105+ return false
106+ }
107+ }
108+ resolved , err := filepath .EvalSymlinks (path )
109+ if err != nil {
110+ return false
111+ }
112+ rel , err := filepath .Rel (cleanContext , resolved )
113+ if err != nil {
114+ return false
115+ }
116+ if rel == ".." || strings .HasPrefix (rel , ".." + string (filepath .Separator )) {
117+ return false
118+ }
119+ fi , err := os .Stat (path )
120+ if err != nil {
121+ return false
122+ }
123+ return fi .Mode ().IsRegular ()
82124}
0 commit comments