From 52752f3aa246d4a84a4da6768119fd0a95b52d68 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 6 May 2025 15:05:06 +0200 Subject: [PATCH] inspect: improve (flag) validation Produce an error if the `--type` flag was set, but an empty value was passed. Before this patch: docker inspect --type "" foo # json output docker inspect --type unknown foo "unknown" is not a valid value for --type With this patch: docker inspect --type "" foo type is empty: must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume" docker inspect --type unknown foo unknown type: "unknown": must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume" Signed-off-by: Sebastiaan van Stijn --- cli/command/system/inspect.go | 5 +++- cli/command/system/inspect_test.go | 48 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 cli/command/system/inspect_test.go diff --git a/cli/command/system/inspect.go b/cli/command/system/inspect.go index 389edf148a..9cbca4c421 100644 --- a/cli/command/system/inspect.go +++ b/cli/command/system/inspect.go @@ -69,6 +69,9 @@ func NewInspectCommand(dockerCli command.Cli) *cobra.Command { Args: cli.RequiresMinArgs(1), RunE: func(cmd *cobra.Command, args []string) error { opts.ids = args + if cmd.Flags().Changed("type") && opts.objectType == "" { + return fmt.Errorf(`type is empty: must be one of "%s"`, strings.Join(allTypes, `", "`)) + } return runInspect(cmd.Context(), dockerCli, opts) }, // TODO(thaJeztah): should we consider adding completion for common object-types? (images, containers?) @@ -97,7 +100,7 @@ func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) typePlugin, typeSecret, typeService, typeTask, typeVolume: elementSearcher = inspectAll(ctx, dockerCli, opts.size, opts.objectType) default: - return errors.Errorf("%q is not a valid value for --type", opts.objectType) + return errors.Errorf(`unknown type: %q: must be one of "%s"`, opts.objectType, strings.Join(allTypes, `", "`)) } return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher) } diff --git a/cli/command/system/inspect_test.go b/cli/command/system/inspect_test.go new file mode 100644 index 0000000000..56ad5fd5b5 --- /dev/null +++ b/cli/command/system/inspect_test.go @@ -0,0 +1,48 @@ +package system + +import ( + "io" + "testing" + + "github.com/docker/cli/internal/test" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestInspectValidateFlagsAndArgs(t *testing.T) { + for _, tc := range []struct { + name string + args []string + expectedErr string + }{ + { + name: "empty type", + args: []string{"--type", "", "something"}, + expectedErr: `type is empty: must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`, + }, + { + name: "unknown type", + args: []string{"--type", "unknown", "something"}, + expectedErr: `unknown type: "unknown": must be one of "config", "container", "image", "network", "node", "plugin", "secret", "service", "task", "volume"`, + }, + { + name: "no arg", + args: []string{}, + expectedErr: `inspect: 'inspect' requires at least 1 argument`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + cmd := NewInspectCommand(test.NewFakeCli(&fakeClient{})) + cmd.SetOut(io.Discard) + cmd.SetErr(io.Discard) + cmd.SetArgs(tc.args) + + err := cmd.Execute() + if tc.expectedErr != "" { + assert.Check(t, is.ErrorContains(err, tc.expectedErr)) + } else { + assert.Check(t, is.Nil(err)) + } + }) + } +}