Commit Graph

26 Commits

Author SHA1 Message Date
Sebastiaan van Stijn 55a1f6eb73
cli-plugins/manager: add GoDoc for getPluginDirs, defaultSystemPluginDirs
Add some documentation about their purpose, and document order of preference
when resolving plugins.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-06-19 14:02:40 +02:00
Sebastiaan van Stijn 5ccb48459b
cli-plugins: PluginRunCommand: use cmd.Environ instead of os.Environ
Commit 5011759056 implemented a fix that
caused the current environment to be discarded, using `os.Environ()`.
On Windows, `os.Environ()` may produce an incorrect value for `PWD`,
for which a new function was added in go1.19;

- https://tip.golang.org/doc/go1.19#osexecpkgosexec
- https://go-review.googlesource.com/c/go/+/401340

Replace the use of `os.Environ()` with `cmd.Environ()` to address that.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-04-25 19:27:05 +02:00
Jonathan A. Sternberg 85dcacd78f
plugins: set OTEL_RESOURCE_ATTRIBUTES when invoking a plugin
When a plugin is invoked, the docker cli will now set
`OTEL_RESOURCE_ATTRIBUTES` to pass OTEL resource attribute names to the
plugin as additional resource attributes. At the moment, the only
resource attribute passed is `cobra.command_path`.

All resource attributes passed by the CLI are prepended with the
namespace `docker.cli` to avoid clashing with existing ones the plugin
uses or ones defined by the user.

For aliased commands like the various builder commands, the command path
is overwritten to match with the original name (such as `docker
builder`) instead of the forwarded name (such as `docker buildx build`).

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
2024-02-28 12:43:05 -08:00
Laura Brehm 26560ff93c
Revert "plugins: run plugin with new process group ID"
This reverts commit ef5e5fa03f.

