From 9e66f55d23a4614718c1d94ec1ff765fd97f1c66 Mon Sep 17 00:00:00 2001 From: Shane Starcher Date: Mon, 22 Jun 2026 18:59:18 -0400 Subject: [PATCH] fix: resolve symlinked plugin directories in GetPluginVersion (#2661) In nix/devbox environments, helm plugin directories are typically symlinks into the Nix store. GetPluginVersion used entry.IsDir() which does not follow symlinks, causing the plugin to be reported as not installed. Follow symlinks with os.Stat before skipping non-directory entries. Signed-off-by: Shane Starcher Co-authored-by: Shane Starcher Co-authored-by: Claude Opus 4.6 --- pkg/helmexec/exec.go | 9 ++++++++- pkg/helmexec/exec_test.go | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/helmexec/exec.go b/pkg/helmexec/exec.go index 59e18c6c..dd6edea7 100644 --- a/pkg/helmexec/exec.go +++ b/pkg/helmexec/exec.go @@ -141,7 +141,14 @@ func GetPluginVersion(name, pluginsDir string) (*semver.Version, error) { } for _, entry := range entries { - if !entry.IsDir() { + isDir := entry.IsDir() + if !isDir && entry.Type()&os.ModeSymlink != 0 { + info, err := os.Stat(filepath.Join(dir, entry.Name())) + if err == nil { + isDir = info.IsDir() + } + } + if !isDir { continue } diff --git a/pkg/helmexec/exec_test.go b/pkg/helmexec/exec_test.go index 2be59612..27e609c4 100644 --- a/pkg/helmexec/exec_test.go +++ b/pkg/helmexec/exec_test.go @@ -1402,6 +1402,27 @@ func Test_GetPluginVersion_XDGPaths(t *testing.T) { assert.Contains(t, err.Error(), "plugin nonexistent-plugin not installed") } +func Test_GetPluginVersion_Symlink(t *testing.T) { + // Simulate a nix/devbox environment where the plugin directory is a symlink + tmpDir := t.TempDir() + + // Create a real plugin directory with plugin.yaml + realPluginDir := filepath.Join(tmpDir, "real", "helm-diff") + require.NoError(t, os.MkdirAll(realPluginDir, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(realPluginDir, "plugin.yaml"), []byte(`name: "diff" +version: "3.12.0" +`), 0o644)) + + // Create a plugins directory where helm-diff is a symlink (like nix/devbox) + symlinkPluginsDir := filepath.Join(tmpDir, "plugins") + require.NoError(t, os.MkdirAll(symlinkPluginsDir, 0o755)) + require.NoError(t, os.Symlink(realPluginDir, filepath.Join(symlinkPluginsDir, "helm-diff"))) + + version, err := GetPluginVersion("diff", symlinkPluginsDir) + require.NoError(t, err) + assert.Equal(t, "3.12.0", version.String()) +} + func Test_GetVersion(t *testing.T) { helm2Runner := mockRunner{output: []byte("Client: v2.16.1+ge13bc94\n")} helm, err := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)