Skip to content

cmd/docker: Add --cloud with configurable context resolution - #7343

Merged
thaJeztah merged 3 commits into
docker:masterfrom
vvoland:work-cloud
Oct 1, 2026
Merged

thaJeztah merged 3 commits into
docker:masterfrom
vvoland:work-cloud

Conversation

@vvoland

@vvoland vvoland commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Resolve it through the offload plugin by default, with a provider override in features.cloud in the Docker config.

Require the selected plugin to advertise CloudContextResolver in its metadata before showing the flag in help and completion or invoking its __resolve-context operation.

Resolve before client initialization without wrapping or re-executing Docker.

Forward --context to downstream plugins so they need not support --cloud or repeat provisioning.
Skip provisioning for help, version, and completion requests.

Summary

Release notes (optional)

A picture of a cute animal (not mandatory but encouraged)

@vvoland vvoland added this to the 29.9.0 milestone Oct 1, 2026
Comment thread cli-plugins/metadata/metadata.go Outdated
@codecov-commenter

codecov-commenter commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.47368% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/docker/cloud.go 87.03% 8 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

Comment thread cmd/docker/cloud.go Outdated

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

Lower-confidence findings (not posted inline)

  • [medium] cmd/docker/docker.go:514 — os.Args mutated globally before tcmd.Initialize(), affecting processAliases (confidence: weak 52/100)

Comment thread cmd/docker/cloud.go
Comment thread cmd/docker/cloud.go Outdated
Comment thread cmd/docker/cloud.go Outdated
Comment thread cmd/docker/cloud.go
Plugins had no generic way to declare support for optional CLI
contracts, so each one would need its own top-level metadata field.

Add Features, keyed by feature name. Values are arbitrary JSON so a
feature can carry more than a boolean.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Callers that choose the context from configuration had to do it before
Initialize. That meant loading the config file and context store
themselves and handling --config a second time.

WithContextResolver runs a callback inside Initialize after the config
file and context store are loaded, but before telemetry and endpoint
initialization. A non-empty result replaces the selected context, an
empty result keeps normal selection, and an error aborts
initialization.

The API client and endpoint are resolved lazily, so they use the
overridden context.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Nested plugin help requests can unexpectedly provision a context or fail before displaying help.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds configurable cloud-context resolution before Docker client initialization.

Changes:

  • Adds --cloud with plugin capability discovery and context provisioning.
  • Forwards resolved contexts to downstream plugins.
  • Adds resolver metadata, initialization hooks, and integration tests.
File Description
cmd/​docker/​docker.go Integrates cloud resolution into startup and help.
cmd/​docker/​cloud.go Implements provider discovery, resolution, and argument rewriting.
cmd/​docker/​cloud_test.go Tests cloud resolution and plugin forwarding.
cli/​command/​cli.go Runs context resolvers during initialization.
cli/​command/​cli_test.go Tests resolver initialization behavior.
cli/​command/​cli_options.go Adds the context-resolver option.
cli-plugins/​metadata/​metadata.go Adds plugin feature metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/docker/cloud.go
Comment on lines +192 to +195
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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah not sure theres a better way. We can't just scan the whole command line.. what about something like compose run web some-command--help ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's a good way around this due to the early context resolution that needs to happen before invoking the plugin. We could do a naive/full scan for --help and skip context resolution entirely perhaps?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-h might be too broad. For --help that would break for usages where for example you call a container with a cmd that involves --help (although thats probably a big edge case).

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

Lower-confidence findings (not posted inline)

  • [low] cmd/docker/docker.go:519 — WithContextResolver callback mutates os.Args as a global side-effect before returning (confidence: weak 52/100)
  • [low] cmd/docker/cloud.go:195 — cloudHelpRequest returns false for a single unknown subcommand, causing cloud provisioning for invalid commands (confidence: weak 52/100)

