mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	Merge pull request #3071 from thaJeztah/bump_engine_28.0.2
vendor: github.com/docker/docker, docker/cli v28.0.2
This commit is contained in:
		@@ -11,7 +11,7 @@ import (
 | 
			
		||||
	"github.com/docker/buildx/util/desktop"
 | 
			
		||||
	"github.com/docker/buildx/version"
 | 
			
		||||
	"github.com/docker/cli/cli"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/manager"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/metadata"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/plugin"
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/docker/cli/cli/debug"
 | 
			
		||||
@@ -64,7 +64,7 @@ func flushMetrics(cmd *command.DockerCli) {
 | 
			
		||||
 | 
			
		||||
func runPlugin(cmd *command.DockerCli) error {
 | 
			
		||||
	rootCmd := commands.NewRootCmd("buildx", true, cmd)
 | 
			
		||||
	return plugin.RunPlugin(cmd, rootCmd, manager.Metadata{
 | 
			
		||||
	return plugin.RunPlugin(cmd, rootCmd, metadata.Metadata{
 | 
			
		||||
		SchemaVersion: "0.1.0",
 | 
			
		||||
		Vendor:        "Docker Inc.",
 | 
			
		||||
		Version:       version.Version,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								go.mod
									
									
									
									
									
								
							@@ -8,7 +8,7 @@ require (
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/config v1.27.27
 | 
			
		||||
	github.com/compose-spec/compose-go/v2 v2.4.8
 | 
			
		||||
	github.com/containerd/console v1.0.4
 | 
			
		||||
	github.com/containerd/containerd/v2 v2.0.3
 | 
			
		||||
	github.com/containerd/containerd/v2 v2.0.4
 | 
			
		||||
	github.com/containerd/continuity v0.4.5
 | 
			
		||||
	github.com/containerd/errdefs v1.0.0
 | 
			
		||||
	github.com/containerd/log v0.1.0
 | 
			
		||||
@@ -17,9 +17,9 @@ require (
 | 
			
		||||
	github.com/creack/pty v1.1.24
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1
 | 
			
		||||
	github.com/distribution/reference v0.6.0
 | 
			
		||||
	github.com/docker/cli v28.0.1+incompatible
 | 
			
		||||
	github.com/docker/cli v28.0.2+incompatible
 | 
			
		||||
	github.com/docker/cli-docs-tool v0.9.0
 | 
			
		||||
	github.com/docker/docker v28.0.1+incompatible
 | 
			
		||||
	github.com/docker/docker v28.0.2+incompatible
 | 
			
		||||
	github.com/docker/go-units v0.5.0
 | 
			
		||||
	github.com/gofrs/flock v0.12.1
 | 
			
		||||
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.sum
									
									
									
									
									
								
							@@ -85,8 +85,8 @@ github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn
 | 
			
		||||
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
 | 
			
		||||
github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0=
 | 
			
		||||
github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
 | 
			
		||||
github.com/containerd/containerd/v2 v2.0.3 h1:zBKgwgZsuu+LPCMzCLgA4sC4MiZzZ59ZT31XkmiISQM=
 | 
			
		||||
github.com/containerd/containerd/v2 v2.0.3/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY=
 | 
			
		||||
github.com/containerd/containerd/v2 v2.0.4 h1:+r7yJMwhTfMm3CDyiBjMBQO8a9CTBxL2Bg/JtqtIwB8=
 | 
			
		||||
github.com/containerd/containerd/v2 v2.0.4/go.mod h1:5j9QUUaV/cy9ZeAx4S+8n9ffpf+iYnEj4jiExgcbuLY=
 | 
			
		||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
 | 
			
		||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
 | 
			
		||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
 | 
			
		||||
@@ -122,15 +122,15 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 | 
			
		||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 | 
			
		||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 | 
			
		||||
github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs=
 | 
			
		||||
github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
			
		||||
github.com/docker/cli v28.0.2+incompatible h1:cRPZ77FK3/IXTAIQQj1vmhlxiLS5m+MIUDwS6f57lrE=
 | 
			
		||||
github.com/docker/cli v28.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
			
		||||
github.com/docker/cli-docs-tool v0.9.0 h1:CVwQbE+ZziwlPqrJ7LRyUF6GvCA+6gj7MTCsayaK9t0=
 | 
			
		||||
github.com/docker/cli-docs-tool v0.9.0/go.mod h1:ClrwlNW+UioiRyH9GiAOe1o3J/TsY3Tr1ipoypjAUtc=
 | 
			
		||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
			
		||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 | 
			
		||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
			
		||||
github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0=
 | 
			
		||||
github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
			
		||||
github.com/docker/docker v28.0.2+incompatible h1:9BILleFwug5FSSqWBgVevgL3ewDJfWWWyZVqlDMttE8=
 | 
			
		||||
github.com/docker/docker v28.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
			
		||||
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
 | 
			
		||||
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
 | 
			
		||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/containerd/containerd/v2/core/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/containerd/containerd/v2/core/images/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -369,8 +369,8 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return append([]ocispec.Descriptor{}, index.Manifests...), nil
 | 
			
		||||
	} else if !IsLayerType(desc.MediaType) && !IsKnownConfig(desc.MediaType) {
 | 
			
		||||
		// Layers and configs are childless data types and should not be logged.
 | 
			
		||||
	} else if !IsLayerType(desc.MediaType) && !IsKnownConfig(desc.MediaType) && !IsAttestationType(desc.MediaType) {
 | 
			
		||||
		// Layers, configs, and attestations are childless data types and should not be logged.
 | 
			
		||||
		log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType)
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/containerd/containerd/v2/core/images/mediatypes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -58,6 +58,9 @@ const (
 | 
			
		||||
 | 
			
		||||
	MediaTypeImageLayerEncrypted     = ocispec.MediaTypeImageLayer + "+encrypted"
 | 
			
		||||
	MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted"
 | 
			
		||||
 | 
			
		||||
	// In-toto attestation
 | 
			
		||||
	MediaTypeInToto = "application/vnd.in-toto+json"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DiffCompression returns the compression as defined by the layer diff media
 | 
			
		||||
@@ -193,6 +196,16 @@ func IsKnownConfig(mt string) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsAttestationType returns true if the media type is an attestation type
 | 
			
		||||
func IsAttestationType(mt string) bool {
 | 
			
		||||
	switch mt {
 | 
			
		||||
	case MediaTypeInToto:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChildGCLabels returns the label for a given descriptor to reference it
 | 
			
		||||
func ChildGCLabels(desc ocispec.Descriptor) []string {
 | 
			
		||||
	mt := desc.MediaType
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/containerd/v2/core/remotes/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -80,6 +80,8 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
 | 
			
		||||
		return "layer-" + key
 | 
			
		||||
	case images.IsKnownConfig(desc.MediaType):
 | 
			
		||||
		return "config-" + key
 | 
			
		||||
	case images.IsAttestationType(desc.MediaType):
 | 
			
		||||
		return "attestation-" + key
 | 
			
		||||
	default:
 | 
			
		||||
		log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
 | 
			
		||||
		return "unknown-" + key
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/containerd/v2/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/containerd/v2/version/version.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -19,11 +19,12 @@ package version
 | 
			
		||||
import "runtime"
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Name = "containerd"
 | 
			
		||||
	// Package is filled at linking time
 | 
			
		||||
	Package = "github.com/containerd/containerd/v2"
 | 
			
		||||
 | 
			
		||||
	// Version holds the complete version number. Filled in at linking time.
 | 
			
		||||
	Version = "2.0.3+unknown"
 | 
			
		||||
	Version = "2.0.4+unknown"
 | 
			
		||||
 | 
			
		||||
	// Revision is filled with the VCS (e.g. git) revision being used to build
 | 
			
		||||
	// the program at linking time.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/printer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/printer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,18 +0,0 @@
 | 
			
		||||
package hooks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/morikuni/aec"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func PrintNextSteps(out io.Writer, messages []string) {
 | 
			
		||||
	if len(messages) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	_, _ = fmt.Fprintln(out, aec.Bold.Apply("\nWhat's next:"))
 | 
			
		||||
	for _, n := range messages {
 | 
			
		||||
		_, _ = fmt.Fprintln(out, "   ", n)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/docker/cli/cli-plugins/hooks/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,116 +0,0 @@
 | 
			
		||||
package hooks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"text/template"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type HookType int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	NextSteps = iota
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HookMessage represents a plugin hook response. Plugins
 | 
			
		||||
// declaring support for CLI hooks need to print a json
 | 
			
		||||
// representation of this type when their hook subcommand
 | 
			
		||||
// is invoked.
 | 
			
		||||
type HookMessage struct {
 | 
			
		||||
	Type     HookType
 | 
			
		||||
	Template string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TemplateReplaceSubcommandName returns a hook template string
 | 
			
		||||
// that will be replaced by the CLI subcommand being executed
 | 
			
		||||
//
 | 
			
		||||
// Example:
 | 
			
		||||
//
 | 
			
		||||
// "you ran the subcommand: " + TemplateReplaceSubcommandName()
 | 
			
		||||
//
 | 
			
		||||
// when being executed after the command:
 | 
			
		||||
// `docker run --name "my-container" alpine`
 | 
			
		||||
// will result in the message:
 | 
			
		||||
// `you ran the subcommand: run`
 | 
			
		||||
func TemplateReplaceSubcommandName() string {
 | 
			
		||||
	return hookTemplateCommandName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TemplateReplaceFlagValue returns a hook template string
 | 
			
		||||
// that will be replaced by the flags value.
 | 
			
		||||
//
 | 
			
		||||
// Example:
 | 
			
		||||
//
 | 
			
		||||
// "you ran a container named: " + TemplateReplaceFlagValue("name")
 | 
			
		||||
//
 | 
			
		||||
// when being executed after the command:
 | 
			
		||||
// `docker run --name "my-container" alpine`
 | 
			
		||||
// will result in the message:
 | 
			
		||||
// `you ran a container named: my-container`
 | 
			
		||||
func TemplateReplaceFlagValue(flag string) string {
 | 
			
		||||
	return fmt.Sprintf(hookTemplateFlagValue, flag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TemplateReplaceArg takes an index i and returns a hook
 | 
			
		||||
// template string that the CLI will replace the template with
 | 
			
		||||
// the ith argument, after processing the passed flags.
 | 
			
		||||
//
 | 
			
		||||
// Example:
 | 
			
		||||
//
 | 
			
		||||
// "run this image with `docker run " + TemplateReplaceArg(0) + "`"
 | 
			
		||||
//
 | 
			
		||||
// when being executed after the command:
 | 
			
		||||
// `docker pull alpine`
 | 
			
		||||
// will result in the message:
 | 
			
		||||
// "Run this image with `docker run alpine`"
 | 
			
		||||
func TemplateReplaceArg(i int) string {
 | 
			
		||||
	return fmt.Sprintf(hookTemplateArg, strconv.Itoa(i))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
 | 
			
		||||
	tmpl := template.New("").Funcs(commandFunctions)
 | 
			
		||||
	tmpl, err := tmpl.Parse(hookTemplate)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	b := bytes.Buffer{}
 | 
			
		||||
	err = tmpl.Execute(&b, cmd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Split(b.String(), "\n"), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrHookTemplateParse = errors.New("failed to parse hook template")
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	hookTemplateCommandName = "{{.Name}}"
 | 
			
		||||
	hookTemplateFlagValue   = `{{flag . "%s"}}`
 | 
			
		||||
	hookTemplateArg         = "{{arg . %s}}"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var commandFunctions = template.FuncMap{
 | 
			
		||||
	"flag": getFlagValue,
 | 
			
		||||
	"arg":  getArgValue,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFlagValue(cmd *cobra.Command, flag string) (string, error) {
 | 
			
		||||
	cmdFlag := cmd.Flag(flag)
 | 
			
		||||
	if cmdFlag == nil {
 | 
			
		||||
		return "", ErrHookTemplateParse
 | 
			
		||||
	}
 | 
			
		||||
	return cmdFlag.Value.String(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getArgValue(cmd *cobra.Command, i int) (string, error) {
 | 
			
		||||
	flags := cmd.Flags()
 | 
			
		||||
	if flags == nil {
 | 
			
		||||
		return "", ErrHookTemplateParse
 | 
			
		||||
	}
 | 
			
		||||
	return flags.Arg(i), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/candidate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/candidate.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import "os/exec"
 | 
			
		||||
 | 
			
		||||
// Candidate represents a possible plugin candidate, for mocking purposes
 | 
			
		||||
type Candidate interface {
 | 
			
		||||
	Path() string
 | 
			
		||||
	Metadata() ([]byte, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type candidate struct {
 | 
			
		||||
	path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *candidate) Path() string {
 | 
			
		||||
	return c.path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *candidate) Metadata() ([]byte, error) {
 | 
			
		||||
	return exec.Command(c.path, MetadataSubcommandName).Output() // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,147 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"go.opentelemetry.io/otel/attribute"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// CommandAnnotationPlugin is added to every stub command added by
 | 
			
		||||
	// AddPluginCommandStubs with the value "true" and so can be
 | 
			
		||||
	// used to distinguish plugin stubs from regular commands.
 | 
			
		||||
	CommandAnnotationPlugin = "com.docker.cli.plugin"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginVendor is added to every stub command
 | 
			
		||||
	// added by AddPluginCommandStubs and contains the vendor of
 | 
			
		||||
	// that plugin.
 | 
			
		||||
	CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginVersion is added to every stub command
 | 
			
		||||
	// added by AddPluginCommandStubs and contains the version of
 | 
			
		||||
	// that plugin.
 | 
			
		||||
	CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginInvalid is added to any stub command
 | 
			
		||||
	// added by AddPluginCommandStubs for an invalid command (that
 | 
			
		||||
	// is, one which failed it's candidate test) and contains the
 | 
			
		||||
	// reason for the failure.
 | 
			
		||||
	CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginCommandPath is added to overwrite the
 | 
			
		||||
	// command path for a plugin invocation.
 | 
			
		||||
	CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pluginCommandStubsOnce sync.Once
 | 
			
		||||
 | 
			
		||||
// AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
 | 
			
		||||
// plugin. The command stubs will have several annotations added, see
 | 
			
		||||
// `CommandAnnotationPlugin*`.
 | 
			
		||||
func AddPluginCommandStubs(dockerCli command.Cli, rootCmd *cobra.Command) (err error) {
 | 
			
		||||
	pluginCommandStubsOnce.Do(func() {
 | 
			
		||||
		var plugins []Plugin
 | 
			
		||||
		plugins, err = ListPlugins(dockerCli, rootCmd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		for _, p := range plugins {
 | 
			
		||||
			vendor := p.Vendor
 | 
			
		||||
			if vendor == "" {
 | 
			
		||||
				vendor = "unknown"
 | 
			
		||||
			}
 | 
			
		||||
			annotations := map[string]string{
 | 
			
		||||
				CommandAnnotationPlugin:        "true",
 | 
			
		||||
				CommandAnnotationPluginVendor:  vendor,
 | 
			
		||||
				CommandAnnotationPluginVersion: p.Version,
 | 
			
		||||
			}
 | 
			
		||||
			if p.Err != nil {
 | 
			
		||||
				annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
 | 
			
		||||
			}
 | 
			
		||||
			rootCmd.AddCommand(&cobra.Command{
 | 
			
		||||
				Use:                p.Name,
 | 
			
		||||
				Short:              p.ShortDescription,
 | 
			
		||||
				Run:                func(_ *cobra.Command, _ []string) {},
 | 
			
		||||
				Annotations:        annotations,
 | 
			
		||||
				DisableFlagParsing: true,
 | 
			
		||||
				RunE: func(cmd *cobra.Command, args []string) error {
 | 
			
		||||
					flags := rootCmd.PersistentFlags()
 | 
			
		||||
					flags.SetOutput(nil)
 | 
			
		||||
					perr := flags.Parse(args)
 | 
			
		||||
					if perr != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					if flags.Changed("help") {
 | 
			
		||||
						cmd.HelpFunc()(rootCmd, args)
 | 
			
		||||
						return nil
 | 
			
		||||
					}
 | 
			
		||||
					return fmt.Errorf("docker: unknown command: docker %s\n\nRun 'docker --help' for more information", cmd.Name())
 | 
			
		||||
				},
 | 
			
		||||
				ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
					// Delegate completion to plugin
 | 
			
		||||
					cargs := []string{p.Path, cobra.ShellCompRequestCmd, p.Name}
 | 
			
		||||
					cargs = append(cargs, args...)
 | 
			
		||||
					cargs = append(cargs, toComplete)
 | 
			
		||||
					os.Args = cargs
 | 
			
		||||
					runCommand, runErr := PluginRunCommand(dockerCli, p.Name, cmd)
 | 
			
		||||
					if runErr != nil {
 | 
			
		||||
						return nil, cobra.ShellCompDirectiveError
 | 
			
		||||
					}
 | 
			
		||||
					runErr = runCommand.Run()
 | 
			
		||||
					if runErr == nil {
 | 
			
		||||
						os.Exit(0) // plugin already rendered complete data
 | 
			
		||||
					}
 | 
			
		||||
					return nil, cobra.ShellCompDirectiveError
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	dockerCliAttributePrefix = attribute.Key("docker.cli")
 | 
			
		||||
 | 
			
		||||
	cobraCommandPath = attribute.Key("cobra.command_path")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getPluginResourceAttributes(cmd *cobra.Command, plugin Plugin) attribute.Set {
 | 
			
		||||
	commandPath := cmd.Annotations[CommandAnnotationPluginCommandPath]
 | 
			
		||||
	if commandPath == "" {
 | 
			
		||||
		commandPath = fmt.Sprintf("%s %s", cmd.CommandPath(), plugin.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attrSet := attribute.NewSet(
 | 
			
		||||
		cobraCommandPath.String(commandPath),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	kvs := make([]attribute.KeyValue, 0, attrSet.Len())
 | 
			
		||||
	for iter := attrSet.Iter(); iter.Next(); {
 | 
			
		||||
		attr := iter.Attribute()
 | 
			
		||||
		kvs = append(kvs, attribute.KeyValue{
 | 
			
		||||
			Key:   dockerCliAttributePrefix + "." + attr.Key,
 | 
			
		||||
			Value: attr.Value,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return attribute.NewSet(kvs...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func appendPluginResourceAttributesEnvvar(env []string, cmd *cobra.Command, plugin Plugin) []string {
 | 
			
		||||
	if attrs := getPluginResourceAttributes(cmd, plugin); attrs.Len() > 0 {
 | 
			
		||||
		// values in environment variables need to be in baggage format
 | 
			
		||||
		// otel/baggage package can be used after update to v1.22, currently it encodes incorrectly
 | 
			
		||||
		attrsSlice := make([]string, attrs.Len())
 | 
			
		||||
		for iter := attrs.Iter(); iter.Next(); {
 | 
			
		||||
			i, v := iter.IndexedAttribute()
 | 
			
		||||
			attrsSlice[i] = string(v.Key) + "=" + url.PathEscape(v.Value.AsString())
 | 
			
		||||
		}
 | 
			
		||||
		env = append(env, ResourceAttributesEnvvar+"="+strings.Join(attrsSlice, ","))
 | 
			
		||||
	}
 | 
			
		||||
	return env
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,54 +0,0 @@
 | 
			
		||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
 | 
			
		||||
//go:build go1.22
 | 
			
		||||
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// pluginError is set as Plugin.Err by NewPlugin if the plugin
 | 
			
		||||
// candidate fails one of the candidate tests. This exists primarily
 | 
			
		||||
// to implement encoding.TextMarshaller such that rendering a plugin as JSON
 | 
			
		||||
// (e.g. for `docker info -f '{{json .CLIPlugins}}'`) renders the Err
 | 
			
		||||
// field as a useful string and not just `{}`. See
 | 
			
		||||
// https://github.com/golang/go/issues/10748 for some discussion
 | 
			
		||||
// around why the builtin error type doesn't implement this.
 | 
			
		||||
type pluginError struct {
 | 
			
		||||
	cause error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error satisfies the core error interface for pluginError.
 | 
			
		||||
func (e *pluginError) Error() string {
 | 
			
		||||
	return e.cause.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cause satisfies the errors.causer interface for pluginError.
 | 
			
		||||
func (e *pluginError) Cause() error {
 | 
			
		||||
	return e.cause
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unwrap provides compatibility for Go 1.13 error chains.
 | 
			
		||||
func (e *pluginError) Unwrap() error {
 | 
			
		||||
	return e.cause
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalText marshalls the pluginError into a textual form.
 | 
			
		||||
func (e *pluginError) MarshalText() (text []byte, err error) {
 | 
			
		||||
	return []byte(e.cause.Error()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wrapAsPluginError wraps an error in a pluginError with an
 | 
			
		||||
// additional message, analogous to errors.Wrapf.
 | 
			
		||||
func wrapAsPluginError(err error, msg string) error {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return &pluginError{cause: errors.Wrap(err, msg)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewPluginError creates a new pluginError, analogous to
 | 
			
		||||
// errors.Errorf.
 | 
			
		||||
func NewPluginError(msg string, args ...any) error {
 | 
			
		||||
	return &pluginError{cause: errors.Errorf(msg, args...)}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										199
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/hooks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,199 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/hooks"
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HookPluginData is the type representing the information
 | 
			
		||||
// that plugins declaring support for hooks get passed when
 | 
			
		||||
// being invoked following a CLI command execution.
 | 
			
		||||
type HookPluginData struct {
 | 
			
		||||
	// RootCmd is a string representing the matching hook configuration
 | 
			
		||||
	// which is currently being invoked. If a hook for `docker context` is
 | 
			
		||||
	// configured and the user executes `docker context ls`, the plugin will
 | 
			
		||||
	// be invoked with `context`.
 | 
			
		||||
	RootCmd      string
 | 
			
		||||
	Flags        map[string]string
 | 
			
		||||
	CommandError string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunCLICommandHooks is the entrypoint into the hooks execution flow after
 | 
			
		||||
// a main CLI command was executed. It calls the hook subcommand for all
 | 
			
		||||
// present CLI plugins that declare support for hooks in their metadata and
 | 
			
		||||
// parses/prints their responses.
 | 
			
		||||
func RunCLICommandHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, cmdErrorMessage string) {
 | 
			
		||||
	commandName := strings.TrimPrefix(subCommand.CommandPath(), rootCmd.Name()+" ")
 | 
			
		||||
	flags := getCommandFlags(subCommand)
 | 
			
		||||
 | 
			
		||||
	runHooks(ctx, dockerCli, rootCmd, subCommand, commandName, flags, cmdErrorMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunPluginHooks is the entrypoint for the hooks execution flow
 | 
			
		||||
// after a plugin command was just executed by the CLI.
 | 
			
		||||
func RunPluginHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, args []string) {
 | 
			
		||||
	commandName := strings.Join(args, " ")
 | 
			
		||||
	flags := getNaiveFlags(args)
 | 
			
		||||
 | 
			
		||||
	runHooks(ctx, dockerCli, rootCmd, subCommand, commandName, flags, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCommand *cobra.Command, invokedCommand string, flags map[string]string, cmdErrorMessage string) {
 | 
			
		||||
	nextSteps := invokeAndCollectHooks(ctx, dockerCli, rootCmd, subCommand, invokedCommand, flags, cmdErrorMessage)
 | 
			
		||||
 | 
			
		||||
	hooks.PrintNextSteps(dockerCli.Err(), nextSteps)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func invokeAndCollectHooks(ctx context.Context, dockerCli command.Cli, rootCmd, subCmd *cobra.Command, subCmdStr string, flags map[string]string, cmdErrorMessage string) []string {
 | 
			
		||||
	// check if the context was cancelled before invoking hooks
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		return nil
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pluginsCfg := dockerCli.ConfigFile().Plugins
 | 
			
		||||
	if pluginsCfg == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nextSteps := make([]string, 0, len(pluginsCfg))
 | 
			
		||||
	for pluginName, cfg := range pluginsCfg {
 | 
			
		||||
		match, ok := pluginMatch(cfg, subCmdStr)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p, err := GetPlugin(pluginName, dockerCli, rootCmd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		hookReturn, err := p.RunHook(ctx, HookPluginData{
 | 
			
		||||
			RootCmd:      match,
 | 
			
		||||
			Flags:        flags,
 | 
			
		||||
			CommandError: cmdErrorMessage,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// skip misbehaving plugins, but don't halt execution
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var hookMessageData hooks.HookMessage
 | 
			
		||||
		err = json.Unmarshal(hookReturn, &hookMessageData)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// currently the only hook type
 | 
			
		||||
		if hookMessageData.Type != hooks.NextSteps {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		processedHook, err := hooks.ParseTemplate(hookMessageData.Template, subCmd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var appended bool
 | 
			
		||||
		nextSteps, appended = appendNextSteps(nextSteps, processedHook)
 | 
			
		||||
		if !appended {
 | 
			
		||||
			logrus.Debugf("Plugin %s responded with an empty hook message %q. Ignoring.", pluginName, string(hookReturn))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nextSteps
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// appendNextSteps appends the processed hook output to the nextSteps slice.
 | 
			
		||||
// If the processed hook output is empty, it is not appended.
 | 
			
		||||
// Empty lines are not stripped if there's at least one non-empty line.
 | 
			
		||||
func appendNextSteps(nextSteps []string, processed []string) ([]string, bool) {
 | 
			
		||||
	empty := true
 | 
			
		||||
	for _, l := range processed {
 | 
			
		||||
		if strings.TrimSpace(l) != "" {
 | 
			
		||||
			empty = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if empty {
 | 
			
		||||
		return nextSteps, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return append(nextSteps, processed...), true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pluginMatch takes a plugin configuration and a string representing the
 | 
			
		||||
// command being executed (such as 'image ls' – the root 'docker' is omitted)
 | 
			
		||||
// and, if the configuration includes a hook for the invoked command, returns
 | 
			
		||||
// the configured hook string.
 | 
			
		||||
func pluginMatch(pluginCfg map[string]string, subCmd string) (string, bool) {
 | 
			
		||||
	configuredPluginHooks, ok := pluginCfg["hooks"]
 | 
			
		||||
	if !ok || configuredPluginHooks == "" {
 | 
			
		||||
		return "", false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commands := strings.Split(configuredPluginHooks, ",")
 | 
			
		||||
	for _, hookCmd := range commands {
 | 
			
		||||
		if hookMatch(hookCmd, subCmd) {
 | 
			
		||||
			return hookCmd, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hookMatch(hookCmd, subCmd string) bool {
 | 
			
		||||
	hookCmdTokens := strings.Split(hookCmd, " ")
 | 
			
		||||
	subCmdTokens := strings.Split(subCmd, " ")
 | 
			
		||||
 | 
			
		||||
	if len(hookCmdTokens) > len(subCmdTokens) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range hookCmdTokens {
 | 
			
		||||
		if v != subCmdTokens[i] {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCommandFlags(cmd *cobra.Command) map[string]string {
 | 
			
		||||
	flags := make(map[string]string)
 | 
			
		||||
	cmd.Flags().Visit(func(f *pflag.Flag) {
 | 
			
		||||
		var fValue string
 | 
			
		||||
		if f.Value.Type() == "bool" {
 | 
			
		||||
			fValue = f.Value.String()
 | 
			
		||||
		}
 | 
			
		||||
		flags[f.Name] = fValue
 | 
			
		||||
	})
 | 
			
		||||
	return flags
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getNaiveFlags string-matches argv and parses them into a map.
 | 
			
		||||
// This is used when calling hooks after a plugin command, since
 | 
			
		||||
// in this case we can't rely on the cobra command tree to parse
 | 
			
		||||
// flags in this case. In this case, no values are ever passed,
 | 
			
		||||
// since we don't have enough information to process them.
 | 
			
		||||
func getNaiveFlags(args []string) map[string]string {
 | 
			
		||||
	flags := make(map[string]string)
 | 
			
		||||
	for _, arg := range args {
 | 
			
		||||
		if strings.HasPrefix(arg, "--") {
 | 
			
		||||
			flags[arg[2:]] = ""
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(arg, "-") {
 | 
			
		||||
			flags[arg[1:]] = ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return flags
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										247
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										247
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,247 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/docker/cli/cli/config"
 | 
			
		||||
	"github.com/docker/cli/cli/config/configfile"
 | 
			
		||||
	"github.com/fvbommel/sortorder"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ReexecEnvvar is the name of an ennvar which is set to the command
 | 
			
		||||
	// used to originally invoke the docker CLI when executing a
 | 
			
		||||
	// plugin. Assuming $PATH and $CWD remain unchanged this should allow
 | 
			
		||||
	// the plugin to re-execute the original CLI.
 | 
			
		||||
	ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
 | 
			
		||||
 | 
			
		||||
	// ResourceAttributesEnvvar is the name of the envvar that includes additional
 | 
			
		||||
	// resource attributes for OTEL.
 | 
			
		||||
	ResourceAttributesEnvvar = "OTEL_RESOURCE_ATTRIBUTES"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// errPluginNotFound is the error returned when a plugin could not be found.
 | 
			
		||||
type errPluginNotFound string
 | 
			
		||||
 | 
			
		||||
func (errPluginNotFound) NotFound() {}
 | 
			
		||||
 | 
			
		||||
func (e errPluginNotFound) Error() string {
 | 
			
		||||
	return "Error: No such CLI plugin: " + string(e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type notFound interface{ NotFound() }
 | 
			
		||||
 | 
			
		||||
// IsNotFound is true if the given error is due to a plugin not being found.
 | 
			
		||||
func IsNotFound(err error) bool {
 | 
			
		||||
	if e, ok := err.(*pluginError); ok {
 | 
			
		||||
		err = e.Cause()
 | 
			
		||||
	}
 | 
			
		||||
	_, ok := err.(notFound)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getPluginDirs returns the platform-specific locations to search for plugins
 | 
			
		||||
// in order of preference.
 | 
			
		||||
//
 | 
			
		||||
// Plugin-discovery is performed in the following order of preference:
 | 
			
		||||
//
 | 
			
		||||
// 1. The "cli-plugins" directory inside the CLIs [config.Path] (usually "~/.docker/cli-plugins").
 | 
			
		||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
			
		||||
// 3. Platform-specific defaultSystemPluginDirs.
 | 
			
		||||
//
 | 
			
		||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
			
		||||
func getPluginDirs(cfg *configfile.ConfigFile) ([]string, error) {
 | 
			
		||||
	var pluginDirs []string
 | 
			
		||||
 | 
			
		||||
	if cfg != nil {
 | 
			
		||||
		pluginDirs = append(pluginDirs, cfg.CLIPluginsExtraDirs...)
 | 
			
		||||
	}
 | 
			
		||||
	pluginDir, err := config.Path("cli-plugins")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pluginDirs = append(pluginDirs, pluginDir)
 | 
			
		||||
	pluginDirs = append(pluginDirs, defaultSystemPluginDirs...)
 | 
			
		||||
	return pluginDirs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addPluginCandidatesFromDir(res map[string][]string, d string) {
 | 
			
		||||
	dentries, err := os.ReadDir(d)
 | 
			
		||||
	// Silently ignore any directories which we cannot list (e.g. due to
 | 
			
		||||
	// permissions or anything else) or which is not a directory
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for _, dentry := range dentries {
 | 
			
		||||
		switch dentry.Type() & os.ModeType {
 | 
			
		||||
		case 0, os.ModeSymlink:
 | 
			
		||||
			// Regular file or symlink, keep going
 | 
			
		||||
		default:
 | 
			
		||||
			// Something else, ignore.
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		name := dentry.Name()
 | 
			
		||||
		if !strings.HasPrefix(name, NamePrefix) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		name = strings.TrimPrefix(name, NamePrefix)
 | 
			
		||||
		var err error
 | 
			
		||||
		if name, err = trimExeSuffix(name); err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		res[name] = append(res[name], filepath.Join(d, dentry.Name()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// listPluginCandidates returns a map from plugin name to the list of (unvalidated) Candidates. The list is in descending order of priority.
 | 
			
		||||
func listPluginCandidates(dirs []string) map[string][]string {
 | 
			
		||||
	result := make(map[string][]string)
 | 
			
		||||
	for _, d := range dirs {
 | 
			
		||||
		addPluginCandidatesFromDir(result, d)
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPlugin returns a plugin on the system by its name
 | 
			
		||||
func GetPlugin(name string, dockerCli command.Cli, rootcmd *cobra.Command) (*Plugin, error) {
 | 
			
		||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	candidates := listPluginCandidates(pluginDirs)
 | 
			
		||||
	if paths, ok := candidates[name]; ok {
 | 
			
		||||
		if len(paths) == 0 {
 | 
			
		||||
			return nil, errPluginNotFound(name)
 | 
			
		||||
		}
 | 
			
		||||
		c := &candidate{paths[0]}
 | 
			
		||||
		p, err := newPlugin(c, rootcmd.Commands())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if !IsNotFound(p.Err) {
 | 
			
		||||
			p.ShadowedPaths = paths[1:]
 | 
			
		||||
		}
 | 
			
		||||
		return &p, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errPluginNotFound(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListPlugins produces a list of the plugins available on the system
 | 
			
		||||
func ListPlugins(dockerCli command.Cli, rootcmd *cobra.Command) ([]Plugin, error) {
 | 
			
		||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	candidates := listPluginCandidates(pluginDirs)
 | 
			
		||||
 | 
			
		||||
	var plugins []Plugin
 | 
			
		||||
	var mu sync.Mutex
 | 
			
		||||
	eg, _ := errgroup.WithContext(context.TODO())
 | 
			
		||||
	cmds := rootcmd.Commands()
 | 
			
		||||
	for _, paths := range candidates {
 | 
			
		||||
		func(paths []string) {
 | 
			
		||||
			eg.Go(func() error {
 | 
			
		||||
				if len(paths) == 0 {
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
				c := &candidate{paths[0]}
 | 
			
		||||
				p, err := newPlugin(c, cmds)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if !IsNotFound(p.Err) {
 | 
			
		||||
					p.ShadowedPaths = paths[1:]
 | 
			
		||||
					mu.Lock()
 | 
			
		||||
					defer mu.Unlock()
 | 
			
		||||
					plugins = append(plugins, p)
 | 
			
		||||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			})
 | 
			
		||||
		}(paths)
 | 
			
		||||
	}
 | 
			
		||||
	if err := eg.Wait(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sort.Slice(plugins, func(i, j int) bool {
 | 
			
		||||
		return sortorder.NaturalLess(plugins[i].Name, plugins[j].Name)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return plugins, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PluginRunCommand returns an "os/exec".Cmd which when .Run() will execute the named plugin.
 | 
			
		||||
// The rootcmd argument is referenced to determine the set of builtin commands in order to detect conficts.
 | 
			
		||||
// The error returned satisfies the IsNotFound() predicate if no plugin was found or if the first candidate plugin was invalid somehow.
 | 
			
		||||
func PluginRunCommand(dockerCli command.Cli, name string, rootcmd *cobra.Command) (*exec.Cmd, error) {
 | 
			
		||||
	// This uses the full original args, not the args which may
 | 
			
		||||
	// have been provided by cobra to our caller. This is because
 | 
			
		||||
	// they lack e.g. global options which we must propagate here.
 | 
			
		||||
	args := os.Args[1:]
 | 
			
		||||
	if !pluginNameRe.MatchString(name) {
 | 
			
		||||
		// We treat this as "not found" so that callers will
 | 
			
		||||
		// fallback to their "invalid" command path.
 | 
			
		||||
		return nil, errPluginNotFound(name)
 | 
			
		||||
	}
 | 
			
		||||
	exename := addExeSuffix(NamePrefix + name)
 | 
			
		||||
	pluginDirs, err := getPluginDirs(dockerCli.ConfigFile())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, d := range pluginDirs {
 | 
			
		||||
		path := filepath.Join(d, exename)
 | 
			
		||||
 | 
			
		||||
		// We stat here rather than letting the exec tell us
 | 
			
		||||
		// ENOENT because the latter does not distinguish a
 | 
			
		||||
		// file not existing from its dynamic loader or one of
 | 
			
		||||
		// its libraries not existing.
 | 
			
		||||
		if _, err := os.Stat(path); os.IsNotExist(err) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c := &candidate{path: path}
 | 
			
		||||
		plugin, err := newPlugin(c, rootcmd.Commands())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if plugin.Err != nil {
 | 
			
		||||
			// TODO: why are we not returning plugin.Err?
 | 
			
		||||
			return nil, errPluginNotFound(name)
 | 
			
		||||
		}
 | 
			
		||||
		cmd := exec.Command(plugin.Path, args...) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
			
		||||
 | 
			
		||||
		// Using dockerCli.{In,Out,Err}() here results in a hang until something is input.
 | 
			
		||||
		// See: - https://github.com/golang/go/issues/10338
 | 
			
		||||
		//      - https://github.com/golang/go/commit/d000e8742a173aa0659584aa01b7ba2834ba28ab
 | 
			
		||||
		// os.Stdin is a *os.File which avoids this behaviour. We don't need the functionality
 | 
			
		||||
		// of the wrappers here anyway.
 | 
			
		||||
		cmd.Stdin = os.Stdin
 | 
			
		||||
		cmd.Stdout = os.Stdout
 | 
			
		||||
		cmd.Stderr = os.Stderr
 | 
			
		||||
 | 
			
		||||
		cmd.Env = append(cmd.Environ(), ReexecEnvvar+"="+os.Args[0])
 | 
			
		||||
		cmd.Env = appendPluginResourceAttributesEnvvar(cmd.Env, rootcmd, plugin)
 | 
			
		||||
 | 
			
		||||
		return cmd, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, errPluginNotFound(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsPluginCommand checks if the given cmd is a plugin-stub.
 | 
			
		||||
func IsPluginCommand(cmd *cobra.Command) bool {
 | 
			
		||||
	return cmd.Annotations[CommandAnnotationPlugin] == "true"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,20 +0,0 @@
 | 
			
		||||
//go:build !windows
 | 
			
		||||
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
// defaultSystemPluginDirs are the platform-specific locations to search
 | 
			
		||||
// for plugins in order of preference.
 | 
			
		||||
//
 | 
			
		||||
// Plugin-discovery is performed in the following order of preference:
 | 
			
		||||
//
 | 
			
		||||
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
 | 
			
		||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
			
		||||
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
 | 
			
		||||
//
 | 
			
		||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
			
		||||
var defaultSystemPluginDirs = []string{
 | 
			
		||||
	"/usr/local/lib/docker/cli-plugins",
 | 
			
		||||
	"/usr/local/libexec/docker/cli-plugins",
 | 
			
		||||
	"/usr/lib/docker/cli-plugins",
 | 
			
		||||
	"/usr/libexec/docker/cli-plugins",
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/manager_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// defaultSystemPluginDirs are the platform-specific locations to search
 | 
			
		||||
// for plugins in order of preference.
 | 
			
		||||
//
 | 
			
		||||
// Plugin-discovery is performed in the following order of preference:
 | 
			
		||||
//
 | 
			
		||||
// 1. The "cli-plugins" directory inside the CLIs config-directory (usually "~/.docker/cli-plugins").
 | 
			
		||||
// 2. Additional plugin directories as configured through [ConfigFile.CLIPluginsExtraDirs].
 | 
			
		||||
// 3. Platform-specific defaultSystemPluginDirs (as defined below).
 | 
			
		||||
//
 | 
			
		||||
// [ConfigFile.CLIPluginsExtraDirs]: https://pkg.go.dev/github.com/docker/cli@v26.1.4+incompatible/cli/config/configfile#ConfigFile.CLIPluginsExtraDirs
 | 
			
		||||
var defaultSystemPluginDirs = []string{
 | 
			
		||||
	filepath.Join(os.Getenv("ProgramData"), "Docker", "cli-plugins"),
 | 
			
		||||
	filepath.Join(os.Getenv("ProgramFiles"), "Docker", "cli-plugins"),
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,124 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pluginNameRe = regexp.MustCompile("^[a-z][a-z0-9]*$")
 | 
			
		||||
 | 
			
		||||
// Plugin represents a potential plugin with all it's metadata.
 | 
			
		||||
type Plugin struct {
 | 
			
		||||
	Metadata
 | 
			
		||||
 | 
			
		||||
	Name string `json:",omitempty"`
 | 
			
		||||
	Path string `json:",omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Err is non-nil if the plugin failed one of the candidate tests.
 | 
			
		||||
	Err error `json:",omitempty"`
 | 
			
		||||
 | 
			
		||||
	// ShadowedPaths contains the paths of any other plugins which this plugin takes precedence over.
 | 
			
		||||
	ShadowedPaths []string `json:",omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newPlugin determines if the given candidate is valid and returns a
 | 
			
		||||
// Plugin.  If the candidate fails one of the tests then `Plugin.Err`
 | 
			
		||||
// is set, and is always a `pluginError`, but the `Plugin` is still
 | 
			
		||||
// returned with no error. An error is only returned due to a
 | 
			
		||||
// non-recoverable error.
 | 
			
		||||
func newPlugin(c Candidate, cmds []*cobra.Command) (Plugin, error) {
 | 
			
		||||
	path := c.Path()
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return Plugin{}, errors.New("plugin candidate path cannot be empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The candidate listing process should have skipped anything
 | 
			
		||||
	// which would fail here, so there are all real errors.
 | 
			
		||||
	fullname := filepath.Base(path)
 | 
			
		||||
	if fullname == "." {
 | 
			
		||||
		return Plugin{}, errors.Errorf("unable to determine basename of plugin candidate %q", path)
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	if fullname, err = trimExeSuffix(fullname); err != nil {
 | 
			
		||||
		return Plugin{}, errors.Wrapf(err, "plugin candidate %q", path)
 | 
			
		||||
	}
 | 
			
		||||
	if !strings.HasPrefix(fullname, NamePrefix) {
 | 
			
		||||
		return Plugin{}, errors.Errorf("plugin candidate %q: does not have %q prefix", path, NamePrefix)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p := Plugin{
 | 
			
		||||
		Name: strings.TrimPrefix(fullname, NamePrefix),
 | 
			
		||||
		Path: path,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now apply the candidate tests, so these update p.Err.
 | 
			
		||||
	if !pluginNameRe.MatchString(p.Name) {
 | 
			
		||||
		p.Err = NewPluginError("plugin candidate %q did not match %q", p.Name, pluginNameRe.String())
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, cmd := range cmds {
 | 
			
		||||
		// Ignore conflicts with commands which are
 | 
			
		||||
		// just plugin stubs (i.e. from a previous
 | 
			
		||||
		// call to AddPluginCommandStubs).
 | 
			
		||||
		if IsPluginCommand(cmd) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if cmd.Name() == p.Name {
 | 
			
		||||
			p.Err = NewPluginError("plugin %q duplicates builtin command", p.Name)
 | 
			
		||||
			return p, nil
 | 
			
		||||
		}
 | 
			
		||||
		if cmd.HasAlias(p.Name) {
 | 
			
		||||
			p.Err = NewPluginError("plugin %q duplicates an alias of builtin command %q", p.Name, cmd.Name())
 | 
			
		||||
			return p, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We are supposed to check for relevant execute permissions here. Instead we rely on an attempt to execute.
 | 
			
		||||
	meta, err := c.Metadata()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		p.Err = wrapAsPluginError(err, "failed to fetch metadata")
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := json.Unmarshal(meta, &p.Metadata); err != nil {
 | 
			
		||||
		p.Err = wrapAsPluginError(err, "invalid metadata")
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
	if p.Metadata.SchemaVersion != "0.1.0" {
 | 
			
		||||
		p.Err = NewPluginError("plugin SchemaVersion %q is not valid, must be 0.1.0", p.Metadata.SchemaVersion)
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
	if p.Metadata.Vendor == "" {
 | 
			
		||||
		p.Err = NewPluginError("plugin metadata does not define a vendor")
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
	return p, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunHook executes the plugin's hooks command
 | 
			
		||||
// and returns its unprocessed output.
 | 
			
		||||
func (p *Plugin) RunHook(ctx context.Context, hookData HookPluginData) ([]byte, error) {
 | 
			
		||||
	hDataBytes, err := json.Marshal(hookData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, wrapAsPluginError(err, "failed to marshall hook data")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pCmd := exec.CommandContext(ctx, p.Path, p.Name, HookSubcommandName, string(hDataBytes)) // #nosec G204 -- ignore "Subprocess launched with a potential tainted input or cmd arguments"
 | 
			
		||||
	pCmd.Env = os.Environ()
 | 
			
		||||
	pCmd.Env = append(pCmd.Env, ReexecEnvvar+"="+os.Args[0])
 | 
			
		||||
	hookCmdOutput, err := pCmd.Output()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, wrapAsPluginError(err, "failed to execute plugin hook subcommand")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hookCmdOutput, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,11 +0,0 @@
 | 
			
		||||
//go:build !windows
 | 
			
		||||
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
func trimExeSuffix(s string) (string, error) {
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addExeSuffix(s string) string {
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/docker/cli/cli-plugins/manager/suffix_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,26 +0,0 @@
 | 
			
		||||
package manager
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This is made slightly more complex due to needing to be case insensitive.
 | 
			
		||||
func trimExeSuffix(s string) (string, error) {
 | 
			
		||||
	ext := filepath.Ext(s)
 | 
			
		||||
	if ext == "" {
 | 
			
		||||
		return "", errors.Errorf("path %q lacks required file extension", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exe := ".exe"
 | 
			
		||||
	if !strings.EqualFold(ext, exe) {
 | 
			
		||||
		return "", errors.Errorf("path %q lacks required %q suffix", s, exe)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.TrimSuffix(s, ext), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addExeSuffix(s string) string {
 | 
			
		||||
	return s + ".exe"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/docker/cli/cli-plugins/metadata/annotations.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/docker/cli/cli-plugins/metadata/annotations.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
package metadata
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// CommandAnnotationPlugin is added to every stub command added by
 | 
			
		||||
	// AddPluginCommandStubs with the value "true" and so can be
 | 
			
		||||
	// used to distinguish plugin stubs from regular commands.
 | 
			
		||||
	CommandAnnotationPlugin = "com.docker.cli.plugin"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginVendor is added to every stub command
 | 
			
		||||
	// added by AddPluginCommandStubs and contains the vendor of
 | 
			
		||||
	// that plugin.
 | 
			
		||||
	CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginVersion is added to every stub command
 | 
			
		||||
	// added by AddPluginCommandStubs and contains the version of
 | 
			
		||||
	// that plugin.
 | 
			
		||||
	CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginInvalid is added to any stub command
 | 
			
		||||
	// added by AddPluginCommandStubs for an invalid command (that
 | 
			
		||||
	// is, one which failed it's candidate test) and contains the
 | 
			
		||||
	// reason for the failure.
 | 
			
		||||
	CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
 | 
			
		||||
 | 
			
		||||
	// CommandAnnotationPluginCommandPath is added to overwrite the
 | 
			
		||||
	// command path for a plugin invocation.
 | 
			
		||||
	CommandAnnotationPluginCommandPath = "com.docker.cli.plugin.command_path"
 | 
			
		||||
)
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package manager
 | 
			
		||||
package metadata
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// NamePrefix is the prefix required on all plugin binary names
 | 
			
		||||
@@ -13,6 +13,12 @@ const (
 | 
			
		||||
	// which must be implemented by plugins declaring support
 | 
			
		||||
	// for hooks in their metadata.
 | 
			
		||||
	HookSubcommandName = "docker-cli-plugin-hooks"
 | 
			
		||||
 | 
			
		||||
	// ReexecEnvvar is the name of an ennvar which is set to the command
 | 
			
		||||
	// used to originally invoke the docker CLI when executing a
 | 
			
		||||
	// plugin. Assuming $PATH and $CWD remain unchanged this should allow
 | 
			
		||||
	// the plugin to re-execute the original CLI.
 | 
			
		||||
	ReexecEnvvar = "DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Metadata provided by the plugin.
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli-plugins/plugin/plugin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -9,7 +9,7 @@ import (
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/manager"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/metadata"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/socket"
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	"github.com/docker/cli/cli/connhelper"
 | 
			
		||||
@@ -30,7 +30,7 @@ import (
 | 
			
		||||
var PersistentPreRunE func(*cobra.Command, []string) error
 | 
			
		||||
 | 
			
		||||
// RunPlugin executes the specified plugin command
 | 
			
		||||
func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) error {
 | 
			
		||||
func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) error {
 | 
			
		||||
	tcmd := newPluginCommand(dockerCli, plugin, meta)
 | 
			
		||||
 | 
			
		||||
	var persistentPreRunOnce sync.Once
 | 
			
		||||
@@ -81,7 +81,7 @@ func RunPlugin(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function.
 | 
			
		||||
func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
 | 
			
		||||
func Run(makeCmd func(command.Cli) *cobra.Command, meta metadata.Metadata) {
 | 
			
		||||
	otel.SetErrorHandler(debug.OTELErrorHandler)
 | 
			
		||||
 | 
			
		||||
	dockerCli, err := command.NewDockerCli()
 | 
			
		||||
@@ -111,7 +111,7 @@ func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) {
 | 
			
		||||
func withPluginClientConn(name string) command.CLIOption {
 | 
			
		||||
	return command.WithInitializeClient(func(dockerCli *command.DockerCli) (client.APIClient, error) {
 | 
			
		||||
		cmd := "docker"
 | 
			
		||||
		if x := os.Getenv(manager.ReexecEnvvar); x != "" {
 | 
			
		||||
		if x := os.Getenv(metadata.ReexecEnvvar); x != "" {
 | 
			
		||||
			cmd = x
 | 
			
		||||
		}
 | 
			
		||||
		var flags []string
 | 
			
		||||
@@ -140,9 +140,9 @@ func withPluginClientConn(name string) command.CLIOption {
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) *cli.TopLevelCommand {
 | 
			
		||||
func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta metadata.Metadata) *cli.TopLevelCommand {
 | 
			
		||||
	name := plugin.Name()
 | 
			
		||||
	fullname := manager.NamePrefix + name
 | 
			
		||||
	fullname := metadata.NamePrefix + name
 | 
			
		||||
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:           fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name),
 | 
			
		||||
@@ -177,12 +177,12 @@ func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta
 | 
			
		||||
	return cli.NewTopLevelCommand(cmd, dockerCli, opts, cmd.Flags())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.Command {
 | 
			
		||||
func newMetadataSubcommand(plugin *cobra.Command, meta metadata.Metadata) *cobra.Command {
 | 
			
		||||
	if meta.ShortDescription == "" {
 | 
			
		||||
		meta.ShortDescription = plugin.Short
 | 
			
		||||
	}
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:    manager.MetadataSubcommandName,
 | 
			
		||||
		Use:    metadata.MetadataSubcommandName,
 | 
			
		||||
		Hidden: true,
 | 
			
		||||
		// Suppress the global/parent PersistentPreRunE, which
 | 
			
		||||
		// needlessly initializes the client and tries to
 | 
			
		||||
@@ -200,8 +200,8 @@ func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.
 | 
			
		||||
 | 
			
		||||
// RunningStandalone tells a CLI plugin it is run standalone by direct execution
 | 
			
		||||
func RunningStandalone() bool {
 | 
			
		||||
	if os.Getenv(manager.ReexecEnvvar) != "" {
 | 
			
		||||
	if os.Getenv(metadata.ReexecEnvvar) != "" {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName
 | 
			
		||||
	return len(os.Args) < 2 || os.Args[1] != metadata.MetadataSubcommandName
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/cli/cli/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/cli/cli/cobra.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,15 +3,12 @@ package cli
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	pluginmanager "github.com/docker/cli/cli-plugins/manager"
 | 
			
		||||
	"github.com/docker/cli/cli-plugins/metadata"
 | 
			
		||||
	"github.com/docker/cli/cli/command"
 | 
			
		||||
	cliflags "github.com/docker/cli/cli/flags"
 | 
			
		||||
	"github.com/docker/docker/pkg/homedir"
 | 
			
		||||
	"github.com/docker/docker/registry"
 | 
			
		||||
	"github.com/fvbommel/sortorder"
 | 
			
		||||
	"github.com/moby/term"
 | 
			
		||||
	"github.com/morikuni/aec"
 | 
			
		||||
@@ -62,13 +59,6 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *c
 | 
			
		||||
		"docs.code-delimiter": `"`, // https://github.com/docker/cli-docs-tool/blob/77abede22166eaea4af7335096bdcedd043f5b19/annotation/annotation.go#L20-L22
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Configure registry.CertsDir() when running in rootless-mode
 | 
			
		||||
	if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" {
 | 
			
		||||
		if configHome, err := homedir.GetConfigHome(); err == nil {
 | 
			
		||||
			registry.SetCertsDir(filepath.Join(configHome, "docker/certs.d"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return opts, helpCommand
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -252,7 +242,7 @@ func hasAdditionalHelp(cmd *cobra.Command) bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isPlugin(cmd *cobra.Command) bool {
 | 
			
		||||
	return pluginmanager.IsPluginCommand(cmd)
 | 
			
		||||
	return cmd.Annotations[metadata.CommandAnnotationPlugin] == "true"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAliases(cmd *cobra.Command) bool {
 | 
			
		||||
@@ -356,9 +346,9 @@ func decoratedName(cmd *cobra.Command) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func vendorAndVersion(cmd *cobra.Command) string {
 | 
			
		||||
	if vendor, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVendor]; ok && isPlugin(cmd) {
 | 
			
		||||
	if vendor, ok := cmd.Annotations[metadata.CommandAnnotationPluginVendor]; ok && isPlugin(cmd) {
 | 
			
		||||
		version := ""
 | 
			
		||||
		if v, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVersion]; ok && v != "" {
 | 
			
		||||
		if v, ok := cmd.Annotations[metadata.CommandAnnotationPluginVersion]; ok && v != "" {
 | 
			
		||||
			version = ", " + v
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Sprintf("(%s%s)", vendor, version)
 | 
			
		||||
@@ -417,7 +407,7 @@ func invalidPlugins(cmd *cobra.Command) []*cobra.Command {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func invalidPluginReason(cmd *cobra.Command) string {
 | 
			
		||||
	return cmd.Annotations[pluginmanager.CommandAnnotationPluginInvalid]
 | 
			
		||||
	return cmd.Annotations[metadata.CommandAnnotationPluginInvalid]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const usageTemplate = `Usage:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										59
									
								
								vendor/github.com/docker/cli/cli/command/cli.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/docker/cli/cli/command/cli.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"sync"
 | 
			
		||||
@@ -21,21 +20,15 @@ import (
 | 
			
		||||
	"github.com/docker/cli/cli/context/store"
 | 
			
		||||
	"github.com/docker/cli/cli/debug"
 | 
			
		||||
	cliflags "github.com/docker/cli/cli/flags"
 | 
			
		||||
	manifeststore "github.com/docker/cli/cli/manifest/store"
 | 
			
		||||
	registryclient "github.com/docker/cli/cli/registry/client"
 | 
			
		||||
	"github.com/docker/cli/cli/streams"
 | 
			
		||||
	"github.com/docker/cli/cli/trust"
 | 
			
		||||
	"github.com/docker/cli/cli/version"
 | 
			
		||||
	dopts "github.com/docker/cli/opts"
 | 
			
		||||
	"github.com/docker/docker/api"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/docker/docker/api/types/registry"
 | 
			
		||||
	"github.com/docker/docker/api/types/swarm"
 | 
			
		||||
	"github.com/docker/docker/client"
 | 
			
		||||
	"github.com/docker/go-connections/tlsconfig"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	notaryclient "github.com/theupdateframework/notary/client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultInitTimeout = 2 * time.Second
 | 
			
		||||
@@ -53,19 +46,18 @@ type Cli interface {
 | 
			
		||||
	Streams
 | 
			
		||||
	SetIn(in *streams.In)
 | 
			
		||||
	Apply(ops ...CLIOption) error
 | 
			
		||||
	ConfigFile() *configfile.ConfigFile
 | 
			
		||||
	config.Provider
 | 
			
		||||
	ServerInfo() ServerInfo
 | 
			
		||||
	NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
 | 
			
		||||
	DefaultVersion() string
 | 
			
		||||
	CurrentVersion() string
 | 
			
		||||
	ManifestStore() manifeststore.Store
 | 
			
		||||
	RegistryClient(bool) registryclient.RegistryClient
 | 
			
		||||
	ContentTrustEnabled() bool
 | 
			
		||||
	BuildKitEnabled() (bool, error)
 | 
			
		||||
	ContextStore() store.Store
 | 
			
		||||
	CurrentContext() string
 | 
			
		||||
	DockerEndpoint() docker.Endpoint
 | 
			
		||||
	TelemetryClient
 | 
			
		||||
	DeprecatedNotaryClient
 | 
			
		||||
	DeprecatedManifestClient
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DockerCli is an instance the docker command line client.
 | 
			
		||||
@@ -96,7 +88,7 @@ type DockerCli struct {
 | 
			
		||||
	enableGlobalMeter, enableGlobalTracer bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultVersion returns api.defaultVersion.
 | 
			
		||||
// DefaultVersion returns [api.DefaultVersion].
 | 
			
		||||
func (*DockerCli) DefaultVersion() string {
 | 
			
		||||
	return api.DefaultVersion
 | 
			
		||||
}
 | 
			
		||||
@@ -202,16 +194,16 @@ func (cli *DockerCli) BuildKitEnabled() (bool, error) {
 | 
			
		||||
 | 
			
		||||
// HooksEnabled returns whether plugin hooks are enabled.
 | 
			
		||||
func (cli *DockerCli) HooksEnabled() bool {
 | 
			
		||||
	// legacy support DOCKER_CLI_HINTS env var
 | 
			
		||||
	if v := os.Getenv("DOCKER_CLI_HINTS"); v != "" {
 | 
			
		||||
	// use DOCKER_CLI_HOOKS env var value if set and not empty
 | 
			
		||||
	if v := os.Getenv("DOCKER_CLI_HOOKS"); v != "" {
 | 
			
		||||
		enabled, err := strconv.ParseBool(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return enabled
 | 
			
		||||
	}
 | 
			
		||||
	// use DOCKER_CLI_HOOKS env var value if set and not empty
 | 
			
		||||
	if v := os.Getenv("DOCKER_CLI_HOOKS"); v != "" {
 | 
			
		||||
	// legacy support DOCKER_CLI_HINTS env var
 | 
			
		||||
	if v := os.Getenv("DOCKER_CLI_HINTS"); v != "" {
 | 
			
		||||
		enabled, err := strconv.ParseBool(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false
 | 
			
		||||
@@ -230,21 +222,6 @@ func (cli *DockerCli) HooksEnabled() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ManifestStore returns a store for local manifests
 | 
			
		||||
func (*DockerCli) ManifestStore() manifeststore.Store {
 | 
			
		||||
	// TODO: support override default location from config file
 | 
			
		||||
	return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegistryClient returns a client for communicating with a Docker distribution
 | 
			
		||||
// registry
 | 
			
		||||
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
 | 
			
		||||
	resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
 | 
			
		||||
		return ResolveAuthConfig(cli.ConfigFile(), index)
 | 
			
		||||
	}
 | 
			
		||||
	return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithInitializeClient is passed to DockerCli.Initialize by callers who wish to set a particular API Client for use by the CLI.
 | 
			
		||||
func WithInitializeClient(makeClient func(dockerCli *DockerCli) (client.APIClient, error)) CLIOption {
 | 
			
		||||
	return func(dockerCli *DockerCli) error {
 | 
			
		||||
@@ -292,6 +269,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...CLIOption)
 | 
			
		||||
	if cli.enableGlobalTracer {
 | 
			
		||||
		cli.createGlobalTracerProvider(cli.baseCtx)
 | 
			
		||||
	}
 | 
			
		||||
	filterResourceAttributesEnvvar()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -345,7 +323,10 @@ func resolveDockerEndpoint(s store.Reader, contextName string) (docker.Endpoint,
 | 
			
		||||
 | 
			
		||||
// Resolve the Docker endpoint for the default context (based on config, env vars and CLI flags)
 | 
			
		||||
func resolveDefaultDockerEndpoint(opts *cliflags.ClientOptions) (docker.Endpoint, error) {
 | 
			
		||||
	host, err := getServerHost(opts.Hosts, opts.TLSOptions)
 | 
			
		||||
	// defaultToTLS determines whether we should use a TLS host as default
 | 
			
		||||
	// if nothing was configured by the user.
 | 
			
		||||
	defaultToTLS := opts.TLSOptions != nil
 | 
			
		||||
	host, err := getServerHost(opts.Hosts, defaultToTLS)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return docker.Endpoint{}, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -403,11 +384,6 @@ func (cli *DockerCli) initializeFromClient() {
 | 
			
		||||
	cli.client.NegotiateAPIVersionPing(ping)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
			
		||||
func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
 | 
			
		||||
	return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContextStore returns the ContextStore
 | 
			
		||||
func (cli *DockerCli) ContextStore() store.Store {
 | 
			
		||||
	return cli.contextStore
 | 
			
		||||
@@ -553,18 +529,15 @@ func NewDockerCli(ops ...CLIOption) (*DockerCli, error) {
 | 
			
		||||
	return cli, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error) {
 | 
			
		||||
	var host string
 | 
			
		||||
func getServerHost(hosts []string, defaultToTLS bool) (string, error) {
 | 
			
		||||
	switch len(hosts) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		host = os.Getenv(client.EnvOverrideHost)
 | 
			
		||||
		return dopts.ParseHost(defaultToTLS, os.Getenv(client.EnvOverrideHost))
 | 
			
		||||
	case 1:
 | 
			
		||||
		host = hosts[0]
 | 
			
		||||
		return dopts.ParseHost(defaultToTLS, hosts[0])
 | 
			
		||||
	default:
 | 
			
		||||
		return "", errors.New("Specify only one -H")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dopts.ParseHost(tlsOptions != nil, host)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UserAgent returns the user agent string used for making API requests
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								vendor/github.com/docker/cli/cli/command/cli_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/docker/cli/cli/command/cli_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
package command
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli/config"
 | 
			
		||||
	manifeststore "github.com/docker/cli/cli/manifest/store"
 | 
			
		||||
	registryclient "github.com/docker/cli/cli/registry/client"
 | 
			
		||||
	"github.com/docker/cli/cli/trust"
 | 
			
		||||
	"github.com/docker/docker/api/types/registry"
 | 
			
		||||
	notaryclient "github.com/theupdateframework/notary/client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type DeprecatedNotaryClient interface {
 | 
			
		||||
	// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
			
		||||
	//
 | 
			
		||||
	// Deprecated: use [trust.GetNotaryRepository] instead. This method is no longer used and will be removed in the next release.
 | 
			
		||||
	NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeprecatedManifestClient interface {
 | 
			
		||||
	// ManifestStore returns a store for local manifests
 | 
			
		||||
	//
 | 
			
		||||
	// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
 | 
			
		||||
	ManifestStore() manifeststore.Store
 | 
			
		||||
 | 
			
		||||
	// RegistryClient returns a client for communicating with a Docker distribution
 | 
			
		||||
	// registry.
 | 
			
		||||
	//
 | 
			
		||||
	// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
 | 
			
		||||
	RegistryClient(bool) registryclient.RegistryClient
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotaryClient provides a Notary Repository to interact with signed metadata for an image
 | 
			
		||||
func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
 | 
			
		||||
	return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ManifestStore returns a store for local manifests
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use [manifeststore.NewStore] instead. This method is no longer used and will be removed in the next release.
 | 
			
		||||
func (*DockerCli) ManifestStore() manifeststore.Store {
 | 
			
		||||
	return manifeststore.NewStore(filepath.Join(config.Dir(), "manifests"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RegistryClient returns a client for communicating with a Docker distribution
 | 
			
		||||
// registry
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use [registryclient.NewRegistryClient]. This method is no longer used and will be removed in the next release.
 | 
			
		||||
func (cli *DockerCli) RegistryClient(allowInsecure bool) registryclient.RegistryClient {
 | 
			
		||||
	resolver := func(ctx context.Context, index *registry.IndexInfo) registry.AuthConfig {
 | 
			
		||||
		return ResolveAuthConfig(cli.ConfigFile(), index)
 | 
			
		||||
	}
 | 
			
		||||
	return registryclient.NewRegistryClient(resolver, UserAgent(), allowInsecure)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/docker/cli/cli/command/formatter/displayutils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/docker/cli/cli/command/formatter/displayutils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,11 @@
 | 
			
		||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
 | 
			
		||||
//go:build go1.22
 | 
			
		||||
 | 
			
		||||
package formatter
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/text/width"
 | 
			
		||||
@@ -59,3 +64,27 @@ func Ellipsis(s string, maxDisplayWidth int) string {
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// capitalizeFirst capitalizes the first character of string
 | 
			
		||||
func capitalizeFirst(s string) string {
 | 
			
		||||
	switch l := len(s); l {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return s
 | 
			
		||||
	case 1:
 | 
			
		||||
		return strings.ToLower(s)
 | 
			
		||||
	default:
 | 
			
		||||
		return strings.ToUpper(string(s[0])) + strings.ToLower(s[1:])
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PrettyPrint outputs arbitrary data for human formatted output by uppercasing the first letter.
 | 
			
		||||
func PrettyPrint(i any) string {
 | 
			
		||||
	switch t := i.(type) {
 | 
			
		||||
	case nil:
 | 
			
		||||
		return "None"
 | 
			
		||||
	case string:
 | 
			
		||||
		return capitalizeFirst(t)
 | 
			
		||||
	default:
 | 
			
		||||
		return capitalizeFirst(fmt.Sprintf("%s", t))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/cli/cli/command/formatter/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/cli/cli/command/formatter/formatter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -76,9 +76,9 @@ func (c *Context) preFormat() {
 | 
			
		||||
func (c *Context) parseFormat() (*template.Template, error) {
 | 
			
		||||
	tmpl, err := templates.Parse(c.finalFormat)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return tmpl, errors.Wrap(err, "template parsing error")
 | 
			
		||||
		return nil, errors.Wrap(err, "template parsing error")
 | 
			
		||||
	}
 | 
			
		||||
	return tmpl, err
 | 
			
		||||
	return tmpl, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								vendor/github.com/docker/cli/cli/command/telemetry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/docker/cli/cli/command/telemetry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,10 +4,11 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/distribution/uuid"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"go.opentelemetry.io/otel"
 | 
			
		||||
	"go.opentelemetry.io/otel/metric"
 | 
			
		||||
	sdkmetric "go.opentelemetry.io/otel/sdk/metric"
 | 
			
		||||
@@ -142,7 +143,7 @@ func defaultResourceOptions() []resource.Option {
 | 
			
		||||
			// of the CLI is its own instance. Without this, downstream
 | 
			
		||||
			// OTEL processors may think the same process is restarting
 | 
			
		||||
			// continuously.
 | 
			
		||||
			semconv.ServiceInstanceID(uuid.Generate().String()),
 | 
			
		||||
			semconv.ServiceInstanceID(uuid.NewString()),
 | 
			
		||||
		),
 | 
			
		||||
		resource.WithFromEnv(),
 | 
			
		||||
		resource.WithTelemetrySDK(),
 | 
			
		||||
@@ -216,3 +217,49 @@ func (r *cliReader) ForceFlush(ctx context.Context) error {
 | 
			
		||||
func deltaTemporality(_ sdkmetric.InstrumentKind) metricdata.Temporality {
 | 
			
		||||
	return metricdata.DeltaTemporality
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// resourceAttributesEnvVar is the name of the envvar that includes additional
 | 
			
		||||
// resource attributes for OTEL as defined in the [OpenTelemetry specification].
 | 
			
		||||
//
 | 
			
		||||
// [OpenTelemetry specification]: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration
 | 
			
		||||
const resourceAttributesEnvVar = "OTEL_RESOURCE_ATTRIBUTES"
 | 
			
		||||
 | 
			
		||||
func filterResourceAttributesEnvvar() {
 | 
			
		||||
	if v := os.Getenv(resourceAttributesEnvVar); v != "" {
 | 
			
		||||
		if filtered := filterResourceAttributes(v); filtered != "" {
 | 
			
		||||
			_ = os.Setenv(resourceAttributesEnvVar, filtered)
 | 
			
		||||
		} else {
 | 
			
		||||
			_ = os.Unsetenv(resourceAttributesEnvVar)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dockerCLIAttributePrefix is the prefix for any docker cli OTEL attributes.
 | 
			
		||||
// When updating, make sure to also update the copy in cli-plugins/manager.
 | 
			
		||||
//
 | 
			
		||||
// TODO(thaJeztah): move telemetry-related code to an (internal) package to reduce dependency on cli/command in cli-plugins, which has too many imports.
 | 
			
		||||
const dockerCLIAttributePrefix = "docker.cli."
 | 
			
		||||
 | 
			
		||||
func filterResourceAttributes(s string) string {
 | 
			
		||||
	if trimmed := strings.TrimSpace(s); trimmed == "" {
 | 
			
		||||
		return trimmed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pairs := strings.Split(s, ",")
 | 
			
		||||
	elems := make([]string, 0, len(pairs))
 | 
			
		||||
	for _, p := range pairs {
 | 
			
		||||
		k, _, found := strings.Cut(p, "=")
 | 
			
		||||
		if !found {
 | 
			
		||||
			// Do not interact with invalid otel resources.
 | 
			
		||||
			elems = append(elems, p)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Skip attributes that have our docker.cli prefix.
 | 
			
		||||
		if strings.HasPrefix(k, dockerCLIAttributePrefix) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		elems = append(elems, p)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(elems, ",")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								vendor/github.com/docker/cli/cli/command/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/docker/cli/cli/command/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,10 +13,9 @@ import (
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/cli/cli/config"
 | 
			
		||||
	"github.com/docker/cli/cli/streams"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	mounttypes "github.com/docker/docker/api/types/mount"
 | 
			
		||||
	"github.com/docker/docker/api/types/versions"
 | 
			
		||||
	"github.com/docker/docker/errdefs"
 | 
			
		||||
	"github.com/moby/sys/sequential"
 | 
			
		||||
	"github.com/moby/term"
 | 
			
		||||
@@ -51,30 +50,6 @@ func CopyToFile(outfile string, r io.Reader) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// capitalizeFirst capitalizes the first character of string
 | 
			
		||||
func capitalizeFirst(s string) string {
 | 
			
		||||
	switch l := len(s); l {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return s
 | 
			
		||||
	case 1:
 | 
			
		||||
		return strings.ToLower(s)
 | 
			
		||||
	default:
 | 
			
		||||
		return strings.ToUpper(string(s[0])) + strings.ToLower(s[1:])
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PrettyPrint outputs arbitrary data for human formatted output by uppercasing the first letter.
 | 
			
		||||
func PrettyPrint(i any) string {
 | 
			
		||||
	switch t := i.(type) {
 | 
			
		||||
	case nil:
 | 
			
		||||
		return "None"
 | 
			
		||||
	case string:
 | 
			
		||||
		return capitalizeFirst(t)
 | 
			
		||||
	default:
 | 
			
		||||
		return capitalizeFirst(fmt.Sprintf("%s", t))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var ErrPromptTerminated = errdefs.Cancelled(errors.New("prompt terminated"))
 | 
			
		||||
 | 
			
		||||
// DisableInputEcho disables input echo on the provided streams.In.
 | 
			
		||||
@@ -166,11 +141,12 @@ func PromptForConfirmation(ctx context.Context, ins io.Reader, outs io.Writer, m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PruneFilters returns consolidated prune filters obtained from config.json and cli
 | 
			
		||||
func PruneFilters(dockerCli Cli, pruneFilters filters.Args) filters.Args {
 | 
			
		||||
	if dockerCli.ConfigFile() == nil {
 | 
			
		||||
func PruneFilters(dockerCLI config.Provider, pruneFilters filters.Args) filters.Args {
 | 
			
		||||
	cfg := dockerCLI.ConfigFile()
 | 
			
		||||
	if cfg == nil {
 | 
			
		||||
		return pruneFilters
 | 
			
		||||
	}
 | 
			
		||||
	for _, f := range dockerCli.ConfigFile().PruneFilters {
 | 
			
		||||
	for _, f := range cfg.PruneFilters {
 | 
			
		||||
		k, v, ok := strings.Cut(f, "=")
 | 
			
		||||
		if !ok {
 | 
			
		||||
			continue
 | 
			
		||||
@@ -239,48 +215,3 @@ func ValidateOutputPathFileMode(fileMode os.FileMode) error {
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func stringSliceIndex(s, subs []string) int {
 | 
			
		||||
	j := 0
 | 
			
		||||
	if len(subs) > 0 {
 | 
			
		||||
		for i, x := range s {
 | 
			
		||||
			if j < len(subs) && subs[j] == x {
 | 
			
		||||
				j++
 | 
			
		||||
			} else {
 | 
			
		||||
				j = 0
 | 
			
		||||
			}
 | 
			
		||||
			if len(subs) == j {
 | 
			
		||||
				return i + 1 - j
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return -1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StringSliceReplaceAt replaces the sub-slice find, with the sub-slice replace, in the string
 | 
			
		||||
// slice s, returning a new slice and a boolean indicating if the replacement happened.
 | 
			
		||||
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
 | 
			
		||||
func StringSliceReplaceAt(s, find, replace []string, requireIndex int) ([]string, bool) {
 | 
			
		||||
	idx := stringSliceIndex(s, find)
 | 
			
		||||
	if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
 | 
			
		||||
		return s, false
 | 
			
		||||
	}
 | 
			
		||||
	out := append([]string{}, s[:idx]...)
 | 
			
		||||
	out = append(out, replace...)
 | 
			
		||||
	out = append(out, s[idx+len(find):]...)
 | 
			
		||||
	return out, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateMountWithAPIVersion validates a mount with the server API version.
 | 
			
		||||
func ValidateMountWithAPIVersion(m mounttypes.Mount, serverAPIVersion string) error {
 | 
			
		||||
	if m.BindOptions != nil {
 | 
			
		||||
		if m.BindOptions.NonRecursive && versions.LessThan(serverAPIVersion, "1.40") {
 | 
			
		||||
			return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
 | 
			
		||||
		}
 | 
			
		||||
		// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
			
		||||
		if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(serverAPIVersion, "1.44") {
 | 
			
		||||
			return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/docker/cli/cli/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/docker/cli/cli/config/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -69,6 +69,11 @@ func getHomeDir() string {
 | 
			
		||||
	return home
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Provider defines an interface for providing the CLI config.
 | 
			
		||||
type Provider interface {
 | 
			
		||||
	ConfigFile() *configfile.ConfigFile
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dir returns the directory the configuration file is stored in
 | 
			
		||||
func Dir() string {
 | 
			
		||||
	initConfigDir.Do(func() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								vendor/github.com/docker/cli/cli/internal/jsonstream/display.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/docker/cli/cli/internal/jsonstream/display.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
package jsonstream
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/pkg/jsonmessage"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	Stream       = jsonmessage.Stream
 | 
			
		||||
	JSONMessage  = jsonmessage.JSONMessage
 | 
			
		||||
	JSONError    = jsonmessage.JSONError
 | 
			
		||||
	JSONProgress = jsonmessage.JSONProgress
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ctxReader struct {
 | 
			
		||||
	err chan error
 | 
			
		||||
	r   io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *ctxReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case err = <-r.err:
 | 
			
		||||
		return 0, err
 | 
			
		||||
	default:
 | 
			
		||||
		return r.r.Read(p)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Options func(*options)
 | 
			
		||||
 | 
			
		||||
type options struct {
 | 
			
		||||
	AuxCallback func(JSONMessage)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WithAuxCallback(cb func(JSONMessage)) Options {
 | 
			
		||||
	return func(o *options) {
 | 
			
		||||
		o.AuxCallback = cb
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Display prints the JSON messages from the given reader to the given stream.
 | 
			
		||||
//
 | 
			
		||||
// It wraps the [jsonmessage.DisplayJSONMessagesStream] function to make it
 | 
			
		||||
// "context aware" and appropriately returns why the function was canceled.
 | 
			
		||||
//
 | 
			
		||||
// It returns an error if the context is canceled, but not if the input reader / stream is closed.
 | 
			
		||||
func Display(ctx context.Context, in io.Reader, stream Stream, opts ...Options) error {
 | 
			
		||||
	if ctx.Err() != nil {
 | 
			
		||||
		return ctx.Err()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reader := &ctxReader{err: make(chan error, 1), r: in}
 | 
			
		||||
	stopFunc := context.AfterFunc(ctx, func() { reader.err <- ctx.Err() })
 | 
			
		||||
	defer stopFunc()
 | 
			
		||||
 | 
			
		||||
	o := options{}
 | 
			
		||||
	for _, opt := range opts {
 | 
			
		||||
		opt(&o)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := jsonmessage.DisplayJSONMessagesStream(reader, stream, stream.FD(), stream.IsTerminal(), o.AuxCallback); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ctx.Err()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/docker/cli/cli/registry/client/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/docker/cli/cli/registry/client/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	manifesttypes "github.com/docker/cli/cli/manifest/types"
 | 
			
		||||
	"github.com/docker/cli/cli/trust"
 | 
			
		||||
	"github.com/docker/distribution"
 | 
			
		||||
	distributionclient "github.com/docker/distribution/registry/client"
 | 
			
		||||
	registrytypes "github.com/docker/docker/api/types/registry"
 | 
			
		||||
@@ -38,12 +37,6 @@ func NewRegistryClient(resolver AuthConfigResolver, userAgent string, insecure b
 | 
			
		||||
// AuthConfigResolver returns Auth Configuration for an index
 | 
			
		||||
type AuthConfigResolver func(ctx context.Context, index *registrytypes.IndexInfo) registrytypes.AuthConfig
 | 
			
		||||
 | 
			
		||||
// PutManifestOptions is the data sent to push a manifest
 | 
			
		||||
type PutManifestOptions struct {
 | 
			
		||||
	MediaType string
 | 
			
		||||
	Payload   []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type client struct {
 | 
			
		||||
	authConfigResolver AuthConfigResolver
 | 
			
		||||
	insecureRegistry   bool
 | 
			
		||||
@@ -61,13 +54,13 @@ func (err ErrBlobCreated) Error() string {
 | 
			
		||||
		err.From, err.Target)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrHTTPProto returned if attempting to use TLS with a non-TLS registry
 | 
			
		||||
type ErrHTTPProto struct {
 | 
			
		||||
	OrigErr string
 | 
			
		||||
// httpProtoError returned if attempting to use TLS with a non-TLS registry
 | 
			
		||||
type httpProtoError struct {
 | 
			
		||||
	cause error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrHTTPProto) Error() string {
 | 
			
		||||
	return err.OrigErr
 | 
			
		||||
func (e httpProtoError) Error() string {
 | 
			
		||||
	return e.cause.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ RegistryClient = &client{}
 | 
			
		||||
@@ -78,7 +71,7 @@ func (c *client) MountBlob(ctx context.Context, sourceRef reference.Canonical, t
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	repoEndpoint.actions = trust.ActionsPushAndPull
 | 
			
		||||
	repoEndpoint.actions = []string{"pull", "push"}
 | 
			
		||||
	repo, err := c.getRepositoryForReference(ctx, targetRef, repoEndpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -104,7 +97,7 @@ func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoEndpoint.actions = trust.ActionsPushAndPull
 | 
			
		||||
	repoEndpoint.actions = []string{"pull", "push"}
 | 
			
		||||
	repo, err := c.getRepositoryForReference(ctx, ref, repoEndpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
@@ -121,8 +114,11 @@ func (c *client) PutManifest(ctx context.Context, ref reference.Named, manifest
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dgst, err := manifestService.Put(ctx, manifest, opts...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return dgst, errors.Wrapf(err, "failed to put manifest %s", ref)
 | 
			
		||||
	}
 | 
			
		||||
	return dgst, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Named, repoEndpoint repositoryEndpoint) (distribution.Repository, error) {
 | 
			
		||||
	repoName, err := reference.WithName(repoEndpoint.Name())
 | 
			
		||||
@@ -135,7 +131,7 @@ func (c *client) getRepositoryForReference(ctx context.Context, ref reference.Na
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if !repoEndpoint.endpoint.TLSConfig.InsecureSkipVerify {
 | 
			
		||||
			return nil, ErrHTTPProto{OrigErr: err.Error()}
 | 
			
		||||
			return nil, httpProtoError{cause: err}
 | 
			
		||||
		}
 | 
			
		||||
		// --insecure was set; fall back to plain HTTP
 | 
			
		||||
		if url := repoEndpoint.endpoint.URL; url != nil && url.Scheme == "https" {
 | 
			
		||||
@@ -157,7 +153,10 @@ func (c *client) getHTTPTransportForRepoEndpoint(ctx context.Context, repoEndpoi
 | 
			
		||||
		c.userAgent,
 | 
			
		||||
		repoEndpoint.actions,
 | 
			
		||||
	)
 | 
			
		||||
	return httpTransport, errors.Wrap(err, "failed to configure transport")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "failed to configure transport")
 | 
			
		||||
	}
 | 
			
		||||
	return httpTransport, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetManifest returns an ImageManifest for the reference
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/github.com/docker/cli/cli/registry/client/endpoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/docker/cli/cli/registry/client/endpoint.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -6,7 +6,6 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/docker/cli/cli/trust"
 | 
			
		||||
	"github.com/docker/distribution/registry/client/auth"
 | 
			
		||||
	"github.com/docker/distribution/registry/client/transport"
 | 
			
		||||
	registrytypes "github.com/docker/docker/api/types/registry"
 | 
			
		||||
@@ -31,10 +30,7 @@ func (r repositoryEndpoint) BaseURL() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newDefaultRepositoryEndpoint(ref reference.Named, insecure bool) (repositoryEndpoint, error) {
 | 
			
		||||
	repoInfo, err := registry.ParseRepositoryInfo(ref)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return repositoryEndpoint{}, err
 | 
			
		||||
	}
 | 
			
		||||
	repoInfo, _ := registry.ParseRepositoryInfo(ref)
 | 
			
		||||
	endpoint, err := getDefaultEndpointFromRepoInfo(repoInfo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return repositoryEndpoint{}, err
 | 
			
		||||
@@ -94,7 +90,7 @@ func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.API
 | 
			
		||||
		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
 | 
			
		||||
	} else {
 | 
			
		||||
		if len(actions) == 0 {
 | 
			
		||||
			actions = trust.ActionsPullOnly
 | 
			
		||||
			actions = []string{"pull"}
 | 
			
		||||
		}
 | 
			
		||||
		creds := registry.NewStaticCredentialStore(&authConfig)
 | 
			
		||||
		tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
 | 
			
		||||
@@ -104,14 +100,11 @@ func getHTTPTransport(authConfig registrytypes.AuthConfig, endpoint registry.API
 | 
			
		||||
	return transport.NewTransport(base, modifiers...), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RepoNameForReference returns the repository name from a reference
 | 
			
		||||
// RepoNameForReference returns the repository name from a reference.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: this function is no longer used and will be removed in the next release.
 | 
			
		||||
func RepoNameForReference(ref reference.Named) (string, error) {
 | 
			
		||||
	// insecure is fine since this only returns the name
 | 
			
		||||
	repo, err := newDefaultRepositoryEndpoint(ref, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return repo.Name(), nil
 | 
			
		||||
	return reference.Path(reference.TrimNamed(ref)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type existingTokenHandler struct {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/docker/cli/cli/registry/client/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/docker/cli/cli/registry/client/fetcher.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -220,10 +220,7 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoInfo, err := registry.ParseRepositoryInfo(namedRef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	repoInfo, _ := registry.ParseRepositoryInfo(namedRef)
 | 
			
		||||
 | 
			
		||||
	confirmedTLSRegistries := make(map[string]bool)
 | 
			
		||||
	for _, endpoint := range endpoints {
 | 
			
		||||
@@ -241,7 +238,8 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
			
		||||
		repo, err := c.getRepositoryForReference(ctx, namedRef, repoEndpoint)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Debugf("error %s with repo endpoint %+v", err, repoEndpoint)
 | 
			
		||||
			if _, ok := err.(ErrHTTPProto); ok {
 | 
			
		||||
			var protoErr httpProtoError
 | 
			
		||||
			if errors.As(err, &protoErr) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			return err
 | 
			
		||||
@@ -272,11 +270,6 @@ func (c *client) iterateEndpoints(ctx context.Context, namedRef reference.Named,
 | 
			
		||||
 | 
			
		||||
// allEndpoints returns a list of endpoints ordered by priority (v2, http).
 | 
			
		||||
func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoint, error) {
 | 
			
		||||
	repoInfo, err := registry.ParseRepositoryInfo(namedRef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var serviceOpts registry.ServiceOptions
 | 
			
		||||
	if insecure {
 | 
			
		||||
		logrus.Debugf("allowing insecure registry for: %s", reference.Domain(namedRef))
 | 
			
		||||
@@ -286,6 +279,7 @@ func allEndpoints(namedRef reference.Named, insecure bool) ([]registry.APIEndpoi
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return []registry.APIEndpoint{}, err
 | 
			
		||||
	}
 | 
			
		||||
	repoInfo, _ := registry.ParseRepositoryInfo(namedRef)
 | 
			
		||||
	endpoints, err := registryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
 | 
			
		||||
	logrus.Debugf("endpoints for %s: %v", namedRef, endpoints)
 | 
			
		||||
	return endpoints, err
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/docker/cli/cli/trust/trust.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/docker/cli/cli/trust/trust.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -40,10 +40,11 @@ var (
 | 
			
		||||
	ActionsPullOnly = []string{"pull"}
 | 
			
		||||
	// ActionsPushAndPull defines the actions for read-write interactions with a Notary Repository
 | 
			
		||||
	ActionsPushAndPull = []string{"pull", "push"}
 | 
			
		||||
	// NotaryServer is the endpoint serving the Notary trust server
 | 
			
		||||
	NotaryServer = "https://notary.docker.io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NotaryServer is the endpoint serving the Notary trust server
 | 
			
		||||
const NotaryServer = "https://notary.docker.io"
 | 
			
		||||
 | 
			
		||||
// GetTrustDirectory returns the base trust directory name
 | 
			
		||||
func GetTrustDirectory() string {
 | 
			
		||||
	return filepath.Join(config.Dir(), "trust")
 | 
			
		||||
@@ -238,6 +239,20 @@ func NotaryError(repoName string, err error) error {
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddToAllSignableRoles attempts to add the image target to all the top level
 | 
			
		||||
// delegation roles we can (based on whether we have the signing key and whether
 | 
			
		||||
// the role's path allows us to).
 | 
			
		||||
//
 | 
			
		||||
// If there are no delegation roles, we add to the targets role.
 | 
			
		||||
func AddToAllSignableRoles(repo client.Repository, target *client.Target) error {
 | 
			
		||||
	signableRoles, err := GetSignableRoles(repo, target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo.AddTarget(target, signableRoles...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetSignableRoles returns a list of roles for which we have valid signing
 | 
			
		||||
// keys, given a notary repository and a target
 | 
			
		||||
func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.RoleName, error) {
 | 
			
		||||
@@ -307,11 +322,7 @@ func GetImageReferencesAndAuth(ctx context.Context,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Resolve the Repository name from fqn to RepositoryInfo
 | 
			
		||||
	repoInfo, err := registry.ParseRepositoryInfo(ref)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ImageRefAndAuth{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoInfo, _ := registry.ParseRepositoryInfo(ref)
 | 
			
		||||
	authConfig := authResolver(ctx, repoInfo.Index)
 | 
			
		||||
	return ImageRefAndAuth{
 | 
			
		||||
		original:   imgName,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										143
									
								
								vendor/github.com/docker/cli/cli/trust/trust_push.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/docker/cli/cli/trust/trust_push.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
package trust
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/docker/cli/cli/internal/jsonstream"
 | 
			
		||||
	"github.com/docker/cli/cli/streams"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	registrytypes "github.com/docker/docker/api/types/registry"
 | 
			
		||||
	"github.com/docker/docker/registry"
 | 
			
		||||
	"github.com/opencontainers/go-digest"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/theupdateframework/notary/client"
 | 
			
		||||
	"github.com/theupdateframework/notary/tuf/data"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Streams is an interface which exposes the standard input and output streams.
 | 
			
		||||
//
 | 
			
		||||
// Same interface as [github.com/docker/cli/cli/command.Streams] but defined here to prevent a circular import.
 | 
			
		||||
type Streams interface {
 | 
			
		||||
	In() *streams.In
 | 
			
		||||
	Out() *streams.Out
 | 
			
		||||
	Err() *streams.Out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PushTrustedReference pushes a canonical reference to the trust server.
 | 
			
		||||
//
 | 
			
		||||
//nolint:gocyclo
 | 
			
		||||
func PushTrustedReference(ctx context.Context, ioStreams Streams, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig registrytypes.AuthConfig, in io.Reader, userAgent string) error {
 | 
			
		||||
	// If it is a trusted push we would like to find the target entry which match the
 | 
			
		||||
	// tag provided in the function and then do an AddTarget later.
 | 
			
		||||
	notaryTarget := &client.Target{}
 | 
			
		||||
	// Count the times of calling for handleTarget,
 | 
			
		||||
	// if it is called more that once, that should be considered an error in a trusted push.
 | 
			
		||||
	cnt := 0
 | 
			
		||||
	handleTarget := func(msg jsonstream.JSONMessage) {
 | 
			
		||||
		cnt++
 | 
			
		||||
		if cnt > 1 {
 | 
			
		||||
			// handleTarget should only be called once. This will be treated as an error.
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var pushResult types.PushResult
 | 
			
		||||
		err := json.Unmarshal(*msg.Aux, &pushResult)
 | 
			
		||||
		if err == nil && pushResult.Tag != "" {
 | 
			
		||||
			if dgst, err := digest.Parse(pushResult.Digest); err == nil {
 | 
			
		||||
				h, err := hex.DecodeString(dgst.Hex())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					notaryTarget = nil
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				notaryTarget.Name = pushResult.Tag
 | 
			
		||||
				notaryTarget.Hashes = data.Hashes{string(dgst.Algorithm()): h}
 | 
			
		||||
				notaryTarget.Length = int64(pushResult.Size)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tag string
 | 
			
		||||
	switch x := ref.(type) {
 | 
			
		||||
	case reference.Canonical:
 | 
			
		||||
		return errors.New("cannot push a digest reference")
 | 
			
		||||
	case reference.NamedTagged:
 | 
			
		||||
		tag = x.Tag()
 | 
			
		||||
	default:
 | 
			
		||||
		// We want trust signatures to always take an explicit tag,
 | 
			
		||||
		// otherwise it will act as an untrusted push.
 | 
			
		||||
		if err := jsonstream.Display(ctx, in, ioStreams.Out()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		_, _ = fmt.Fprintln(ioStreams.Err(), "No tag specified, skipping trust metadata push")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := jsonstream.Display(ctx, in, ioStreams.Out(), jsonstream.WithAuxCallback(handleTarget)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cnt > 1 {
 | 
			
		||||
		return errors.Errorf("internal error: only one call to handleTarget expected")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if notaryTarget == nil {
 | 
			
		||||
		return errors.Errorf("no targets found, provide a specific tag in order to sign it")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _ = fmt.Fprintln(ioStreams.Out(), "Signing and pushing trust metadata")
 | 
			
		||||
 | 
			
		||||
	repo, err := GetNotaryRepository(ioStreams.In(), ioStreams.Out(), userAgent, repoInfo, &authConfig, "push", "pull")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "error establishing connection to trust repository")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get the latest repository metadata so we can figure out which roles to sign
 | 
			
		||||
	_, err = repo.ListTargets()
 | 
			
		||||
 | 
			
		||||
	switch err.(type) {
 | 
			
		||||
	case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
 | 
			
		||||
		keys := repo.GetCryptoService().ListKeys(data.CanonicalRootRole)
 | 
			
		||||
		var rootKeyID string
 | 
			
		||||
		// always select the first root key
 | 
			
		||||
		if len(keys) > 0 {
 | 
			
		||||
			sort.Strings(keys)
 | 
			
		||||
			rootKeyID = keys[0]
 | 
			
		||||
		} else {
 | 
			
		||||
			rootPublicKey, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			rootKeyID = rootPublicKey.ID()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Initialize the notary repository with a remotely managed snapshot key
 | 
			
		||||
		if err := repo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
 | 
			
		||||
			return NotaryError(repoInfo.Name.Name(), err)
 | 
			
		||||
		}
 | 
			
		||||
		_, _ = fmt.Fprintf(ioStreams.Out(), "Finished initializing %q\n", repoInfo.Name.Name())
 | 
			
		||||
		err = repo.AddTarget(notaryTarget, data.CanonicalTargetsRole)
 | 
			
		||||
	case nil:
 | 
			
		||||
		// already initialized and we have successfully downloaded the latest metadata
 | 
			
		||||
		err = AddToAllSignableRoles(repo, notaryTarget)
 | 
			
		||||
	default:
 | 
			
		||||
		return NotaryError(repoInfo.Name.Name(), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		err = repo.Publish()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = errors.Wrapf(err, "failed to sign %s:%s", repoInfo.Name.Name(), tag)
 | 
			
		||||
		return NotaryError(repoInfo.Name.Name(), err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _ = fmt.Fprintf(ioStreams.Out(), "Successfully signed %s:%s\n", repoInfo.Name.Name(), tag)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/cli/cli/trust/trust_tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/cli/cli/trust/trust_tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
package trust
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/docker/docker/client"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TagTrusted tags a trusted ref. It is a shallow wrapper around [client.Client.ImageTag]
 | 
			
		||||
// that updates the given image references to their familiar format for tagging
 | 
			
		||||
// and printing.
 | 
			
		||||
func TagTrusted(ctx context.Context, apiClient client.ImageAPIClient, out io.Writer, trustedRef reference.Canonical, ref reference.NamedTagged) error {
 | 
			
		||||
	// Use familiar references when interacting with client and output
 | 
			
		||||
	familiarRef := reference.FamiliarString(ref)
 | 
			
		||||
	trustedFamiliarRef := reference.FamiliarString(trustedRef)
 | 
			
		||||
 | 
			
		||||
	_, _ = fmt.Fprintf(out, "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
 | 
			
		||||
	return apiClient.ImageTag(ctx, trustedFamiliarRef, familiarRef)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/docker/cli/opts/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/docker/cli/opts/duration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,9 +1,8 @@
 | 
			
		||||
package opts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PositiveDurationOpt is an option type for time.Duration that uses a pointer.
 | 
			
		||||
@@ -20,7 +19,7 @@ func (d *PositiveDurationOpt) Set(s string) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if *d.DurationOpt.value < 0 {
 | 
			
		||||
		return errors.Errorf("duration cannot be negative")
 | 
			
		||||
		return errors.New("duration cannot be negative")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/docker/cli/opts/env.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/docker/cli/opts/env.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +1,9 @@
 | 
			
		||||
package opts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ValidateEnv validates an environment variable and returns it.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/docker/cli/opts/gpus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/docker/cli/opts/gpus.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,12 +2,12 @@ package opts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/csv"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/types/container"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GpuOpts is a Value type for parsing mounts
 | 
			
		||||
@@ -20,7 +20,14 @@ func parseCount(s string) (int, error) {
 | 
			
		||||
		return -1, nil
 | 
			
		||||
	}
 | 
			
		||||
	i, err := strconv.Atoi(s)
 | 
			
		||||
	return i, errors.Wrap(err, "count must be an integer")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		var numErr *strconv.NumError
 | 
			
		||||
		if errors.As(err, &numErr) {
 | 
			
		||||
			err = numErr.Err
 | 
			
		||||
		}
 | 
			
		||||
		return 0, fmt.Errorf(`invalid count (%s): value must be either "all" or an integer: %w`, s, err)
 | 
			
		||||
	}
 | 
			
		||||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set a new mount value
 | 
			
		||||
@@ -69,7 +76,7 @@ func (o *GpuOpts) Set(value string) error {
 | 
			
		||||
			r := csv.NewReader(strings.NewReader(val))
 | 
			
		||||
			optFields, err := r.Read()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to read gpu options")
 | 
			
		||||
				return fmt.Errorf("failed to read gpu options: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			req.Options = ConvertKVStringsToMap(optFields)
 | 
			
		||||
		default:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/docker/cli/opts/mount.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/docker/cli/opts/mount.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -135,8 +135,7 @@ func (m *MountOpt) Set(value string) error {
 | 
			
		||||
				// TODO: implicitly set propagation and error if the user specifies a propagation in a future refactor/UX polish pass
 | 
			
		||||
				// https://github.com/docker/cli/pull/4316#discussion_r1341974730
 | 
			
		||||
			default:
 | 
			
		||||
				return fmt.Errorf("invalid value for %s: %s (must be \"enabled\", \"disabled\", \"writable\", or \"readonly\")",
 | 
			
		||||
					key, val)
 | 
			
		||||
				return fmt.Errorf(`invalid value for %s: %s (must be "enabled", "disabled", "writable", or "readonly")`, key, val)
 | 
			
		||||
			}
 | 
			
		||||
		case "volume-subpath":
 | 
			
		||||
			volumeOptions().Subpath = val
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/cli/opts/network.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/cli/opts/network.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -89,7 +89,11 @@ func (n *NetworkOpt) Set(value string) error { //nolint:gocyclo
 | 
			
		||||
			case gwPriorityOpt:
 | 
			
		||||
				netOpt.GwPriority, err = strconv.Atoi(val)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return fmt.Errorf("invalid gw-priority: %w", err)
 | 
			
		||||
					var numErr *strconv.NumError
 | 
			
		||||
					if errors.As(err, &numErr) {
 | 
			
		||||
						err = numErr.Err
 | 
			
		||||
					}
 | 
			
		||||
					return fmt.Errorf("invalid gw-priority (%s): %w", val, err)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
				return errors.New("invalid field key " + key)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/cli/opts/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/cli/opts/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
package opts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net"
 | 
			
		||||
@@ -9,8 +10,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
	units "github.com/docker/go-units"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/docker/go-units"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								vendor/github.com/docker/cli/opts/opts_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/docker/cli/opts/opts_deprecated.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
package opts
 | 
			
		||||
 | 
			
		||||
import "github.com/docker/cli/opts/swarmopts"
 | 
			
		||||
 | 
			
		||||
// PortOpt represents a port config in swarm mode.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use [swarmopts.PortOpt]
 | 
			
		||||
type PortOpt = swarmopts.PortOpt
 | 
			
		||||
 | 
			
		||||
// ConfigOpt is a Value type for parsing configs.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use [swarmopts.ConfigOpt]
 | 
			
		||||
type ConfigOpt = swarmopts.ConfigOpt
 | 
			
		||||
 | 
			
		||||
// SecretOpt is a Value type for parsing secrets
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use [swarmopts.SecretOpt]
 | 
			
		||||
type SecretOpt = swarmopts.SecretOpt
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package opts
 | 
			
		||||
package swarmopts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/csv"
 | 
			
		||||
@@ -8,12 +8,12 @@ import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	swarmtypes "github.com/docker/docker/api/types/swarm"
 | 
			
		||||
	"github.com/docker/docker/api/types/swarm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ConfigOpt is a Value type for parsing configs
 | 
			
		||||
type ConfigOpt struct {
 | 
			
		||||
	values []*swarmtypes.ConfigReference
 | 
			
		||||
	values []*swarm.ConfigReference
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set a new config value
 | 
			
		||||
@@ -24,8 +24,8 @@ func (o *ConfigOpt) Set(value string) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	options := &swarmtypes.ConfigReference{
 | 
			
		||||
		File: &swarmtypes.ConfigReferenceFileTarget{
 | 
			
		||||
	options := &swarm.ConfigReference{
 | 
			
		||||
		File: &swarm.ConfigReferenceFileTarget{
 | 
			
		||||
			UID:  "0",
 | 
			
		||||
			GID:  "0",
 | 
			
		||||
			Mode: 0o444,
 | 
			
		||||
@@ -95,6 +95,6 @@ func (o *ConfigOpt) String() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value returns the config requests
 | 
			
		||||
func (o *ConfigOpt) Value() []*swarmtypes.ConfigReference {
 | 
			
		||||
func (o *ConfigOpt) Value() []*swarm.ConfigReference {
 | 
			
		||||
	return o.values
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package opts
 | 
			
		||||
package swarmopts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/csv"
 | 
			
		||||
@@ -46,42 +46,50 @@ func (p *PortOpt) Set(value string) error {
 | 
			
		||||
			// TODO(thaJeztah): these options should not be case-insensitive.
 | 
			
		||||
			key, val, ok := strings.Cut(strings.ToLower(field), "=")
 | 
			
		||||
			if !ok || key == "" {
 | 
			
		||||
				return fmt.Errorf("invalid field %s", field)
 | 
			
		||||
				return fmt.Errorf("invalid field: %s", field)
 | 
			
		||||
			}
 | 
			
		||||
			switch key {
 | 
			
		||||
			case portOptProtocol:
 | 
			
		||||
				if val != string(swarm.PortConfigProtocolTCP) && val != string(swarm.PortConfigProtocolUDP) && val != string(swarm.PortConfigProtocolSCTP) {
 | 
			
		||||
					return fmt.Errorf("invalid protocol value %s", val)
 | 
			
		||||
					return fmt.Errorf("invalid protocol value '%s'", val)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pConfig.Protocol = swarm.PortConfigProtocol(val)
 | 
			
		||||
			case portOptMode:
 | 
			
		||||
				if val != string(swarm.PortConfigPublishModeIngress) && val != string(swarm.PortConfigPublishModeHost) {
 | 
			
		||||
					return fmt.Errorf("invalid publish mode value %s", val)
 | 
			
		||||
					return fmt.Errorf("invalid publish mode value (%s): must be either '%s' or '%s'", val, swarm.PortConfigPublishModeIngress, swarm.PortConfigPublishModeHost)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pConfig.PublishMode = swarm.PortConfigPublishMode(val)
 | 
			
		||||
			case portOptTargetPort:
 | 
			
		||||
				tPort, err := strconv.ParseUint(val, 10, 16)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
					var numErr *strconv.NumError
 | 
			
		||||
					if errors.As(err, &numErr) {
 | 
			
		||||
						err = numErr.Err
 | 
			
		||||
					}
 | 
			
		||||
					return fmt.Errorf("invalid target port (%s): value must be an integer: %w", val, err)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pConfig.TargetPort = uint32(tPort)
 | 
			
		||||
			case portOptPublishedPort:
 | 
			
		||||
				pPort, err := strconv.ParseUint(val, 10, 16)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
					var numErr *strconv.NumError
 | 
			
		||||
					if errors.As(err, &numErr) {
 | 
			
		||||
						err = numErr.Err
 | 
			
		||||
					}
 | 
			
		||||
					return fmt.Errorf("invalid published port (%s): value must be an integer: %w", val, err)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pConfig.PublishedPort = uint32(pPort)
 | 
			
		||||
			default:
 | 
			
		||||
				return fmt.Errorf("invalid field key %s", key)
 | 
			
		||||
				return fmt.Errorf("invalid field key: %s", key)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if pConfig.TargetPort == 0 {
 | 
			
		||||
			return fmt.Errorf("missing mandatory field %q", portOptTargetPort)
 | 
			
		||||
			return fmt.Errorf("missing mandatory field '%s'", portOptTargetPort)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if pConfig.PublishMode == "" {
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package opts
 | 
			
		||||
package swarmopts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/csv"
 | 
			
		||||
@@ -8,12 +8,12 @@ import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	swarmtypes "github.com/docker/docker/api/types/swarm"
 | 
			
		||||
	"github.com/docker/docker/api/types/swarm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SecretOpt is a Value type for parsing secrets
 | 
			
		||||
type SecretOpt struct {
 | 
			
		||||
	values []*swarmtypes.SecretReference
 | 
			
		||||
	values []*swarm.SecretReference
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set a new secret value
 | 
			
		||||
@@ -24,8 +24,8 @@ func (o *SecretOpt) Set(value string) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	options := &swarmtypes.SecretReference{
 | 
			
		||||
		File: &swarmtypes.SecretReferenceFileTarget{
 | 
			
		||||
	options := &swarm.SecretReference{
 | 
			
		||||
		File: &swarm.SecretReferenceFileTarget{
 | 
			
		||||
			UID:  "0",
 | 
			
		||||
			GID:  "0",
 | 
			
		||||
			Mode: 0o444,
 | 
			
		||||
@@ -94,6 +94,6 @@ func (o *SecretOpt) String() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value returns the secret requests
 | 
			
		||||
func (o *SecretOpt) Value() []*swarmtypes.SecretReference {
 | 
			
		||||
func (o *SecretOpt) Value() []*swarm.SecretReference {
 | 
			
		||||
	return o.values
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5508,8 +5508,11 @@ definitions:
 | 
			
		||||
          com.example.some-other-label: "some-other-value"
 | 
			
		||||
      Data:
 | 
			
		||||
        description: |
 | 
			
		||||
          Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5))
 | 
			
		||||
          data to store as secret.
 | 
			
		||||
          Data is the data to store as a secret, formatted as a Base64-url-safe-encoded
 | 
			
		||||
          ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) string.
 | 
			
		||||
          It must be empty if the Driver field is set, in which case the data is
 | 
			
		||||
          loaded from an external secret store. The maximum allowed size is 500KB,
 | 
			
		||||
          as defined in [MaxSecretSize](https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize).
 | 
			
		||||
 | 
			
		||||
          This field is only used to _create_ a secret, and is not returned by
 | 
			
		||||
          other endpoints.
 | 
			
		||||
@@ -5560,8 +5563,9 @@ definitions:
 | 
			
		||||
          type: "string"
 | 
			
		||||
      Data:
 | 
			
		||||
        description: |
 | 
			
		||||
          Base64-url-safe-encoded ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5))
 | 
			
		||||
          config data.
 | 
			
		||||
          Data is the data to store as a config, formatted as a Base64-url-safe-encoded
 | 
			
		||||
          ([RFC 4648](https://tools.ietf.org/html/rfc4648#section-5)) string.
 | 
			
		||||
          The maximum allowed size is 1000KB, as defined in [MaxConfigSize](https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize).
 | 
			
		||||
        type: "string"
 | 
			
		||||
      Templating:
 | 
			
		||||
        description: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/docker/docker/api/types/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/docker/docker/api/types/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -49,15 +49,17 @@ func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON sets the IPNet from a byte array of JSON
 | 
			
		||||
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) (err error) {
 | 
			
		||||
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	var ipnetStr string
 | 
			
		||||
	if err = json.Unmarshal(b, &ipnetStr); err == nil {
 | 
			
		||||
		var cidr *net.IPNet
 | 
			
		||||
		if _, cidr, err = net.ParseCIDR(ipnetStr); err == nil {
 | 
			
		||||
	if err := json.Unmarshal(b, &ipnetStr); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, cidr, err := net.ParseCIDR(ipnetStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*ipnet = NetIPNet(*cidr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IndexInfo contains information about a registry
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/api/types/swarm/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/api/types/swarm/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -12,6 +12,12 @@ type Config struct {
 | 
			
		||||
// ConfigSpec represents a config specification from a config in swarm
 | 
			
		||||
type ConfigSpec struct {
 | 
			
		||||
	Annotations
 | 
			
		||||
 | 
			
		||||
	// Data is the data to store as a config.
 | 
			
		||||
	//
 | 
			
		||||
	// The maximum allowed size is 1000KB, as defined in [MaxConfigSize].
 | 
			
		||||
	//
 | 
			
		||||
	// [MaxConfigSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize
 | 
			
		||||
	Data []byte `json:",omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Templating controls whether and how to evaluate the config payload as
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/docker/docker/api/types/swarm/secret.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/docker/docker/api/types/swarm/secret.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -12,8 +12,22 @@ type Secret struct {
 | 
			
		||||
// SecretSpec represents a secret specification from a secret in swarm
 | 
			
		||||
type SecretSpec struct {
 | 
			
		||||
	Annotations
 | 
			
		||||
 | 
			
		||||
	// Data is the data to store as a secret. It must be empty if a
 | 
			
		||||
	// [Driver] is used, in which case the data is loaded from an external
 | 
			
		||||
	// secret store. The maximum allowed size is 500KB, as defined in
 | 
			
		||||
	// [MaxSecretSize].
 | 
			
		||||
	//
 | 
			
		||||
	// This field is only used to create the secret, and is not returned
 | 
			
		||||
	// by other endpoints.
 | 
			
		||||
	//
 | 
			
		||||
	// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize
 | 
			
		||||
	Data []byte `json:",omitempty"`
 | 
			
		||||
	Driver *Driver `json:",omitempty"` // name of the secrets driver used to fetch the secret's value from an external secret store
 | 
			
		||||
 | 
			
		||||
	// Driver is the name of the secrets driver used to fetch the secret's
 | 
			
		||||
	// value from an external secret store. If not set, the default built-in
 | 
			
		||||
	// store is used.
 | 
			
		||||
	Driver *Driver `json:",omitempty"`
 | 
			
		||||
 | 
			
		||||
	// Templating controls whether and how to evaluate the secret payload as
 | 
			
		||||
	// a template. If it is not set, no templating is used.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/docker/docker/client/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/docker/docker/client/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ package client // import "github.com/docker/docker/client"
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"sort"
 | 
			
		||||
@@ -54,6 +55,19 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
 | 
			
		||||
			// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
 | 
			
		||||
			hostConfig.ConsoleSize = [2]uint{0, 0}
 | 
			
		||||
		}
 | 
			
		||||
		if versions.LessThan(cli.ClientVersion(), "1.44") {
 | 
			
		||||
			for _, m := range hostConfig.Mounts {
 | 
			
		||||
				if m.BindOptions != nil {
 | 
			
		||||
					// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
			
		||||
					if m.BindOptions.ReadOnlyForceRecursive {
 | 
			
		||||
						return response, errors.New("bind-recursive=readonly requires API v1.44 or later")
 | 
			
		||||
					}
 | 
			
		||||
					if m.BindOptions.NonRecursive && versions.LessThan(cli.ClientVersion(), "1.40") {
 | 
			
		||||
						return response, errors.New("bind-recursive=disabled requires API v1.40 or later")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd)
 | 
			
		||||
		hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/docker/docker/client/service_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/docker/docker/client/service_create.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -37,6 +37,11 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
 | 
			
		||||
	if err := validateServiceSpec(service); err != nil {
 | 
			
		||||
		return response, err
 | 
			
		||||
	}
 | 
			
		||||
	if versions.LessThan(cli.version, "1.30") {
 | 
			
		||||
		if err := validateAPIVersion(service, cli.version); err != nil {
 | 
			
		||||
			return response, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ensure that the image is tagged
 | 
			
		||||
	var resolveWarning string
 | 
			
		||||
@@ -191,3 +196,18 @@ func validateServiceSpec(s swarm.ServiceSpec) error {
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateAPIVersion(c swarm.ServiceSpec, apiVersion string) error {
 | 
			
		||||
	for _, m := range c.TaskTemplate.ContainerSpec.Mounts {
 | 
			
		||||
		if m.BindOptions != nil {
 | 
			
		||||
			if m.BindOptions.NonRecursive && versions.LessThan(apiVersion, "1.40") {
 | 
			
		||||
				return errors.Errorf("bind-recursive=disabled requires API v1.40 or later")
 | 
			
		||||
			}
 | 
			
		||||
			// ReadOnlyNonRecursive can be safely ignored when API < 1.44
 | 
			
		||||
			if m.BindOptions.ReadOnlyForceRecursive && versions.LessThan(apiVersion, "1.44") {
 | 
			
		||||
				return errors.Errorf("bind-recursive=readonly requires API v1.44 or later")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/archive.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/archive.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -236,11 +236,9 @@ func (r *readCloserWrapper) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	bufioReader32KPool = &sync.Pool{
 | 
			
		||||
var bufioReader32KPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
 | 
			
		||||
}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type bufferedReader struct {
 | 
			
		||||
	buf *bufio.Reader
 | 
			
		||||
@@ -252,17 +250,17 @@ func newBufferedReader(r io.Reader) *bufferedReader {
 | 
			
		||||
	return &bufferedReader{buf}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *bufferedReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
func (r *bufferedReader) Read(p []byte) (int, error) {
 | 
			
		||||
	if r.buf == nil {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	n, err = r.buf.Read(p)
 | 
			
		||||
	n, err := r.buf.Read(p)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		r.buf.Reset(nil)
 | 
			
		||||
		bufioReader32KPool.Put(r.buf)
 | 
			
		||||
		r.buf = nil
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *bufferedReader) Peek(n int) ([]byte, error) {
 | 
			
		||||
@@ -428,7 +426,7 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
 | 
			
		||||
					pipeWriter.CloseWithError(err)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				if _, err := copyWithBuffer(tarWriter, tarReader); err != nil {
 | 
			
		||||
				if err := copyWithBuffer(tarWriter, tarReader); err != nil {
 | 
			
		||||
					pipeWriter.CloseWithError(err)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
@@ -731,7 +729,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_, err = copyWithBuffer(ta.TarWriter, file)
 | 
			
		||||
		err = copyWithBuffer(ta.TarWriter, file)
 | 
			
		||||
		file.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -778,11 +776,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := copyWithBuffer(file, reader); err != nil {
 | 
			
		||||
			file.Close()
 | 
			
		||||
		if err := copyWithBuffer(file, reader); err != nil {
 | 
			
		||||
			_ = file.Close()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		file.Close()
 | 
			
		||||
		_ = file.Close()
 | 
			
		||||
 | 
			
		||||
	case tar.TypeBlock, tar.TypeChar:
 | 
			
		||||
		if inUserns { // cannot create devices in a userns
 | 
			
		||||
@@ -1438,7 +1436,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 | 
			
		||||
			if err := tw.WriteHeader(hdr); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if _, err := copyWithBuffer(tw, srcF); err != nil {
 | 
			
		||||
			if err := copyWithBuffer(tw, srcF); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -20,7 +20,7 @@ func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
 | 
			
		||||
 | 
			
		||||
type overlayWhiteoutConverter struct{}
 | 
			
		||||
 | 
			
		||||
func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
 | 
			
		||||
func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, _ error) {
 | 
			
		||||
	// convert whiteouts to AUFS format
 | 
			
		||||
	if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
 | 
			
		||||
		// we just rename the file and make it normal
 | 
			
		||||
@@ -31,7 +31,11 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 | 
			
		||||
		hdr.Size = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fi.Mode()&os.ModeDir != 0 {
 | 
			
		||||
	if fi.Mode()&os.ModeDir == 0 {
 | 
			
		||||
		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opaqueXattrName := "trusted.overlay.opaque"
 | 
			
		||||
	if userns.RunningInUserNS() {
 | 
			
		||||
		opaqueXattrName = "user.overlay.opaque"
 | 
			
		||||
@@ -42,12 +46,15 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
		if len(opaque) == 1 && opaque[0] == 'y' {
 | 
			
		||||
	if len(opaque) != 1 || opaque[0] != 'y' {
 | 
			
		||||
		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
 | 
			
		||||
 | 
			
		||||
	// create a header for the whiteout file
 | 
			
		||||
	// it should inherit some properties from the parent, but be a regular file
 | 
			
		||||
			wo = &tar.Header{
 | 
			
		||||
	return &tar.Header{
 | 
			
		||||
		Typeflag:   tar.TypeReg,
 | 
			
		||||
		Mode:       hdr.Mode & int64(os.ModePerm),
 | 
			
		||||
		Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
 | 
			
		||||
@@ -58,11 +65,7 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 | 
			
		||||
		Gname:      hdr.Gname,
 | 
			
		||||
		AccessTime: hdr.AccessTime,
 | 
			
		||||
		ChangeTime: hdr.ChangeTime,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -73,14 +73,13 @@ func statUnix(fi os.FileInfo, hdr *tar.Header) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getInodeFromStat(stat interface{}) (inode uint64, err error) {
 | 
			
		||||
func getInodeFromStat(stat interface{}) (uint64, error) {
 | 
			
		||||
	s, ok := stat.(*syscall.Stat_t)
 | 
			
		||||
 | 
			
		||||
	if ok {
 | 
			
		||||
		inode = s.Ino
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// FIXME(thaJeztah): this should likely return an error; see https://github.com/moby/moby/pull/49493#discussion_r1979152897
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
	return s.Ino, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/docker/pkg/archive/archive_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -48,9 +48,9 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getInodeFromStat(stat interface{}) (inode uint64, err error) {
 | 
			
		||||
func getInodeFromStat(stat interface{}) (uint64, error) {
 | 
			
		||||
	// do nothing. no notion of Inode in stat on Windows
 | 
			
		||||
	return
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleTarTypeBlockCharFifo is an OS-specific helper function used by
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/docker/docker/pkg/archive/changes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/docker/docker/pkg/archive/changes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -83,7 +83,7 @@ func aufsMetadataSkip(path string) (skip bool, err error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		skip = true
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return skip, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/docker/pkg/archive/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -25,11 +25,11 @@ var copyPool = sync.Pool{
 | 
			
		||||
	New: func() interface{} { s := make([]byte, 32*1024); return &s },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
 | 
			
		||||
func copyWithBuffer(dst io.Writer, src io.Reader) error {
 | 
			
		||||
	buf := copyPool.Get().(*[]byte)
 | 
			
		||||
	written, err = io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	copyPool.Put(buf)
 | 
			
		||||
	return
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PreserveTrailingDotOrSeparator returns the given cleaned path (after
 | 
			
		||||
@@ -105,13 +105,13 @@ func TarResource(sourceInfo CopyInfo) (content io.ReadCloser, err error) {
 | 
			
		||||
 | 
			
		||||
// TarResourceRebase is like TarResource but renames the first path element of
 | 
			
		||||
// items in the resulting tar archive to match the given rebaseName if not "".
 | 
			
		||||
func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, err error) {
 | 
			
		||||
func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, _ error) {
 | 
			
		||||
	sourcePath = normalizePath(sourcePath)
 | 
			
		||||
	if _, err = os.Lstat(sourcePath); err != nil {
 | 
			
		||||
	if _, err := os.Lstat(sourcePath); err != nil {
 | 
			
		||||
		// Catches the case where the source does not exist or is not a
 | 
			
		||||
		// directory if asserted to be a directory, as this also causes an
 | 
			
		||||
		// error.
 | 
			
		||||
		return
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Separate the source path between its directory and
 | 
			
		||||
@@ -442,11 +442,12 @@ func CopyTo(content io.Reader, srcInfo CopyInfo, dstPath string) error {
 | 
			
		||||
// whether to follow symbol link or not, if followLink is true, resolvedPath will return
 | 
			
		||||
// link target of any symbol link file, else it will only resolve symlink of directory
 | 
			
		||||
// but return symbol link file itself without resolving.
 | 
			
		||||
func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, err error) {
 | 
			
		||||
func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, _ error) {
 | 
			
		||||
	if followLink {
 | 
			
		||||
		var err error
 | 
			
		||||
		resolvedPath, err = filepath.EvalSymlinks(path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
			return "", "", err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		resolvedPath, rebaseName = GetRebaseName(path, resolvedPath)
 | 
			
		||||
@@ -454,10 +455,9 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
 | 
			
		||||
		dirPath, basePath := filepath.Split(path)
 | 
			
		||||
 | 
			
		||||
		// if not follow symbol link, then resolve symbol link of parent dir
 | 
			
		||||
		var resolvedDirPath string
 | 
			
		||||
		resolvedDirPath, err = filepath.EvalSymlinks(dirPath)
 | 
			
		||||
		resolvedDirPath, err := filepath.EvalSymlinks(dirPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
			return "", "", err
 | 
			
		||||
		}
 | 
			
		||||
		// resolvedDirPath will have been cleaned (no trailing path separators) so
 | 
			
		||||
		// we can manually join it with the base path element.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -17,12 +17,13 @@ func chtimes(name string, atime time.Time, mtime time.Time) error {
 | 
			
		||||
	return os.Chtimes(name, atime, mtime)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func timeToTimespec(time time.Time) (ts unix.Timespec) {
 | 
			
		||||
func timeToTimespec(time time.Time) unix.Timespec {
 | 
			
		||||
	if time.IsZero() {
 | 
			
		||||
		// Return UTIME_OMIT special value
 | 
			
		||||
		ts.Sec = 0
 | 
			
		||||
		ts.Nsec = (1 << 30) - 2
 | 
			
		||||
		return
 | 
			
		||||
		return unix.Timespec{
 | 
			
		||||
			Sec:  0,
 | 
			
		||||
			Nsec: (1 << 30) - 2,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return unix.NsecToTimespec(time.UnixNano())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/pkg/archive/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/pkg/archive/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -45,8 +45,8 @@ func Generate(input ...string) (io.Reader, error) {
 | 
			
		||||
	return buf, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseStringPairs(input ...string) (output [][2]string) {
 | 
			
		||||
	output = make([][2]string, 0, len(input)/2+1)
 | 
			
		||||
func parseStringPairs(input ...string) [][2]string {
 | 
			
		||||
	output := make([][2]string, 0, len(input)/2+1)
 | 
			
		||||
	for i := 0; i < len(input); i += 2 {
 | 
			
		||||
		var pair [2]string
 | 
			
		||||
		pair[0] = input[i]
 | 
			
		||||
@@ -55,5 +55,5 @@ func parseStringPairs(input ...string) (output [][2]string) {
 | 
			
		||||
		}
 | 
			
		||||
		output = append(output, pair)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return output
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -11,12 +11,12 @@ import (
 | 
			
		||||
// destination path. Writing and closing concurrently is not allowed.
 | 
			
		||||
// NOTE: umask is not considered for the file's permissions.
 | 
			
		||||
func New(filename string, perm os.FileMode) (io.WriteCloser, error) {
 | 
			
		||||
	f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
 | 
			
		||||
	abspath, err := filepath.Abs(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	abspath, err := filepath.Abs(filename)
 | 
			
		||||
	f, err := os.CreateTemp(filepath.Dir(abspath), ".tmp-"+filepath.Base(filename))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -43,9 +43,9 @@ type stdWriter struct {
 | 
			
		||||
// It inserts the prefix header before the buffer,
 | 
			
		||||
// so stdcopy.StdCopy knows where to multiplex the output.
 | 
			
		||||
// It makes stdWriter to implement io.Writer.
 | 
			
		||||
func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
func (w *stdWriter) Write(p []byte) (int, error) {
 | 
			
		||||
	if w == nil || w.Writer == nil {
 | 
			
		||||
		return 0, errors.New("Writer not instantiated")
 | 
			
		||||
		return 0, errors.New("writer not instantiated")
 | 
			
		||||
	}
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
@@ -57,7 +57,7 @@ func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	buf.Write(header[:])
 | 
			
		||||
	buf.Write(p)
 | 
			
		||||
 | 
			
		||||
	n, err = w.Writer.Write(buf.Bytes())
 | 
			
		||||
	n, err := w.Writer.Write(buf.Bytes())
 | 
			
		||||
	n -= stdWriterPrefixLen
 | 
			
		||||
	if n < 0 {
 | 
			
		||||
		n = 0
 | 
			
		||||
@@ -65,7 +65,7 @@ func (w *stdWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
 | 
			
		||||
	buf.Reset()
 | 
			
		||||
	bufPool.Put(buf)
 | 
			
		||||
	return
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewStdWriter instantiates a new Writer.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/docker/docker/registry/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/docker/docker/registry/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -66,13 +66,13 @@ func (scs staticCredentialStore) SetRefreshToken(*url.URL, string, string) {
 | 
			
		||||
// loginV2 tries to login to the v2 registry server. The given registry
 | 
			
		||||
// endpoint will be pinged to get authorization challenges. These challenges
 | 
			
		||||
// will be used to authenticate against the registry to validate credentials.
 | 
			
		||||
func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent string) (status string, token string, _ error) {
 | 
			
		||||
func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent string) (token string, _ error) {
 | 
			
		||||
	endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
			
		||||
	log.G(context.TODO()).Debugf("attempting v2 login to registry endpoint %s", endpointStr)
 | 
			
		||||
 | 
			
		||||
	req, err := http.NewRequest(http.MethodGet, endpointStr, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
@@ -84,22 +84,22 @@ func loginV2(authConfig *registry.AuthConfig, endpoint APIEndpoint, userAgent st
 | 
			
		||||
 | 
			
		||||
	loginClient, err := v2AuthHTTPClient(endpoint.URL, authTrans, modifiers, creds, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := loginClient.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = translateV2AuthError(err)
 | 
			
		||||
		return "", "", err
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode == http.StatusOK {
 | 
			
		||||
		return "Login Succeeded", credentialAuthConfig.IdentityToken, nil
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
 | 
			
		||||
		return "", errors.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
 | 
			
		||||
	return "", "", errors.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
 | 
			
		||||
	return credentialAuthConfig.IdentityToken, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										160
									
								
								vendor/github.com/docker/docker/registry/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										160
									
								
								vendor/github.com/docker/docker/registry/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,13 +4,17 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/log"
 | 
			
		||||
	"github.com/distribution/reference"
 | 
			
		||||
	"github.com/docker/docker/api/types/registry"
 | 
			
		||||
	"github.com/docker/docker/internal/lazyregexp"
 | 
			
		||||
	"github.com/docker/docker/pkg/homedir"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ServiceOptions holds command line options.
 | 
			
		||||
@@ -56,26 +60,52 @@ var (
 | 
			
		||||
		Host:   DefaultRegistryHost,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	emptyServiceConfig, _ = newServiceConfig(ServiceOptions{})
 | 
			
		||||
	validHostPortRegex = lazyregexp.New(`^` + reference.DomainRegexp.String() + `$`)
 | 
			
		||||
 | 
			
		||||
	// certsDir is used to override defaultCertsDir.
 | 
			
		||||
	// certsDir is used to override defaultCertsDir when running with rootlessKit.
 | 
			
		||||
	//
 | 
			
		||||
	// TODO(thaJeztah): change to a sync.OnceValue once we remove [SetCertsDir]
 | 
			
		||||
	// TODO(thaJeztah): certsDir should not be a package variable, but stored in our config, and passed when needed.
 | 
			
		||||
	setCertsDirOnce sync.Once
 | 
			
		||||
	certsDir        string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func setCertsDir(dir string) string {
 | 
			
		||||
	setCertsDirOnce.Do(func() {
 | 
			
		||||
		if dir != "" {
 | 
			
		||||
			certsDir = dir
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" {
 | 
			
		||||
			// Configure registry.CertsDir() when running in rootless-mode
 | 
			
		||||
			// This is the equivalent of [rootless.RunningWithRootlessKit],
 | 
			
		||||
			// but inlining it to prevent adding that as a dependency
 | 
			
		||||
			// for docker/cli.
 | 
			
		||||
			//
 | 
			
		||||
			// [rootless.RunningWithRootlessKit]: https://github.com/moby/moby/blob/b4bdf12daec84caaf809a639f923f7370d4926ad/pkg/rootless/rootless.go#L5-L8
 | 
			
		||||
			if configHome, _ := homedir.GetConfigHome(); configHome != "" {
 | 
			
		||||
				certsDir = filepath.Join(configHome, "docker/certs.d")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		certsDir = defaultCertsDir
 | 
			
		||||
	})
 | 
			
		||||
	return certsDir
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetCertsDir allows the default certs directory to be changed. This function
 | 
			
		||||
// is used at daemon startup to set the correct location when running in
 | 
			
		||||
// rootless mode.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: the cert-directory is now automatically selected when running with rootlessKit, and should no longer be set manually.
 | 
			
		||||
func SetCertsDir(path string) {
 | 
			
		||||
	certsDir = path
 | 
			
		||||
	setCertsDir(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CertsDir is the directory where certificates are stored.
 | 
			
		||||
func CertsDir() string {
 | 
			
		||||
	if certsDir != "" {
 | 
			
		||||
		return certsDir
 | 
			
		||||
	}
 | 
			
		||||
	return defaultCertsDir
 | 
			
		||||
	// call setCertsDir with an empty path to synchronise with [SetCertsDir]
 | 
			
		||||
	return setCertsDir("")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newServiceConfig returns a new instance of ServiceConfig
 | 
			
		||||
@@ -181,7 +211,7 @@ skip:
 | 
			
		||||
			// Assume `host:port` if not CIDR.
 | 
			
		||||
			indexConfigs[r] = ®istry.IndexInfo{
 | 
			
		||||
				Name:     r,
 | 
			
		||||
				Mirrors:  make([]string, 0),
 | 
			
		||||
				Mirrors:  []string{},
 | 
			
		||||
				Secure:   false,
 | 
			
		||||
				Official: false,
 | 
			
		||||
			}
 | 
			
		||||
@@ -288,16 +318,22 @@ func ValidateMirror(val string) (string, error) {
 | 
			
		||||
// ValidateIndexName validates an index name. It is used by the daemon to
 | 
			
		||||
// validate the daemon configuration.
 | 
			
		||||
func ValidateIndexName(val string) (string, error) {
 | 
			
		||||
	// TODO: upstream this to check to reference package
 | 
			
		||||
	if val == "index.docker.io" {
 | 
			
		||||
		val = "docker.io"
 | 
			
		||||
	}
 | 
			
		||||
	val = normalizeIndexName(val)
 | 
			
		||||
	if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
 | 
			
		||||
		return "", invalidParamf("invalid index name (%s). Cannot begin or end with a hyphen", val)
 | 
			
		||||
	}
 | 
			
		||||
	return val, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func normalizeIndexName(val string) string {
 | 
			
		||||
	// TODO(thaJeztah): consider normalizing other known options, such as "(https://)registry-1.docker.io", "https://index.docker.io/v1/".
 | 
			
		||||
	// TODO: upstream this to check to reference package
 | 
			
		||||
	if val == "index.docker.io" {
 | 
			
		||||
		return "docker.io"
 | 
			
		||||
	}
 | 
			
		||||
	return val
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasScheme(reposName string) bool {
 | 
			
		||||
	return strings.Contains(reposName, "://")
 | 
			
		||||
}
 | 
			
		||||
@@ -327,25 +363,20 @@ func validateHostPort(s string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newIndexInfo returns IndexInfo configuration from indexName
 | 
			
		||||
func newIndexInfo(config *serviceConfig, indexName string) (*registry.IndexInfo, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	indexName, err = ValidateIndexName(indexName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
func newIndexInfo(config *serviceConfig, indexName string) *registry.IndexInfo {
 | 
			
		||||
	indexName = normalizeIndexName(indexName)
 | 
			
		||||
 | 
			
		||||
	// Return any configured index info, first.
 | 
			
		||||
	if index, ok := config.IndexConfigs[indexName]; ok {
 | 
			
		||||
		return index, nil
 | 
			
		||||
		return index
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Construct a non-configured index info.
 | 
			
		||||
	return ®istry.IndexInfo{
 | 
			
		||||
		Name:    indexName,
 | 
			
		||||
		Mirrors:  make([]string, 0),
 | 
			
		||||
		Mirrors: []string{},
 | 
			
		||||
		Secure:  config.isSecureIndex(indexName),
 | 
			
		||||
		Official: false,
 | 
			
		||||
	}, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAuthConfigKey special-cases using the full index address of the official
 | 
			
		||||
@@ -358,18 +389,22 @@ func GetAuthConfigKey(index *registry.IndexInfo) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
 | 
			
		||||
func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
 | 
			
		||||
	index, err := newIndexInfo(config, reference.Domain(name))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
func newRepositoryInfo(config *serviceConfig, name reference.Named) *RepositoryInfo {
 | 
			
		||||
	index := newIndexInfo(config, reference.Domain(name))
 | 
			
		||||
	var officialRepo bool
 | 
			
		||||
	if index.Official {
 | 
			
		||||
		// RepositoryInfo.Official indicates whether the image repository
 | 
			
		||||
		// is an official (docker library official images) repository.
 | 
			
		||||
		//
 | 
			
		||||
		// We only need to check this if the image-repository is on Docker Hub.
 | 
			
		||||
		officialRepo = !strings.ContainsRune(reference.FamiliarName(name), '/')
 | 
			
		||||
	}
 | 
			
		||||
	official := !strings.ContainsRune(reference.FamiliarName(name), '/')
 | 
			
		||||
 | 
			
		||||
	return &RepositoryInfo{
 | 
			
		||||
		Name:     reference.TrimNamed(name),
 | 
			
		||||
		Index:    index,
 | 
			
		||||
		Official: official,
 | 
			
		||||
	}, nil
 | 
			
		||||
		Official: officialRepo,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseRepositoryInfo performs the breakdown of a repository name into a
 | 
			
		||||
@@ -377,5 +412,70 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
 | 
			
		||||
//
 | 
			
		||||
// It is used by the Docker cli to interact with registry-related endpoints.
 | 
			
		||||
func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
 | 
			
		||||
	return newRepositoryInfo(emptyServiceConfig, reposName)
 | 
			
		||||
	indexName := normalizeIndexName(reference.Domain(reposName))
 | 
			
		||||
	if indexName == IndexName {
 | 
			
		||||
		officialRepo := !strings.ContainsRune(reference.FamiliarName(reposName), '/')
 | 
			
		||||
		return &RepositoryInfo{
 | 
			
		||||
			Name: reference.TrimNamed(reposName),
 | 
			
		||||
			Index: ®istry.IndexInfo{
 | 
			
		||||
				Name:     IndexName,
 | 
			
		||||
				Mirrors:  []string{},
 | 
			
		||||
				Secure:   true,
 | 
			
		||||
				Official: true,
 | 
			
		||||
			},
 | 
			
		||||
			Official: officialRepo,
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	insecure := false
 | 
			
		||||
	if isInsecure(indexName) {
 | 
			
		||||
		insecure = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &RepositoryInfo{
 | 
			
		||||
		Name: reference.TrimNamed(reposName),
 | 
			
		||||
		Index: ®istry.IndexInfo{
 | 
			
		||||
			Name:    indexName,
 | 
			
		||||
			Mirrors: []string{},
 | 
			
		||||
			Secure:  !insecure,
 | 
			
		||||
		},
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isInsecure is used to detect whether a registry domain or IP-address is allowed
 | 
			
		||||
// to use an insecure (non-TLS, or self-signed cert) connection according to the
 | 
			
		||||
// defaults, which allows for insecure connections with registries running on a
 | 
			
		||||
// loopback address ("localhost", "::1/128", "127.0.0.0/8").
 | 
			
		||||
//
 | 
			
		||||
// It is used in situations where we don't have access to the daemon's configuration,
 | 
			
		||||
// for example, when used from the client / CLI.
 | 
			
		||||
func isInsecure(hostNameOrIP string) bool {
 | 
			
		||||
	// Attempt to strip port if present; this also strips brackets for
 | 
			
		||||
	// IPv6 addresses with a port (e.g. "[::1]:5000").
 | 
			
		||||
	//
 | 
			
		||||
	// This is best-effort; we'll continue using the address as-is if it fails.
 | 
			
		||||
	if host, _, err := net.SplitHostPort(hostNameOrIP); err == nil {
 | 
			
		||||
		hostNameOrIP = host
 | 
			
		||||
	}
 | 
			
		||||
	if hostNameOrIP == "127.0.0.1" || hostNameOrIP == "::1" || strings.EqualFold(hostNameOrIP, "localhost") {
 | 
			
		||||
		// Fast path; no need to resolve these, assuming nobody overrides
 | 
			
		||||
		// "localhost" for anything else than a loopback address (sorry, not sorry).
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var addresses []net.IP
 | 
			
		||||
	if ip := net.ParseIP(hostNameOrIP); ip != nil {
 | 
			
		||||
		addresses = append(addresses, ip)
 | 
			
		||||
	} else {
 | 
			
		||||
		// Try to resolve the host's IP-addresses.
 | 
			
		||||
		addrs, _ := lookupIP(hostNameOrIP)
 | 
			
		||||
		addresses = append(addresses, addrs...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, addr := range addresses {
 | 
			
		||||
		if addr.IsLoopback() {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/github.com/docker/docker/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								vendor/github.com/docker/docker/registry/registry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -8,7 +8,6 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/log"
 | 
			
		||||
@@ -18,7 +17,14 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HostCertsDir returns the config directory for a specific host.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: this function was only used internally, and will be removed in a future release.
 | 
			
		||||
func HostCertsDir(hostname string) string {
 | 
			
		||||
	return hostCertsDir(hostname)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// hostCertsDir returns the config directory for a specific host.
 | 
			
		||||
func hostCertsDir(hostname string) string {
 | 
			
		||||
	return filepath.Join(CertsDir(), cleanPath(hostname))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -26,11 +32,10 @@ func HostCertsDir(hostname string) string {
 | 
			
		||||
func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
 | 
			
		||||
	// PreferredServerCipherSuites should have no effect
 | 
			
		||||
	tlsConfig := tlsconfig.ServerDefault()
 | 
			
		||||
 | 
			
		||||
	tlsConfig.InsecureSkipVerify = !isSecure
 | 
			
		||||
 | 
			
		||||
	if isSecure && CertsDir() != "" {
 | 
			
		||||
		hostDir := HostCertsDir(hostname)
 | 
			
		||||
	if isSecure {
 | 
			
		||||
		hostDir := hostCertsDir(hostname)
 | 
			
		||||
		log.G(context.TODO()).Debugf("hostDir: %s", hostDir)
 | 
			
		||||
		if err := ReadCertsDirectory(tlsConfig, hostDir); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
@@ -59,7 +64,8 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range fs {
 | 
			
		||||
		if strings.HasSuffix(f.Name(), ".crt") {
 | 
			
		||||
		switch filepath.Ext(f.Name()) {
 | 
			
		||||
		case ".crt":
 | 
			
		||||
			if tlsConfig.RootCAs == nil {
 | 
			
		||||
				systemPool, err := tlsconfig.SystemCertPool()
 | 
			
		||||
				if err != nil {
 | 
			
		||||
@@ -67,17 +73,17 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
			
		||||
				}
 | 
			
		||||
				tlsConfig.RootCAs = systemPool
 | 
			
		||||
			}
 | 
			
		||||
			log.G(context.TODO()).Debugf("crt: %s", filepath.Join(directory, f.Name()))
 | 
			
		||||
			data, err := os.ReadFile(filepath.Join(directory, f.Name()))
 | 
			
		||||
			fileName := filepath.Join(directory, f.Name())
 | 
			
		||||
			log.G(context.TODO()).Debugf("crt: %s", fileName)
 | 
			
		||||
			data, err := os.ReadFile(fileName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			tlsConfig.RootCAs.AppendCertsFromPEM(data)
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasSuffix(f.Name(), ".cert") {
 | 
			
		||||
		case ".cert":
 | 
			
		||||
			certName := f.Name()
 | 
			
		||||
			keyName := certName[:len(certName)-5] + ".key"
 | 
			
		||||
			log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, f.Name()))
 | 
			
		||||
			log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, certName))
 | 
			
		||||
			if !hasFile(fs, keyName) {
 | 
			
		||||
				return invalidParamf("missing key %s for client certificate %s. CA certificates must use the extension .crt", keyName, certName)
 | 
			
		||||
			}
 | 
			
		||||
@@ -86,11 +92,10 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasSuffix(f.Name(), ".key") {
 | 
			
		||||
		case ".key":
 | 
			
		||||
			keyName := f.Name()
 | 
			
		||||
			certName := keyName[:len(keyName)-4] + ".cert"
 | 
			
		||||
			log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, f.Name()))
 | 
			
		||||
			log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, keyName))
 | 
			
		||||
			if !hasFile(fs, certName) {
 | 
			
		||||
				return invalidParamf("missing client certificate %s for key %s", certName, keyName)
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/docker/docker/registry/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/docker/docker/registry/search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -93,12 +93,8 @@ func (s *Service) searchUnfiltered(ctx context.Context, term string, limit int,
 | 
			
		||||
 | 
			
		||||
	// Search is a long-running operation, just lock s.config to avoid block others.
 | 
			
		||||
	s.mu.RLock()
 | 
			
		||||
	index, err := newIndexInfo(s.config, indexName)
 | 
			
		||||
	index := newIndexInfo(s.config, indexName)
 | 
			
		||||
	s.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if index.Official {
 | 
			
		||||
		// If pull "library/foo", it's stored locally under "foo"
 | 
			
		||||
		remoteName = strings.TrimPrefix(remoteName, "library/")
 | 
			
		||||
@@ -158,5 +154,24 @@ func splitReposSearchTerm(reposName string) (string, string) {
 | 
			
		||||
// for that.
 | 
			
		||||
func ParseSearchIndexInfo(reposName string) (*registry.IndexInfo, error) {
 | 
			
		||||
	indexName, _ := splitReposSearchTerm(reposName)
 | 
			
		||||
	return newIndexInfo(emptyServiceConfig, indexName)
 | 
			
		||||
	indexName = normalizeIndexName(indexName)
 | 
			
		||||
	if indexName == IndexName {
 | 
			
		||||
		return ®istry.IndexInfo{
 | 
			
		||||
			Name:     IndexName,
 | 
			
		||||
			Mirrors:  []string{},
 | 
			
		||||
			Secure:   true,
 | 
			
		||||
			Official: true,
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	insecure := false
 | 
			
		||||
	if isInsecure(indexName) {
 | 
			
		||||
		insecure = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ®istry.IndexInfo{
 | 
			
		||||
		Name:    indexName,
 | 
			
		||||
		Mirrors: []string{},
 | 
			
		||||
		Secure:  !insecure,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/registry/search_session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/registry/search_session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -83,12 +83,12 @@ type onEOFReader struct {
 | 
			
		||||
	Fn func()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *onEOFReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	n, err = r.Rc.Read(p)
 | 
			
		||||
func (r *onEOFReader) Read(p []byte) (int, error) {
 | 
			
		||||
	n, err := r.Rc.Read(p)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		r.runFunc()
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the file and run the function.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/docker/docker/registry/service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/docker/docker/registry/service.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -52,7 +52,7 @@ func (s *Service) ReplaceConfig(options ServiceOptions) (commit func(), err erro
 | 
			
		||||
// Auth contacts the public registry with the provided credentials,
 | 
			
		||||
// and returns OK if authentication was successful.
 | 
			
		||||
// It can be used to verify the validity of a client's credentials.
 | 
			
		||||
func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (status, token string, err error) {
 | 
			
		||||
func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (statusMessage, token string, _ error) {
 | 
			
		||||
	// TODO Use ctx when searching for repositories
 | 
			
		||||
	registryHostName := IndexHostname
 | 
			
		||||
 | 
			
		||||
@@ -77,19 +77,28 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
 | 
			
		||||
		return "", "", invalidParam(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var lastErr error
 | 
			
		||||
	for _, endpoint := range endpoints {
 | 
			
		||||
		status, token, err = loginV2(authConfig, endpoint, userAgent)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		authToken, err := loginV2(authConfig, endpoint, userAgent)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errdefs.IsUnauthorized(err) {
 | 
			
		||||
				// Failed to authenticate; don't continue with (non-TLS) endpoints.
 | 
			
		||||
			return status, token, err
 | 
			
		||||
				return "", "", err
 | 
			
		||||
			}
 | 
			
		||||
		log.G(ctx).WithError(err).Infof("Error logging in to endpoint, trying next endpoint")
 | 
			
		||||
			// Try next endpoint
 | 
			
		||||
			log.G(ctx).WithFields(log.Fields{
 | 
			
		||||
				"error":    err,
 | 
			
		||||
				"endpoint": endpoint,
 | 
			
		||||
			}).Infof("Error logging in to endpoint, trying next endpoint")
 | 
			
		||||
			lastErr = err
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	return "", "", err
 | 
			
		||||
		// TODO(thaJeztah): move the statusMessage to the API endpoint; we don't need to produce that here?
 | 
			
		||||
		return "Login Succeeded", authToken, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", "", lastErr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResolveRepository splits a repository name into its components
 | 
			
		||||
@@ -97,7 +106,8 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
 | 
			
		||||
func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
 | 
			
		||||
	s.mu.RLock()
 | 
			
		||||
	defer s.mu.RUnlock()
 | 
			
		||||
	return newRepositoryInfo(s.config, name)
 | 
			
		||||
	// TODO(thaJeztah): remove error return as it's no longer used.
 | 
			
		||||
	return newRepositoryInfo(s.config, name), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// APIEndpoint represents a remote API endpoint
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/docker/docker/registry/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/docker/docker/registry/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,6 +13,8 @@ type RepositoryInfo struct {
 | 
			
		||||
	// Official indicates whether the repository is considered official.
 | 
			
		||||
	// If the registry is official, and the normalized name does not
 | 
			
		||||
	// contain a '/' (e.g. "foo"), then it is considered an official repo.
 | 
			
		||||
	//
 | 
			
		||||
	// Deprecated: this field is no longer used and will be removed in the next release. The information captured in this field can be obtained from the [Name] field instead.
 | 
			
		||||
	Official bool
 | 
			
		||||
	// Class represents the class of the repository, such as "plugin"
 | 
			
		||||
	// or "image".
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -155,7 +155,7 @@ github.com/containerd/console
 | 
			
		||||
# github.com/containerd/containerd/api v1.8.0
 | 
			
		||||
## explicit; go 1.21
 | 
			
		||||
github.com/containerd/containerd/api/services/content/v1
 | 
			
		||||
# github.com/containerd/containerd/v2 v2.0.3
 | 
			
		||||
# github.com/containerd/containerd/v2 v2.0.4
 | 
			
		||||
## explicit; go 1.22.0
 | 
			
		||||
github.com/containerd/containerd/v2/core/content
 | 
			
		||||
github.com/containerd/containerd/v2/core/content/proxy
 | 
			
		||||
@@ -229,11 +229,10 @@ github.com/davecgh/go-spew/spew
 | 
			
		||||
# github.com/distribution/reference v0.6.0
 | 
			
		||||
## explicit; go 1.20
 | 
			
		||||
github.com/distribution/reference
 | 
			
		||||
# github.com/docker/cli v28.0.1+incompatible
 | 
			
		||||
# github.com/docker/cli v28.0.2+incompatible
 | 
			
		||||
## explicit
 | 
			
		||||
github.com/docker/cli/cli
 | 
			
		||||
github.com/docker/cli/cli-plugins/hooks
 | 
			
		||||
github.com/docker/cli/cli-plugins/manager
 | 
			
		||||
github.com/docker/cli/cli-plugins/metadata
 | 
			
		||||
github.com/docker/cli/cli-plugins/plugin
 | 
			
		||||
github.com/docker/cli/cli-plugins/socket
 | 
			
		||||
github.com/docker/cli/cli/command
 | 
			
		||||
@@ -252,6 +251,7 @@ github.com/docker/cli/cli/context/store
 | 
			
		||||
github.com/docker/cli/cli/debug
 | 
			
		||||
github.com/docker/cli/cli/flags
 | 
			
		||||
github.com/docker/cli/cli/hints
 | 
			
		||||
github.com/docker/cli/cli/internal/jsonstream
 | 
			
		||||
github.com/docker/cli/cli/manifest/store
 | 
			
		||||
github.com/docker/cli/cli/manifest/types
 | 
			
		||||
github.com/docker/cli/cli/registry/client
 | 
			
		||||
@@ -260,6 +260,7 @@ github.com/docker/cli/cli/trust
 | 
			
		||||
github.com/docker/cli/cli/version
 | 
			
		||||
github.com/docker/cli/internal/tui
 | 
			
		||||
github.com/docker/cli/opts
 | 
			
		||||
github.com/docker/cli/opts/swarmopts
 | 
			
		||||
github.com/docker/cli/pkg/kvfile
 | 
			
		||||
github.com/docker/cli/templates
 | 
			
		||||
# github.com/docker/cli-docs-tool v0.9.0
 | 
			
		||||
@@ -283,7 +284,7 @@ github.com/docker/distribution/registry/client/transport
 | 
			
		||||
github.com/docker/distribution/registry/storage/cache
 | 
			
		||||
github.com/docker/distribution/registry/storage/cache/memory
 | 
			
		||||
github.com/docker/distribution/uuid
 | 
			
		||||
# github.com/docker/docker v28.0.1+incompatible
 | 
			
		||||
# github.com/docker/docker v28.0.2+incompatible
 | 
			
		||||
## explicit
 | 
			
		||||
github.com/docker/docker/api
 | 
			
		||||
github.com/docker/docker/api/types
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user