Skip to content

Commit 4d2ec68

Browse files
committed
implement docker trust as plugin
Just a quick experiment to see if we can move the `trust` subcommands to a plugin, so that the subcommands can be installed separate from the `docker trust` integration in push/pull (for situations where trust verification happens on the daemon side). make binary go build -o /usr/libexec/docker/cli-plugins/docker-trust ./cmd/docker-trust docker info Client: Version: 28.2.0-dev Context: default Debug Mode: false Plugins: buildx: Docker Buildx (Docker Inc.) Version: v0.24.0 Path: /usr/libexec/docker/cli-plugins/docker-buildx trust: Manage trust on Docker images (Docker Inc.) Version: unknown-version Path: /usr/libexec/docker/cli-plugins/docker-trust docker trust --help Usage: docker trust [OPTIONS] COMMAND Extended build capabilities with BuildKit Options: -D, --debug Enable debug logging Management Commands: key Manage keys for signing Docker images signer Manage entities who can sign Docker images Commands: inspect Return low-level information about keys and signatures revoke Remove trust for an image sign Sign an image Run 'docker trust COMMAND --help' for more information on a command. Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent 3302212 commit 4d2ec68

40 files changed

+163
-3
lines changed

cli/command/commands/commands.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/docker/cli/cli/command/stack"
2121
"github.com/docker/cli/cli/command/swarm"
2222
"github.com/docker/cli/cli/command/system"
23-
"github.com/docker/cli/cli/command/trust"
2423
"github.com/docker/cli/cli/command/volume"
2524
"github.com/spf13/cobra"
2625
)
@@ -53,7 +52,6 @@ func AddCommands(cmd *cobra.Command, dockerCli command.Cli) {
5352
network.NewNetworkCommand(dockerCli),
5453
plugin.NewPluginCommand(dockerCli),
5554
system.NewSystemCommand(dockerCli),
56-
trust.NewTrustCommand(dockerCli),
5755
volume.NewVolumeCommand(dockerCli),
5856

5957
// orchestration (swarm) commands

cmd/docker-trust/main.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/docker/cli/cli"
10+
"github.com/docker/cli/cli-plugins/metadata"
11+
"github.com/docker/cli/cli-plugins/plugin"
12+
"github.com/docker/cli/cli/command"
13+
"github.com/docker/cli/cli/version"
14+
"github.com/docker/cli/cmd/docker-trust/trust"
15+
"go.opentelemetry.io/otel"
16+
)
17+
18+
func runStandalone(cmd *command.DockerCli) error {
19+
defer flushMetrics(cmd)
20+
executable := os.Args[0]
21+
rootCmd := trust.NewRootCmd(filepath.Base(executable), false, cmd)
22+
return rootCmd.Execute()
23+
}
24+
25+
// flushMetrics will manually flush metrics from the configured
26+
// meter provider. This is needed when running in standalone mode
27+
// because the meter provider is initialized by the cli library,
28+
// but the mechanism for forcing it to report is not presently
29+
// exposed and not invoked when run in standalone mode.
30+
// There are plans to fix that in the next release, but this is
31+
// needed temporarily until the API for this is more thorough.
32+
func flushMetrics(cmd *command.DockerCli) {
33+
if mp, ok := cmd.MeterProvider().(command.MeterProvider); ok {
34+
if err := mp.ForceFlush(context.Background()); err != nil {
35+
otel.Handle(err)
36+
}
37+
}
38+
}
39+
40+
func runPlugin(cmd *command.DockerCli) error {
41+
rootCmd := trust.NewRootCmd("trust", true, cmd)
42+
return plugin.RunPlugin(cmd, rootCmd, metadata.Metadata{
43+
SchemaVersion: "0.1.0",
44+
Vendor: "Docker Inc.",
45+
Version: version.Version,
46+
})
47+
}
48+
49+
func run(cmd *command.DockerCli) error {
50+
if plugin.RunningStandalone() {
51+
return runStandalone(cmd)
52+
}
53+
return runPlugin(cmd)
54+
}
55+
56+
func main() {
57+
cmd, err := command.NewDockerCli()
58+
if err != nil {
59+
_, _ = fmt.Fprintln(os.Stderr, err)
60+
os.Exit(1)
61+
}
62+
63+
if err = run(cmd); err == nil {
64+
return
65+
}
66+
67+
// Check the error from the run function above.
68+
if sterr, ok := err.(cli.StatusError); ok {
69+
if sterr.Status != "" {
70+
_, _ = fmt.Fprintln(cmd.Err(), sterr.Status)
71+
}
72+
// StatusError should only be used for errors, and all errors should
73+
// have a non-zero exit status, so never exit with 0
74+
if sterr.StatusCode == 0 {
75+
os.Exit(1)
76+
}
77+
os.Exit(sterr.StatusCode)
78+
}
79+
80+
os.Exit(1)
81+
}

