From ba536ec18e335048a83d4aee2ab52a655278e047 Mon Sep 17 00:00:00 2001 From: Arnav Nagzirkar <113314200+arnavnagzirkar@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:20:46 -0700 Subject: [PATCH] fix: resolve golangci-lint gofmt and staticcheck failures Move the //go:build !windows constraint in http_installer_test.go above the license header so gofmt accepts the file ordering. Use the promoted i.PluginsDirectory field in OCIInstaller.Path() instead of the explicit i.base.PluginsDirectory selector, satisfying staticcheck QF1008. While here, harden newBase() to skip empty HELM_PLUGINS segments (e.g. ':/path' or '/path:') so installation never targets a relative path, and add TestPathSkipsEmptyPluginDirs to cover it. Signed-off-by: Arnav Nagzirkar <113314200+arnavnagzirkar@users.noreply.github.com> --- internal/plugin/installer/base.go | 13 +++++++++---- internal/plugin/installer/base_test.go | 18 +++++++++++++++++- .../plugin/installer/http_installer_test.go | 4 ++-- internal/plugin/installer/oci_installer.go | 2 +- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/internal/plugin/installer/base.go b/internal/plugin/installer/base.go index 4ef7f2b29..1b2f5c8a9 100644 --- a/internal/plugin/installer/base.go +++ b/internal/plugin/installer/base.go @@ -30,11 +30,16 @@ type base struct { func newBase(source string) base { settings := cli.New() - // When HELM_PLUGINS contains a list of paths, use only the first one for - // installation so the plugin ends up in a directory that is actually searched. + // When HELM_PLUGINS contains a list of paths, install into the first non-empty + // entry so the plugin ends up in a directory that is actually searched. Skipping + // empty segments avoids installing into a relative path when HELM_PLUGINS contains + // entries like ":/path" or "/path:". pluginsDir := settings.PluginsDirectory - if dirs := filepath.SplitList(pluginsDir); len(dirs) > 0 { - pluginsDir = dirs[0] + for _, dir := range filepath.SplitList(pluginsDir) { + if dir != "" { + pluginsDir = dir + break + } } return base{ Source: source, diff --git a/internal/plugin/installer/base_test.go b/internal/plugin/installer/base_test.go index 8a1056605..9f6ade8fd 100644 --- a/internal/plugin/installer/base_test.go +++ b/internal/plugin/installer/base_test.go @@ -66,6 +66,22 @@ func TestPathEmptyPluginDir(t *testing.T) { // When HELM_PLUGINS is explicitly empty, newBase must not panic. t.Setenv("HELM_PLUGINS", "") b := newBase("https://github.com/jkroepke/helm-secrets") - // Path() returns "" when source is "" or PluginsDirectory is ""; just verify no panic. + // Path() only returns "" when Source is ""; with an empty PluginsDirectory it + // returns a relative path. Just verify no panic. _ = b.Path() } + +func TestPathSkipsEmptyPluginDirs(t *testing.T) { + // A leading empty segment (e.g. ":/real/path") must be skipped so the plugin is + // installed into the first real directory rather than a relative path. + real := filepath.FromSlash("/helm/data/plugins") + multiPath := string(filepath.ListSeparator) + real + + t.Setenv("HELM_PLUGINS", multiPath) + b := newBase("https://github.com/jkroepke/helm-secrets") + got := b.Path() + expected := filepath.Join(real, "helm-secrets") + if got != expected { + t.Errorf("expected path %s, got %s", expected, got) + } +} diff --git a/internal/plugin/installer/http_installer_test.go b/internal/plugin/installer/http_installer_test.go index a5fdfb399..a43f4d9d2 100644 --- a/internal/plugin/installer/http_installer_test.go +++ b/internal/plugin/installer/http_installer_test.go @@ -1,3 +1,5 @@ +//go:build !windows + /* Copyright The Helm Authors. Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,8 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -//go:build !windows - package installer // import "helm.sh/helm/v4/internal/plugin/installer" import ( diff --git a/internal/plugin/installer/oci_installer.go b/internal/plugin/installer/oci_installer.go index 0a522e555..f323c7aa7 100644 --- a/internal/plugin/installer/oci_installer.go +++ b/internal/plugin/installer/oci_installer.go @@ -190,7 +190,7 @@ func (i OCIInstaller) Path() string { if i.Source == "" { return "" } - return filepath.Join(i.base.PluginsDirectory, i.PluginName) + return filepath.Join(i.PluginsDirectory, i.PluginName) } // extractTarGz extracts a gzipped tar archive to a directory