Running new plugins under a new pgid isn't a viable solution due to
it causing issues with plugin processes attempting to read from the
TTY (see: https://github.com/moby/moby/issues/47073).

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
2024-01-15 13:30:01 +00:00
Sebastiaan van Stijn 688de6db16
Merge pull request #4769 from laurazard/signal-handling-fix-tty
plugins: run plugin with new process group ID
2024-01-12 22:06:23 +01:00
Laura Brehm ef5e5fa03f
plugins: run plugin with new process group ID
Changes were made in 1554ac3b5f to provide
a mechanism for the CLI to notify running plugin processes that they
should exit, in order to improve the general CLI/plugin UX. The current
implementation boils down to:
1. The CLI creates a socket
2. The CLI executes the plugin
3. The plugin connects to the socket
4. (When) the CLI receives a termination signal, it uses the socket to
   notify the plugin that it should exit
5. The plugin's gets notified via the socket, and cancels it's `cmd.Context`,
   which then gets handled appropriately

This change works in most cases and fixes the issue it sets out to solve
(see: https://github.com/docker/compose/pull/11292) however, in the case
where the user has a TTY attached and the plugin is not already handling
received signals, steps 4+ changes:
4. (When) the CLI receives a termination signal, before it can use the
   socket to notify the plugin that it should exit, the plugin process
   also receives a signal due to sharing the pgid with the CLI

Since we now have a proper "job control" mechanism, we can simplify the
scenarios by executing the plugins with their own process group id,
thereby removing the "double notification" issue and making it so that
plugins can handle the same whether attached to a TTY or not.

In order to make this change "plugin-binary" backwards-compatible, in
the case that a plugin does not connect to the socket, the CLI passes
the signal to the plugin process.

Co-authored-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
Signed-off-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
2024-01-12 13:53:28 -07:00
Sebastiaan van Stijn 4dc2c895b1
cli-plugins/manager: getPluginDirs: take ConfigFile as argument
Update this function to accept a smaller interface, as it doesn't need
all of "CLI".

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-11 18:15:30 +01:00
Sebastiaan van Stijn 4cf04988ae
remove uses of golang.org/x/sys/execabs
the "golang.org/x/sys/execabs" package was introduced to address a security
issue on Windows, and changing the default behavior of os/exec was considered
a breaking change. go1.19 applied the behavior that was previously implemented
in the execabs package;

from the release notes: https://go.dev/doc/go1.19#os-exec-path

> Command and LookPath no longer allow results from a PATH search to be found
> relative to the current directory. This removes a common source of security
> problems but may also break existing programs that depend on using, say,
> exec.Command("prog") to run a binary named prog (or, on Windows, prog.exe)
> in the current directory. See the os/exec package documentation for information
> about how best to update such programs.
>
> On Windows, Command and LookPath now respect the NoDefaultCurrentDirectoryInExePath
> environment variable, making it possible to disable the default implicit search
> of “.” in PATH lookups on Windows systems.

With those changes, we no longer need to use the execabs package, and we can
switch back to os/exec.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-05-26 02:03:45 +02:00
Kevin Alvarez 89583b92b7
improve plugins listing performance
We can slightly improve plugins listing by spawning a
goroutine for each iteration.

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-04-01 16:02:34 +02:00
CrazyMax e14f5fc1a7
revert "improve plugins discovery performance"
This reverts commit 62f2358b99.

Spawning a goroutine for each iteration in the loop when listing
plugins is racy unfortunately. `plugins` slice is protected with
a mutex so not sure why it fails.

I tried using a channel to collect the plugins instead of a slice
to guarantee that they will be appended to the list in the order
they are processed but no dice.

I also tried without errgroup package and simply use sync.WaitGroup
but same. I have also created an extra channel to receive errors
from the goroutines but racy too.

I think the change in this function is not related to the race
condition but newPlugin is. So revert in the meantime :(

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-03-31 16:20:42 +02:00
CrazyMax 62f2358b99
improve plugins discovery performance
We are currently loading plugin commands stubs for every
command invocation to add support for Cobra v2 completion.
This cause a significant performance hit if there is a
lot of plugins in the user space (7 atm in Docker Desktop):

`docker --version` takes in current 23.0.1 ~93ms

Instead of removing completion for plugins to fix the
regression, we can slightly improve plugins discovery by
spawning a goroutine for each iteration in the loop when
listing plugins:

`docker --version` now takes ~38ms

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2023-03-28 06:16:55 +02:00
Sebastiaan van Stijn 90f1238fb2
cli-plugins/manager: add IsPluginCommand(() utility
This makes it more convenient to check if a command is a plugin-stub

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-09-30 02:24:23 +02:00
Sebastiaan van Stijn 6c06950cdf
cli-plugins/manager: remove uses of deprecated io/ioutil
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-02-25 16:01:20 +01:00
CrazyMax 6fef143dbc
Set buildx as default builder
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
2022-02-03 10:38:05 +01:00
Tibor Vass 8d199d5bba Use golang.org/x/sys/execabs
On Windows, the os/exec.{Command,CommandContext,LookPath} functions
resolve command names that have neither path separators nor file extension
(e.g., "git") by first looking in the current working directory before
looking in the PATH environment variable.
Go maintainers intended to match cmd.exe's historical behavior.

However, this is pretty much never the intended behavior and as an abundance of precaution
this patch prevents that when executing commands.
Example of commands that docker.exe may execute: `git`, `docker-buildx` (or other cli plugin), `docker-credential-wincred`, `docker`.

Note that this was prompted by the [Go 1.15.7 security fixes](https://blog.golang.org/path-security), but unlike in `go.exe`,
the windows path lookups in docker are not in a code path allowing remote code execution, thus there is no security impact on docker.

Signed-off-by: Tibor Vass <tibor@docker.com>
2021-01-26 17:18:04 +00:00
Sebastiaan van Stijn 977d3ae046
Always enable experimental features
The CLI disabled experimental features by default, requiring users
to set a configuration option to enable them.

Disabling experimental features was a request from Enterprise users
that did not want experimental features to be accessible.

We are changing this policy, and now enable experimental features
by default. Experimental features may still change and/or removed,
and will be highlighted in the documentation and "usage" output.

For example, the `docker manifest inspect --help` output now shows:

    EXPERIMENTAL:
      docker manifest inspect is an experimental feature.

      Experimental features provide early access to product functionality. These features
      may change between releases without warning or can be removed entirely from a future
      release. Learn more about experimental features: https://docs.docker.com/go/experimental/

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-10-02 15:59:42 +02:00
Sebastiaan van Stijn 6703919c71
Replace vbom.ml/util with fvbommel/sortorder
The vanity domain is down, and the project has moved
to a new location.

vendor check started failing because of this:

    Collecting initial packages
    Download dependencies
    unrecognized import path "vbom.ml/util" (https fetch: Get https://vbom.ml/util?go-get=1: dial tcp: lookup vbom.ml on 169.254.169.254:53: no such host)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-08-28 15:35:42 +02:00
Sebastiaan van Stijn 54ba28f402
docker info: list CLI plugins alphabetically
Before this change, plugins were listed in a random order:

    Client:
     Debug Mode: false
     Plugins:
      doodle: Docker Doodles  all around! 🐳 🎃 (thaJeztah, v0.0.1)
      shell: Open a browser shell on the Docker Host. (thaJeztah, v0.0.1)
      app: Docker Application (Docker Inc., v0.8.0)
      buildx: Build with BuildKit (Docker Inc., v0.3.1-tp-docker)

With this change, plugins are listed alphabetically:

    Client:
     Debug Mode: false
     Plugins:
      app: Docker Application (Docker Inc., v0.8.0)
      buildx: Build with BuildKit (Docker Inc., v0.3.1-tp-docker)
      doodle: Docker Doodles  all around! 🐳 🎃 (thaJeztah, v0.0.1)
      shell: Open a browser shell on the Docker Host. (thaJeztah, v0.0.1)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2019-12-31 14:33:07 +01:00
Tibor Vass 6ca8783730 cli-plugins: add concept of experimental plugin, only enabled in experimental mode
To test, add $(pwd)/build/plugins-linux-amd64 to "cliPluginsExtraDirs" config and run:
make plugins
make binary
HELLO_EXPERIMENTAL=1 docker helloworld

To show it enabled:
HELLO_EXPERIMENTAL=1 DOCKER_CLI_EXPERIMENTAL=enabled docker helloworld

Signed-off-by: Tibor Vass <tibor@docker.com>
2019-05-22 15:35:34 +00:00
Tibor Vass 1ed02c40fe cli-plugins: alias an existing allowed command (only builder for now)
With this patch it is possible to alias an existing allowed command.
At the moment only builder allows an alias.

This also properly puts the build command under builder, instead of image
where it was for historical reasons.

Signed-off-by: Tibor Vass <tibor@docker.com>
2019-04-19 01:26:45 +00:00
Nick Adcock ff51b0d77d harden config.Path() to disallow directory traversal
Signed-off-by: Nick Adcock <nick.adcock@docker.com>
2019-03-07 14:40:53 +00:00
Ian Campbell 891b3d953e cli-plugins: use `docker system dial-stdio` to call the daemon
This means that plugins can use whatever methods the monolithic CLI supports,
which is good for consistency.

This relies on `os.Args[0]` being something which can be executed again to
reach the same binary, since it is propagated (via an envvar) to the plugin for
this purpose. This essentially requires that the current working directory and
path are not modified by the monolithic CLI before it launches the plugin nor
by the plugin before it initializes the client. This should be the case.

Previously the fake apiclient used by `TestExperimentalCLI` was not being used,
since `cli.Initialize` was unconditionally overwriting it with a real one
(talking to a real daemon during unit testing, it seems). This wasn't expected
nor desirable and no longer happens with the new arrangements, exposing the
fact that no `pingFunc` is provided, leading to a panic. Add a `pingFunc` to
the fake client to avoid this.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-02-18 11:53:37 +00:00
Ian Campbell 0a89eb554b Ensure plugins default search path obeys `--config`
A static global initialiser happens before the arguments are parsed, so we need
to calculate the path later.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:26 +00:00
Ian Campbell 63f3ad181b Refactor code which deals with Windows' `.exe` suffix
Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:45:26 +00:00
Ian Campbell f912b55bd1 Integrate CLI plugins into `docker help` output.
To do this we add a stub `cobra.Command` for each installed plugin (only when
invoking `help`, not for normal running).

This requires a function to list all available plugins so that is added here.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:44:06 +00:00
Ian Campbell f1f31abbe5 Add support for running a CLI plugin
Also includes the  scaffolding for finding a validating plugin candidates.

Argument validation is moved to RunE to support this, so `noArgs` is removed.

Signed-off-by: Ian Campbell <ijc@docker.com>
2019-01-30 13:44:04 +00:00