fix(sympath): skip broken symlinks instead of erroring

When sympath.Walk encounters a broken symlink whose target does not
exist, silently skip it instead of returning an error. Other EvalSymlinks
errors (e.g. permission denied, symlink loops) are still propagated.

Broken symlinks cannot contribute useful content, and this prevents
errors when they are listed in .helmignore patterns.

Fixes #13284

Signed-off-by: Kartik Suryavanshi <158498247+KartikSuryavanshi@users.noreply.github.com>
pull/32264/head
Kartik Suryavanshi 3 weeks ago
parent 187a02298a
commit e98a25134a

@ -90,6 +90,56 @@ func TestLoadDirWithSymlink(t *testing.T) {
verifyDependenciesLock(t, c)
}
func TestLoadDirWithBrokenSymlinkInHelmignore(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlink tests require unix")
}
tmpDir := t.TempDir()
// Create minimal chart structure
chartYAML := `apiVersion: v2
name: test
version: 0.1.0
`
valuesYAML := `{}
`
tpl := `config: {}
`
if err := os.WriteFile(filepath.Join(tmpDir, "Chart.yaml"), []byte(chartYAML), 0644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "values.yaml"), []byte(valuesYAML), 0644); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(tmpDir, "templates"), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "templates", "config.yaml"), []byte(tpl), 0644); err != nil {
t.Fatal(err)
}
// Create a broken symlink in templates/
brokenLink := filepath.Join(tmpDir, "templates", "broken")
if err := os.Symlink("nonexistent", brokenLink); err != nil {
t.Fatal(err)
}
// Add the broken symlink to .helmignore
if err := os.WriteFile(filepath.Join(tmpDir, ".helmignore"), []byte("templates/broken\n"), 0644); err != nil {
t.Fatal(err)
}
// Loading should succeed despite the broken symlink
l, err := Loader(tmpDir)
if err != nil {
t.Fatal(err)
}
if _, err := l.Load(); err != nil {
t.Fatalf("loading chart with broken symlink in .helmignore should not fail: %s", err)
}
}
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 {

@ -21,7 +21,6 @@ limitations under the License.
package sympath
import (
"fmt"
"log/slog"
"os"
"path/filepath"
@ -68,7 +67,14 @@ func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
if IsSymlink(info) {
resolved, err := filepath.EvalSymlinks(path)
if err != nil {
return fmt.Errorf("error evaluating symlink %s: %w", path, err)
if os.IsNotExist(err) {
// If a symlink's target does not exist (broken symlink),
// silently skip it. Broken symlinks do not contribute
// content and should not cause errors, especially when
// they match .helmignore patterns.
return nil
}
return err
}
// This log message is to highlight a symlink that is being used within a chart, symlinks can be used for nefarious reasons.
slog.Info("found symbolic link in path. Contents of linked file included and used", "path", path, "resolved", resolved)

@ -90,6 +90,56 @@ func TestLoadDirWithSymlink(t *testing.T) {
verifyDependenciesLock(t, c)
}
func TestLoadDirWithBrokenSymlinkInHelmignore(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlink tests require unix")
}
tmpDir := t.TempDir()
// Create minimal chart structure
chartYAML := `apiVersion: v2
name: test
version: 0.1.0
`
valuesYAML := `{}
`
tpl := `config: {}
`
if err := os.WriteFile(filepath.Join(tmpDir, "Chart.yaml"), []byte(chartYAML), 0644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "values.yaml"), []byte(valuesYAML), 0644); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(tmpDir, "templates"), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "templates", "config.yaml"), []byte(tpl), 0644); err != nil {
t.Fatal(err)
}
// Create a broken symlink in templates/
brokenLink := filepath.Join(tmpDir, "templates", "broken")
if err := os.Symlink("nonexistent", brokenLink); err != nil {
t.Fatal(err)
}
// Add the broken symlink to .helmignore
if err := os.WriteFile(filepath.Join(tmpDir, ".helmignore"), []byte("templates/broken\n"), 0644); err != nil {
t.Fatal(err)
}
// Loading should succeed despite the broken symlink
l, err := Loader(tmpDir)
if err != nil {
t.Fatal(err)
}
if _, err := l.Load(); err != nil {
t.Fatalf("loading chart with broken symlink in .helmignore should not fail: %s", err)
}
}
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 {

Loading…
Cancel
Save