diff --git a/cli/command/completion/functions.go b/cli/command/completion/functions.go index 7777cb84278c..b395850b45b9 100644 --- a/cli/command/completion/functions.go +++ b/cli/command/completion/functions.go @@ -2,6 +2,7 @@ package completion import ( "os" + "strings" "github.com/docker/cli/cli/command/formatter" "github.com/docker/docker/api/types/container" @@ -105,6 +106,29 @@ func NetworkNames(dockerCLI APIClientProvider) ValidArgsFn { } } +// EnvVarNames offers completion for environment-variable names. This +// completion can be used for "--env" and "--build-arg" flags, which +// allow obtaining the value of the given environment-variable if present +// in the local environment, so we only should complete the names of the +// environment variables, and not their value. This also prevents the +// completion script from printing values of environment variables +// containing sensitive values. +// +// For example; +// +// export MY_VAR=hello +// docker run --rm --env MY_VAR alpine printenv MY_VAR +// hello +func EnvVarNames(_ *cobra.Command, _ []string, _ string) (names []string, _ cobra.ShellCompDirective) { + envs := os.Environ() + names = make([]string, 0, len(envs)) + for _, env := range envs { + name, _, _ := strings.Cut(env, "=") + names = append(names, name) + } + return names, cobra.ShellCompDirectiveNoFileComp +} + // FileNames is a convenience function to use [cobra.ShellCompDirectiveDefault], // which indicates to let the shell perform its default behavior after // completions have been provided. diff --git a/cli/command/container/exec.go b/cli/command/container/exec.go index 1f5506ae2a7d..c2a1d447998b 100644 --- a/cli/command/container/exec.go +++ b/cli/command/container/exec.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "os" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -78,9 +77,7 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command { flags.StringVarP(&options.Workdir, "workdir", "w", "", "Working directory inside the container") flags.SetAnnotation("workdir", "version", []string{"1.35"}) - _ = cmd.RegisterFlagCompletionFunc("env", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { - return os.Environ(), cobra.ShellCompDirectiveNoFileComp - }) + _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames) _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames) return cmd diff --git a/cli/command/container/run.go b/cli/command/container/run.go index 32a6284bdc23..704ce159de36 100644 --- a/cli/command/container/run.go +++ b/cli/command/container/run.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "os" "strings" "syscall" @@ -70,9 +69,7 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command { command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled()) copts = addFlags(flags) - _ = cmd.RegisterFlagCompletionFunc("env", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { - return os.Environ(), cobra.ShellCompDirectiveNoFileComp - }) + _ = cmd.RegisterFlagCompletionFunc("env", completion.EnvVarNames) _ = cmd.RegisterFlagCompletionFunc("env-file", completion.FileNames) _ = cmd.RegisterFlagCompletionFunc("network", completion.NetworkNames(dockerCli)) return cmd