diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 42a967defde4..97dee1b3e46b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -75,7 +75,7 @@ jobs: TESTFLAGS: -coverprofile=/tmp/coverage/coverage.txt - name: Send to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: - file: ./build/coverage/coverage.txt + files: ./build/coverage/coverage.txt token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18629f690c2d..f43c6488aa4a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,9 +40,9 @@ jobs: targets: test-coverage - name: Send to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: - file: ./build/coverage/coverage.txt + files: ./build/coverage/coverage.txt token: ${{ secrets.CODECOV_TOKEN }} host: @@ -78,8 +78,8 @@ jobs: shell: bash - name: Send to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: - file: /tmp/coverage.txt + files: /tmp/coverage.txt working-directory: ${{ env.GOPATH }}/src/github.com/docker/cli token: ${{ secrets.CODECOV_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f519a503f2ab..3d199e58e776 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,9 +134,41 @@ committing your changes. Most editors have plug-ins that do this automatically. Pull request descriptions should be as clear as possible and include a reference to all the issues that they address. -Commit messages must start with a capitalized and short summary (max. 50 chars) -written in the imperative, followed by an optional, more detailed explanatory -text which is separated from the summary by an empty line. +Commit messages must be written in the imperative mood (max. 72 chars), followed +by an optional, more detailed explanatory text usually expanding on +why the work is necessary. The explanatory text should be separated by an +empty line. + +The commit message *could* have a prefix scoping the change, however this is +not enforced. Common prefixes are `docs: `, `vendor: `, +`chore: ` or the package/area related to the change such as `pkg/foo: ` +or `telemetry: `. + +A standard commit. +``` +Fix the exploding flux capacitor + +A call to function A causes the flux capacitor to blow up every time +the sun and the moon align. +``` + +Using a package as prefix. +``` +pkg/foo: prevent panic in flux capacitor + +Calling function A causes the flux capacitor to blow up every time +the sun and the moon align. +``` + +Updating a specific vendored package. +``` +vendor: github.com/docker/docker 6ac445c42bad (master, v28.0-dev) +``` + +Fixing a broken docs link. +``` +docs: fix style/lint issues in deprecated.md +``` Code review comments may be added to your pull request. Discuss, then make the suggested modifications and push additional commits to your feature branch. Post diff --git a/Dockerfile b/Dockerfile index c33a66ae8e32..db91ab7f65d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ ARG BASE_DEBIAN_DISTRO=bookworm ARG GO_VERSION=1.23.3 ARG XX_VERSION=1.5.0 -ARG GOVERSIONINFO_VERSION=v1.3.0 +ARG GOVERSIONINFO_VERSION=v1.4.1 ARG GOTESTSUM_VERSION=v1.10.0 ARG BUILDX_VERSION=0.18.0 ARG COMPOSE_VERSION=v2.30.3 diff --git a/cli/command/container/stats.go b/cli/command/container/stats.go index 1ca14ad4c787..d6afb0528c6f 100644 --- a/cli/command/container/stats.go +++ b/cli/command/container/stats.go @@ -287,16 +287,26 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions) cStats.mu.RUnlock() if !options.NoStream { - // Start by clearing the screen and moving the cursor to the top-left - _, _ = fmt.Fprint(&statsTextBuffer, "\033[2J\033[H") + // Start by moving the cursor to the top-left + _, _ = fmt.Fprint(&statsTextBuffer, "\033[H") } if err = statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil { break } - _, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String()) + if !options.NoStream { + for _, line := range strings.Split(statsTextBuffer.String(), "\n") { + // In case the new text is shorter than the one we are writing over, + // we'll append the "erase line" escape sequence to clear the remaining text. + _, _ = fmt.Fprint(&statsTextBuffer, line, "\033[K\n") + } + // We might have fewer containers than before, so let's clear the remaining text + _, _ = fmt.Fprint(&statsTextBuffer, "\033[J") + } + + _, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String()) statsTextBuffer.Reset() if len(cStats.cs) == 0 && !showAll { diff --git a/cli/command/image/load.go b/cli/command/image/load.go index 0bd09c67ee05..3dff2da082e6 100644 --- a/cli/command/image/load.go +++ b/cli/command/image/load.go @@ -78,7 +78,8 @@ func runLoad(ctx context.Context, dockerCli command.Cli, opts loadOptions) error if err != nil { return errors.Wrap(err, "invalid platform") } - options.Platform = &p + // TODO(thaJeztah): change flag-type to support multiple platforms. + options.Platforms = append(options.Platforms, p) } response, err := dockerCli.Client().ImageLoad(ctx, input, options) diff --git a/cli/command/image/load_test.go b/cli/command/image/load_test.go index 8544e58745e4..87f91c6db39f 100644 --- a/cli/command/image/load_test.go +++ b/cli/command/image/load_test.go @@ -109,7 +109,7 @@ func TestNewLoadCommandSuccess(t *testing.T) { name: "with platform", args: []string{"--platform", "linux/amd64"}, imageLoadFunc: func(input io.Reader, options image.LoadOptions) (image.LoadResponse, error) { - assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform)) + assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms)) return image.LoadResponse{Body: io.NopCloser(strings.NewReader("Success"))}, nil }, }, diff --git a/cli/command/image/save.go b/cli/command/image/save.go index dfceecc8656c..802b57b51e7c 100644 --- a/cli/command/image/save.go +++ b/cli/command/image/save.go @@ -63,7 +63,8 @@ func RunSave(ctx context.Context, dockerCli command.Cli, opts saveOptions) error if err != nil { return errors.Wrap(err, "invalid platform") } - options.Platform = &p + // TODO(thaJeztah): change flag-type to support multiple platforms. + options.Platforms = append(options.Platforms, p) } responseBody, err := dockerCli.Client().ImageSave(ctx, opts.images, options) diff --git a/cli/command/image/save_test.go b/cli/command/image/save_test.go index e9b139660073..34b71924a4e7 100644 --- a/cli/command/image/save_test.go +++ b/cli/command/image/save_test.go @@ -106,7 +106,7 @@ func TestNewSaveCommandSuccess(t *testing.T) { imageSaveFunc: func(images []string, options image.SaveOptions) (io.ReadCloser, error) { assert.Assert(t, is.Len(images, 1)) assert.Check(t, is.Equal("arg1", images[0])) - assert.Check(t, is.DeepEqual(ocispec.Platform{OS: "linux", Architecture: "amd64"}, *options.Platform)) + assert.Check(t, is.DeepEqual([]ocispec.Platform{{OS: "linux", Architecture: "amd64"}}, options.Platforms)) return io.NopCloser(strings.NewReader("")), nil }, }, diff --git a/cli/command/utils_test.go b/cli/command/utils_test.go index 2f2140757e34..093eabed9511 100644 --- a/cli/command/utils_test.go +++ b/cli/command/utils_test.go @@ -82,7 +82,7 @@ func TestValidateOutputPath(t *testing.T) { } func TestPromptForInput(t *testing.T) { - t.Run("case=cancelling the context", func(t *testing.T) { + t.Run("cancelling the context", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) reader, _ := io.Pipe() @@ -116,7 +116,7 @@ func TestPromptForInput(t *testing.T) { } }) - t.Run("case=user input should be properly trimmed", func(t *testing.T) { + t.Run("user input should be properly trimmed", func(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) t.Cleanup(cancel) @@ -196,7 +196,7 @@ func TestPromptForConfirmation(t *testing.T) { return promptReader.Close() }, promptResult{false, nil}}, } { - t.Run("case="+tc.desc, func(t *testing.T) { + t.Run(tc.desc, func(t *testing.T) { notifyCtx, notifyCancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) t.Cleanup(notifyCancel) diff --git a/dockerfiles/Dockerfile.lint b/dockerfiles/Dockerfile.lint index 2b0db1f8f492..855ac8aacd04 100644 --- a/dockerfiles/Dockerfile.lint +++ b/dockerfiles/Dockerfile.lint @@ -2,7 +2,7 @@ ARG GO_VERSION=1.23.3 ARG ALPINE_VERSION=3.20 -ARG GOLANGCI_LINT_VERSION=v1.61.0 +ARG GOLANGCI_LINT_VERSION=v1.62.0 FROM golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine AS golangci-lint diff --git a/docs/reference/dockerd.md b/docs/reference/dockerd.md index 5f57756e880d..de8011c2b63d 100644 --- a/docs/reference/dockerd.md +++ b/docs/reference/dockerd.md @@ -26,7 +26,8 @@ Options: --add-runtime runtime Register an additional OCI compatible runtime (default []) --allow-nondistributable-artifacts list Allow push of nondistributable artifacts to registry --authorization-plugin list Authorization plugins to load - --bip string Specify network bridge IP + --bip string Specify default-bridge IPv4 network + --bip6 string Specify default-bridge IPv6 network -b, --bridge string Attach containers to a network bridge --cdi-spec-dir list CDI specification directories to use --cgroup-parent string Set parent cgroup for all containers @@ -891,7 +892,7 @@ Alternatively, you can set custom locations for CDI specifications using the When CDI is enabled for a daemon, you can view the configured CDI specification directories using the `docker info` command. -#### Daemon logging format +#### Daemon logging format {#log-format} The `--log-format` option or "log-format" option in the [daemon configuration file](#daemon-configuration-file) lets you set the format for logs produced by the daemon. The logging format should @@ -999,7 +1000,7 @@ Example of usage: } ``` -### Enable feature in the daemon (--feature) +### Enable feature in the daemon (--feature) {#feature} The `--feature` option lets you enable or disable a feature in the daemon. This option corresponds with the "features" field in the [daemon.json configuration file](#daemon-configuration-file). @@ -1075,6 +1076,7 @@ The following is a full example of the allowed configuration options on Linux: "allow-nondistributable-artifacts": [], "authorization-plugins": [], "bip": "", + "bip6": "", "bridge": "", "builder": { "gc": { diff --git a/e2e/global/cli_test.go b/e2e/global/cli_test.go index 86e67555a20b..f79acd1aa76b 100644 --- a/e2e/global/cli_test.go +++ b/e2e/global/cli_test.go @@ -182,7 +182,7 @@ func TestPromptExitCode(t *testing.T) { } for _, tc := range testCases { - t.Run("case="+tc.name, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { t.Parallel() buf := new(bytes.Buffer) diff --git a/vendor.mod b/vendor.mod index 23e0dff17b7f..8cb6b1988d01 100644 --- a/vendor.mod +++ b/vendor.mod @@ -13,20 +13,20 @@ require ( github.com/distribution/reference v0.6.0 github.com/docker/cli-docs-tool v0.8.0 github.com/docker/distribution v2.8.3+incompatible - github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible // master (v-next) + github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible // master (v-next) github.com/docker/docker-credential-helpers v0.8.2 github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.0 github.com/fvbommel/sortorder v1.1.0 github.com/go-jose/go-jose/v4 v4.0.4 - github.com/go-viper/mapstructure/v2 v2.0.0 + github.com/go-viper/mapstructure/v2 v2.2.1 github.com/gogo/protobuf v1.3.2 github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/mattn/go-runewidth v0.0.15 github.com/moby/patternmatcher v0.6.0 github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e - github.com/moby/sys/capability v0.3.0 + github.com/moby/sys/capability v0.4.0 github.com/moby/sys/sequential v0.6.0 github.com/moby/sys/signal v0.7.1 github.com/moby/term v0.5.0 @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a - github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d + github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 github.com/xeipuuv/gojsonschema v1.2.0 go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 diff --git a/vendor.sum b/vendor.sum index d30731ca6c9e..f0b3eabf1482 100644 --- a/vendor.sum +++ b/vendor.sum @@ -51,8 +51,8 @@ github.com/docker/cli-docs-tool v0.8.0/go.mod h1:8TQQ3E7mOXoYUs811LiPdUnAhXrcVsB 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 v27.0.2-0.20241031194140-6ac445c42bad+incompatible h1:kSQ4U+63JfFxIOrTo6wMW1mqkOkPpiTe/7ZfvUdNLVE= -github.com/docker/docker v27.0.2-0.20241031194140-6ac445c42bad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible h1:ZWh4HhdUCagAd3S+gsFPOobHbc562obYFSrz3irGSsU= +github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+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= @@ -89,8 +89,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc= -github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -168,8 +168,8 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e h1:1yC8fRqStY6NirU/swI74fsrHvZVMbtxsHcvl8YpzDg= github.com/moby/swarmkit/v2 v2.0.0-20241017191044-e8ecf83ee08e/go.mod h1:mTTGIAz/59OGZR5Qe+QByIe3Nxc+sSuJkrsStFhr6Lg= -github.com/moby/sys/capability v0.3.0 h1:kEP+y6te0gEXIaeQhIi0s7vKs/w0RPoH1qPa6jROcVg= -github.com/moby/sys/capability v0.3.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= +github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk= +github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= @@ -266,8 +266,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a h1:tlJ7tGUHvcvL1v3yR6NcCc9nOqh2L+CG6HWrYQtwzQ0= github.com/theupdateframework/notary v0.7.1-0.20210315103452-bf96a202a09a/go.mod h1:Y94A6rPp2OwNfP/7vmf8O2xx2IykP8pPXQ1DLouGnEw= -github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d h1:wvQZpqy8p0D/FUia6ipKDhXrzPzBVJE4PZyPc5+5Ay0= -github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ= +github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 h1:TvtdmeYsYEij78hS4oxnwikoiLdIrgav3BA+CbhaDAI= +github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346/go.mod h1:xKQhd7snlzKFuUi1taTGWjpRE8iFTA06DeacYi3CVFQ= github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss= github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml index 7093625808e2..a237f374aaef 100644 --- a/vendor/github.com/docker/docker/api/swagger.yaml +++ b/vendor/github.com/docker/docker/api/swagger.yaml @@ -1991,6 +1991,18 @@ definitions: type: "string" x-nullable: false example: "sha256:ec3f0931a6e6b6855d76b2d7b0be30e81860baccd891b2e243280bf1cd8ad710" + Descriptor: + description: | + Descriptor is an OCI descriptor of the image target. + In case of a multi-platform image, this descriptor points to the OCI index + or a manifest list. + + This field is only present if the daemon provides a multi-platform image store. + + WARNING: This is experimental and may change at any time without any backward + compatibility. + x-nullable: true + $ref: "#/definitions/OCIDescriptor" RepoTags: description: | List of image names/tags in the local image cache that reference this @@ -2278,6 +2290,18 @@ definitions: x-omitempty: true items: $ref: "#/definitions/ImageManifestSummary" + Descriptor: + description: | + Descriptor is an OCI descriptor of the image target. + In case of a multi-platform image, this descriptor points to the OCI index + or a manifest list. + + This field is only present if the daemon provides a multi-platform image store. + + WARNING: This is experimental and may change at any time without any backward + compatibility. + x-nullable: true + $ref: "#/definitions/OCIDescriptor" AuthConfig: type: "object" @@ -7242,6 +7266,14 @@ paths: type: "string" Platform: type: "string" + ImageManifestDescriptor: + $ref: "#/definitions/OCIDescriptor" + description: | + OCI descriptor of the platform-specific manifest of the image + the container was created from. + + Note: Only available if the daemon provides a multi-platform + image store. MountLabel: type: "string" ProcessLabel: @@ -9210,9 +9242,14 @@ paths: type: "string" in: "query" description: | - JSON encoded OCI platform describing platform to show the history for. - If not provided, the host platform will be used. If it's not - available, any present platform will be picked. + JSON-encoded OCI platform to select the platform-variant. + If omitted, it defaults to any locally available platform, + prioritizing the daemon's host platform. + + If the daemon provides a multi-platform image store, this selects + the platform-variant to show the history for. If the image is + a single-platform image, or if the multi-platform image does not + provide a variant matching the given platform, an error is returned. Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}` tags: ["Image"] @@ -9262,6 +9299,19 @@ paths: all tags of the given image that are present in the local image store are pushed. type: "string" + - name: "platform" + type: "string" + in: "query" + description: | + JSON-encoded OCI platform to select the platform-variant to push. + If not provided, all available variants will attempt to be pushed. + + If the daemon provides a multi-platform image store, this selects + the platform-variant to push to the registry. If the image is + a single-platform image, or if the multi-platform image does not + provide a variant matching the given platform, an error is returned. + + Example: `{"os": "linux", "architecture": "arm", "variant": "v5"}` - name: "X-Registry-Auth" in: "header" description: | @@ -9271,11 +9321,6 @@ paths: details. type: "string" required: true - - name: "platform" - in: "query" - description: "Select a platform-specific manifest to be pushed. OCI platform (JSON encoded)" - type: "string" - x-nullable: true tags: ["Image"] /images/{name}/tag: post: diff --git a/vendor/github.com/docker/docker/api/types/container/container.go b/vendor/github.com/docker/docker/api/types/container/container.go index 398fd6e8863c..0244a3549a19 100644 --- a/vendor/github.com/docker/docker/api/types/container/container.go +++ b/vendor/github.com/docker/docker/api/types/container/container.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/storage" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // PruneReport contains the response for Engine API: @@ -171,4 +172,6 @@ type InspectResponse struct { Mounts []MountPoint Config *Config NetworkSettings *NetworkSettings + // ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container. + ImageManifestDescriptor *ocispec.Descriptor `json:",omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig.go b/vendor/github.com/docker/docker/api/types/container/hostconfig.go index 03648fb7b5dc..83198305e7a8 100644 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig.go +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig.go @@ -10,7 +10,7 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" "github.com/docker/go-connections/nat" - units "github.com/docker/go-units" + "github.com/docker/go-units" ) // CgroupnsMode represents the cgroup namespace mode of the container diff --git a/vendor/github.com/docker/docker/api/types/image/image_inspect.go b/vendor/github.com/docker/docker/api/types/image/image_inspect.go index f47730ac4b6a..5d24dd62a22b 100644 --- a/vendor/github.com/docker/docker/api/types/image/image_inspect.go +++ b/vendor/github.com/docker/docker/api/types/image/image_inspect.go @@ -3,6 +3,7 @@ package image import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/storage" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // RootFS returns Image's RootFS description including the layer IDs. @@ -119,4 +120,11 @@ type InspectResponse struct { // // This information is local to the daemon, and not part of the image itself. Metadata Metadata + + // Descriptor is the OCI descriptor of the image target. + // It's only set if the daemon provides a multi-platform image store. + // + // WARNING: This is experimental and may change at any time without any backward + // compatibility. + Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/image/opts.go b/vendor/github.com/docker/docker/api/types/image/opts.go index 29aa7c5e793a..06365830210b 100644 --- a/vendor/github.com/docker/docker/api/types/image/opts.go +++ b/vendor/github.com/docker/docker/api/types/image/opts.go @@ -98,12 +98,14 @@ type LoadOptions struct { // Quiet suppresses progress output Quiet bool - // Platform is a specific platform to load when the image is a multi-platform - Platform *ocispec.Platform + // Platforms selects the platforms to load if the image is a + // multi-platform image and has multiple variants. + Platforms []ocispec.Platform } // SaveOptions holds parameters to save images. type SaveOptions struct { - // Platform is a specific platform to save if the image is a multi-platform image. - Platform *ocispec.Platform + // Platforms selects the platforms to save if the image is a + // multi-platform image and has multiple variants. + Platforms []ocispec.Platform } diff --git a/vendor/github.com/docker/docker/api/types/image/summary.go b/vendor/github.com/docker/docker/api/types/image/summary.go index e87e216a28b3..c5ae6ab9ca11 100644 --- a/vendor/github.com/docker/docker/api/types/image/summary.go +++ b/vendor/github.com/docker/docker/api/types/image/summary.go @@ -1,5 +1,7 @@ package image +import ocispec "github.com/opencontainers/image-spec/specs-go/v1" + type Summary struct { // Number of containers using this image. Includes both stopped and running @@ -42,6 +44,13 @@ type Summary struct { // Required: true ParentID string `json:"ParentId"` + // Descriptor is the OCI descriptor of the image target. + // It's only set if the daemon provides a multi-platform image store. + // + // WARNING: This is experimental and may change at any time without any backward + // compatibility. + Descriptor *ocispec.Descriptor `json:"Descriptor,omitempty"` + // Manifests is a list of image manifests available in this image. It // provides a more detailed view of the platform-specific image manifests or // other image-attached data like build attestations. diff --git a/vendor/github.com/docker/docker/client/image_history.go b/vendor/github.com/docker/docker/client/image_history.go index 779f4cfb229a..747a569bab6f 100644 --- a/vendor/github.com/docker/docker/client/image_history.go +++ b/vendor/github.com/docker/docker/client/image_history.go @@ -3,7 +3,6 @@ package client // import "github.com/docker/docker/client" import ( "context" "encoding/json" - "fmt" "net/url" "github.com/docker/docker/api/types/image" @@ -11,26 +10,26 @@ import ( // ImageHistory returns the changes in an image in history format. func (cli *Client) ImageHistory(ctx context.Context, imageID string, opts image.HistoryOptions) ([]image.HistoryResponseItem, error) { - values := url.Values{} + query := url.Values{} if opts.Platform != nil { if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil { return nil, err } - p, err := json.Marshal(*opts.Platform) + p, err := encodePlatform(opts.Platform) if err != nil { - return nil, fmt.Errorf("invalid platform: %v", err) + return nil, err } - values.Set("platform", string(p)) + query.Set("platform", p) } - var history []image.HistoryResponseItem - serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", values, nil) + serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", query, nil) defer ensureReaderClosed(serverResp) if err != nil { - return history, err + return nil, err } + var history []image.HistoryResponseItem err = json.NewDecoder(serverResp.body).Decode(&history) return history, err } diff --git a/vendor/github.com/docker/docker/client/image_import.go b/vendor/github.com/docker/docker/client/image_import.go index 43d55eda8eca..dea3626872bd 100644 --- a/vendor/github.com/docker/docker/client/image_import.go +++ b/vendor/github.com/docker/docker/client/image_import.go @@ -21,10 +21,18 @@ func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, r } query := url.Values{} - query.Set("fromSrc", source.SourceName) - query.Set("repo", ref) - query.Set("tag", options.Tag) - query.Set("message", options.Message) + if source.SourceName != "" { + query.Set("fromSrc", source.SourceName) + } + if ref != "" { + query.Set("repo", ref) + } + if options.Tag != "" { + query.Set("tag", options.Tag) + } + if options.Message != "" { + query.Set("message", options.Message) + } if options.Platform != "" { query.Set("platform", strings.ToLower(options.Platform)) } diff --git a/vendor/github.com/docker/docker/client/image_load.go b/vendor/github.com/docker/docker/client/image_load.go index 38e024ba192c..50cce4fd01ba 100644 --- a/vendor/github.com/docker/docker/client/image_load.go +++ b/vendor/github.com/docker/docker/client/image_load.go @@ -2,7 +2,6 @@ package client // import "github.com/docker/docker/client" import ( "context" - "encoding/json" "io" "net/http" "net/url" @@ -18,24 +17,24 @@ import ( // the provided multi-platform image. This is only has effect if the input image // is a multi-platform image. func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, opts image.LoadOptions) (image.LoadResponse, error) { - v := url.Values{} - v.Set("quiet", "0") + query := url.Values{} + query.Set("quiet", "0") if opts.Quiet { - v.Set("quiet", "1") + query.Set("quiet", "1") } - if opts.Platform != nil { + if len(opts.Platforms) > 0 { if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil { return image.LoadResponse{}, err } - p, err := json.Marshal(*opts.Platform) + p, err := encodePlatforms(opts.Platforms...) if err != nil { return image.LoadResponse{}, err } - v.Set("platform", string(p)) + query["platform"] = p } - resp, err := cli.postRaw(ctx, "/images/load", v, input, http.Header{ + resp, err := cli.postRaw(ctx, "/images/load", query, input, http.Header{ "Content-Type": {"application/x-tar"}, }) if err != nil { diff --git a/vendor/github.com/docker/docker/client/image_save.go b/vendor/github.com/docker/docker/client/image_save.go index 847d1dd8b391..1b378c32b7d3 100644 --- a/vendor/github.com/docker/docker/client/image_save.go +++ b/vendor/github.com/docker/docker/client/image_save.go @@ -2,8 +2,6 @@ package client // import "github.com/docker/docker/client" import ( "context" - "encoding/json" - "fmt" "io" "net/url" @@ -17,16 +15,15 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, opts image. "names": imageIDs, } - if opts.Platform != nil { + if len(opts.Platforms) > 0 { if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil { return nil, err } - - p, err := json.Marshal(*opts.Platform) + p, err := encodePlatforms(opts.Platforms...) if err != nil { - return nil, fmt.Errorf("invalid platform: %v", err) + return nil, err } - query.Set("platform", string(p)) + query["platform"] = p } resp, err := cli.get(ctx, "/images/get", query, nil) diff --git a/vendor/github.com/docker/docker/client/utils.go b/vendor/github.com/docker/docker/client/utils.go index 7f3ff44eb80b..db02ca0b9769 100644 --- a/vendor/github.com/docker/docker/client/utils.go +++ b/vendor/github.com/docker/docker/client/utils.go @@ -1,10 +1,14 @@ package client // import "github.com/docker/docker/client" import ( + "encoding/json" + "fmt" "net/url" "regexp" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/errdefs" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) var headerRegexp = regexp.MustCompile(`\ADocker/.+\s\((.+)\)\z`) @@ -32,3 +36,43 @@ func getFiltersQuery(f filters.Args) (url.Values, error) { } return query, nil } + +// encodePlatforms marshals the given platform(s) to JSON format, to +// be used for query-parameters for filtering / selecting platforms. +func encodePlatforms(platform ...ocispec.Platform) ([]string, error) { + if len(platform) == 0 { + return []string{}, nil + } + if len(platform) == 1 { + p, err := encodePlatform(&platform[0]) + if err != nil { + return nil, err + } + return []string{p}, nil + } + + seen := make(map[string]struct{}, len(platform)) + out := make([]string, 0, len(platform)) + for i := range platform { + p, err := encodePlatform(&platform[i]) + if err != nil { + return nil, err + } + if _, ok := seen[p]; !ok { + out = append(out, p) + seen[p] = struct{}{} + } + } + return out, nil +} + +// encodePlatforms marshals the given platform to JSON format, to +// be used for query-parameters for filtering / selecting platforms. It +// is used as a helper for encodePlatforms, +func encodePlatform(platform *ocispec.Platform) (string, error) { + p, err := json.Marshal(platform) + if err != nil { + return "", errdefs.InvalidParameter(fmt.Errorf("invalid platform: %v", err)) + } + return string(p), nil +} diff --git a/vendor/github.com/docker/docker/pkg/archive/changes_linux.go b/vendor/github.com/docker/docker/pkg/archive/changes_linux.go index 81fcbc5bab59..877ec785589c 100644 --- a/vendor/github.com/docker/docker/pkg/archive/changes_linux.go +++ b/vendor/github.com/docker/docker/pkg/archive/changes_linux.go @@ -261,13 +261,13 @@ func readdirnames(dirname string) (names []nameIno, err error) { func parseDirent(buf []byte, names []nameIno) (consumed int, newnames []nameIno) { origlen := len(buf) for len(buf) > 0 { - dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) + dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited" buf = buf[dirent.Reclen:] if dirent.Ino == 0 { // File absent in directory. continue } - bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) - name := string(bytes[0:clen(bytes[:])]) + b := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) // #nosec G103 -- Ignore "G103: Use of unsafe calls should be audited" + name := string(b[0:clen(b[:])]) if name == "." || name == ".." { // Useless names continue } diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools.go b/vendor/github.com/docker/docker/pkg/idtools/idtools.go index 79d682c69456..82b325a2b72b 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools.go +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools.go @@ -22,11 +22,11 @@ type subIDRange struct { Length int } -type ranges []subIDRange +type subIDRanges []subIDRange -func (e ranges) Len() int { return len(e) } -func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } -func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start } +func (e subIDRanges) Len() int { return len(e) } +func (e subIDRanges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } +func (e subIDRanges) Less(i, j int) bool { return e[i].Start < e[j].Start } const ( subuidFileName = "/etc/subuid" @@ -162,7 +162,7 @@ func (i IdentityMapping) Empty() bool { return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0 } -func createIDMap(subidRanges ranges) []IDMap { +func createIDMap(subidRanges subIDRanges) []IDMap { idMap := []IDMap{} containerID := 0 @@ -177,19 +177,19 @@ func createIDMap(subidRanges ranges) []IDMap { return idMap } -func parseSubuid(username string) (ranges, error) { +func parseSubuid(username string) (subIDRanges, error) { return parseSubidFile(subuidFileName, username) } -func parseSubgid(username string) (ranges, error) { +func parseSubgid(username string) (subIDRanges, error) { return parseSubidFile(subgidFileName, username) } // parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid) -// and return all found ranges for a specified username. If the special value -// "ALL" is supplied for username, then all ranges in the file will be returned -func parseSubidFile(path, username string) (ranges, error) { - var rangeList ranges +// and return all found subIDRanges for a specified username. If the special value +// "ALL" is supplied for username, then all subIDRanges in the file will be returned +func parseSubidFile(path, username string) (subIDRanges, error) { + var rangeList subIDRanges subidFile, err := os.Open(path) if err != nil { diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go index f0c075e20f93..7fd6c413d451 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go +++ b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go @@ -145,7 +145,7 @@ func findNextGIDRange() (int, error) { return findNextRangeStart(ranges) } -func findNextRangeStart(rangeList ranges) (int, error) { +func findNextRangeStart(rangeList subIDRanges) (int, error) { startID := defaultRangeStart for _, arange := range rangeList { if wouldOverlap(arange, startID) { diff --git a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go index 8d2c8857fb03..037327b908c1 100644 --- a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go +++ b/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go @@ -7,7 +7,7 @@ import ( "strings" "time" - units "github.com/docker/go-units" + "github.com/docker/go-units" "github.com/moby/term" "github.com/morikuni/aec" ) diff --git a/vendor/github.com/docker/docker/pkg/system/init_windows.go b/vendor/github.com/docker/docker/pkg/system/init_windows.go index 7603efbbd813..51e332c4b73b 100644 --- a/vendor/github.com/docker/docker/pkg/system/init_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/init_windows.go @@ -3,8 +3,8 @@ package system // import "github.com/docker/docker/pkg/system" // containerdRuntimeSupported determines if containerd should be the runtime. var containerdRuntimeSupported = false -// InitContainerdRuntime sets whether to use containerd for runtime on Windows. -func InitContainerdRuntime(cdPath string) { +// EnableContainerdRuntime sets whether to use containerd for runtime on Windows. +func EnableContainerdRuntime(cdPath string) { if len(cdPath) > 0 { containerdRuntimeSupported = true } diff --git a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go index 24d82f07c365..1f3c69d4b8c0 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go +++ b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "net/netip" + "net/url" "reflect" "strconv" "strings" @@ -36,6 +37,30 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { return nil } +// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// it into a closure to be used directly +// if the type fails to convert we return a closure always erroring to keep the previous behaviour +func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) { + switch f := typedDecodeHook(raw).(type) { + case DecodeHookFuncType: + return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return f(from.Type(), to.Type(), from.Interface()) + } + case DecodeHookFuncKind: + return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return f(from.Kind(), to.Kind(), from.Interface()) + } + case DecodeHookFuncValue: + return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return f(from, to) + } + default: + return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return nil, errors.New("invalid decode hook signature") + } + } +} + // DecodeHookExec executes the given decode hook. This should be used // since it'll naturally degrade to the older backwards compatible DecodeHookFunc // that took reflect.Kind instead of reflect.Type. @@ -61,13 +86,17 @@ func DecodeHookExec( // The composed funcs are called in order, with the result of the // previous transformation. func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { + cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs)) + for _, f := range fs { + cached = append(cached, cachedDecodeHook(f)) + } return func(f reflect.Value, t reflect.Value) (interface{}, error) { var err error data := f.Interface() newFrom := f - for _, f1 := range fs { - data, err = DecodeHookExec(f1, newFrom, t) + for _, c := range cached { + data, err = c(newFrom, t) if err != nil { return nil, err } @@ -81,13 +110,17 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { // OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. // If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { + cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff)) + for _, f := range ff { + cached = append(cached, cachedDecodeHook(f)) + } return func(a, b reflect.Value) (interface{}, error) { var allErrs string var out interface{} var err error - for _, f := range ff { - out, err = DecodeHookExec(f, a, b) + for _, c := range cached { + out, err = c(a, b) if err != nil { allErrs += err.Error() + "\n" continue @@ -144,6 +177,26 @@ func StringToTimeDurationHookFunc() DecodeHookFunc { } } +// StringToURLHookFunc returns a DecodeHookFunc that converts +// strings to *url.URL. +func StringToURLHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}, + ) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(&url.URL{}) { + return data, nil + } + + // Convert it by parsing + return url.Parse(data.(string)) + } +} + // StringToIPHookFunc returns a DecodeHookFunc that converts // strings to net.IP func StringToIPHookFunc() DecodeHookFunc { diff --git a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go index 4b54fae08744..e77e63ba3835 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go +++ b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go @@ -266,6 +266,10 @@ type DecoderConfig struct { // defaults to "mapstructure" TagName string + // The option of the value in the tag that indicates a field should + // be squashed. This defaults to "squash". + SquashTagOption string + // IgnoreUntaggedFields ignores all struct fields without explicit // TagName, comparable to `mapstructure:"-"` as default behaviour. IgnoreUntaggedFields bool @@ -274,6 +278,10 @@ type DecoderConfig struct { // field name or tag. Defaults to `strings.EqualFold`. This can be used // to implement case-sensitive tag values, support snake casing, etc. MatchName func(mapKey, fieldName string) bool + + // DecodeNil, if set to true, will cause the DecodeHook (if present) to run + // even if the input is nil. This can be used to provide default values. + DecodeNil bool } // A Decoder takes a raw interface value and turns it into structured @@ -283,7 +291,8 @@ type DecoderConfig struct { // structure. The top-level Decode method is just a convenience that sets // up the most basic Decoder. type Decoder struct { - config *DecoderConfig + config *DecoderConfig + cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error) } // Metadata contains information about decoding a structure that @@ -401,6 +410,10 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { config.TagName = "mapstructure" } + if config.SquashTagOption == "" { + config.SquashTagOption = "squash" + } + if config.MatchName == nil { config.MatchName = strings.EqualFold } @@ -408,6 +421,9 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { result := &Decoder{ config: config, } + if config.DecodeHook != nil { + result.cachedDecodeHook = cachedDecodeHook(config.DecodeHook) + } return result, nil } @@ -426,19 +442,26 @@ func (d *Decoder) Decode(input interface{}) error { return err } +// isNil returns true if the input is nil or a typed nil pointer. +func isNil(input interface{}) bool { + if input == nil { + return true + } + val := reflect.ValueOf(input) + return val.Kind() == reflect.Ptr && val.IsNil() +} + // Decodes an unknown data type into a specific reflection value. func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { - var inputVal reflect.Value - if input != nil { - inputVal = reflect.ValueOf(input) - - // We need to check here if input is a typed nil. Typed nils won't - // match the "input == nil" below so we check that here. - if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() { - input = nil - } + var ( + inputVal = reflect.ValueOf(input) + outputKind = getKind(outVal) + decodeNil = d.config.DecodeNil && d.cachedDecodeHook != nil + ) + if isNil(input) { + // Typed nils won't match the "input == nil" below, so reset input. + input = nil } - if input == nil { // If the data is nil, then we don't set anything, unless ZeroFields is set // to true. @@ -449,30 +472,46 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) } } - return nil + if !decodeNil { + return nil + } } - if !inputVal.IsValid() { - // If the input value is invalid, then we just set the value - // to be the zero value. - outVal.Set(reflect.Zero(outVal.Type())) - if d.config.Metadata != nil && name != "" { - d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + if !decodeNil { + // If the input value is invalid, then we just set the value + // to be the zero value. + outVal.Set(reflect.Zero(outVal.Type())) + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + return nil + } + // Hooks need a valid inputVal, so reset it to zero value of outVal type. + switch outputKind { + case reflect.Struct, reflect.Map: + var mapVal map[string]interface{} + inputVal = reflect.ValueOf(mapVal) // create nil map pointer + case reflect.Slice, reflect.Array: + var sliceVal []interface{} + inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer + default: + inputVal = reflect.Zero(outVal.Type()) } - return nil } - if d.config.DecodeHook != nil { + if d.cachedDecodeHook != nil { // We have a DecodeHook, so let's pre-process the input. var err error - input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal) + input, err = d.cachedDecodeHook(inputVal, outVal) if err != nil { return fmt.Errorf("error decoding '%s': %w", name, err) } } + if isNil(input) { + return nil + } var err error - outputKind := getKind(outVal) addMetaKey := true switch outputKind { case reflect.Bool: @@ -753,8 +792,8 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e } default: return fmt.Errorf( - "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", - name, val.Type(), dataVal.Type(), data) + "'%s' expected type '%s', got unconvertible type '%#v', value: '%#v'", + name, val, dataVal, data) } return nil @@ -973,7 +1012,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re } // If "squash" is specified in the tag, we squash the field down. - squash = squash || strings.Index(tagValue[index+1:], "squash") != -1 + squash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption) if squash { // When squashing, the embedded type can be a pointer to a struct. if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { @@ -1351,7 +1390,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e // We always parse the tags cause we're looking for other tags too tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") for _, tag := range tagParts[1:] { - if tag == "squash" { + if tag == d.config.SquashTagOption { squash = true break } @@ -1363,10 +1402,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e } if squash { - if fieldVal.Kind() != reflect.Struct { - errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) - } else { + switch fieldVal.Kind() { + case reflect.Struct: structs = append(structs, fieldVal) + case reflect.Interface: + if !fieldVal.IsNil() { + structs = append(structs, fieldVal.Elem().Elem()) + } + default: + errs = append(errs, fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) } continue } diff --git a/vendor/github.com/moby/sys/capability/.codespellrc b/vendor/github.com/moby/sys/capability/.codespellrc deleted file mode 100644 index e874be5634b5..000000000000 --- a/vendor/github.com/moby/sys/capability/.codespellrc +++ /dev/null @@ -1,3 +0,0 @@ -[codespell] -skip = ./.git -ignore-words-list = nd diff --git a/vendor/github.com/moby/sys/capability/.golangci.yml b/vendor/github.com/moby/sys/capability/.golangci.yml deleted file mode 100644 index d775aadd6faf..000000000000 --- a/vendor/github.com/moby/sys/capability/.golangci.yml +++ /dev/null @@ -1,6 +0,0 @@ -linters: - enable: - - unconvert - - unparam - - gofumpt - - errorlint diff --git a/vendor/github.com/moby/sys/capability/CHANGELOG.md b/vendor/github.com/moby/sys/capability/CHANGELOG.md index 037ef010a673..299b36d92a51 100644 --- a/vendor/github.com/moby/sys/capability/CHANGELOG.md +++ b/vendor/github.com/moby/sys/capability/CHANGELOG.md @@ -5,6 +5,30 @@ from https://github.com/syndtr/gocapability/commit/42c35b4376354fd5. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.0] - 2024-11-11 + +### Added +* New separate API for ambient ([GetAmbient], [SetAmbient], [ResetAmbient]) + and bound ([GetBound], [DropBound]) capabilities, modelled after libcap. (#176) + +### Fixed +* [Apply] now returns an error if called for non-zero `pid`. Before this change, + it could silently change some capabilities of the current process, instead of + the one identified by the `pid`. (#168, #174) +* Fixed tests that change capabilities to be run in a separate process. (#173) +* Other improvements in tests. (#169, #170) + +### Changed +* Use raw syscalls (which are slightly faster). (#176) +* Most tests are now limited to testing the public API of the package. (#162) +* Simplify parsing /proc/*pid*/status, add a test case. (#162) +* Optimize the number of syscall to set ambient capabilities in Apply + by clearing them first; add a test case. (#163, #164) +* Better documentation for [Apply], [NewFile], [NewFile2], [NewPid], [NewPid2]. (#175) + +### Removed +* `.golangci.yml` and `.codespellrc` are no longer part of the package. (#158) + ## [0.3.0] - 2024-09-25 ### Added @@ -63,14 +87,24 @@ This is an initial release since the fork. * Removed init function so programs that use this package start faster. [#6] * Removed `CAP_LAST_CAP` (use [LastCap] instead). [#6] - + [Apply]: https://pkg.go.dev/github.com/moby/sys/capability#Capabilities.Apply +[DropBound]: https://pkg.go.dev/github.com/moby/sys/capability#DropBound +[GetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#GetAmbient +[GetBound]: https://pkg.go.dev/github.com/moby/sys/capability#GetBound [LastCap]: https://pkg.go.dev/github.com/moby/sys/capability#LastCap -[List]: https://pkg.go.dev/github.com/moby/sys/capability#List [ListKnown]: https://pkg.go.dev/github.com/moby/sys/capability#ListKnown [ListSupported]: https://pkg.go.dev/github.com/moby/sys/capability#ListSupported +[List]: https://pkg.go.dev/github.com/moby/sys/capability#List +[NewFile2]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile2 +[NewFile]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile +[NewPid2]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid2 +[NewPid]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid +[ResetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#ResetAmbient +[SetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#SetAmbient +[0.4.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.4.0 [0.3.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.3.0 [0.2.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.2.0 [0.1.1]: https://github.com/kolyshkin/capability/compare/v0.1.0...v0.1.1 diff --git a/vendor/github.com/moby/sys/capability/capability.go b/vendor/github.com/moby/sys/capability/capability.go index 1b36f5f22a25..11e47bed7311 100644 --- a/vendor/github.com/moby/sys/capability/capability.go +++ b/vendor/github.com/moby/sys/capability/capability.go @@ -56,16 +56,16 @@ type Capabilities interface { // outstanding changes. Load() error - // Apply apply the capabilities settings, so all changes will take - // effect. + // Apply apply the capabilities settings, so all changes made by + // [Set], [Unset], [Fill], or [Clear] will take effect. Apply(kind CapType) error } // NewPid initializes a new [Capabilities] object for given pid when // it is nonzero, or for the current process if pid is 0. // -// Deprecated: Replace with [NewPid2] followed by [Capabilities.Load]. -// For example, replace: +// Deprecated: replace with [NewPid2] followed by optional [Capabilities.Load] +// (only if needed). For example, replace: // // c, err := NewPid(0) // if err != nil { @@ -93,16 +93,16 @@ func NewPid(pid int) (Capabilities, error) { // NewPid2 initializes a new [Capabilities] object for given pid when // it is nonzero, or for the current process if pid is 0. This -// does not load the process's current capabilities; to do that you -// must call [Capabilities.Load] explicitly. +// does not load the process's current capabilities; if needed, +// call [Capabilities.Load]. func NewPid2(pid int) (Capabilities, error) { return newPid(pid) } // NewFile initializes a new Capabilities object for given file path. // -// Deprecated: Replace with [NewFile2] followed by [Capabilities.Load]. -// For example, replace: +// Deprecated: replace with [NewFile2] followed by optional [Capabilities.Load] +// (only if needed). For example, replace: // // c, err := NewFile(path) // if err != nil { @@ -130,7 +130,7 @@ func NewFile(path string) (Capabilities, error) { // NewFile2 creates a new initialized [Capabilities] object for given // file path. This does not load the process's current capabilities; -// to do that you must call [Capabilities.Load] explicitly. +// if needed, call [Capabilities.Load]. func NewFile2(path string) (Capabilities, error) { return newFile(path) } @@ -142,3 +142,35 @@ func NewFile2(path string) (Capabilities, error) { func LastCap() (Cap, error) { return lastCap() } + +// GetAmbient determines if a specific ambient capability is raised in the +// calling thread. +func GetAmbient(c Cap) (bool, error) { + return getAmbient(c) +} + +// SetAmbient raises or lowers specified ambient capabilities for the calling +// thread. To complete successfully, the prevailing effective capability set +// must have a raised CAP_SETPCAP. Further, to raise a specific ambient +// capability the inheritable and permitted sets of the calling thread must +// already contain the specified capability. +func SetAmbient(raise bool, caps ...Cap) error { + return setAmbient(raise, caps...) +} + +// ResetAmbient resets all of the ambient capabilities for the calling thread +// to their lowered value. +func ResetAmbient() error { + return resetAmbient() +} + +// GetBound determines if a specific bounding capability is raised in the +// calling thread. +func GetBound(c Cap) (bool, error) { + return getBound(c) +} + +// DropBound lowers the specified bounding set capability. +func DropBound(caps ...Cap) error { + return dropBound(caps...) +} diff --git a/vendor/github.com/moby/sys/capability/capability_linux.go b/vendor/github.com/moby/sys/capability/capability_linux.go index aa600e1d9fc5..234b1efb29ac 100644 --- a/vendor/github.com/moby/sys/capability/capability_linux.go +++ b/vendor/github.com/moby/sys/capability/capability_linux.go @@ -117,6 +117,13 @@ func newPid(pid int) (c Capabilities, retErr error) { return } +func ignoreEINVAL(err error) error { + if errors.Is(err, syscall.EINVAL) { + err = nil + } + return err +} + type capsV3 struct { hdr capHeader data [2]capData @@ -307,15 +314,15 @@ func (c *capsV3) Load() (err error) { } break } - if strings.HasPrefix(line, "CapB") { - _, err = fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) + if val, ok := strings.CutPrefix(line, "CapBnd:\t"); ok { + _, err = fmt.Sscanf(val, "%08x%08x", &c.bounds[1], &c.bounds[0]) if err != nil { break } continue } - if strings.HasPrefix(line, "CapA") { - _, err = fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) + if val, ok := strings.CutPrefix(line, "CapAmb:\t"); ok { + _, err = fmt.Sscanf(val, "%08x%08x", &c.ambient[1], &c.ambient[0]) if err != nil { break } @@ -327,7 +334,10 @@ func (c *capsV3) Load() (err error) { return } -func (c *capsV3) Apply(kind CapType) (err error) { +func (c *capsV3) Apply(kind CapType) error { + if c.hdr.pid != 0 { + return errors.New("unable to modify capabilities of another process") + } last, err := LastCap() if err != nil { return err @@ -336,21 +346,17 @@ func (c *capsV3) Apply(kind CapType) (err error) { var data [2]capData err = capget(&c.hdr, &data[0]) if err != nil { - return + return err } if (1< 0, nil +} + +func setAmbient(raise bool, caps ...Cap) error { + op := pr_CAP_AMBIENT_RAISE + if !raise { + op = pr_CAP_AMBIENT_LOWER + } + for _, val := range caps { + err := prctl(pr_CAP_AMBIENT, op, uintptr(val)) + if err != nil { + return err + } + } + return nil +} + +func resetAmbient() error { + return prctl(pr_CAP_AMBIENT, pr_CAP_AMBIENT_CLEAR_ALL, 0) +} + +func getBound(c Cap) (bool, error) { + res, err := prctlRetInt(syscall.PR_CAPBSET_READ, uintptr(c), 0) + if err != nil { + return false, err + } + return res > 0, nil +} + +func dropBound(caps ...Cap) error { + for _, val := range caps { + err := prctl(syscall.PR_CAPBSET_DROP, uintptr(val), 0) + if err != nil { + return err + } + } + return nil } func newFile(path string) (c Capabilities, err error) { diff --git a/vendor/github.com/moby/sys/capability/capability_noop.go b/vendor/github.com/moby/sys/capability/capability_noop.go index ba819ff057e9..b766e444f396 100644 --- a/vendor/github.com/moby/sys/capability/capability_noop.go +++ b/vendor/github.com/moby/sys/capability/capability_noop.go @@ -24,3 +24,23 @@ func newFile(_ string) (Capabilities, error) { func lastCap() (Cap, error) { return -1, errNotSup } + +func getAmbient(_ Cap) (bool, error) { + return false, errNotSup +} + +func setAmbient(_ bool, _ ...Cap) error { + return errNotSup +} + +func resetAmbient() error { + return errNotSup +} + +func getBound(_ Cap) (bool, error) { + return false, errNotSup +} + +func dropBound(_ ...Cap) error { + return errNotSup +} diff --git a/vendor/github.com/moby/sys/capability/enum.go b/vendor/github.com/moby/sys/capability/enum.go index f89f0273aa47..f88593310eae 100644 --- a/vendor/github.com/moby/sys/capability/enum.go +++ b/vendor/github.com/moby/sys/capability/enum.go @@ -316,7 +316,7 @@ func ListKnown() []Cap { return list() } -// ListSupported retuns the list of all capabilities known to the package, +// ListSupported returns the list of all capabilities known to the package, // except those that are not supported by the currently running Linux kernel. func ListSupported() ([]Cap, error) { last, err := LastCap() diff --git a/vendor/github.com/moby/sys/capability/syscall_linux.go b/vendor/github.com/moby/sys/capability/syscall_linux.go index d6b6932a94b2..2d8faa85fffb 100644 --- a/vendor/github.com/moby/sys/capability/syscall_linux.go +++ b/vendor/github.com/moby/sys/capability/syscall_linux.go @@ -24,7 +24,7 @@ type capData struct { } func capget(hdr *capHeader, data *capData) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + _, _, e1 := syscall.RawSyscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) if e1 != 0 { err = e1 } @@ -32,7 +32,7 @@ func capget(hdr *capHeader, data *capData) (err error) { } func capset(hdr *capHeader, data *capData) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + _, _, e1 := syscall.RawSyscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) if e1 != 0 { err = e1 } @@ -48,14 +48,22 @@ const ( pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) ) -func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { - _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) +func prctl(option int, arg2, arg3 uintptr) (err error) { + _, _, e1 := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3) if e1 != 0 { err = e1 } return } +func prctlRetInt(option int, arg2, arg3 uintptr) (int, error) { + ret, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3) + if err != 0 { + return 0, err + } + return int(ret), nil +} + const ( vfsXattrName = "security.capability" @@ -92,7 +100,7 @@ func getVfsCap(path string, dest *vfscapData) (err error) { if err != nil { return } - r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) + r0, _, e1 := syscall.RawSyscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) if e1 != 0 { if e1 == syscall.ENODATA { dest.version = 2 @@ -145,7 +153,7 @@ func setVfsCap(path string, data *vfscapData) (err error) { } else { return syscall.EINVAL } - _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) + _, _, e1 := syscall.RawSyscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) if e1 != 0 { err = e1 } diff --git a/vendor/github.com/tonistiigi/go-rosetta/README.md b/vendor/github.com/tonistiigi/go-rosetta/README.md new file mode 100644 index 000000000000..4a70dc4a8930 --- /dev/null +++ b/vendor/github.com/tonistiigi/go-rosetta/README.md @@ -0,0 +1,8 @@ +go-rosetta +========== + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/tonistiigi/go-rosetta)](https://pkg.go.dev/github.com/tonistiigi/go-rosetta) + +`go-rosetta` provides utilities to detect if an application is running as a +[Rosetta](https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment) translated binary, and +to determine the native architecture. diff --git a/vendor/github.com/tonistiigi/go-rosetta/rosetta.go b/vendor/github.com/tonistiigi/go-rosetta/rosetta.go index c44ff011e62b..cc278dbc1849 100644 --- a/vendor/github.com/tonistiigi/go-rosetta/rosetta.go +++ b/vendor/github.com/tonistiigi/go-rosetta/rosetta.go @@ -1,17 +1,28 @@ +//go:build darwin // +build darwin package rosetta import ( + "os" "runtime" "syscall" ) +// Available returns true if Rosetta is installed/available +func Available() bool { + _, err := os.Stat("/Library/Apple/usr/share/rosetta") + return err == nil +} + +// Enabled returns true if running in a Rosetta Translated Binary, false otherwise. func Enabled() bool { v, err := syscall.SysctlUint32("sysctl.proc_translated") return err == nil && v == 1 } +// NativeArch returns the native architecture, even if binary architecture +// is emulated by Rosetta. func NativeArch() string { if Enabled() && runtime.GOARCH == "amd64" { return "arm64" diff --git a/vendor/github.com/tonistiigi/go-rosetta/rosetta_unsupported.go b/vendor/github.com/tonistiigi/go-rosetta/rosetta_unsupported.go index f8781cea262e..808890e7b028 100644 --- a/vendor/github.com/tonistiigi/go-rosetta/rosetta_unsupported.go +++ b/vendor/github.com/tonistiigi/go-rosetta/rosetta_unsupported.go @@ -1,3 +1,4 @@ +//go:build !darwin // +build !darwin package rosetta @@ -6,10 +7,18 @@ import ( "runtime" ) +// Available returns true if Rosetta is installed/available +func Available() bool { + return false +} + +// Enabled returns true if running in a Rosetta Translated Binary, false otherwise. func Enabled() bool { return false } +// NativeArch returns the native architecture, even if binary architecture +// is emulated by Rosetta. func NativeArch() string { return runtime.GOARCH } diff --git a/vendor/modules.txt b/vendor/modules.txt index 430194d8426f..5856c811c015 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -55,7 +55,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 v27.0.2-0.20241031194140-6ac445c42bad+incompatible +# github.com/docker/docker v27.0.2-0.20241120142749-e5c2b5e10d68+incompatible ## explicit github.com/docker/docker/api github.com/docker/docker/api/types @@ -136,7 +136,7 @@ github.com/go-logr/logr/funcr # github.com/go-logr/stdr v1.2.2 ## explicit; go 1.16 github.com/go-logr/stdr -# github.com/go-viper/mapstructure/v2 v2.0.0 +# github.com/go-viper/mapstructure/v2 v2.2.1 ## explicit; go 1.18 github.com/go-viper/mapstructure/v2 github.com/go-viper/mapstructure/v2/internal/errors @@ -205,7 +205,7 @@ github.com/moby/swarmkit/v2/api/defaults github.com/moby/swarmkit/v2/api/genericresource github.com/moby/swarmkit/v2/manager/raftselector github.com/moby/swarmkit/v2/protobuf/plugin -# github.com/moby/sys/capability v0.3.0 +# github.com/moby/sys/capability v0.4.0 ## explicit; go 1.21 github.com/moby/sys/capability # github.com/moby/sys/sequential v0.6.0 @@ -293,7 +293,7 @@ github.com/theupdateframework/notary/tuf/data github.com/theupdateframework/notary/tuf/signed github.com/theupdateframework/notary/tuf/utils github.com/theupdateframework/notary/tuf/validation -# github.com/tonistiigi/go-rosetta v0.0.0-20200727161949-f79598599c5d +# github.com/tonistiigi/go-rosetta v0.0.0-20220804170347-3f4430f2d346 ## explicit; go 1.13 github.com/tonistiigi/go-rosetta # github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb