github.com/argoproj/argo-cd/v3@v3.2.1/reposerver/repository/utils.go (about) 1 package repository 2 3 import ( 4 "path/filepath" 5 "strings" 6 7 securejoin "github.com/cyphar/filepath-securejoin" 8 log "github.com/sirupsen/logrus" 9 10 "github.com/argoproj/argo-cd/v3/reposerver/apiclient" 11 "github.com/argoproj/argo-cd/v3/util/io/files" 12 ) 13 14 // getApplicationRootPath returns the common root path (shortest shared structure between all paths) among a 15 // set of application-related paths for manifest generation. AppPath is the lower possible value 16 func getApplicationRootPath(q *apiclient.ManifestRequest, appPath, repoPath string) string { 17 paths := getPaths(q, appPath, repoPath) 18 19 if len(paths) == 0 { 20 // backward compatibility, by default the root path is the repoPath 21 return repoPath 22 } 23 24 // the app path must be the lower possible value 25 commonParts := strings.Split(appPath, string(filepath.Separator)) 26 27 var disjoint bool 28 for _, path := range paths { 29 parts := strings.Split(path, string(filepath.Separator)) 30 // find the minimum length between the current common parts and the current path 31 minLen := func(a, b int) int { 32 if a < b { 33 return a 34 } 35 return b 36 }(len(commonParts), len(parts)) 37 38 // check if diverge /disjoint in some point 39 for i := 0; i < minLen; i++ { 40 if commonParts[i] != parts[i] { 41 commonParts = commonParts[:i] 42 disjoint = true 43 break 44 } 45 } 46 47 // for non-disjoint paths 48 if !disjoint && minLen < len(commonParts) { 49 commonParts = commonParts[:minLen] 50 } 51 } 52 return string(filepath.Separator) + filepath.Join(commonParts...) 53 } 54 55 // getPaths retrieves all absolute paths associated with the generation of application manifests. 56 func getPaths(q *apiclient.ManifestRequest, appPath, repoPath string) []string { 57 var paths []string 58 for _, annotationPath := range strings.Split(q.AnnotationManifestGeneratePaths, ";") { 59 if annotationPath == "" { 60 continue 61 } 62 var err error 63 var path, unsafePath string 64 65 if filepath.IsAbs(annotationPath) { 66 unsafePath = filepath.Clean(annotationPath) 67 } else { 68 appRelPath, err := files.RelativePath(appPath, repoPath) 69 if err != nil { 70 log.Errorf("error building app relative path: %v", err) 71 continue 72 } 73 unsafePath = filepath.Clean(filepath.Join(appRelPath, annotationPath)) 74 } 75 76 path, err = securejoin.SecureJoin(repoPath, unsafePath) 77 if err != nil { 78 log.Errorf("error joining repoPath %q and absolute unsafePath %q: %v", repoPath, unsafePath, err) 79 continue 80 } 81 82 paths = append(paths, path) 83 } 84 return paths 85 }