From 9b478d5ac2cf0dc1d78463489e8a8631a64168c2 Mon Sep 17 00:00:00 2001 From: ronantakizawa Date: Sun, 1 Sep 2024 11:17:38 -0600 Subject: [PATCH] fix: .helmignore not ignoring broken symlinks Signed-off-by: ronantakizawa --- internal/sympath/walk.go | 86 +++++++++++++++++++--------------------- pkg/ignore/rules.go | 85 ++++++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/internal/sympath/walk.go b/internal/sympath/walk.go index 6b221fb6c..5324ecb2b 100644 --- a/internal/sympath/walk.go +++ b/internal/sympath/walk.go @@ -26,7 +26,6 @@ import ( "path/filepath" "sort" - "github.com/pkg/errors" ) // Walk walks the file tree rooted at root, calling walkFn for each file or directory @@ -65,56 +64,53 @@ func readDirNames(dirname string) ([]string, error) { // symwalk recursively descends path, calling walkFn. func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { - // Recursively walk symlinked directories. - if IsSymlink(info) { - resolved, err := filepath.EvalSymlinks(path) - if err != nil { - return errors.Wrapf(err, "error evaluating symlink %s", path) - } - //This log message is to highlight a symlink that is being used within a chart, symlinks can be used for nefarious reasons. - log.Printf("found symbolic link in path: %s resolves to %s. Contents of linked file included and used", path, resolved) - if info, err = os.Lstat(resolved); err != nil { - return err - } - if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir { - return err - } - return nil - } + // Recursively walk symlinked directories. + if IsSymlink(info) { + resolved, err := filepath.EvalSymlinks(path) + if err != nil { + log.Printf("Skipping broken symlink: %s", path) // Log broken symlink + return nil // Skip this symlink and continue + } + log.Printf("Found symbolic link in path: %s resolves to %s. Contents of linked file included and used", path, resolved) + if info, err = os.Lstat(resolved); err != nil { + return err + } + return symwalk(resolved, info, walkFn) + } - if err := walkFn(path, info, nil); err != nil { - return err - } + if err := walkFn(path, info, nil); err != nil { + return err + } - if !info.IsDir() { - return nil - } + if !info.IsDir() { + return nil + } - names, err := readDirNames(path) - if err != nil { - return walkFn(path, info, err) - } + names, err := readDirNames(path) + if err != nil { + return walkFn(path, info, err) + } - for _, name := range names { - filename := filepath.Join(path, name) - fileInfo, err := os.Lstat(filename) - if err != nil { - if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { - return err - } - } else { - err = symwalk(filename, fileInfo, walkFn) - if err != nil { - if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { - return err - } - } - } - } - return nil + for _, name := range names { + filename := filepath.Join(path, name) + fileInfo, err := os.Lstat(filename) + if err != nil { + if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { + return err + } + } else { + err = symwalk(filename, fileInfo, walkFn) + if err != nil { + if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { + return err + } + } + } + } + return nil } // IsSymlink is used to determine if the fileinfo is a symbolic link. func IsSymlink(fi os.FileInfo) bool { return fi.Mode()&os.ModeSymlink != 0 -} +} \ No newline at end of file diff --git a/pkg/ignore/rules.go b/pkg/ignore/rules.go index 88de407ad..ff8119736 100644 --- a/pkg/ignore/rules.go +++ b/pkg/ignore/rules.go @@ -88,46 +88,59 @@ func Parse(file io.Reader) (*Rules, error) { // // Ignore evaluates path against the rules in order. Evaluation stops when a match // is found. Matching a negative rule will stop evaluation. +// Ignore evaluates the file at the given path, and returns true if it should be ignored. func (r *Rules) Ignore(path string, fi os.FileInfo) bool { - // Don't match on empty dirs. - if path == "" { - return false - } + // Don't match on empty dirs. + if path == "" { + return false + } - // Disallow ignoring the current working directory. + // Disallow ignoring the current working directory. // See issue: // 1776 (New York City) Hamilton: "Pardon me, are you Aaron Burr, sir?" - if path == "." || path == "./" { - return false - } - for _, p := range r.patterns { - if p.match == nil { - log.Printf("ignore: no matcher supplied for %q", p.raw) - return false - } - - // For negative rules, we need to capture and return non-matches, - // and continue for matches. - if p.negate { - if p.mustDir && !fi.IsDir() { - return true - } - if !p.match(path, fi) { - return true - } - continue - } - - // If the rule is looking for directories, and this is not a directory, - // skip it. - if p.mustDir && !fi.IsDir() { - continue - } - if p.match(path, fi) { - return true - } - } - return false + if path == "." || path == "./" { + return false + } + + // Check for symlink and ignore based on pattern + if fi.Mode()&os.ModeSymlink != 0 { + resolvedPath, err := filepath.EvalSymlinks(path) + if err != nil { + log.Printf("Ignoring broken symlink: %s -> %s", path, resolvedPath) // Log and ignore broken symlink + return false // Skip this symlink and continue + } + for _, p := range r.patterns { + if p.match == nil { + log.Printf("ignore: no matcher supplied for %q", p.raw) + return false + } + if p.mustDir && !fi.IsDir() { + continue + } + if p.match(resolvedPath, fi) { + log.Printf("Ignoring symlink path: %s", path) + return true + } + } + return false // Skip further evaluation for this symlink + } + + for _, p := range r.patterns { + if p.match == nil { + log.Printf("ignore: no matcher supplied for %q", p.raw) + return false + } + + // If the rule is looking for directories, and this is not a directory, + // skip it. + if p.mustDir && !fi.IsDir() { + continue + } + if p.match(path, fi) { + return true + } + } + return false } // parseRule parses a rule string and creates a pattern, which is then stored in the Rules object.