diff --git a/private/buf/cmd/buf/command/alpha/plugin/pluginpush/pluginpush.go b/private/buf/cmd/buf/command/alpha/plugin/pluginpush/pluginpush.go index a4d2cfd654..b06363b20a 100644 --- a/private/buf/cmd/buf/command/alpha/plugin/pluginpush/pluginpush.go +++ b/private/buf/cmd/buf/command/alpha/plugin/pluginpush/pluginpush.go @@ -188,7 +188,7 @@ func run( if err != nil { return err } - client, err := bufplugindocker.NewClient(container.Logger()) + client, err := bufplugindocker.NewClient(container.Logger(), bufcli.Version) if err != nil { return err } diff --git a/private/bufpkg/bufplugin/bufplugindocker/docker.go b/private/bufpkg/bufplugin/bufplugindocker/docker.go index db0b59ef12..5396e446c1 100644 --- a/private/bufpkg/bufplugin/bufplugindocker/docker.go +++ b/private/bufpkg/bufplugin/bufplugindocker/docker.go @@ -35,6 +35,15 @@ import ( const ( // PluginsImagePrefix is used to prefix all image names with the correct path for pushing to the OCI registry. PluginsImagePrefix = "plugins." + + // Setting this value on the buf docker client allows us to propagate a custom + // value to the OCI registry. This is a useful property that enables registries + // to differentiate between the buf cli vs other tools like docker cli. + // Note, this does not override the final User-Agent entirely, but instead adds + // the value to the final outgoing User-Agent value in the form: [docker client's UA] UpstreamClient(buf-cli-1.11.0) + // + // Example: User-Agent = [docker/20.10.21 go/go1.18.7 git-commit/3056208 kernel/5.15.49-linuxkit os/linux arch/arm64 UpstreamClient(buf-cli-1.11.0)] + BufUpstreamClientUserAgentPrefix = "buf-cli-" ) // Client is a small abstraction over a Docker API client, providing the basic APIs we need to build plugins. @@ -203,7 +212,7 @@ func (d *dockerAPIClient) Close() error { } // NewClient creates a new Client to use to build Docker plugins. -func NewClient(logger *zap.Logger, options ...ClientOption) (Client, error) { +func NewClient(logger *zap.Logger, cliVersion string, options ...ClientOption) (Client, error) { if logger == nil { return nil, errors.New("logger required") } @@ -211,7 +220,12 @@ func NewClient(logger *zap.Logger, options ...ClientOption) (Client, error) { for _, option := range options { option(opts) } - dockerClientOpts := []client.Opt{client.FromEnv} + dockerClientOpts := []client.Opt{ + client.FromEnv, + client.WithHTTPHeaders(map[string]string{ + "User-Agent": BufUpstreamClientUserAgentPrefix + cliVersion, + }), + } if len(opts.host) > 0 { dockerClientOpts = append(dockerClientOpts, client.WithHost(opts.host)) } diff --git a/private/bufpkg/bufplugin/bufplugindocker/docker_test.go b/private/bufpkg/bufplugin/bufplugindocker/docker_test.go index 81dcc45dfe..610e6a9edf 100644 --- a/private/bufpkg/bufplugin/bufplugindocker/docker_test.go +++ b/private/bufpkg/bufplugin/bufplugindocker/docker_test.go @@ -113,7 +113,7 @@ func createClient(t testing.TB, options ...ClientOption) Client { t.Helper() logger, err := zap.NewDevelopment() require.Nilf(t, err, "failed to create zap logger") - dockerClient, err := NewClient(logger, options...) + dockerClient, err := NewClient(logger, "buf-cli-1.11.0", options...) require.Nilf(t, err, "failed to create client") t.Cleanup(func() { if err := dockerClient.Close(); err != nil {