From 6cb63efe6f0df2dc8b5658404edc6d7c0ad8ed96 Mon Sep 17 00:00:00 2001 From: Nick Sieger Date: Fri, 2 Oct 2026 16:45:34 -0500 Subject: [PATCH] fix(cli): recognize build/bake/builder aliasing before cloud help check docker --cloud build rejected every BuildKit-only flag (--secret, --ssh, --push, --output, ...) because cloudHelpRequest parsed remaining args against the legacy build command's flag set before processAliases rewrites build into a buildx invocation. Treat build/bake/builder/image build the same as plugin commands: only recognize --help/-h immediately after the resolved command path instead of validating flags. Fixes #7350 Signed-off-by: Nick Sieger --- cmd/docker/cloud.go | 18 +++++++++++++++++- cmd/docker/cloud_test.go | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmd/docker/cloud.go b/cmd/docker/cloud.go index f2a127bb4219..72a37bd44d5b 100644 --- a/cmd/docker/cloud.go +++ b/cmd/docker/cloud.go @@ -199,7 +199,17 @@ func cloudHelpRequest(rootCmd *cobra.Command, args []string) (bool, error) { if err != nil || cmd == rootCmd || pluginmanager.IsPluginCommand(cmd) { // Plugin flags are opaque. Only recognize help immediately after the // plugin name; deeper help is available through "docker help PLUGIN". - return len(args) > 1 && (args[1] == "--help" || args[1] == "-h" || args[1] == "--help=true"), nil + return len(args) > 1 && isHelpFlag(args[1]), nil + } + + // "build", "bake", "builder", and "image build" are builtin commands that + // processAliases may still rewrite into a call to the builder plugin + // (buildx) after cloud resolution runs, so their flag set here is only the + // legacy builder's and does not reflect what will actually parse the + // remaining args. Treat them like a plugin command above: only recognize + // help immediately after the resolved command path. + if _, _, _, forwarded := forwardBuilder(builderDefaultPlugin, args, args); forwarded { + return len(remaining) > 0 && isHelpFlag(remaining[0]), nil } cmd.InitDefaultHelpFlag() @@ -226,6 +236,12 @@ func cloudHelpRequest(rootCmd *cobra.Command, args []string) (bool, error) { return help, nil } +// isHelpFlag reports whether arg requests help, in any of the forms pflag +// accepts for a boolean flag. +func isHelpFlag(arg string) bool { + return arg == "--help" || arg == "-h" || arg == "--help=true" +} + // cloudPluginArgs only rewrites the global prefix, leaving subcommand arguments // untouched. Parsing also distinguishes --cloud from another flag's value. func cloudPluginArgs(cmd *cobra.Command, osArgs []string, contextName string) ([]string, error) { diff --git a/cmd/docker/cloud_test.go b/cmd/docker/cloud_test.go index f1ce8a60a840..9f6b1ab463d5 100644 --- a/cmd/docker/cloud_test.go +++ b/cmd/docker/cloud_test.go @@ -62,6 +62,11 @@ func TestCloudHelpRequest(t *testing.T) { {name: "container help", args: []string{"run", "alpine", "--help"}}, {name: "flag value", args: []string{"run", "--name", "--help", "alpine"}}, {name: "help disabled", args: []string{"run", "--help=false", "alpine"}}, + {name: "build help", args: []string{"build", "--help"}, help: true}, + {name: "build buildkit-only flag", args: []string{"build", "--secret", "id=s,src=./s", "."}}, + {name: "image build buildkit-only flag", args: []string{"image", "build", "--push", "."}}, + {name: "builder build buildkit-only flag", args: []string{"builder", "build", "--ssh", "default", "."}}, + {name: "bake help", args: []string{"bake", "--help"}, help: true}, } { t.Run(tc.name, func(t *testing.T) { dockerCli, err := command.NewDockerCli()