Dismissed security findings (review manually)

  • cmd/docker/cloud.go:135 — Plugin executable path from discovery used in exec.CommandContext with #nosec G204 suppression (verifier mitigation: consistent with the existing docker CLI plugin execution model; all plugins execute user-installed binaries with the same trust level; the extra cloudResolverFeature metadata check adds an additional validation step)

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

Lower-confidence findings (not posted inline)

  • [low] cmd/docker/cloud.go:221 — cloudPluginArgs shares *pflag.Flag pointers via AddFlagSet, so ParseAll sets Changed=true on the original root command's flags; notably --cloud is parsed but excluded from the rewritten os.Args, so it remains Changed=true on the root command's actual FlagSet after cobra re-parses (cobra never resets Changed, only sets it). In practice this is benign since no code between cloudPluginArgs and cmd.ExecuteContext reads root-flag Changed state — but it is a latent inconsistency. (confidence: 🟠 weak 52/100)

@vvoland
vvoland marked this pull request as ready for review October 1, 2026 17:19

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

Comment thread cmd/docker/cloud.go Outdated
thaJeztah
thaJeztah previously approved these changes Oct 1, 2026

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vvoland
vvoland requested review from docker-agent and a balanced review from Copilot October 1, 2026 17:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Invalid typed command flags can trigger cloud provisioning before Cobra rejects them.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

Comment thread cmd/docker/cloud.go
Comment on lines +207 to +214
err = flags.ParseAll(remaining, func(flag *pflag.Flag, value string) error {
if flag.Name == "help" {
var err error
if help, err = strconv.ParseBool(value); err != nil {
return fmt.Errorf("invalid argument %q for \"--help\" flag: %w", value, err)
}
}
return nil

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

Comment thread cmd/docker/cloud.go Outdated
Comment thread cmd/docker/cloud.go
Comment thread cmd/docker/cloud.go
Resolve it through the offload plugin by default, with a provider
override in features.cloud in the Docker config.

Require the selected plugin to declare the cloud-context-resolver
feature in its metadata before showing the flag in help and completion
or invoking its __resolve-context operation.

Resolve through WithContextResolver, after the config file and context
store are loaded but before client initialization, without wrapping or
re-executing Docker.

Forward --context to downstream plugins so they need not support
--cloud or repeat provisioning. Skip provisioning for help, version,
and completion requests. Report unknown flags and missing flag values
before provisioning, so a mistyped invocation fails without creating
cloud resources or contacting the engine selected before resolution.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation satisfies the described resolver contract and includes broad coverage of success and failure paths.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

Comment thread cmd/docker/cloud.go
@vvoland
vvoland requested a review from thaJeztah October 1, 2026 18:42

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

Comment thread cmd/docker/docker.go
command.WithEnableGlobalTracerProvider(),
command.WithContextResolver(func(cli *command.DockerCli) (string, error) {
var err error
os.Args, err = processCloud(ctx, cli, cmd, args, os.Args)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[medium] os.Args is mutated inside the WithContextResolver callback; mutation survives if processCloud returns (modifiedArgs, error)

In Go, a multi-return assignment os.Args, err = processCloud(...) always assigns both return values simultaneously. If processCloud returns a partially-rewritten args slice and a non-nil error, the callback returns ("", err), causing Initialize to return that error — but os.Args is already overwritten with the mutated value. The caller in runDocker propagates the error upward and exits, leaving the process-wide os.Args permanently modified.

Because os.Args is a package-level global, any code or goroutine that reads it after the callback fires (including shell-completion paths or signal handlers) sees the rewritten form even when the --cloud operation ultimately failed.

The standard Go idiom is to keep the original value and only commit the change after success:

Suggested change
os.Args, err = processCloud(ctx, cli, cmd, args, os.Args)
newArgs, err := processCloud(ctx, cli, cmd, args, os.Args)
if err != nil {
return "", err
}
os.Args = newArgs
Confidence Score
🟡 moderate 75/100

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically correct, but I think it's fine to ignore this one; if an error happens, it's a fail

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thaJeztah
thaJeztah merged commit cd7b908 into docker:master Oct 1, 2026
101 of 102 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants