diff --git a/internal/sympath/walk.go b/internal/sympath/walk.go index 6b221fb6c..92d68d6d6 100644 --- a/internal/sympath/walk.go +++ b/internal/sympath/walk.go @@ -69,7 +69,11 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { if IsSymlink(info) { resolved, err := filepath.EvalSymlinks(path) if err != nil { - return errors.Wrapf(err, "error evaluating symlink %s", path) + err = walkFn(path, info, errors.Wrapf(err, "error evaluating symlink %s", path)) + if err != nil && err != filepath.SkipDir { + return err + } + return nil } //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) diff --git a/pkg/chart/loader/directory.go b/pkg/chart/loader/directory.go index fd8e02e1a..0e8fe6870 100644 --- a/pkg/chart/loader/directory.go +++ b/pkg/chart/loader/directory.go @@ -77,20 +77,20 @@ func LoadDir(dir string) (*chart.Chart, error) { // Normalize to / since it will also work on Windows n = filepath.ToSlash(n) + // If a .helmignore file matches, skip this file. + if fi != nil && rules.Ignore(n, fi) { + if fi.IsDir() { + return filepath.SkipDir + } + return nil + } + if err != nil { return err } if fi.IsDir() { // Directory-based ignore rules should involve skipping the entire // contents of that directory. - if rules.Ignore(n, fi) { - return filepath.SkipDir - } - return nil - } - - // If a .helmignore file matches, skip this file. - if rules.Ignore(n, fi) { return nil } diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 098e6155f..ad7b60284 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -86,6 +86,42 @@ func TestLoadDirWithSymlink(t *testing.T) { verifyDependenciesLock(t, c) } +func TestLoadDirWithIgnoredBrokenSymlink(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("symlink creation requires additional privileges on Windows") + } + + dir := t.TempDir() + + if err := os.WriteFile(filepath.Join(dir, "Chart.yaml"), []byte("apiVersion: v2\nname: broken-symlink\nversion: 0.1.0\n"), 0644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, ".helmignore"), []byte("templates/broken-link\n"), 0644); err != nil { + t.Fatal(err) + } + if err := os.Mkdir(filepath.Join(dir, "templates"), 0755); err != nil { + t.Fatal(err) + } + if err := os.Symlink("missing-target", filepath.Join(dir, "templates", "broken-link")); err != nil { + t.Fatal(err) + } + + l, err := Loader(dir) + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + + c, err := l.Load() + if err != nil { + t.Fatalf("Failed to load chart with ignored broken symlink: %s", err) + } + for _, f := range c.Raw { + if f.Name == "templates/broken-link" { + t.Fatalf("ignored broken symlink was loaded") + } + } +} + func TestBomTestData(t *testing.T) { testFiles := []string{"frobnitz_with_bom/.helmignore", "frobnitz_with_bom/templates/template.tpl", "frobnitz_with_bom/Chart.yaml"} for _, file := range testFiles {