cmd/docker-trust/trust/commands.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package trust
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/docker/cli-docs-tool/annotation"
7+
"github.com/docker/cli/cli"
8+
"github.com/docker/cli/cli-plugins/plugin"
9+
"github.com/docker/cli/cli/command"
10+
"github.com/docker/cli/cli/debug"
11+
cliflags "github.com/docker/cli/cli/flags"
12+
"github.com/spf13/cobra"
13+
"github.com/spf13/pflag"
14+
)
15+
16+
func NewRootCmd(name string, isPlugin bool, dockerCLI *command.DockerCli) *cobra.Command {
17+
var opt rootOptions
18+
cmd := &cobra.Command{
19+
Use: name,
20+
Short: "Manage trust on Docker images",
21+
Long: `Extended build capabilities with BuildKit`,
22+
Annotations: map[string]string{
23+
annotation.CodeDelimiter: `"`,
24+
},
25+
CompletionOptions: cobra.CompletionOptions{
26+
HiddenDefaultCmd: true,
27+
},
28+
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
29+
if opt.debug {
30+
debug.Enable()
31+
}
32+
// cmd.SetContext(appcontext.Context())
33+
if !isPlugin {
34+
// InstallFlags and SetDefaultOptions are necessary to match
35+
// the plugin mode behavior to handle env vars such as
36+
// DOCKER_TLS, DOCKER_TLS_VERIFY, ... and we also need to use a
37+
// new flagset to avoid conflict with the global debug flag
38+
// that we already handle in the root command otherwise it
39+
// would panic.
40+
nflags := pflag.NewFlagSet(cmd.DisplayName(), pflag.ContinueOnError)
41+
options := cliflags.NewClientOptions()
42+
options.InstallFlags(nflags)
43+
options.SetDefaultOptions(nflags)
44+
return dockerCLI.Initialize(options)
45+
}
46+
return plugin.PersistentPreRunE(cmd, args)
47+
},
48+
RunE: func(cmd *cobra.Command, args []string) error {
49+
if len(args) == 0 {
50+
return cmd.Help()
51+
}
52+
_ = cmd.Help()
53+
return cli.StatusError{
54+
StatusCode: 1,
55+
Status: fmt.Sprintf("ERROR: unknown command: %q", args[0]),
56+
}
57+
},
58+
}
59+
if !isPlugin {
60+
// match plugin behavior for standalone mode
61+
// https://github.com/docker/cli/blob/6c9eb708fa6d17765d71965f90e1c59cea686ee9/cli-plugins/plugin/plugin.go#L117-L127
62+
cmd.SilenceUsage = true
63+
cmd.SilenceErrors = true
64+
cmd.TraverseChildren = true
65+
cmd.DisableFlagsInUseLine = true
66+
cli.DisableFlagsInUseLine(cmd)
67+
}
68+
69+
cmd.AddCommand(
70+
newRevokeCommand(dockerCLI),
71+
newSignCommand(dockerCLI),
72+
newTrustKeyCommand(dockerCLI),
73+
newTrustSignerCommand(dockerCLI),
74+
newInspectCommand(dockerCLI),
75+
)
76+
77+
return cmd
78+
}
79+
80+
type rootOptions struct {
81+
debug bool
82+
}

0 commit comments

Comments
 (0)