diff --git a/cli-plugins/manager/manager.go b/cli-plugins/manager/manager.go index 48a0db34173d..8ca3354935eb 100644 --- a/cli-plugins/manager/manager.go +++ b/cli-plugins/manager/manager.go @@ -41,9 +41,8 @@ func (e errPluginNotFound) Error() string { // [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs func getPluginDirs(cfg *configfile.ConfigFile) []string { var pluginDirs []string - if cfg != nil { - pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...) + pluginDirs = append(pluginDirs, expandEnvVars(cfg.CLIPluginsExtraDirs)...) } pluginDir := filepath.Join(config.Dir(), "cli-plugins") pluginDirs = append(pluginDirs, pluginDir) @@ -51,6 +50,15 @@ func getPluginDirs(cfg *configfile.ConfigFile) []string { return pluginDirs } +// Resolve statements like $HOME in plugin directory paths +func expandEnvVars(pluginDirs []string) []string { + var replacedPluginDirs []string + for _, dir := range pluginDirs { + replacedPluginDirs = append(replacedPluginDirs, os.ExpandEnv(dir)) + } + return replacedPluginDirs +} + func addPluginCandidatesFromDir(res map[string][]string, d string) { dentries, err := os.ReadDir(d) // Silently ignore any directories which we cannot list (e.g. due to diff --git a/cli-plugins/manager/manager_test.go b/cli-plugins/manager/manager_test.go index 16c43b29d338..ae279c69ce0a 100644 --- a/cli-plugins/manager/manager_test.go +++ b/cli-plugins/manager/manager_test.go @@ -86,6 +86,30 @@ func TestListPluginCandidatesEmpty(t *testing.T) { assert.Assert(t, len(candidates) == 0) } +func TestPluginDirEnvironmentVariableExpansion(t *testing.T) { + pluginDir := "plugins1" + t.Setenv("MY_PLUGIN_DIR", pluginDir) + dir := fs.NewDir(t, t.Name(), + fs.WithDir("${MY_PLUGIN_DIR}", + fs.WithFile("docker-plugin1", ""), + ), + ) + defer dir.Remove() + + t.Setenv("DOCKER_CLI_E2E_PLUGINS_EXTRA_DIRS", dir.Join(pluginDir)) + + cli := test.NewFakeCli(nil) + cli.SetConfigFile(&configfile.ConfigFile{CLIPluginsExtraDirs: []string{"$DOCKER_CLI_E2E_PLUGINS_EXTRA_DIRS"}}) + + pluginDirs := getPluginDirs(cli.ConfigFile()) + expected := []string{ + dir.Join(pluginDir), + filepath.Join(config.Dir(), "cli-plugins"), + } + expected = append(expected, defaultSystemPluginDirs...) + assert.DeepEqual(t, expected, pluginDirs) +} + // Regression test for https://github.com/docker/cli/issues/5643. // Check that inaccessible directories that come before accessible ones are ignored // and do not prevent the latter from being processed.