From bee70bbd874c8587ac9aae3bad73ab9a53d6decc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 17:57:31 +0000 Subject: [PATCH 1/2] build(deps): Bump github.com/google/go-containerregistry Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.14.0 to 0.15.2. - [Release notes](https://github.com/google/go-containerregistry/releases) - [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml) - [Commits](https://github.com/google/go-containerregistry/compare/v0.14.0...v0.15.2) --- updated-dependencies: - dependency-name: github.com/google/go-containerregistry dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 24 +- go.sum | 63 +- .../pkg/authn/keychain.go | 71 ++- .../go-containerregistry/pkg/name/registry.go | 6 + .../pkg/v1/empty/index.go | 1 + .../pkg/v1/google/keychain.go | 13 +- .../pkg/v1/google/list.go | 16 +- .../pkg/v1/mutate/image.go | 6 + .../pkg/v1/mutate/index.go | 28 + .../pkg/v1/partial/index.go | 80 +++ .../pkg/v1/random/image.go | 18 +- .../pkg/v1/random/index.go | 4 +- .../pkg/v1/random/options.go | 60 ++ .../pkg/v1/remote/catalog.go | 131 ++-- .../pkg/v1/remote/delete.go | 37 +- .../pkg/v1/remote/descriptor.go | 393 ++---------- .../pkg/v1/remote/fetcher.go | 311 ++++++++++ .../pkg/v1/remote/image.go | 35 +- .../pkg/v1/remote/index.go | 60 +- .../pkg/v1/remote/layer.go | 37 +- .../pkg/v1/remote/list.go | 123 ++-- .../pkg/v1/remote/multi_write.go | 282 +-------- .../pkg/v1/remote/options.go | 75 ++- .../pkg/v1/remote/progress.go | 7 + .../pkg/v1/remote/puller.go | 222 +++++++ .../pkg/v1/remote/pusher.go | 559 ++++++++++++++++++ .../pkg/v1/remote/referrers.go | 90 ++- .../pkg/v1/remote/schema1.go | 118 ++++ .../pkg/v1/remote/transport/error.go | 27 +- .../pkg/v1/remote/transport/retry.go | 2 +- .../pkg/v1/remote/write.go | 485 +++------------ .../pkg/v1/stream/layer.go | 2 + .../pkg/v1/tarball/image.go | 6 +- .../pkg/v1/tarball/layer.go | 5 + .../pkg/v1/types/types.go | 16 + .../github.com/klauspost/compress/README.md | 26 + .../klauspost/compress/fse/decompress.go | 4 +- .../klauspost/compress/huff0/bitwriter.go | 16 + .../klauspost/compress/huff0/compress.go | 3 +- .../klauspost/compress/zstd/blockdec.go | 4 + .../klauspost/compress/zstd/blockenc.go | 9 +- .../klauspost/compress/zstd/bytebuf.go | 4 +- .../klauspost/compress/zstd/decoder.go | 7 +- .../klauspost/compress/zstd/enc_best.go | 266 ++++----- .../klauspost/compress/zstd/encoder.go | 78 +-- .../compress/zstd/encoder_options.go | 4 +- .../klauspost/compress/zstd/framedec.go | 35 +- .../klauspost/compress/zstd/seqdec.go | 11 +- .../klauspost/compress/zstd/seqdec_amd64.go | 17 +- .../klauspost/compress/zstd/seqdec_amd64.s | 124 +++- .../klauspost/compress/zstd/zstd.go | 4 +- .../image-spec/specs-go/v1/annotations.go | 3 - .../image-spec/specs-go/v1/artifact.go | 34 -- .../image-spec/specs-go/v1/config.go | 29 +- .../image-spec/specs-go/v1/manifest.go | 11 + .../image-spec/specs-go/v1/mediatype.go | 19 +- .../image-spec/specs-go/version.go | 2 +- .../vbatts/tar-split/archive/tar/reader.go | 12 +- vendor/golang.org/x/oauth2/README.md | 12 +- vendor/golang.org/x/oauth2/google/default.go | 16 +- vendor/golang.org/x/oauth2/google/doc.go | 61 +- vendor/golang.org/x/oauth2/google/google.go | 6 +- vendor/golang.org/x/oauth2/oauth2.go | 33 +- vendor/golang.org/x/oauth2/token.go | 14 +- .../x/tools/internal/gcimporter/iexport.go | 8 +- .../x/tools/internal/gcimporter/iimport.go | 34 +- .../internal/tokeninternal/tokeninternal.go | 92 +++ .../protobuf/internal/version/version.go | 4 +- vendor/modules.txt | 26 +- 69 files changed, 2710 insertions(+), 1731 deletions(-) create mode 100644 vendor/github.com/google/go-containerregistry/pkg/v1/random/options.go create mode 100644 vendor/github.com/google/go-containerregistry/pkg/v1/remote/fetcher.go create mode 100644 vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go create mode 100644 vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go create mode 100644 vendor/github.com/google/go-containerregistry/pkg/v1/remote/schema1.go delete mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go diff --git a/go.mod b/go.mod index 12f9d88c8..a81bd737a 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65 github.com/cppforlife/go-cli-ui v0.0.0-20220425131040-94f26b16bc14 github.com/fatih/color v1.14.1 // indirect - github.com/google/go-containerregistry v0.14.0 + github.com/google/go-containerregistry v0.15.2 github.com/mattn/go-isatty v0.0.19 github.com/maxbrunsfeld/counterfeiter/v6 v6.6.1 github.com/spf13/cobra v1.7.0 @@ -47,35 +47,35 @@ require ( github.com/creack/pty v1.1.11 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.0 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect + github.com/docker/cli v23.0.5+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v23.0.3+incompatible // indirect + github.com/docker/docker v23.0.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.16.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/image-spec v1.1.0-rc3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/vbatts/tar-split v0.11.2 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect github.com/vito/go-interact v1.0.1 // indirect golang.org/x/crypto v0.1.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/tools v0.8.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.29.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1e4521980..c6665f86a 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,7 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= @@ -120,7 +121,6 @@ github.com/cppforlife/color v1.9.1-0.20200716202919-6706ac40b835 h1:mYQweUIBD+TB github.com/cppforlife/color v1.9.1-0.20200716202919-6706ac40b835/go.mod h1:dYeVsKp1vvK8XjdTPR1gF+uk+9doxKeO3hqQTOCr7T4= github.com/cppforlife/go-cli-ui v0.0.0-20220425131040-94f26b16bc14 h1:MjRdR01xh0sfkeS3OOBv+MYkYsrbHuTDc4rfBnVdFaI= github.com/cppforlife/go-cli-ui v0.0.0-20220425131040-94f26b16bc14/go.mod h1:AlgTssDlstr4mf92TR4DPITLfl5+7wEY4cKStCmeeto= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= @@ -131,12 +131,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= -github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= +github.com/docker/cli v23.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= -github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v23.0.5+incompatible h1:DaxtlTJjFSnLOXVNUBU1+6kXGz2lpDoEAH6QoxaSg8k= +github.com/docker/docker v23.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= @@ -208,8 +208,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-containerregistry v0.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw= -github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk= +github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= +github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -249,8 +249,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -285,8 +285,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= +github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -297,13 +297,10 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -313,17 +310,22 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= -github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= github.com/vito/go-interact v1.0.1 h1:O8xi8c93bRUv2Tb/v6HdiuGc+WnWt+AQzF74MOOdlBs= github.com/vito/go-interact v1.0.1/go.mod h1:HrdHSJXD2yn1MhlTwSIMeFgQ5WftiIorszVGd3S/DAA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -382,8 +384,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -421,8 +423,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -439,8 +441,8 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -511,13 +513,14 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -526,7 +529,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -581,8 +584,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -722,8 +725,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go b/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go index a4a88b3d5..4e32500cd 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go +++ b/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go @@ -18,6 +18,7 @@ import ( "os" "path/filepath" "sync" + "time" "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config/configfile" @@ -52,7 +53,7 @@ type defaultKeychain struct { var ( // DefaultKeychain implements Keychain by interpreting the docker config file. - DefaultKeychain Keychain = &defaultKeychain{} + DefaultKeychain = RefreshingKeychain(&defaultKeychain{}, 5*time.Minute) ) const ( @@ -178,3 +179,71 @@ func (w wrapper) Resolve(r Resource) (Authenticator, error) { } return FromConfig(AuthConfig{Username: u, Password: p}), nil } + +func RefreshingKeychain(inner Keychain, duration time.Duration) Keychain { + return &refreshingKeychain{ + keychain: inner, + duration: duration, + } +} + +type refreshingKeychain struct { + keychain Keychain + duration time.Duration + clock func() time.Time +} + +func (r *refreshingKeychain) Resolve(target Resource) (Authenticator, error) { + last := time.Now() + auth, err := r.keychain.Resolve(target) + if err != nil || auth == Anonymous { + return auth, err + } + return &refreshing{ + target: target, + keychain: r.keychain, + last: last, + cached: auth, + duration: r.duration, + clock: r.clock, + }, nil +} + +type refreshing struct { + sync.Mutex + target Resource + keychain Keychain + + duration time.Duration + + last time.Time + cached Authenticator + + // for testing + clock func() time.Time +} + +func (r *refreshing) Authorization() (*AuthConfig, error) { + r.Lock() + defer r.Unlock() + if r.cached == nil || r.expired() { + r.last = r.now() + auth, err := r.keychain.Resolve(r.target) + if err != nil { + return nil, err + } + r.cached = auth + } + return r.cached.Authorization() +} + +func (r *refreshing) now() time.Time { + if r.clock == nil { + return time.Now() + } + return r.clock() +} + +func (r *refreshing) expired() bool { + return r.now().Sub(r.last) > r.duration +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/registry.go b/vendor/github.com/google/go-containerregistry/pkg/name/registry.go index 2a26b66d0..5b0d01769 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/registry.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/registry.go @@ -17,6 +17,7 @@ package name import ( "net" "net/url" + "path" "regexp" "strings" ) @@ -50,6 +51,11 @@ func (r Registry) String() string { return r.Name() } +// Repo returns a Repository in the Registry with the given name. +func (r Registry) Repo(repo ...string) Repository { + return Repository{Registry: r, repository: path.Join(repo...)} +} + // Scope returns the scope required to access the registry. func (r Registry) Scope(string) string { // The only resource under 'registry' is 'catalog'. http://goo.gl/N9cN9Z diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/empty/index.go b/vendor/github.com/google/go-containerregistry/pkg/v1/empty/index.go index 10665356e..18b414891 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/empty/index.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/empty/index.go @@ -60,5 +60,6 @@ func base() *v1.IndexManifest { return &v1.IndexManifest{ SchemaVersion: 2, MediaType: types.OCIImageIndex, + Manifests: []v1.Descriptor{}, } } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/google/keychain.go b/vendor/github.com/google/go-containerregistry/pkg/v1/google/keychain.go index 6dc7a50ea..5472b1879 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/google/keychain.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/google/keychain.go @@ -53,11 +53,7 @@ type googleKeychain struct { // gcloud configuration in the scope of this one process. func (gk *googleKeychain) Resolve(target authn.Resource) (authn.Authenticator, error) { // Only authenticate GCR and AR so it works with authn.NewMultiKeychain to fallback. - host := target.RegistryStr() - if host != "gcr.io" && - !strings.HasSuffix(host, ".gcr.io") && - !strings.HasSuffix(host, ".pkg.dev") && - !strings.HasSuffix(host, ".google.com") { + if !isGoogle(target.RegistryStr()) { return authn.Anonymous, nil } @@ -90,3 +86,10 @@ func resolve() authn.Authenticator { } return authn.Anonymous } + +func isGoogle(host string) bool { + return host == "gcr.io" || + strings.HasSuffix(host, ".gcr.io") || + strings.HasSuffix(host, ".pkg.dev") || + strings.HasSuffix(host, ".google.com") +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/google/list.go b/vendor/github.com/google/go-containerregistry/pkg/v1/google/list.go index a70bb27ee..8a5906c23 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/google/list.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/google/list.go @@ -89,12 +89,16 @@ func newLister(repo name.Repository, options ...Option) (*lister, error) { func (l *lister) list(repo name.Repository) (*Tags, error) { uri := &url.URL{ - Scheme: repo.Registry.Scheme(), - Host: repo.Registry.RegistryStr(), - Path: fmt.Sprintf("/v2/%s/tags/list", repo.RepositoryStr()), - // ECR returns an error if n > 1000: - // https://github.com/google/go-containerregistry/issues/681 - RawQuery: "n=1000", + Scheme: repo.Registry.Scheme(), + Host: repo.Registry.RegistryStr(), + Path: fmt.Sprintf("/v2/%s/tags/list", repo.RepositoryStr()), + RawQuery: "n=10000", + } + + // ECR returns an error if n > 1000: + // https://github.com/google/go-containerregistry/issues/681 + if !isGoogle(repo.RegistryStr()) { + uri.RawQuery = "n=1000" } tags := Tags{} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/image.go b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/image.go index 727abe29c..3ea27fe47 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/image.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/image.go @@ -18,6 +18,7 @@ import ( "bytes" "encoding/json" "errors" + "sync" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/partial" @@ -38,6 +39,8 @@ type image struct { diffIDMap map[v1.Hash]v1.Layer digestMap map[v1.Hash]v1.Layer subject *v1.Descriptor + + sync.Mutex } var _ v1.Image = (*image)(nil) @@ -50,6 +53,9 @@ func (i *image) MediaType() (types.MediaType, error) { } func (i *image) compute() error { + i.Lock() + defer i.Unlock() + // Don't re-compute if already computed. if i.computed { return nil diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/index.go b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/index.go index ba062f9f1..512effef6 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/index.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/index.go @@ -16,12 +16,15 @@ package mutate import ( "encoding/json" + "errors" "fmt" + "sync" "github.com/google/go-containerregistry/pkg/logs" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/match" "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/stream" "github.com/google/go-containerregistry/pkg/v1/types" ) @@ -71,6 +74,8 @@ type index struct { indexMap map[v1.Hash]v1.ImageIndex layerMap map[v1.Hash]v1.Layer subject *v1.Descriptor + + sync.Mutex } var _ v1.ImageIndex = (*index)(nil) @@ -85,6 +90,9 @@ func (i *index) MediaType() (types.MediaType, error) { func (i *index) Size() (int64, error) { return partial.Size(i) } func (i *index) compute() error { + i.Lock() + defer i.Unlock() + // Don't re-compute if already computed. if i.computed { return nil @@ -202,3 +210,23 @@ func (i *index) RawManifest() ([]byte, error) { } return json.Marshal(i.manifest) } + +func (i *index) Manifests() ([]partial.Describable, error) { + if err := i.compute(); errors.Is(err, stream.ErrNotComputed) { + // Index contains a streamable layer which has not yet been + // consumed. Just return the manifests we have in case the caller + // is going to consume the streamable layers. + manifests, err := partial.Manifests(i.base) + if err != nil { + return nil, err + } + for _, add := range i.adds { + manifests = append(manifests, add.Add) + } + return manifests, nil + } else if err != nil { + return nil, err + } + + return partial.ComputeManifests(i) +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/partial/index.go b/vendor/github.com/google/go-containerregistry/pkg/v1/partial/index.go index f17f27446..10cfb2b2f 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/partial/index.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/partial/index.go @@ -19,6 +19,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/types" ) // FindManifests given a v1.ImageIndex, find the manifests that fit the matcher. @@ -83,3 +84,82 @@ func FindIndexes(index v1.ImageIndex, matcher match.Matcher) ([]v1.ImageIndex, e } return matches, nil } + +type withManifests interface { + Manifests() ([]Describable, error) +} + +type withLayer interface { + Layer(v1.Hash) (v1.Layer, error) +} + +type describable struct { + desc v1.Descriptor +} + +func (d describable) Digest() (v1.Hash, error) { + return d.desc.Digest, nil +} + +func (d describable) Size() (int64, error) { + return d.desc.Size, nil +} + +func (d describable) MediaType() (types.MediaType, error) { + return d.desc.MediaType, nil +} + +func (d describable) Descriptor() (*v1.Descriptor, error) { + return &d.desc, nil +} + +// Manifests is analogous to v1.Image.Layers in that it allows values in the +// returned list to be lazily evaluated, which enables an index to contain +// an image that contains a streaming layer. +// +// This should have been part of the v1.ImageIndex interface, but wasn't. +// It is instead usable through this extension interface. +func Manifests(idx v1.ImageIndex) ([]Describable, error) { + if wm, ok := idx.(withManifests); ok { + return wm.Manifests() + } + + return ComputeManifests(idx) +} + +// ComputeManifests provides a fallback implementation for Manifests. +func ComputeManifests(idx v1.ImageIndex) ([]Describable, error) { + m, err := idx.IndexManifest() + if err != nil { + return nil, err + } + manifests := []Describable{} + for _, desc := range m.Manifests { + switch { + case desc.MediaType.IsImage(): + img, err := idx.Image(desc.Digest) + if err != nil { + return nil, err + } + manifests = append(manifests, img) + case desc.MediaType.IsIndex(): + idx, err := idx.ImageIndex(desc.Digest) + if err != nil { + return nil, err + } + manifests = append(manifests, idx) + default: + if wl, ok := idx.(withLayer); ok { + layer, err := wl.Layer(desc.Digest) + if err != nil { + return nil, err + } + manifests = append(manifests, layer) + } else { + manifests = append(manifests, describable{desc}) + } + } + } + + return manifests, nil +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/random/image.go b/vendor/github.com/google/go-containerregistry/pkg/v1/random/image.go index 4b28913db..6121aa715 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/random/image.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/random/image.go @@ -18,12 +18,10 @@ import ( "archive/tar" "bytes" "crypto" - "crypto/rand" "encoding/hex" "fmt" "io" - mrand "math/rand" - "time" + "math/rand" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" @@ -57,10 +55,10 @@ func (ul *uncompressedLayer) MediaType() (types.MediaType, error) { var _ partial.UncompressedLayer = (*uncompressedLayer)(nil) // Image returns a pseudo-randomly generated Image. -func Image(byteSize, layers int64) (v1.Image, error) { +func Image(byteSize, layers int64, options ...Option) (v1.Image, error) { adds := make([]mutate.Addendum, 0, 5) for i := int64(0); i < layers; i++ { - layer, err := Layer(byteSize, types.DockerLayer) + layer, err := Layer(byteSize, types.DockerLayer, options...) if err != nil { return nil, err } @@ -70,7 +68,6 @@ func Image(byteSize, layers int64) (v1.Image, error) { Author: "random.Image", Comment: fmt.Sprintf("this is a random history %d of %d", i, layers), CreatedBy: "random", - Created: v1.Time{Time: time.Now()}, }, }) } @@ -79,8 +76,11 @@ func Image(byteSize, layers int64) (v1.Image, error) { } // Layer returns a layer with pseudo-randomly generated content. -func Layer(byteSize int64, mt types.MediaType) (v1.Layer, error) { - fileName := fmt.Sprintf("random_file_%d.txt", mrand.Int()) //nolint: gosec +func Layer(byteSize int64, mt types.MediaType, options ...Option) (v1.Layer, error) { + o := getOptions(options) + rng := rand.New(o.source) //nolint:gosec + + fileName := fmt.Sprintf("random_file_%d.txt", rng.Int()) // Hash the contents as we write it out to the buffer. var b bytes.Buffer @@ -96,7 +96,7 @@ func Layer(byteSize int64, mt types.MediaType) (v1.Layer, error) { }); err != nil { return nil, err } - if _, err := io.CopyN(tw, rand.Reader, byteSize); err != nil { + if _, err := io.CopyN(tw, rng, byteSize); err != nil { return nil, err } if err := tw.Close(); err != nil { diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/random/index.go b/vendor/github.com/google/go-containerregistry/pkg/v1/random/index.go index 89a88438f..4368bddff 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/random/index.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/random/index.go @@ -31,7 +31,7 @@ type randomIndex struct { // Index returns a pseudo-randomly generated ImageIndex with count images, each // having the given number of layers of size byteSize. -func Index(byteSize, layers, count int64) (v1.ImageIndex, error) { +func Index(byteSize, layers, count int64, options ...Option) (v1.ImageIndex, error) { manifest := v1.IndexManifest{ SchemaVersion: 2, MediaType: types.OCIImageIndex, @@ -40,7 +40,7 @@ func Index(byteSize, layers, count int64) (v1.ImageIndex, error) { images := make(map[v1.Hash]v1.Image) for i := int64(0); i < count; i++ { - img, err := Image(byteSize, layers) + img, err := Image(byteSize, layers, options...) if err != nil { return nil, err } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/random/options.go b/vendor/github.com/google/go-containerregistry/pkg/v1/random/options.go new file mode 100644 index 000000000..af1d2f969 --- /dev/null +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/random/options.go @@ -0,0 +1,60 @@ +// Copyright 2018 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package random + +import "math/rand" + +// Option is an optional parameter to the random functions +type Option func(opts *options) + +type options struct { + source rand.Source + + // TODO opens the door to add this in the future + // algorithm digest.Algorithm +} + +func getOptions(opts []Option) *options { + // get a random seed + + // TODO in go 1.20 this is fine (it will be random) + seed := rand.Int63() //nolint:gosec + /* + // in prior go versions this needs to come from crypto/rand + var b [8]byte + _, err := crypto_rand.Read(b[:]) + if err != nil { + panic("cryptographically secure random number generator is not working") + } + seed := int64(binary.LittleEndian.Int64(b[:])) + */ + + // defaults + o := &options{ + source: rand.NewSource(seed), + } + + for _, opt := range opts { + opt(o) + } + return o +} + +// WithSource sets the random number generator source +func WithSource(source rand.Source) Option { + return func(opts *options) { + opts.source = source + } +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/catalog.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/catalog.go index eb4306f28..a0281b9fd 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/catalog.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/catalog.go @@ -25,38 +25,35 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) -type catalog struct { +type Catalogs struct { Repos []string `json:"repositories"` + Next string `json:"next,omitempty"` } // CatalogPage calls /_catalog, returning the list of repositories on the registry. func CatalogPage(target name.Registry, last string, n int, options ...Option) ([]string, error) { - o, err := makeOptions(target, options...) + o, err := makeOptions(options...) if err != nil { return nil, err } - scopes := []string{target.Scope(transport.PullScope)} - tr, err := transport.NewWithContext(o.context, target, o.auth, o.transport, scopes) + f, err := newPuller(o).fetcher(o.context, target) if err != nil { return nil, err } - query := fmt.Sprintf("last=%s&n=%d", url.QueryEscape(last), n) - uri := url.URL{ Scheme: target.Scheme(), Host: target.RegistryStr(), Path: "/v2/_catalog", - RawQuery: query, + RawQuery: fmt.Sprintf("last=%s&n=%d", url.QueryEscape(last), n), } - client := http.Client{Transport: tr} req, err := http.NewRequest(http.MethodGet, uri.String(), nil) if err != nil { return nil, err } - resp, err := client.Do(req.WithContext(o.context)) + resp, err := f.client.Do(req.WithContext(o.context)) if err != nil { return nil, err } @@ -66,7 +63,7 @@ func CatalogPage(target name.Registry, last string, n int, options ...Option) ([ return nil, err } - var parsed catalog + var parsed Catalogs if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { return nil, err } @@ -76,79 +73,87 @@ func CatalogPage(target name.Registry, last string, n int, options ...Option) ([ // Catalog calls /_catalog, returning the list of repositories on the registry. func Catalog(ctx context.Context, target name.Registry, options ...Option) ([]string, error) { - o, err := makeOptions(target, options...) + o, err := makeOptions(options...) if err != nil { return nil, err } - scopes := []string{target.Scope(transport.PullScope)} - tr, err := transport.NewWithContext(o.context, target, o.auth, o.transport, scopes) + // WithContext overrides the ctx passed directly. + if o.context != context.Background() { + ctx = o.context + } + + return newPuller(o).catalog(ctx, target, o.pageSize) +} + +func (f *fetcher) catalogPage(ctx context.Context, reg name.Registry, next string, pageSize int) (*Catalogs, error) { + if next == "" { + uri := &url.URL{ + Scheme: reg.Scheme(), + Host: reg.RegistryStr(), + Path: "/v2/_catalog", + } + if pageSize > 0 { + uri.RawQuery = fmt.Sprintf("n=%d", pageSize) + } + next = uri.String() + } + + req, err := http.NewRequestWithContext(ctx, "GET", next, nil) if err != nil { return nil, err } - uri := &url.URL{ - Scheme: target.Scheme(), - Host: target.RegistryStr(), - Path: "/v2/_catalog", + resp, err := f.client.Do(req) + if err != nil { + return nil, err } - if o.pageSize > 0 { - uri.RawQuery = fmt.Sprintf("n=%d", o.pageSize) + if err := transport.CheckError(resp, http.StatusOK); err != nil { + return nil, err } - client := http.Client{Transport: tr} - - // WithContext overrides the ctx passed directly. - if o.context != context.Background() { - ctx = o.context + parsed := Catalogs{} + if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { + return nil, err } - var ( - parsed catalog - repoList []string - ) + if err := resp.Body.Close(); err != nil { + return nil, err + } - // get responses until there is no next page - for { - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - } + uri, err := getNextPageURL(resp) + if err != nil { + return nil, err + } - req, err := http.NewRequest("GET", uri.String(), nil) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) + if uri != nil { + parsed.Next = uri.String() + } - resp, err := client.Do(req) - if err != nil { - return nil, err - } + return &parsed, nil +} - if err := transport.CheckError(resp, http.StatusOK); err != nil { - return nil, err - } +type Catalogger struct { + f *fetcher + reg name.Registry + pageSize int - if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { - return nil, err - } - if err := resp.Body.Close(); err != nil { - return nil, err - } + page *Catalogs + err error - repoList = append(repoList, parsed.Repos...) + needMore bool +} - uri, err = getNextPageURL(resp) - if err != nil { - return nil, err - } - // no next page - if uri == nil { - break - } +func (l *Catalogger) Next(ctx context.Context) (*Catalogs, error) { + if l.needMore { + l.page, l.err = l.f.catalogPage(ctx, l.reg, l.page.Next, l.pageSize) + } else { + l.needMore = true } - return repoList, nil + return l.page, l.err +} + +func (l *Catalogger) HasNext() bool { + return l.page != nil && (!l.needMore || l.page.Next != "") } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/delete.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/delete.go index 74a06fd22..36e1d0816 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/delete.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/delete.go @@ -15,47 +15,14 @@ package remote import ( - "fmt" - "net/http" - "net/url" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) // Delete removes the specified image reference from the remote registry. func Delete(ref name.Reference, options ...Option) error { - o, err := makeOptions(ref.Context(), options...) - if err != nil { - return err - } - scopes := []string{ref.Scope(transport.DeleteScope)} - tr, err := transport.NewWithContext(o.context, ref.Context().Registry, o.auth, o.transport, scopes) - if err != nil { - return err - } - c := &http.Client{Transport: tr} - - u := url.URL{ - Scheme: ref.Context().Registry.Scheme(), - Host: ref.Context().RegistryStr(), - Path: fmt.Sprintf("/v2/%s/manifests/%s", ref.Context().RepositoryStr(), ref.Identifier()), - } - - req, err := http.NewRequest(http.MethodDelete, u.String(), nil) - if err != nil { - return err - } - - resp, err := c.Do(req.WithContext(o.context)) + o, err := makeOptions(options...) if err != nil { return err } - defer resp.Body.Close() - - return transport.CheckError(resp, http.StatusOK, http.StatusAccepted) - - // TODO(jason): If the manifest had a `subject`, and if the registry - // doesn't support Referrers, update the index pointed to by the - // subject's fallback tag to remove the descriptor for this manifest. + return newPusher(o).Delete(o.context, ref) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/descriptor.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/descriptor.go index 78919d7a8..61f28f4c0 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/descriptor.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/descriptor.go @@ -15,26 +15,21 @@ package remote import ( - "bytes" "context" - "encoding/json" - "errors" "fmt" - "io" - "net/http" - "net/url" - "strings" - "github.com/google/go-containerregistry/internal/redact" - "github.com/google/go-containerregistry/internal/verify" "github.com/google/go-containerregistry/pkg/logs" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/partial" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/google/go-containerregistry/pkg/v1/types" ) +var allManifestMediaTypes = append(append([]types.MediaType{ + types.DockerManifestSchema1, + types.DockerManifestSchema1Signed, +}, acceptableImageMediaTypes...), acceptableIndexMediaTypes...) + // ErrSchema1 indicates that we received a schema1 manifest from the registry. // This library doesn't have plans to support this legacy image format: // https://github.com/google/go-containerregistry/issues/377 @@ -57,14 +52,21 @@ func (e *ErrSchema1) Error() string { // Descriptor provides access to metadata about remote artifact and accessors // for efficiently converting it into a v1.Image or v1.ImageIndex. type Descriptor struct { - fetcher + fetcher fetcher v1.Descriptor + + ref name.Reference Manifest []byte + ctx context.Context // So we can share this implementation with Image. platform v1.Platform } +func (d *Descriptor) toDesc() v1.Descriptor { + return d.Descriptor +} + // RawManifest exists to satisfy the Taggable interface. func (d *Descriptor) RawManifest() ([]byte, error) { return d.Manifest, nil @@ -76,14 +78,7 @@ func (d *Descriptor) RawManifest() ([]byte, error) { // // See Head if you don't need the response body. func Get(ref name.Reference, options ...Option) (*Descriptor, error) { - acceptable := []types.MediaType{ - // Just to look at them. - types.DockerManifestSchema1, - types.DockerManifestSchema1Signed, - } - acceptable = append(acceptable, acceptableImageMediaTypes...) - acceptable = append(acceptable, acceptableIndexMediaTypes...) - return get(ref, acceptable, options...) + return get(ref, allManifestMediaTypes, options...) } // Head returns a v1.Descriptor for the given reference by issuing a HEAD @@ -92,48 +87,22 @@ func Get(ref name.Reference, options ...Option) (*Descriptor, error) { // Note that the server response will not have a body, so any errors encountered // should be retried with Get to get more details. func Head(ref name.Reference, options ...Option) (*v1.Descriptor, error) { - acceptable := []types.MediaType{ - // Just to look at them. - types.DockerManifestSchema1, - types.DockerManifestSchema1Signed, - } - acceptable = append(acceptable, acceptableImageMediaTypes...) - acceptable = append(acceptable, acceptableIndexMediaTypes...) - - o, err := makeOptions(ref.Context(), options...) - if err != nil { - return nil, err - } - - f, err := makeFetcher(ref, o) + o, err := makeOptions(options...) if err != nil { return nil, err } - return f.headManifest(ref, acceptable) + return newPuller(o).Head(o.context, ref) } // Handle options and fetch the manifest with the acceptable MediaTypes in the // Accept header. func get(ref name.Reference, acceptable []types.MediaType, options ...Option) (*Descriptor, error) { - o, err := makeOptions(ref.Context(), options...) - if err != nil { - return nil, err - } - f, err := makeFetcher(ref, o) - if err != nil { - return nil, err - } - b, desc, err := f.fetchManifest(ref, acceptable) + o, err := makeOptions(options...) if err != nil { return nil, err } - return &Descriptor{ - fetcher: *f, - Manifest: b, - Descriptor: *desc, - platform: o.platform, - }, nil + return newPuller(o).get(o.context, ref, acceptable, o.platform) } // Image converts the Descriptor into a v1.Image. @@ -169,7 +138,28 @@ func (d *Descriptor) Image() (v1.Image, error) { } return &mountableImage{ Image: imgCore, - Reference: d.Ref, + Reference: d.ref, + }, nil +} + +// Schema1 converts the Descriptor into a v1.Image for v2 schema 1 media types. +// +// The v1.Image returned by this method does not implement the entire interface because it would be inefficient. +// This exists mostly to make it easier to copy schema 1 images around or look at their filesystems. +// This is separate from Image() to avoid a backward incompatible change for callers expecting ErrSchema1. +func (d *Descriptor) Schema1() (v1.Image, error) { + i := &schema1{ + ref: d.ref, + fetcher: d.fetcher, + ctx: d.ctx, + manifest: d.Manifest, + mediaType: d.MediaType, + descriptor: &d.Descriptor, + } + + return &mountableImage{ + Image: i, + Reference: d.ref, }, nil } @@ -195,6 +185,8 @@ func (d *Descriptor) ImageIndex() (v1.ImageIndex, error) { func (d *Descriptor) remoteImage() *remoteImage { return &remoteImage{ + ref: d.ref, + ctx: d.ctx, fetcher: d.fetcher, manifest: d.Manifest, mediaType: d.MediaType, @@ -204,308 +196,11 @@ func (d *Descriptor) remoteImage() *remoteImage { func (d *Descriptor) remoteIndex() *remoteIndex { return &remoteIndex{ + ref: d.ref, + ctx: d.ctx, fetcher: d.fetcher, manifest: d.Manifest, mediaType: d.MediaType, descriptor: &d.Descriptor, } } - -// fetcher implements methods for reading from a registry. -type fetcher struct { - Ref name.Reference - Client *http.Client - context context.Context -} - -func makeFetcher(ref name.Reference, o *options) (*fetcher, error) { - tr, err := transport.NewWithContext(o.context, ref.Context().Registry, o.auth, o.transport, []string{ref.Scope(transport.PullScope)}) - if err != nil { - return nil, err - } - return &fetcher{ - Ref: ref, - Client: &http.Client{Transport: tr}, - context: o.context, - }, nil -} - -// url returns a url.Url for the specified path in the context of this remote image reference. -func (f *fetcher) url(resource, identifier string) url.URL { - return url.URL{ - Scheme: f.Ref.Context().Registry.Scheme(), - Host: f.Ref.Context().RegistryStr(), - Path: fmt.Sprintf("/v2/%s/%s/%s", f.Ref.Context().RepositoryStr(), resource, identifier), - } -} - -// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#referrers-tag-schema -func fallbackTag(d name.Digest) name.Tag { - return d.Context().Tag(strings.Replace(d.DigestStr(), ":", "-", 1)) -} - -func (f *fetcher) fetchReferrers(ctx context.Context, filter map[string]string, d name.Digest) (*v1.IndexManifest, error) { - // Check the Referrers API endpoint first. - u := f.url("referrers", d.DigestStr()) - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", string(types.OCIImageIndex)) - - resp, err := f.Client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound, http.StatusBadRequest); err != nil { - return nil, err - } - if resp.StatusCode == http.StatusOK { - var im v1.IndexManifest - if err := json.NewDecoder(resp.Body).Decode(&im); err != nil { - return nil, err - } - return filterReferrersResponse(filter, &im), nil - } - - // The registry doesn't support the Referrers API endpoint, so we'll use the fallback tag scheme. - b, _, err := f.fetchManifest(fallbackTag(d), []types.MediaType{types.OCIImageIndex}) - if err != nil { - return nil, err - } - var terr *transport.Error - if ok := errors.As(err, &terr); ok && terr.StatusCode == http.StatusNotFound { - // Not found just means there are no attachments yet. Start with an empty manifest. - return &v1.IndexManifest{MediaType: types.OCIImageIndex}, nil - } - - var im v1.IndexManifest - if err := json.Unmarshal(b, &im); err != nil { - return nil, err - } - - return filterReferrersResponse(filter, &im), nil -} - -func (f *fetcher) fetchManifest(ref name.Reference, acceptable []types.MediaType) ([]byte, *v1.Descriptor, error) { - u := f.url("manifests", ref.Identifier()) - req, err := http.NewRequest(http.MethodGet, u.String(), nil) - if err != nil { - return nil, nil, err - } - accept := []string{} - for _, mt := range acceptable { - accept = append(accept, string(mt)) - } - req.Header.Set("Accept", strings.Join(accept, ",")) - - resp, err := f.Client.Do(req.WithContext(f.context)) - if err != nil { - return nil, nil, err - } - defer resp.Body.Close() - - if err := transport.CheckError(resp, http.StatusOK); err != nil { - return nil, nil, err - } - - manifest, err := io.ReadAll(resp.Body) - if err != nil { - return nil, nil, err - } - - digest, size, err := v1.SHA256(bytes.NewReader(manifest)) - if err != nil { - return nil, nil, err - } - - mediaType := types.MediaType(resp.Header.Get("Content-Type")) - contentDigest, err := v1.NewHash(resp.Header.Get("Docker-Content-Digest")) - if err == nil && mediaType == types.DockerManifestSchema1Signed { - // If we can parse the digest from the header, and it's a signed schema 1 - // manifest, let's use that for the digest to appease older registries. - digest = contentDigest - } - - // Validate the digest matches what we asked for, if pulling by digest. - if dgst, ok := ref.(name.Digest); ok { - if digest.String() != dgst.DigestStr() { - return nil, nil, fmt.Errorf("manifest digest: %q does not match requested digest: %q for %q", digest, dgst.DigestStr(), f.Ref) - } - } - - var artifactType string - mf, _ := v1.ParseManifest(bytes.NewReader(manifest)) - // Failing to parse as a manifest should just be ignored. - // The manifest might not be valid, and that's okay. - if mf != nil && !mf.Config.MediaType.IsConfig() { - artifactType = string(mf.Config.MediaType) - } - - // Do nothing for tags; I give up. - // - // We'd like to validate that the "Docker-Content-Digest" header matches what is returned by the registry, - // but so many registries implement this incorrectly that it's not worth checking. - // - // For reference: - // https://github.com/GoogleContainerTools/kaniko/issues/298 - - // Return all this info since we have to calculate it anyway. - desc := v1.Descriptor{ - Digest: digest, - Size: size, - MediaType: mediaType, - ArtifactType: artifactType, - } - - return manifest, &desc, nil -} - -func (f *fetcher) headManifest(ref name.Reference, acceptable []types.MediaType) (*v1.Descriptor, error) { - u := f.url("manifests", ref.Identifier()) - req, err := http.NewRequest(http.MethodHead, u.String(), nil) - if err != nil { - return nil, err - } - accept := []string{} - for _, mt := range acceptable { - accept = append(accept, string(mt)) - } - req.Header.Set("Accept", strings.Join(accept, ",")) - - resp, err := f.Client.Do(req.WithContext(f.context)) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - if err := transport.CheckError(resp, http.StatusOK); err != nil { - return nil, err - } - - mth := resp.Header.Get("Content-Type") - if mth == "" { - return nil, fmt.Errorf("HEAD %s: response did not include Content-Type header", u.String()) - } - mediaType := types.MediaType(mth) - - size := resp.ContentLength - if size == -1 { - return nil, fmt.Errorf("GET %s: response did not include Content-Length header", u.String()) - } - - dh := resp.Header.Get("Docker-Content-Digest") - if dh == "" { - return nil, fmt.Errorf("HEAD %s: response did not include Docker-Content-Digest header", u.String()) - } - digest, err := v1.NewHash(dh) - if err != nil { - return nil, err - } - - // Validate the digest matches what we asked for, if pulling by digest. - if dgst, ok := ref.(name.Digest); ok { - if digest.String() != dgst.DigestStr() { - return nil, fmt.Errorf("manifest digest: %q does not match requested digest: %q for %q", digest, dgst.DigestStr(), f.Ref) - } - } - - // Return all this info since we have to calculate it anyway. - return &v1.Descriptor{ - Digest: digest, - Size: size, - MediaType: mediaType, - }, nil -} - -func (f *fetcher) fetchBlob(ctx context.Context, size int64, h v1.Hash) (io.ReadCloser, error) { - u := f.url("blobs", h.String()) - req, err := http.NewRequest(http.MethodGet, u.String(), nil) - if err != nil { - return nil, err - } - - resp, err := f.Client.Do(req.WithContext(ctx)) - if err != nil { - return nil, redact.Error(err) - } - - if err := transport.CheckError(resp, http.StatusOK); err != nil { - resp.Body.Close() - return nil, err - } - - // Do whatever we can. - // If we have an expected size and Content-Length doesn't match, return an error. - // If we don't have an expected size and we do have a Content-Length, use Content-Length. - if hsize := resp.ContentLength; hsize != -1 { - if size == verify.SizeUnknown { - size = hsize - } else if hsize != size { - return nil, fmt.Errorf("GET %s: Content-Length header %d does not match expected size %d", u.String(), hsize, size) - } - } - - return verify.ReadCloser(resp.Body, size, h) -} - -func (f *fetcher) headBlob(h v1.Hash) (*http.Response, error) { - u := f.url("blobs", h.String()) - req, err := http.NewRequest(http.MethodHead, u.String(), nil) - if err != nil { - return nil, err - } - - resp, err := f.Client.Do(req.WithContext(f.context)) - if err != nil { - return nil, redact.Error(err) - } - - if err := transport.CheckError(resp, http.StatusOK); err != nil { - resp.Body.Close() - return nil, err - } - - return resp, nil -} - -func (f *fetcher) blobExists(h v1.Hash) (bool, error) { - u := f.url("blobs", h.String()) - req, err := http.NewRequest(http.MethodHead, u.String(), nil) - if err != nil { - return false, err - } - - resp, err := f.Client.Do(req.WithContext(f.context)) - if err != nil { - return false, redact.Error(err) - } - defer resp.Body.Close() - - if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound); err != nil { - return false, err - } - - return resp.StatusCode == http.StatusOK, nil -} - -// If filter applied, filter out by artifactType. -// See https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers -func filterReferrersResponse(filter map[string]string, origIndex *v1.IndexManifest) *v1.IndexManifest { - newIndex := origIndex - if filter == nil { - return newIndex - } - if v, ok := filter["artifactType"]; ok { - tmp := []v1.Descriptor{} - for _, desc := range newIndex.Manifests { - if desc.ArtifactType == v { - tmp = append(tmp, desc) - } - } - newIndex.Manifests = tmp - } - return newIndex -} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/fetcher.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/fetcher.go new file mode 100644 index 000000000..b671f836c --- /dev/null +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/fetcher.go @@ -0,0 +1,311 @@ +// Copyright 2023 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package remote + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/google/go-containerregistry/internal/redact" + "github.com/google/go-containerregistry/internal/verify" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +// fetcher implements methods for reading from a registry. +type fetcher struct { + target resource + client *http.Client +} + +func makeFetcher(ctx context.Context, target resource, o *options) (*fetcher, error) { + auth := o.auth + if o.keychain != nil { + kauth, err := o.keychain.Resolve(target) + if err != nil { + return nil, err + } + auth = kauth + } + + reg, ok := target.(name.Registry) + if !ok { + repo, ok := target.(name.Repository) + if !ok { + return nil, fmt.Errorf("unexpected resource: %T", target) + } + reg = repo.Registry + } + + tr, err := transport.NewWithContext(ctx, reg, auth, o.transport, []string{target.Scope(transport.PullScope)}) + if err != nil { + return nil, err + } + return &fetcher{ + target: target, + client: &http.Client{Transport: tr}, + }, nil +} + +func (f *fetcher) Do(req *http.Request) (*http.Response, error) { + return f.client.Do(req) +} + +type resource interface { + Scheme() string + RegistryStr() string + Scope(string) string + + authn.Resource +} + +// url returns a url.Url for the specified path in the context of this remote image reference. +func (f *fetcher) url(resource, identifier string) url.URL { + u := url.URL{ + Scheme: f.target.Scheme(), + Host: f.target.RegistryStr(), + // Default path if this is not a repository. + Path: "/v2/_catalog", + } + if repo, ok := f.target.(name.Repository); ok { + u.Path = fmt.Sprintf("/v2/%s/%s/%s", repo.RepositoryStr(), resource, identifier) + } + return u +} + +func (f *fetcher) get(ctx context.Context, ref name.Reference, acceptable []types.MediaType, platform v1.Platform) (*Descriptor, error) { + b, desc, err := f.fetchManifest(ctx, ref, acceptable) + if err != nil { + return nil, err + } + return &Descriptor{ + ref: ref, + ctx: ctx, + fetcher: *f, + Manifest: b, + Descriptor: *desc, + platform: platform, + }, nil +} + +func (f *fetcher) fetchManifest(ctx context.Context, ref name.Reference, acceptable []types.MediaType) ([]byte, *v1.Descriptor, error) { + u := f.url("manifests", ref.Identifier()) + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return nil, nil, err + } + accept := []string{} + for _, mt := range acceptable { + accept = append(accept, string(mt)) + } + req.Header.Set("Accept", strings.Join(accept, ",")) + + resp, err := f.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + + if err := transport.CheckError(resp, http.StatusOK); err != nil { + return nil, nil, err + } + + manifest, err := io.ReadAll(resp.Body) + if err != nil { + return nil, nil, err + } + + digest, size, err := v1.SHA256(bytes.NewReader(manifest)) + if err != nil { + return nil, nil, err + } + + mediaType := types.MediaType(resp.Header.Get("Content-Type")) + contentDigest, err := v1.NewHash(resp.Header.Get("Docker-Content-Digest")) + if err == nil && mediaType == types.DockerManifestSchema1Signed { + // If we can parse the digest from the header, and it's a signed schema 1 + // manifest, let's use that for the digest to appease older registries. + digest = contentDigest + } + + // Validate the digest matches what we asked for, if pulling by digest. + if dgst, ok := ref.(name.Digest); ok { + if digest.String() != dgst.DigestStr() { + return nil, nil, fmt.Errorf("manifest digest: %q does not match requested digest: %q for %q", digest, dgst.DigestStr(), ref) + } + } + + var artifactType string + mf, _ := v1.ParseManifest(bytes.NewReader(manifest)) + // Failing to parse as a manifest should just be ignored. + // The manifest might not be valid, and that's okay. + if mf != nil && !mf.Config.MediaType.IsConfig() { + artifactType = string(mf.Config.MediaType) + } + + // Do nothing for tags; I give up. + // + // We'd like to validate that the "Docker-Content-Digest" header matches what is returned by the registry, + // but so many registries implement this incorrectly that it's not worth checking. + // + // For reference: + // https://github.com/GoogleContainerTools/kaniko/issues/298 + + // Return all this info since we have to calculate it anyway. + desc := v1.Descriptor{ + Digest: digest, + Size: size, + MediaType: mediaType, + ArtifactType: artifactType, + } + + return manifest, &desc, nil +} + +func (f *fetcher) headManifest(ctx context.Context, ref name.Reference, acceptable []types.MediaType) (*v1.Descriptor, error) { + u := f.url("manifests", ref.Identifier()) + req, err := http.NewRequest(http.MethodHead, u.String(), nil) + if err != nil { + return nil, err + } + accept := []string{} + for _, mt := range acceptable { + accept = append(accept, string(mt)) + } + req.Header.Set("Accept", strings.Join(accept, ",")) + + resp, err := f.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if err := transport.CheckError(resp, http.StatusOK); err != nil { + return nil, err + } + + mth := resp.Header.Get("Content-Type") + if mth == "" { + return nil, fmt.Errorf("HEAD %s: response did not include Content-Type header", u.String()) + } + mediaType := types.MediaType(mth) + + size := resp.ContentLength + if size == -1 { + return nil, fmt.Errorf("GET %s: response did not include Content-Length header", u.String()) + } + + dh := resp.Header.Get("Docker-Content-Digest") + if dh == "" { + return nil, fmt.Errorf("HEAD %s: response did not include Docker-Content-Digest header", u.String()) + } + digest, err := v1.NewHash(dh) + if err != nil { + return nil, err + } + + // Validate the digest matches what we asked for, if pulling by digest. + if dgst, ok := ref.(name.Digest); ok { + if digest.String() != dgst.DigestStr() { + return nil, fmt.Errorf("manifest digest: %q does not match requested digest: %q for %q", digest, dgst.DigestStr(), ref) + } + } + + // Return all this info since we have to calculate it anyway. + return &v1.Descriptor{ + Digest: digest, + Size: size, + MediaType: mediaType, + }, nil +} + +func (f *fetcher) fetchBlob(ctx context.Context, size int64, h v1.Hash) (io.ReadCloser, error) { + u := f.url("blobs", h.String()) + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return nil, err + } + + resp, err := f.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, redact.Error(err) + } + + if err := transport.CheckError(resp, http.StatusOK); err != nil { + resp.Body.Close() + return nil, err + } + + // Do whatever we can. + // If we have an expected size and Content-Length doesn't match, return an error. + // If we don't have an expected size and we do have a Content-Length, use Content-Length. + if hsize := resp.ContentLength; hsize != -1 { + if size == verify.SizeUnknown { + size = hsize + } else if hsize != size { + return nil, fmt.Errorf("GET %s: Content-Length header %d does not match expected size %d", u.String(), hsize, size) + } + } + + return verify.ReadCloser(resp.Body, size, h) +} + +func (f *fetcher) headBlob(ctx context.Context, h v1.Hash) (*http.Response, error) { + u := f.url("blobs", h.String()) + req, err := http.NewRequest(http.MethodHead, u.String(), nil) + if err != nil { + return nil, err + } + + resp, err := f.client.Do(req.WithContext(ctx)) + if err != nil { + return nil, redact.Error(err) + } + + if err := transport.CheckError(resp, http.StatusOK); err != nil { + resp.Body.Close() + return nil, err + } + + return resp, nil +} + +func (f *fetcher) blobExists(ctx context.Context, h v1.Hash) (bool, error) { + u := f.url("blobs", h.String()) + req, err := http.NewRequest(http.MethodHead, u.String(), nil) + if err != nil { + return false, err + } + + resp, err := f.client.Do(req.WithContext(ctx)) + if err != nil { + return false, redact.Error(err) + } + defer resp.Body.Close() + + if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound); err != nil { + return false, err + } + + return resp.StatusCode == http.StatusOK, nil +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/image.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/image.go index fde614274..f085967ed 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/image.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/image.go @@ -16,6 +16,7 @@ package remote import ( "bytes" + "context" "io" "net/http" "net/url" @@ -37,7 +38,9 @@ var acceptableImageMediaTypes = []types.MediaType{ // remoteImage accesses an image from a remote registry type remoteImage struct { - fetcher + fetcher fetcher + ref name.Reference + ctx context.Context manifestLock sync.Mutex // Protects manifest manifest []byte configLock sync.Mutex // Protects config @@ -84,7 +87,7 @@ func (r *remoteImage) RawManifest() ([]byte, error) { // NOTE(jonjohnsonjr): We should never get here because the public entrypoints // do type-checking via remote.Descriptor. I've left this here for tests that // directly instantiate a remoteImage. - manifest, desc, err := r.fetchManifest(r.Ref, acceptableImageMediaTypes) + manifest, desc, err := r.fetcher.fetchManifest(r.ctx, r.ref, acceptableImageMediaTypes) if err != nil { return nil, err } @@ -117,7 +120,7 @@ func (r *remoteImage) RawConfigFile() ([]byte, error) { return r.config, nil } - body, err := r.fetchBlob(r.context, m.Config.Size, m.Config.Digest) + body, err := r.fetcher.fetchBlob(r.ctx, m.Config.Size, m.Config.Digest) if err != nil { return nil, err } @@ -139,9 +142,26 @@ func (r *remoteImage) Descriptor() (*v1.Descriptor, error) { return r.descriptor, err } +func (r *remoteImage) ConfigLayer() (v1.Layer, error) { + if _, err := r.RawManifest(); err != nil { + return nil, err + } + m, err := partial.Manifest(r) + if err != nil { + return nil, err + } + + return partial.CompressedToLayer(&remoteImageLayer{ + ri: r, + ctx: r.ctx, + digest: m.Config.Digest, + }) +} + // remoteImageLayer implements partial.CompressedLayer type remoteImageLayer struct { ri *remoteImage + ctx context.Context digest v1.Hash } @@ -152,7 +172,7 @@ func (rl *remoteImageLayer) Digest() (v1.Hash, error) { // Compressed implements partial.CompressedLayer func (rl *remoteImageLayer) Compressed() (io.ReadCloser, error) { - urls := []url.URL{rl.ri.url("blobs", rl.digest.String())} + urls := []url.URL{rl.ri.fetcher.url("blobs", rl.digest.String())} // Add alternative layer sources from URLs (usually none). d, err := partial.BlobDescriptor(rl, rl.digest) @@ -165,7 +185,7 @@ func (rl *remoteImageLayer) Compressed() (io.ReadCloser, error) { } // We don't want to log binary layers -- this can break terminals. - ctx := redact.NewContext(rl.ri.context, "omitting binary blobs from logs") + ctx := redact.NewContext(rl.ctx, "omitting binary blobs from logs") for _, s := range d.URLs { u, err := url.Parse(s) @@ -186,7 +206,7 @@ func (rl *remoteImageLayer) Compressed() (io.ReadCloser, error) { return nil, err } - resp, err := rl.ri.Client.Do(req.WithContext(ctx)) + resp, err := rl.ri.fetcher.Do(req.WithContext(ctx)) if err != nil { lastErr = err continue @@ -244,13 +264,14 @@ func (rl *remoteImageLayer) Descriptor() (*v1.Descriptor, error) { // See partial.Exists. func (rl *remoteImageLayer) Exists() (bool, error) { - return rl.ri.blobExists(rl.digest) + return rl.ri.fetcher.blobExists(rl.ri.ctx, rl.digest) } // LayerByDigest implements partial.CompressedLayer func (r *remoteImage) LayerByDigest(h v1.Hash) (partial.CompressedLayer, error) { return &remoteImageLayer{ ri: r, + ctx: r.ctx, digest: h, }, nil } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/index.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/index.go index 0939947e3..b80972c80 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/index.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/index.go @@ -16,6 +16,7 @@ package remote import ( "bytes" + "context" "fmt" "sync" @@ -33,7 +34,9 @@ var acceptableIndexMediaTypes = []types.MediaType{ // remoteIndex accesses an index from a remote registry type remoteIndex struct { - fetcher + fetcher fetcher + ref name.Reference + ctx context.Context manifestLock sync.Mutex // Protects manifest manifest []byte mediaType types.MediaType @@ -75,7 +78,7 @@ func (r *remoteIndex) RawManifest() ([]byte, error) { // NOTE(jonjohnsonjr): We should never get here because the public entrypoints // do type-checking via remote.Descriptor. I've left this here for tests that // directly instantiate a remoteIndex. - manifest, desc, err := r.fetchManifest(r.Ref, acceptableIndexMediaTypes) + manifest, desc, err := r.fetcher.fetchManifest(r.ctx, r.ref, acceptableIndexMediaTypes) if err != nil { return nil, err } @@ -133,6 +136,7 @@ func (r *remoteIndex) Layer(h v1.Hash) (v1.Layer, error) { if h == childDesc.Digest { l, err := partial.CompressedToLayer(&remoteLayer{ fetcher: r.fetcher, + ctx: r.ctx, digest: h, }) if err != nil { @@ -140,47 +144,13 @@ func (r *remoteIndex) Layer(h v1.Hash) (v1.Layer, error) { } return &MountableLayer{ Layer: l, - Reference: r.Ref.Context().Digest(h.String()), + Reference: r.ref.Context().Digest(h.String()), }, nil } } return nil, fmt.Errorf("layer not found: %s", h) } -// Experiment with a better API for v1.ImageIndex. We might want to move this -// to partial? -func (r *remoteIndex) Manifests() ([]partial.Describable, error) { - m, err := r.IndexManifest() - if err != nil { - return nil, err - } - manifests := []partial.Describable{} - for _, desc := range m.Manifests { - switch { - case desc.MediaType.IsImage(): - img, err := r.Image(desc.Digest) - if err != nil { - return nil, err - } - manifests = append(manifests, img) - case desc.MediaType.IsIndex(): - idx, err := r.ImageIndex(desc.Digest) - if err != nil { - return nil, err - } - manifests = append(manifests, idx) - default: - layer, err := r.Layer(desc.Digest) - if err != nil { - return nil, err - } - manifests = append(manifests, layer) - } - } - - return manifests, nil -} - func (r *remoteIndex) imageByPlatform(platform v1.Platform) (v1.Image, error) { desc, err := r.childByPlatform(platform) if err != nil { @@ -216,7 +186,7 @@ func (r *remoteIndex) childByPlatform(platform v1.Platform) (*Descriptor, error) return r.childDescriptor(childDesc, platform) } } - return nil, fmt.Errorf("no child with platform %+v in index %s", platform, r.Ref) + return nil, fmt.Errorf("no child with platform %+v in index %s", platform, r.ref) } func (r *remoteIndex) childByHash(h v1.Hash) (*Descriptor, error) { @@ -229,12 +199,12 @@ func (r *remoteIndex) childByHash(h v1.Hash) (*Descriptor, error) { return r.childDescriptor(childDesc, defaultPlatform) } } - return nil, fmt.Errorf("no child with digest %s in index %s", h, r.Ref) + return nil, fmt.Errorf("no child with digest %s in index %s", h, r.ref) } // Convert one of this index's child's v1.Descriptor into a remote.Descriptor, with the given platform option. func (r *remoteIndex) childDescriptor(child v1.Descriptor, platform v1.Platform) (*Descriptor, error) { - ref := r.Ref.Context().Digest(child.Digest.String()) + ref := r.ref.Context().Digest(child.Digest.String()) var ( manifest []byte err error @@ -245,7 +215,7 @@ func (r *remoteIndex) childDescriptor(child v1.Descriptor, platform v1.Platform) } manifest = child.Data } else { - manifest, _, err = r.fetchManifest(ref, []types.MediaType{child.MediaType}) + manifest, _, err = r.fetcher.fetchManifest(r.ctx, ref, []types.MediaType{child.MediaType}) if err != nil { return nil, err } @@ -261,11 +231,9 @@ func (r *remoteIndex) childDescriptor(child v1.Descriptor, platform v1.Platform) } return &Descriptor{ - fetcher: fetcher{ - Ref: ref, - Client: r.Client, - context: r.context, - }, + ref: ref, + ctx: r.ctx, + fetcher: r.fetcher, Manifest: manifest, Descriptor: child, platform: platform, diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/layer.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/layer.go index b2126f599..39c205950 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/layer.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/layer.go @@ -15,32 +15,33 @@ package remote import ( + "context" "io" "github.com/google/go-containerregistry/internal/redact" "github.com/google/go-containerregistry/internal/verify" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/types" ) // remoteImagelayer implements partial.CompressedLayer type remoteLayer struct { - fetcher - digest v1.Hash + ctx context.Context + fetcher fetcher + digest v1.Hash } // Compressed implements partial.CompressedLayer func (rl *remoteLayer) Compressed() (io.ReadCloser, error) { // We don't want to log binary layers -- this can break terminals. - ctx := redact.NewContext(rl.context, "omitting binary blobs from logs") - return rl.fetchBlob(ctx, verify.SizeUnknown, rl.digest) + ctx := redact.NewContext(rl.ctx, "omitting binary blobs from logs") + return rl.fetcher.fetchBlob(ctx, verify.SizeUnknown, rl.digest) } // Compressed implements partial.CompressedLayer func (rl *remoteLayer) Size() (int64, error) { - resp, err := rl.headBlob(rl.digest) + resp, err := rl.fetcher.headBlob(rl.ctx, rl.digest) if err != nil { return -1, err } @@ -60,7 +61,7 @@ func (rl *remoteLayer) MediaType() (types.MediaType, error) { // See partial.Exists. func (rl *remoteLayer) Exists() (bool, error) { - return rl.blobExists(rl.digest) + return rl.fetcher.blobExists(rl.ctx, rl.digest) } // Layer reads the given blob reference from a registry as a Layer. A blob @@ -68,27 +69,9 @@ func (rl *remoteLayer) Exists() (bool, error) { // digest of the blob to be read and the repository portion is the repo where // that blob lives. func Layer(ref name.Digest, options ...Option) (v1.Layer, error) { - o, err := makeOptions(ref.Context(), options...) + o, err := makeOptions(options...) if err != nil { return nil, err } - f, err := makeFetcher(ref, o) - if err != nil { - return nil, err - } - h, err := v1.NewHash(ref.Identifier()) - if err != nil { - return nil, err - } - l, err := partial.CompressedToLayer(&remoteLayer{ - fetcher: *f, - digest: h, - }) - if err != nil { - return nil, err - } - return &MountableLayer{ - Layer: l, - Reference: ref, - }, nil + return newPuller(o).Layer(o.context, ref) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/list.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/list.go index e643c49aa..910d2a94c 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/list.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/list.go @@ -26,11 +26,6 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) -type tags struct { - Name string `json:"name"` - Tags []string `json:"tags"` -} - // ListWithContext calls List with the given context. // // Deprecated: Use List and WithContext. This will be removed in a future release. @@ -41,73 +36,65 @@ func ListWithContext(ctx context.Context, repo name.Repository, options ...Optio // List calls /tags/list for the given repository, returning the list of tags // in the "tags" property. func List(repo name.Repository, options ...Option) ([]string, error) { - o, err := makeOptions(repo, options...) + o, err := makeOptions(options...) if err != nil { return nil, err } - scopes := []string{repo.Scope(transport.PullScope)} - tr, err := transport.NewWithContext(o.context, repo.Registry, o.auth, o.transport, scopes) + return newPuller(o).List(o.context, repo) +} + +type Tags struct { + Name string `json:"name"` + Tags []string `json:"tags"` + Next string `json:"next,omitempty"` +} + +func (f *fetcher) listPage(ctx context.Context, repo name.Repository, next string, pageSize int) (*Tags, error) { + if next == "" { + uri := &url.URL{ + Scheme: repo.Scheme(), + Host: repo.RegistryStr(), + Path: fmt.Sprintf("/v2/%s/tags/list", repo.RepositoryStr()), + } + if pageSize > 0 { + uri.RawQuery = fmt.Sprintf("n=%d", pageSize) + } + next = uri.String() + } + + req, err := http.NewRequestWithContext(ctx, "GET", next, nil) if err != nil { return nil, err } - uri := &url.URL{ - Scheme: repo.Registry.Scheme(), - Host: repo.Registry.RegistryStr(), - Path: fmt.Sprintf("/v2/%s/tags/list", repo.RepositoryStr()), + resp, err := f.client.Do(req) + if err != nil { + return nil, err } - if o.pageSize > 0 { - uri.RawQuery = fmt.Sprintf("n=%d", o.pageSize) + if err := transport.CheckError(resp, http.StatusOK); err != nil { + return nil, err } - client := http.Client{Transport: tr} - tagList := []string{} - parsed := tags{} - - // get responses until there is no next page - for { - select { - case <-o.context.Done(): - return nil, o.context.Err() - default: - } - - req, err := http.NewRequestWithContext(o.context, "GET", uri.String(), nil) - if err != nil { - return nil, err - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - if err := transport.CheckError(resp, http.StatusOK); err != nil { - return nil, err - } - - if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { - return nil, err - } + parsed := Tags{} + if err := json.NewDecoder(resp.Body).Decode(&parsed); err != nil { + return nil, err + } - if err := resp.Body.Close(); err != nil { - return nil, err - } + if err := resp.Body.Close(); err != nil { + return nil, err + } - tagList = append(tagList, parsed.Tags...) + uri, err := getNextPageURL(resp) + if err != nil { + return nil, err + } - uri, err = getNextPageURL(resp) - if err != nil { - return nil, err - } - // no next page - if uri == nil { - break - } + if uri != nil { + parsed.Next = uri.String() } - return tagList, nil + return &parsed, nil } // getNextPageURL checks if there is a Link header in a http.Response which @@ -139,3 +126,27 @@ func getNextPageURL(resp *http.Response) (*url.URL, error) { linkURL = resp.Request.URL.ResolveReference(linkURL) return linkURL, nil } + +type Lister struct { + f *fetcher + repo name.Repository + pageSize int + + page *Tags + err error + + needMore bool +} + +func (l *Lister) Next(ctx context.Context) (*Tags, error) { + if l.needMore { + l.page, l.err = l.f.listPage(ctx, l.repo, l.page.Next, l.pageSize) + } else { + l.needMore = true + } + return l.page, l.err +} + +func (l *Lister) HasNext() bool { + return l.page != nil && (!l.needMore || l.page.Next != "") +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/multi_write.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/multi_write.go index 7f32413ce..a6705de89 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/multi_write.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/multi_write.go @@ -15,288 +15,32 @@ package remote import ( - "context" - "fmt" - "net/http" - "github.com/google/go-containerregistry/pkg/name" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/partial" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/google/go-containerregistry/pkg/v1/types" "golang.org/x/sync/errgroup" ) // MultiWrite writes the given Images or ImageIndexes to the given refs, as -// efficiently as possible, by deduping shared layer blobs and uploading layers -// in parallel, then uploading all manifests in parallel. -// -// Current limitations: -// - All refs must share the same repository. -// - Images cannot consist of stream.Layers. -func MultiWrite(m map[name.Reference]Taggable, options ...Option) (rerr error) { - // Determine the repository being pushed to; if asked to push to - // multiple repositories, give up. - var repo, zero name.Repository - for ref := range m { - if repo == zero { - repo = ref.Context() - } else if ref.Context() != repo { - return fmt.Errorf("MultiWrite can only push to the same repository (saw %q and %q)", repo, ref.Context()) - } - } - - o, err := makeOptions(repo, options...) - if err != nil { - return err - } - - // Collect unique blobs (layers and config blobs). - blobs := map[v1.Hash]v1.Layer{} - newManifests := []map[name.Reference]Taggable{} - // Separate originally requested images and indexes, so we can push images first. - images, indexes := map[name.Reference]Taggable{}, map[name.Reference]Taggable{} - for ref, i := range m { - if img, ok := i.(v1.Image); ok { - images[ref] = i - if err := addImageBlobs(img, blobs, o.allowNondistributableArtifacts); err != nil { - return err - } - continue - } - if idx, ok := i.(v1.ImageIndex); ok { - indexes[ref] = i - newManifests, err = addIndexBlobs(idx, blobs, repo, newManifests, 0, o.allowNondistributableArtifacts) - if err != nil { - return err - } - continue - } - return fmt.Errorf("pushable resource was not Image or ImageIndex: %T", i) - } - - // Determine if any of the layers are Mountable, because if so we need - // to request Pull scope too. - ls := []v1.Layer{} - for _, l := range blobs { - ls = append(ls, l) - } - scopes := scopesForUploadingImage(repo, ls) - tr, err := transport.NewWithContext(o.context, repo.Registry, o.auth, o.transport, scopes) +// efficiently as possible, by deduping shared layer blobs while uploading them +// in parallel. +func MultiWrite(todo map[name.Reference]Taggable, options ...Option) (rerr error) { + o, err := makeOptions(options...) if err != nil { return err } - w := writer{ - repo: repo, - client: &http.Client{Transport: tr}, - backoff: o.retryBackoff, - predicate: o.retryPredicate, + if o.progress != nil { + defer func() { o.progress.Close(rerr) }() } + p := newPusher(o) - // Collect the total size of blobs and manifests we're about to write. - if o.updates != nil { - w.progress = &progress{updates: o.updates} - w.progress.lastUpdate = &v1.Update{} - defer close(o.updates) - defer func() { _ = w.progress.err(rerr) }() - for _, b := range blobs { - size, err := b.Size() - if err != nil { - return err - } - w.progress.total(size) - } - countManifest := func(t Taggable) error { - b, err := t.RawManifest() - if err != nil { - return err - } - w.progress.total(int64(len(b))) - return nil - } - for _, i := range images { - if err := countManifest(i); err != nil { - return err - } - } - for _, nm := range newManifests { - for _, i := range nm { - if err := countManifest(i); err != nil { - return err - } - } - } - for _, i := range indexes { - if err := countManifest(i); err != nil { - return err - } - } - } + g, ctx := errgroup.WithContext(o.context) + g.SetLimit(o.jobs) - // Upload individual blobs and collect any errors. - blobChan := make(chan v1.Layer, 2*o.jobs) - ctx := o.context - g, gctx := errgroup.WithContext(o.context) - for i := 0; i < o.jobs; i++ { - // Start N workers consuming blobs to upload. + for ref, t := range todo { + ref, t := ref, t g.Go(func() error { - for b := range blobChan { - if err := w.uploadOne(gctx, b); err != nil { - return err - } - } - return nil + return p.Push(ctx, ref, t) }) } - g.Go(func() error { - defer close(blobChan) - for _, b := range blobs { - select { - case blobChan <- b: - case <-gctx.Done(): - return gctx.Err() - } - } - return nil - }) - if err := g.Wait(); err != nil { - return err - } - - commitMany := func(ctx context.Context, m map[name.Reference]Taggable) error { - g, ctx := errgroup.WithContext(ctx) - // With all of the constituent elements uploaded, upload the manifests - // to commit the images and indexes, and collect any errors. - type task struct { - i Taggable - ref name.Reference - } - taskChan := make(chan task, 2*o.jobs) - for i := 0; i < o.jobs; i++ { - // Start N workers consuming tasks to upload manifests. - g.Go(func() error { - for t := range taskChan { - if err := w.commitManifest(ctx, t.i, t.ref); err != nil { - return err - } - } - return nil - }) - } - go func() { - for ref, i := range m { - taskChan <- task{i, ref} - } - close(taskChan) - }() - return g.Wait() - } - // Push originally requested image manifests. These have no - // dependencies. - if err := commitMany(ctx, images); err != nil { - return err - } - // Push new manifests from lowest levels up. - for i := len(newManifests) - 1; i >= 0; i-- { - if err := commitMany(ctx, newManifests[i]); err != nil { - return err - } - } - // Push originally requested index manifests, which might depend on - // newly discovered manifests. - - return commitMany(ctx, indexes) -} -// addIndexBlobs adds blobs to the set of blobs we intend to upload, and -// returns the latest copy of the ordered collection of manifests to upload. -func addIndexBlobs(idx v1.ImageIndex, blobs map[v1.Hash]v1.Layer, repo name.Repository, newManifests []map[name.Reference]Taggable, lvl int, allowNondistributableArtifacts bool) ([]map[name.Reference]Taggable, error) { - if lvl > len(newManifests)-1 { - newManifests = append(newManifests, map[name.Reference]Taggable{}) - } - - im, err := idx.IndexManifest() - if err != nil { - return nil, err - } - for _, desc := range im.Manifests { - switch desc.MediaType { - case types.OCIImageIndex, types.DockerManifestList: - idx, err := idx.ImageIndex(desc.Digest) - if err != nil { - return nil, err - } - newManifests, err = addIndexBlobs(idx, blobs, repo, newManifests, lvl+1, allowNondistributableArtifacts) - if err != nil { - return nil, err - } - - // Also track the sub-index manifest to upload later by digest. - newManifests[lvl][repo.Digest(desc.Digest.String())] = idx - case types.OCIManifestSchema1, types.DockerManifestSchema2: - img, err := idx.Image(desc.Digest) - if err != nil { - return nil, err - } - if err := addImageBlobs(img, blobs, allowNondistributableArtifacts); err != nil { - return nil, err - } - - // Also track the sub-image manifest to upload later by digest. - newManifests[lvl][repo.Digest(desc.Digest.String())] = img - default: - // Workaround for #819. - if wl, ok := idx.(withLayer); ok { - layer, err := wl.Layer(desc.Digest) - if err != nil { - return nil, err - } - if err := addLayerBlob(layer, blobs, allowNondistributableArtifacts); err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("unknown media type: %v", desc.MediaType) - } - } - } - return newManifests, nil -} - -func addLayerBlob(l v1.Layer, blobs map[v1.Hash]v1.Layer, allowNondistributableArtifacts bool) error { - // Ignore foreign layers. - mt, err := l.MediaType() - if err != nil { - return err - } - - if mt.IsDistributable() || allowNondistributableArtifacts { - d, err := l.Digest() - if err != nil { - return err - } - - blobs[d] = l - } - - return nil -} - -func addImageBlobs(img v1.Image, blobs map[v1.Hash]v1.Layer, allowNondistributableArtifacts bool) error { - ls, err := img.Layers() - if err != nil { - return err - } - // Collect all layers. - for _, l := range ls { - if err := addLayerBlob(l, blobs, allowNondistributableArtifacts); err != nil { - return err - } - } - - // Collect config blob. - cl, err := partial.ConfigLayer(img) - if err != nil { - return err - } - return addLayerBlob(cl, blobs, allowNondistributableArtifacts) + return g.Wait() } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go index 54a0af227..a722c2ca6 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go @@ -37,16 +37,23 @@ type options struct { auth authn.Authenticator keychain authn.Keychain transport http.RoundTripper - platform v1.Platform context context.Context jobs int userAgent string allowNondistributableArtifacts bool - updates chan<- v1.Update - pageSize int + progress *progress retryBackoff Backoff retryPredicate retry.Predicate - filter map[string]string + retryStatusCodes []int + + // Only these options can overwrite Reuse()d options. + platform v1.Platform + pageSize int + filter map[string]string + + // Set by Reuse, we currently store one or the other. + puller *Puller + pusher *Pusher } var defaultPlatform = v1.Platform{ @@ -60,7 +67,7 @@ type Backoff = retry.Backoff var defaultRetryPredicate retry.Predicate = func(err error) bool { // Various failure modes here, as we're often reading from and writing to // the network. - if retry.IsTemporary(err) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) { + if retry.IsTemporary(err) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, net.ErrClosed) { logs.Warn.Printf("retrying %v", err) return true } @@ -83,12 +90,13 @@ var fastBackoff = Backoff{ Steps: 3, } -var retryableStatusCodes = []int{ +var defaultRetryStatusCodes = []int{ http.StatusRequestTimeout, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout, + 499, } const ( @@ -112,17 +120,20 @@ var DefaultTransport http.RoundTripper = &http.Transport{ IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, + // We usually are dealing with 2 hosts (at most), split MaxIdleConns between them. + MaxIdleConnsPerHost: 50, } -func makeOptions(target authn.Resource, opts ...Option) (*options, error) { +func makeOptions(opts ...Option) (*options, error) { o := &options{ - transport: DefaultTransport, - platform: defaultPlatform, - context: context.Background(), - jobs: defaultJobs, - pageSize: defaultPageSize, - retryPredicate: defaultRetryPredicate, - retryBackoff: defaultRetryBackoff, + transport: DefaultTransport, + platform: defaultPlatform, + context: context.Background(), + jobs: defaultJobs, + pageSize: defaultPageSize, + retryPredicate: defaultRetryPredicate, + retryBackoff: defaultRetryBackoff, + retryStatusCodes: defaultRetryStatusCodes, } for _, option := range opts { @@ -136,12 +147,6 @@ func makeOptions(target authn.Resource, opts ...Option) (*options, error) { // It is a better experience to explicitly tell a caller their auth is misconfigured // than potentially fail silently when the correct auth is overridden by option misuse. return nil, errors.New("provide an option for either authn.Authenticator or authn.Keychain, not both") - case o.keychain != nil: - auth, err := o.keychain.Resolve(target) - if err != nil { - return nil, err - } - o.auth = auth case o.auth == nil: o.auth = authn.Anonymous } @@ -157,7 +162,7 @@ func makeOptions(target authn.Resource, opts ...Option) (*options, error) { } // Wrap the transport in something that can retry network flakes. - o.transport = transport.NewRetry(o.transport, transport.WithRetryPredicate(defaultRetryPredicate), transport.WithRetryStatusCodes(retryableStatusCodes...)) + o.transport = transport.NewRetry(o.transport, transport.WithRetryPredicate(defaultRetryPredicate), transport.WithRetryStatusCodes(o.retryStatusCodes...)) // Wrap this last to prevent transport.New from double-wrapping. if o.userAgent != "" { @@ -273,7 +278,8 @@ func WithNondistributable(o *options) error { // should provide a buffered channel to avoid potential deadlocks. func WithProgress(updates chan<- v1.Update) Option { return func(o *options) error { - o.updates = updates + o.progress = &progress{updates: updates} + o.progress.lastUpdate = &v1.Update{} return nil } } @@ -305,6 +311,14 @@ func WithRetryPredicate(predicate retry.Predicate) Option { } } +// WithRetryStatusCodes sets which http response codes will be retried. +func WithRetryStatusCodes(codes ...int) Option { + return func(o *options) error { + o.retryStatusCodes = codes + return nil + } +} + // WithFilter sets the filter querystring for HTTP operations. func WithFilter(key string, value string) Option { return func(o *options) error { @@ -315,3 +329,20 @@ func WithFilter(key string, value string) Option { return nil } } + +// Reuse takes a Puller or Pusher and reuses it for remote interactions +// rather than starting from a clean slate. For example, it will reuse token exchanges +// when possible and avoid sending redundant HEAD requests. +// +// Reuse will take precedence over other options passed to most remote functions because +// most options deal with setting up auth and transports, which Reuse intetionally skips. +func Reuse[I *Puller | *Pusher](i I) Option { + return func(o *options) error { + if puller, ok := any(i).(*Puller); ok { + o.puller = puller + } else if pusher, ok := any(i).(*Pusher); ok { + o.pusher = pusher + } + return nil + } +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/progress.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/progress.go index 1f4396350..fe60c8c35 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/progress.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/progress.go @@ -29,6 +29,8 @@ type progress struct { } func (p *progress) total(delta int64) { + p.Lock() + defer p.Unlock() atomic.AddInt64(&p.lastUpdate.Total, delta) } @@ -48,6 +50,11 @@ func (p *progress) err(err error) error { return err } +func (p *progress) Close(err error) { + _ = p.err(err) + close(p.updates) +} + type progressReader struct { rc io.ReadCloser diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go new file mode 100644 index 000000000..7da8017ee --- /dev/null +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go @@ -0,0 +1,222 @@ +// Copyright 2023 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package remote + +import ( + "context" + "sync" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +type Puller struct { + o *options + + // map[resource]*reader + readers sync.Map +} + +func NewPuller(options ...Option) (*Puller, error) { + o, err := makeOptions(options...) + if err != nil { + return nil, err + } + + return newPuller(o), nil +} + +func newPuller(o *options) *Puller { + if o.puller != nil { + return o.puller + } + return &Puller{ + o: o, + } +} + +type reader struct { + // in + target resource + o *options + + // f() + once sync.Once + + // out + f *fetcher + err error +} + +// this will run once per reader instance +func (r *reader) init(ctx context.Context) error { + r.once.Do(func() { + r.f, r.err = makeFetcher(ctx, r.target, r.o) + }) + return r.err +} + +func (p *Puller) fetcher(ctx context.Context, target resource) (*fetcher, error) { + v, _ := p.readers.LoadOrStore(target, &reader{ + target: target, + o: p.o, + }) + rr := v.(*reader) + return rr.f, rr.init(ctx) +} + +// Head is like remote.Head, but avoids re-authenticating when possible. +func (p *Puller) Head(ctx context.Context, ref name.Reference) (*v1.Descriptor, error) { + f, err := p.fetcher(ctx, ref.Context()) + if err != nil { + return nil, err + } + + return f.headManifest(ctx, ref, allManifestMediaTypes) +} + +// Get is like remote.Get, but avoids re-authenticating when possible. +func (p *Puller) Get(ctx context.Context, ref name.Reference) (*Descriptor, error) { + return p.get(ctx, ref, allManifestMediaTypes, p.o.platform) +} + +func (p *Puller) get(ctx context.Context, ref name.Reference, acceptable []types.MediaType, platform v1.Platform) (*Descriptor, error) { + f, err := p.fetcher(ctx, ref.Context()) + if err != nil { + return nil, err + } + return f.get(ctx, ref, acceptable, platform) +} + +// Layer is like remote.Layer, but avoids re-authenticating when possible. +func (p *Puller) Layer(ctx context.Context, ref name.Digest) (v1.Layer, error) { + f, err := p.fetcher(ctx, ref.Context()) + if err != nil { + return nil, err + } + + h, err := v1.NewHash(ref.Identifier()) + if err != nil { + return nil, err + } + l, err := partial.CompressedToLayer(&remoteLayer{ + fetcher: *f, + ctx: ctx, + digest: h, + }) + if err != nil { + return nil, err + } + return &MountableLayer{ + Layer: l, + Reference: ref, + }, nil +} + +// List lists tags in a repo and handles pagination, returning the full list of tags. +func (p *Puller) List(ctx context.Context, repo name.Repository) ([]string, error) { + lister, err := p.Lister(ctx, repo) + if err != nil { + return nil, err + } + + tagList := []string{} + for lister.HasNext() { + tags, err := lister.Next(ctx) + if err != nil { + return nil, err + } + tagList = append(tagList, tags.Tags...) + } + + return tagList, nil +} + +// Lister lists tags in a repo and returns a Lister for paginating through the results. +func (p *Puller) Lister(ctx context.Context, repo name.Repository) (*Lister, error) { + return p.lister(ctx, repo, p.o.pageSize) +} + +func (p *Puller) lister(ctx context.Context, repo name.Repository, pageSize int) (*Lister, error) { + f, err := p.fetcher(ctx, repo) + if err != nil { + return nil, err + } + page, err := f.listPage(ctx, repo, "", pageSize) + if err != nil { + return nil, err + } + return &Lister{ + f: f, + repo: repo, + pageSize: pageSize, + page: page, + err: err, + }, nil +} + +// Catalog lists repos in a registry and handles pagination, returning the full list of repos. +func (p *Puller) Catalog(ctx context.Context, reg name.Registry) ([]string, error) { + return p.catalog(ctx, reg, p.o.pageSize) +} + +func (p *Puller) catalog(ctx context.Context, reg name.Registry, pageSize int) ([]string, error) { + catalogger, err := p.catalogger(ctx, reg, pageSize) + if err != nil { + return nil, err + } + repoList := []string{} + for catalogger.HasNext() { + repos, err := catalogger.Next(ctx) + if err != nil { + return nil, err + } + repoList = append(repoList, repos.Repos...) + } + return repoList, nil +} + +// Catalogger lists repos in a registry and returns a Catalogger for paginating through the results. +func (p *Puller) Catalogger(ctx context.Context, reg name.Registry) (*Catalogger, error) { + return p.catalogger(ctx, reg, p.o.pageSize) +} + +func (p *Puller) catalogger(ctx context.Context, reg name.Registry, pageSize int) (*Catalogger, error) { + f, err := p.fetcher(ctx, reg) + if err != nil { + return nil, err + } + page, err := f.catalogPage(ctx, reg, "", pageSize) + if err != nil { + return nil, err + } + return &Catalogger{ + f: f, + reg: reg, + pageSize: pageSize, + page: page, + err: err, + }, nil +} + +func (p *Puller) referrers(ctx context.Context, d name.Digest, filter map[string]string) (v1.ImageIndex, error) { + f, err := p.fetcher(ctx, d.Context()) + if err != nil { + return nil, err + } + return f.fetchReferrers(ctx, filter, d) +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go new file mode 100644 index 000000000..1c07bd475 --- /dev/null +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go @@ -0,0 +1,559 @@ +// Copyright 2023 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package remote + +import ( + "bytes" + "context" + "errors" + "fmt" + "net/http" + "net/url" + "sync" + + "github.com/google/go-containerregistry/pkg/logs" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/google/go-containerregistry/pkg/v1/stream" + "github.com/google/go-containerregistry/pkg/v1/types" + "golang.org/x/sync/errgroup" +) + +type manifest interface { + Taggable + partial.Describable +} + +// key is either v1.Hash or v1.Layer (for stream.Layer) +type workers struct { + // map[v1.Hash|v1.Layer]*sync.Once + onces sync.Map + + // map[v1.Hash|v1.Layer]error + errors sync.Map +} + +func nop() error { + return nil +} + +func (w *workers) err(digest v1.Hash) error { + v, ok := w.errors.Load(digest) + if !ok || v == nil { + return nil + } + return v.(error) +} + +func (w *workers) Do(digest v1.Hash, f func() error) error { + // We don't care if it was loaded or not because the sync.Once will do it for us. + once, _ := w.onces.LoadOrStore(digest, &sync.Once{}) + + once.(*sync.Once).Do(func() { + w.errors.Store(digest, f()) + }) + + err := w.err(digest) + if err != nil { + // Allow this to be retried by another caller. + w.onces.Delete(digest) + } + return err +} + +func (w *workers) Stream(layer v1.Layer, f func() error) error { + // We don't care if it was loaded or not because the sync.Once will do it for us. + once, _ := w.onces.LoadOrStore(layer, &sync.Once{}) + + once.(*sync.Once).Do(func() { + w.errors.Store(layer, f()) + }) + + v, ok := w.errors.Load(layer) + if !ok || v == nil { + return nil + } + + return v.(error) +} + +type Pusher struct { + o *options + + // map[name.Repository]*repoWriter + writers sync.Map +} + +func NewPusher(options ...Option) (*Pusher, error) { + o, err := makeOptions(options...) + if err != nil { + return nil, err + } + + return newPusher(o), nil +} + +func newPusher(o *options) *Pusher { + if o.pusher != nil { + return o.pusher + } + return &Pusher{ + o: o, + } +} + +func (p *Pusher) writer(ctx context.Context, repo name.Repository, o *options) (*repoWriter, error) { + v, _ := p.writers.LoadOrStore(repo, &repoWriter{ + repo: repo, + o: o, + }) + rw := v.(*repoWriter) + return rw, rw.init(ctx) +} + +func (p *Pusher) Push(ctx context.Context, ref name.Reference, t Taggable) error { + w, err := p.writer(ctx, ref.Context(), p.o) + if err != nil { + return err + } + return w.writeManifest(ctx, ref, t) +} + +func (p *Pusher) Upload(ctx context.Context, repo name.Repository, l v1.Layer) error { + w, err := p.writer(ctx, repo, p.o) + if err != nil { + return err + } + return w.writeLayer(ctx, l) +} + +func (p *Pusher) Delete(ctx context.Context, ref name.Reference) error { + w, err := p.writer(ctx, ref.Context(), p.o) + if err != nil { + return err + } + + u := url.URL{ + Scheme: ref.Context().Registry.Scheme(), + Host: ref.Context().RegistryStr(), + Path: fmt.Sprintf("/v2/%s/manifests/%s", ref.Context().RepositoryStr(), ref.Identifier()), + } + + req, err := http.NewRequest(http.MethodDelete, u.String(), nil) + if err != nil { + return err + } + + resp, err := w.w.client.Do(req.WithContext(ctx)) + if err != nil { + return err + } + defer resp.Body.Close() + + return transport.CheckError(resp, http.StatusOK, http.StatusAccepted) + + // TODO(jason): If the manifest had a `subject`, and if the registry + // doesn't support Referrers, update the index pointed to by the + // subject's fallback tag to remove the descriptor for this manifest. +} + +type repoWriter struct { + repo name.Repository + o *options + once sync.Once + + w *writer + err error + + work *workers +} + +// this will run once per repoWriter instance +func (rw *repoWriter) init(ctx context.Context) error { + rw.once.Do(func() { + rw.work = &workers{} + rw.w, rw.err = makeWriter(ctx, rw.repo, nil, rw.o) + }) + return rw.err +} + +func (rw *repoWriter) writeDeps(ctx context.Context, m manifest) error { + if img, ok := m.(v1.Image); ok { + return rw.writeLayers(ctx, img) + } + + if idx, ok := m.(v1.ImageIndex); ok { + return rw.writeChildren(ctx, idx) + } + + // This has no deps, not an error (e.g. something you want to just PUT). + return nil +} + +type describable struct { + desc v1.Descriptor +} + +func (d describable) Digest() (v1.Hash, error) { + return d.desc.Digest, nil +} + +func (d describable) Size() (int64, error) { + return d.desc.Size, nil +} + +func (d describable) MediaType() (types.MediaType, error) { + return d.desc.MediaType, nil +} + +type tagManifest struct { + Taggable + partial.Describable +} + +func taggableToManifest(t Taggable) (manifest, error) { + if m, ok := t.(manifest); ok { + return m, nil + } + + if d, ok := t.(*Descriptor); ok { + if d.MediaType.IsIndex() { + return d.ImageIndex() + } + + if d.MediaType.IsImage() { + return d.Image() + } + + if d.MediaType.IsSchema1() { + return d.Schema1() + } + + return tagManifest{t, describable{d.toDesc()}}, nil + } + + desc := v1.Descriptor{ + // A reasonable default if Taggable doesn't implement MediaType. + MediaType: types.DockerManifestSchema2, + } + + b, err := t.RawManifest() + if err != nil { + return nil, err + } + + if wmt, ok := t.(withMediaType); ok { + desc.MediaType, err = wmt.MediaType() + if err != nil { + return nil, err + } + } + + desc.Digest, desc.Size, err = v1.SHA256(bytes.NewReader(b)) + if err != nil { + return nil, err + } + + return tagManifest{t, describable{desc}}, nil +} + +func (rw *repoWriter) writeManifest(ctx context.Context, ref name.Reference, t Taggable) error { + m, err := taggableToManifest(t) + if err != nil { + return err + } + + needDeps := true + + digest, err := m.Digest() + if errors.Is(err, stream.ErrNotComputed) { + if err := rw.writeDeps(ctx, m); err != nil { + return err + } + + needDeps = false + + digest, err = m.Digest() + if err != nil { + return err + } + } else if err != nil { + return err + } + + // This may be a lazy child where we have no ref until digest is computed. + if ref == nil { + ref = rw.repo.Digest(digest.String()) + } + + // For tags, we want to do this check outside of our Work.Do closure because + // we don't want to dedupe based on the manifest digest. + _, byTag := ref.(name.Tag) + if byTag { + if exists, err := rw.manifestExists(ctx, ref, t); err != nil { + return err + } else if exists { + return nil + } + } + + // The following work.Do will get deduped by digest, so it won't happen unless + // this tag happens to be the first commitManifest to run for that digest. + needPut := byTag + + if err := rw.work.Do(digest, func() error { + if !byTag { + if exists, err := rw.manifestExists(ctx, ref, t); err != nil { + return err + } else if exists { + return nil + } + } + + if needDeps { + if err := rw.writeDeps(ctx, m); err != nil { + return err + } + } + + needPut = false + return rw.commitManifest(ctx, ref, m) + }); err != nil { + return err + } + + if !needPut { + return nil + } + + // Only runs for tags that got deduped by digest. + return rw.commitManifest(ctx, ref, m) +} + +func (rw *repoWriter) writeChildren(ctx context.Context, idx v1.ImageIndex) error { + children, err := partial.Manifests(idx) + if err != nil { + return err + } + + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(rw.o.jobs) + + for _, child := range children { + child := child + if err := rw.writeChild(ctx, child, g); err != nil { + return err + } + } + + return g.Wait() +} + +func (rw *repoWriter) writeChild(ctx context.Context, child partial.Describable, g *errgroup.Group) error { + switch child := child.(type) { + case v1.ImageIndex: + // For recursive index, we want to do a depth-first launching of goroutines + // to avoid deadlocking. + // + // Note that this is rare, so the impact of this should be really small. + return rw.writeManifest(ctx, nil, child) + case v1.Image: + g.Go(func() error { + return rw.writeManifest(ctx, nil, child) + }) + case v1.Layer: + g.Go(func() error { + return rw.writeLayer(ctx, child) + }) + default: + // This can't happen. + return fmt.Errorf("encountered unknown child: %T", child) + } + return nil +} + +// TODO: Consider caching some representation of the tags/digests in the destination +// repository as a hint to avoid this optimistic check in cases where we will most +// likely have to do a PUT anyway, e.g. if we are overwriting a tag we just wrote. +func (rw *repoWriter) manifestExists(ctx context.Context, ref name.Reference, t Taggable) (bool, error) { + f := &fetcher{ + target: ref.Context(), + client: rw.w.client, + } + + m, err := taggableToManifest(t) + if err != nil { + return false, err + } + + digest, err := m.Digest() + if err != nil { + // Possibly due to streaming layers. + return false, nil + } + got, err := f.headManifest(ctx, ref, allManifestMediaTypes) + if err != nil { + var terr *transport.Error + if errors.As(err, &terr) { + if terr.StatusCode == http.StatusNotFound { + return false, nil + } + + // We treat a 403 here as non-fatal because this existence check is an optimization and + // some registries will return a 403 instead of a 404 in certain situations. + // E.g. https://jfrog.atlassian.net/browse/RTFACT-13797 + if terr.StatusCode == http.StatusForbidden { + logs.Debug.Printf("manifestExists unexpected 403: %v", err) + return false, nil + } + } + + return false, err + } + + if digest != got.Digest { + // Mark that we saw this digest in the registry so we don't have to check it again. + rw.work.Do(got.Digest, nop) + + return false, nil + } + + if tag, ok := ref.(name.Tag); ok { + logs.Progress.Printf("existing manifest: %s@%s", tag.Identifier(), got.Digest) + } else { + logs.Progress.Print("existing manifest: ", got.Digest) + } + + return true, nil +} + +func (rw *repoWriter) commitManifest(ctx context.Context, ref name.Reference, m manifest) error { + if rw.o.progress != nil { + size, err := m.Size() + if err != nil { + return err + } + rw.o.progress.total(size) + } + + return rw.w.commitManifest(ctx, m, ref) +} + +func (rw *repoWriter) writeLayers(pctx context.Context, img v1.Image) error { + ls, err := img.Layers() + if err != nil { + return err + } + + g, ctx := errgroup.WithContext(pctx) + g.SetLimit(rw.o.jobs) + + for _, l := range ls { + l := l + + g.Go(func() error { + return rw.writeLayer(ctx, l) + }) + } + + mt, err := img.MediaType() + if err != nil { + return err + } + + if mt.IsSchema1() { + return g.Wait() + } + + cl, err := partial.ConfigLayer(img) + if errors.Is(err, stream.ErrNotComputed) { + if err := g.Wait(); err != nil { + return err + } + + cl, err := partial.ConfigLayer(img) + if err != nil { + return err + } + + return rw.writeLayer(pctx, cl) + } else if err != nil { + return err + } + + g.Go(func() error { + return rw.writeLayer(ctx, cl) + }) + + return g.Wait() +} + +func (rw *repoWriter) writeLayer(ctx context.Context, l v1.Layer) error { + // Skip any non-distributable things. + mt, err := l.MediaType() + if err != nil { + return err + } + if !mt.IsDistributable() && !rw.o.allowNondistributableArtifacts { + return nil + } + + digest, err := l.Digest() + if err != nil { + if errors.Is(err, stream.ErrNotComputed) { + return rw.lazyWriteLayer(ctx, l) + } + return err + } + + return rw.work.Do(digest, func() error { + if rw.o.progress != nil { + size, err := l.Size() + if err != nil { + return err + } + rw.o.progress.total(size) + } + return rw.w.uploadOne(ctx, l) + }) +} + +func (rw *repoWriter) lazyWriteLayer(ctx context.Context, l v1.Layer) error { + return rw.work.Stream(l, func() error { + if err := rw.w.uploadOne(ctx, l); err != nil { + return err + } + + // Mark this upload completed. + digest, err := l.Digest() + if err != nil { + return err + } + + rw.work.Do(digest, nop) + + if rw.o.progress != nil { + size, err := l.Size() + if err != nil { + return err + } + rw.o.progress.total(size) + } + + return nil + }) +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go index b3db863d1..e30ca57ed 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go @@ -15,21 +15,103 @@ package remote import ( + "bytes" + "context" + "errors" + "io" + "net/http" + "strings" + "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/google/go-containerregistry/pkg/v1/types" ) // Referrers returns a list of descriptors that refer to the given manifest digest. // // The subject manifest doesn't have to exist in the registry for there to be descriptors that refer to it. -func Referrers(d name.Digest, options ...Option) (*v1.IndexManifest, error) { - o, err := makeOptions(d.Context(), options...) +func Referrers(d name.Digest, options ...Option) (v1.ImageIndex, error) { + o, err := makeOptions(options...) + if err != nil { + return nil, err + } + return newPuller(o).referrers(o.context, d, o.filter) +} + +// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#referrers-tag-schema +func fallbackTag(d name.Digest) name.Tag { + return d.Context().Tag(strings.Replace(d.DigestStr(), ":", "-", 1)) +} + +func (f *fetcher) fetchReferrers(ctx context.Context, filter map[string]string, d name.Digest) (v1.ImageIndex, error) { + // Check the Referrers API endpoint first. + u := f.url("referrers", d.DigestStr()) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { return nil, err } - f, err := makeFetcher(d, o) + req.Header.Set("Accept", string(types.OCIImageIndex)) + + resp, err := f.client.Do(req) if err != nil { return nil, err } - return f.fetchReferrers(o.context, o.filter, d) + defer resp.Body.Close() + + if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound, http.StatusBadRequest); err != nil { + return nil, err + } + + var b []byte + if resp.StatusCode == http.StatusOK { + b, err = io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + } else { + // The registry doesn't support the Referrers API endpoint, so we'll use the fallback tag scheme. + b, _, err = f.fetchManifest(ctx, fallbackTag(d), []types.MediaType{types.OCIImageIndex}) + var terr *transport.Error + if errors.As(err, &terr) && terr.StatusCode == http.StatusNotFound { + // Not found just means there are no attachments yet. Start with an empty manifest. + return empty.Index, nil + } else if err != nil { + return nil, err + } + } + + h, sz, err := v1.SHA256(bytes.NewReader(b)) + if err != nil { + return nil, err + } + idx := &remoteIndex{ + fetcher: *f, + ctx: ctx, + manifest: b, + mediaType: types.OCIImageIndex, + descriptor: &v1.Descriptor{ + Digest: h, + MediaType: types.OCIImageIndex, + Size: sz, + }, + } + return filterReferrersResponse(filter, idx), nil +} + +// If filter applied, filter out by artifactType. +// See https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers +func filterReferrersResponse(filter map[string]string, in v1.ImageIndex) v1.ImageIndex { + if filter == nil { + return in + } + v, ok := filter["artifactType"] + if !ok { + return in + } + return mutate.RemoveManifests(in, func(desc v1.Descriptor) bool { + return desc.ArtifactType != v + }) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/schema1.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/schema1.go new file mode 100644 index 000000000..4bc1c4c45 --- /dev/null +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/schema1.go @@ -0,0 +1,118 @@ +// Copyright 2023 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package remote + +import ( + "bytes" + "context" + "encoding/json" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +type schema1 struct { + ref name.Reference + ctx context.Context + fetcher fetcher + manifest []byte + mediaType types.MediaType + descriptor *v1.Descriptor +} + +func (s *schema1) Layers() ([]v1.Layer, error) { + m := schema1Manifest{} + if err := json.NewDecoder(bytes.NewReader(s.manifest)).Decode(&m); err != nil { + return nil, err + } + + layers := []v1.Layer{} + for i := len(m.FSLayers) - 1; i >= 0; i-- { + fsl := m.FSLayers[i] + + h, err := v1.NewHash(fsl.BlobSum) + if err != nil { + return nil, err + } + l, err := s.LayerByDigest(h) + if err != nil { + return nil, err + } + layers = append(layers, l) + } + + return layers, nil +} + +func (s *schema1) MediaType() (types.MediaType, error) { + return s.mediaType, nil +} + +func (s *schema1) Size() (int64, error) { + return s.descriptor.Size, nil +} + +func (s *schema1) ConfigName() (v1.Hash, error) { + return partial.ConfigName(s) +} + +func (s *schema1) ConfigFile() (*v1.ConfigFile, error) { + return nil, newErrSchema1(s.mediaType) +} + +func (s *schema1) RawConfigFile() ([]byte, error) { + return []byte("{}"), nil +} + +func (s *schema1) Digest() (v1.Hash, error) { + return s.descriptor.Digest, nil +} + +func (s *schema1) Manifest() (*v1.Manifest, error) { + return nil, newErrSchema1(s.mediaType) +} + +func (s *schema1) RawManifest() ([]byte, error) { + return s.manifest, nil +} + +func (s *schema1) LayerByDigest(h v1.Hash) (v1.Layer, error) { + l, err := partial.CompressedToLayer(&remoteLayer{ + fetcher: s.fetcher, + ctx: s.ctx, + digest: h, + }) + if err != nil { + return nil, err + } + return &MountableLayer{ + Layer: l, + Reference: s.ref.Context().Digest(h.String()), + }, nil +} + +func (s *schema1) LayerByDiffID(v1.Hash) (v1.Layer, error) { + return nil, newErrSchema1(s.mediaType) +} + +type fslayer struct { + BlobSum string `json:"blobSum"` +} + +type schema1Manifest struct { + FSLayers []fslayer `json:"fsLayers"` +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/error.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/error.go index c0e433730..482a4adee 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/error.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/error.go @@ -34,6 +34,9 @@ type Error struct { Request *http.Request // The raw body if we couldn't understand it. rawBody string + + // Bit of a hack to make it easier to force a retry. + temporary bool } // Check that Error implements error @@ -72,6 +75,10 @@ func (e *Error) responseErr() string { // Temporary returns whether the request that preceded the error is temporary. func (e *Error) Temporary() bool { + if e.temporary { + return true + } + if len(e.Errors) == 0 { _, ok := temporaryStatusCodes[e.StatusCode] return ok @@ -153,21 +160,37 @@ func CheckError(resp *http.Response, codes ...int) error { return nil } } + b, err := io.ReadAll(resp.Body) if err != nil { return err } + return makeError(resp, b) +} + +func makeError(resp *http.Response, body []byte) *Error { // https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors structuredError := &Error{} // This can fail if e.g. the response body is not valid JSON. That's fine, // we'll construct an appropriate error string from the body and status code. - _ = json.Unmarshal(b, structuredError) + _ = json.Unmarshal(body, structuredError) - structuredError.rawBody = string(b) + structuredError.rawBody = string(body) structuredError.StatusCode = resp.StatusCode structuredError.Request = resp.Request return structuredError } + +func retryError(resp *http.Response) error { + b, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + rerr := makeError(resp, b) + rerr.temporary = true + return rerr +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/retry.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/retry.go index e5621e305..093f55d02 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/retry.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/retry.go @@ -100,7 +100,7 @@ func (t *retryTransport) RoundTrip(in *http.Request) (out *http.Response, err er if out != nil { for _, code := range t.codes { if out.StatusCode == code { - return CheckError(out) + return retryError(out) } } } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go index 5dbaa7c23..f4369e2a0 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go @@ -25,17 +25,17 @@ import ( "net/url" "sort" "strings" + "sync" "github.com/google/go-containerregistry/internal/redact" "github.com/google/go-containerregistry/internal/retry" + "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/logs" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/google/go-containerregistry/pkg/v1/stream" "github.com/google/go-containerregistry/pkg/v1/types" - "golang.org/x/sync/errgroup" ) // Taggable is an interface that enables a manifest PUT (e.g. for tagging). @@ -45,146 +45,101 @@ type Taggable interface { // Write pushes the provided img to the specified image reference. func Write(ref name.Reference, img v1.Image, options ...Option) (rerr error) { - o, err := makeOptions(ref.Context(), options...) + o, err := makeOptions(options...) if err != nil { return err } + if o.progress != nil { + defer func() { o.progress.Close(rerr) }() + } + return newPusher(o).Push(o.context, ref, img) +} + +// writer writes the elements of an image to a remote image reference. +type writer struct { + repo name.Repository + auth authn.Authenticator + transport http.RoundTripper + + client *http.Client - var p *progress - if o.updates != nil { - p = &progress{updates: o.updates} - p.lastUpdate = &v1.Update{} - p.lastUpdate.Total, err = countImage(img, o.allowNondistributableArtifacts) + progress *progress + backoff Backoff + predicate retry.Predicate + + scopeLock sync.Mutex + // Keep track of scopes that we have already requested. + scopeSet map[string]struct{} + scopes []string +} + +func makeWriter(ctx context.Context, repo name.Repository, ls []v1.Layer, o *options) (*writer, error) { + auth := o.auth + if o.keychain != nil { + kauth, err := o.keychain.Resolve(repo) if err != nil { - return err + return nil, err } - defer close(o.updates) - defer func() { _ = p.err(rerr) }() + auth = kauth } - return writeImage(o.context, ref, img, o, p) -} - -func writeImage(ctx context.Context, ref name.Reference, img v1.Image, o *options, progress *progress) error { - ls, err := img.Layers() + scopes := scopesForUploadingImage(repo, ls) + tr, err := transport.NewWithContext(ctx, repo.Registry, auth, o.transport, scopes) if err != nil { - return err + return nil, err } - scopes := scopesForUploadingImage(ref.Context(), ls) - tr, err := transport.NewWithContext(o.context, ref.Context().Registry, o.auth, o.transport, scopes) - if err != nil { - return err + + scopeSet := map[string]struct{}{} + for _, scope := range scopes { + scopeSet[scope] = struct{}{} } - w := writer{ - repo: ref.Context(), + return &writer{ + repo: repo, client: &http.Client{Transport: tr}, - progress: progress, + auth: auth, + transport: o.transport, + progress: o.progress, backoff: o.retryBackoff, predicate: o.retryPredicate, - } + scopes: scopes, + scopeSet: scopeSet, + }, nil +} - // Upload individual blobs and collect any errors. - blobChan := make(chan v1.Layer, 2*o.jobs) - g, gctx := errgroup.WithContext(ctx) - for i := 0; i < o.jobs; i++ { - // Start N workers consuming blobs to upload. - g.Go(func() error { - for b := range blobChan { - if err := w.uploadOne(gctx, b); err != nil { - return err - } - } - return nil - }) +// url returns a url.Url for the specified path in the context of this remote image reference. +func (w *writer) url(path string) url.URL { + return url.URL{ + Scheme: w.repo.Registry.Scheme(), + Host: w.repo.RegistryStr(), + Path: path, } +} - // Upload individual layers in goroutines and collect any errors. - // If we can dedupe by the layer digest, try to do so. If we can't determine - // the digest for whatever reason, we can't dedupe and might re-upload. - g.Go(func() error { - defer close(blobChan) - uploaded := map[v1.Hash]bool{} - for _, l := range ls { - l := l +func (w *writer) maybeUpdateScopes(ctx context.Context, ml *MountableLayer) error { + if ml.Reference.Context().String() == w.repo.String() { + return nil + } + if ml.Reference.Context().Registry.String() != w.repo.Registry.String() { + return nil + } - // Handle foreign layers. - mt, err := l.MediaType() - if err != nil { - return err - } - if !mt.IsDistributable() && !o.allowNondistributableArtifacts { - continue - } + scope := ml.Reference.Scope(transport.PullScope) - // Streaming layers calculate their digests while uploading them. Assume - // an error here indicates we need to upload the layer. - h, err := l.Digest() - if err == nil { - // If we can determine the layer's digest ahead of - // time, use it to dedupe uploads. - if uploaded[h] { - continue // Already uploading. - } - uploaded[h] = true - } - select { - case blobChan <- l: - case <-gctx.Done(): - return gctx.Err() - } - } - return nil - }) + w.scopeLock.Lock() + defer w.scopeLock.Unlock() - if l, err := partial.ConfigLayer(img); err != nil { - // We can't read the ConfigLayer, possibly because of streaming layers, - // since the layer DiffIDs haven't been calculated yet. Attempt to wait - // for the other layers to be uploaded, then try the config again. - if err := g.Wait(); err != nil { - return err - } + if _, ok := w.scopeSet[scope]; !ok { + w.scopeSet[scope] = struct{}{} + w.scopes = append(w.scopes, scope) - // Now that all the layers are uploaded, try to upload the config file blob. - l, err := partial.ConfigLayer(img) + logs.Debug.Printf("Refreshing token to add scope %q", scope) + wt, err := transport.NewWithContext(ctx, w.repo.Registry, w.auth, w.transport, w.scopes) if err != nil { return err } - if err := w.uploadOne(ctx, l); err != nil { - return err - } - } else { - // We *can* read the ConfigLayer, so upload it concurrently with the layers. - g.Go(func() error { - return w.uploadOne(gctx, l) - }) - - // Wait for the layers + config. - if err := g.Wait(); err != nil { - return err - } + w.client = &http.Client{Transport: wt} } - // With all of the constituent elements uploaded, upload the manifest - // to commit the image. - return w.commitManifest(ctx, img, ref) -} - -// writer writes the elements of an image to a remote image reference. -type writer struct { - repo name.Repository - client *http.Client - - progress *progress - backoff Backoff - predicate retry.Predicate -} - -// url returns a url.Url for the specified path in the context of this remote image reference. -func (w *writer) url(path string) url.URL { - return url.URL{ - Scheme: w.repo.Registry.Scheme(), - Host: w.repo.RegistryStr(), - Path: path, - } + return nil } // nextLocation extracts the fully-qualified URL to which we should send the next request in an upload sequence. @@ -228,30 +183,6 @@ func (w *writer) checkExistingBlob(ctx context.Context, h v1.Hash) (bool, error) return resp.StatusCode == http.StatusOK, nil } -// checkExistingManifest checks if a manifest exists already in the repository -// by making a HEAD request to the manifest API. -func (w *writer) checkExistingManifest(ctx context.Context, h v1.Hash, mt types.MediaType) (bool, error) { - u := w.url(fmt.Sprintf("/v2/%s/manifests/%s", w.repo.RepositoryStr(), h.String())) - - req, err := http.NewRequest(http.MethodHead, u.String(), nil) - if err != nil { - return false, err - } - req.Header.Set("Accept", string(mt)) - - resp, err := w.client.Do(req.WithContext(ctx)) - if err != nil { - return false, err - } - defer resp.Body.Close() - - if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound); err != nil { - return false, err - } - - return resp.StatusCode == http.StatusOK, nil -} - // initiateUpload initiates the blob upload, which starts with a POST that can // optionally include the hash of the layer and a list of repositories from // which that layer might be read. On failure, an error is returned. @@ -279,6 +210,11 @@ func (w *writer) initiateUpload(ctx context.Context, from, mount, origin string) req.Header.Set("Content-Type", "application/json") resp, err := w.client.Do(req.WithContext(ctx)) if err != nil { + if origin != "" && origin != w.repo.RegistryStr() { + // https://github.com/google/go-containerregistry/issues/1679 + logs.Warn.Printf("retrying without mount: %v", err) + return w.initiateUpload(ctx, "", "", "") + } return "", false, err } defer resp.Body.Close() @@ -421,6 +357,9 @@ func (w *writer) uploadOne(ctx context.Context, l v1.Layer) error { mount = h.String() } if ml, ok := l.(*MountableLayer); ok { + if err := w.maybeUpdateScopes(ctx, ml); err != nil { + return err + } from = ml.Reference.Context().RepositoryStr() origin = ml.Reference.Context().RegistryStr() } @@ -474,69 +413,6 @@ func (w *writer) uploadOne(ctx context.Context, l v1.Layer) error { return retry.Retry(tryUpload, w.predicate, w.backoff) } -type withLayer interface { - Layer(v1.Hash) (v1.Layer, error) -} - -func (w *writer) writeIndex(ctx context.Context, ref name.Reference, ii v1.ImageIndex, options ...Option) error { - index, err := ii.IndexManifest() - if err != nil { - return err - } - - o, err := makeOptions(ref.Context(), options...) - if err != nil { - return err - } - - // TODO(#803): Pipe through remote.WithJobs and upload these in parallel. - for _, desc := range index.Manifests { - ref := ref.Context().Digest(desc.Digest.String()) - exists, err := w.checkExistingManifest(ctx, desc.Digest, desc.MediaType) - if err != nil { - return err - } - if exists { - logs.Progress.Print("existing manifest: ", desc.Digest) - continue - } - - switch desc.MediaType { - case types.OCIImageIndex, types.DockerManifestList: - ii, err := ii.ImageIndex(desc.Digest) - if err != nil { - return err - } - if err := w.writeIndex(ctx, ref, ii, options...); err != nil { - return err - } - case types.OCIManifestSchema1, types.DockerManifestSchema2: - img, err := ii.Image(desc.Digest) - if err != nil { - return err - } - if err := writeImage(ctx, ref, img, o, w.progress); err != nil { - return err - } - default: - // Workaround for #819. - if wl, ok := ii.(withLayer); ok { - layer, err := wl.Layer(desc.Digest) - if err != nil { - return err - } - if err := w.uploadOne(ctx, layer); err != nil { - return err - } - } - } - } - - // With all of the constituent elements uploaded, upload the manifest - // to commit the image. - return w.commitManifest(ctx, ii, ref) -} - type withMediaType interface { MediaType() (types.MediaType, error) } @@ -655,10 +531,7 @@ func (w *writer) commitSubjectReferrers(ctx context.Context, sub name.Digest, ad return im.Manifests[i].Digest.String() < im.Manifests[j].Digest.String() }) logs.Progress.Printf("updating fallback tag %s with new referrer", t.Identifier()) - if err := w.commitManifest(ctx, fallbackTaggable{im}, t); err != nil { - return err - } - return nil + return w.commitManifest(ctx, fallbackTaggable{im}, t) } type fallbackTaggable struct { @@ -770,183 +643,26 @@ func scopesForUploadingImage(repo name.Repository, layers []v1.Layer) []string { // WriteIndex will attempt to push all of the referenced manifests before // attempting to push the ImageIndex, to retain referential integrity. func WriteIndex(ref name.Reference, ii v1.ImageIndex, options ...Option) (rerr error) { - o, err := makeOptions(ref.Context(), options...) + o, err := makeOptions(options...) if err != nil { return err } - - scopes := []string{ref.Scope(transport.PushScope)} - tr, err := transport.NewWithContext(o.context, ref.Context().Registry, o.auth, o.transport, scopes) - if err != nil { - return err - } - w := writer{ - repo: ref.Context(), - client: &http.Client{Transport: tr}, - backoff: o.retryBackoff, - predicate: o.retryPredicate, - } - - if o.updates != nil { - w.progress = &progress{updates: o.updates} - w.progress.lastUpdate = &v1.Update{} - - defer close(o.updates) - defer func() { w.progress.err(rerr) }() - - w.progress.lastUpdate.Total, err = countIndex(ii, o.allowNondistributableArtifacts) - if err != nil { - return err - } + if o.progress != nil { + defer func() { o.progress.Close(rerr) }() } - - return w.writeIndex(o.context, ref, ii, options...) -} - -// countImage counts the total size of all layers + config blob + manifest for -// an image. It de-dupes duplicate layers. -func countImage(img v1.Image, allowNondistributableArtifacts bool) (int64, error) { - var total int64 - ls, err := img.Layers() - if err != nil { - return 0, err - } - seen := map[v1.Hash]bool{} - for _, l := range ls { - // Handle foreign layers. - mt, err := l.MediaType() - if err != nil { - return 0, err - } - if !mt.IsDistributable() && !allowNondistributableArtifacts { - continue - } - - // TODO: support streaming layers which update the total count as they write. - if _, ok := l.(*stream.Layer); ok { - return 0, errors.New("cannot use stream.Layer and WithProgress") - } - - // Dedupe layers. - d, err := l.Digest() - if err != nil { - return 0, err - } - if seen[d] { - continue - } - seen[d] = true - - size, err := l.Size() - if err != nil { - return 0, err - } - total += size - } - b, err := img.RawConfigFile() - if err != nil { - return 0, err - } - total += int64(len(b)) - size, err := img.Size() - if err != nil { - return 0, err - } - total += size - return total, nil -} - -// countIndex counts the total size of all images + sub-indexes for an index. -// It does not attempt to de-dupe duplicate images, etc. -func countIndex(idx v1.ImageIndex, allowNondistributableArtifacts bool) (int64, error) { - var total int64 - mf, err := idx.IndexManifest() - if err != nil { - return 0, err - } - - for _, desc := range mf.Manifests { - switch desc.MediaType { - case types.OCIImageIndex, types.DockerManifestList: - sidx, err := idx.ImageIndex(desc.Digest) - if err != nil { - return 0, err - } - size, err := countIndex(sidx, allowNondistributableArtifacts) - if err != nil { - return 0, err - } - total += size - case types.OCIManifestSchema1, types.DockerManifestSchema2: - simg, err := idx.Image(desc.Digest) - if err != nil { - return 0, err - } - size, err := countImage(simg, allowNondistributableArtifacts) - if err != nil { - return 0, err - } - total += size - default: - // Workaround for #819. - if wl, ok := idx.(withLayer); ok { - layer, err := wl.Layer(desc.Digest) - if err != nil { - return 0, err - } - size, err := layer.Size() - if err != nil { - return 0, err - } - total += size - } - } - } - - size, err := idx.Size() - if err != nil { - return 0, err - } - total += size - return total, nil + return newPusher(o).Push(o.context, ref, ii) } // WriteLayer uploads the provided Layer to the specified repo. func WriteLayer(repo name.Repository, layer v1.Layer, options ...Option) (rerr error) { - o, err := makeOptions(repo, options...) - if err != nil { - return err - } - scopes := scopesForUploadingImage(repo, []v1.Layer{layer}) - tr, err := transport.NewWithContext(o.context, repo.Registry, o.auth, o.transport, scopes) + o, err := makeOptions(options...) if err != nil { return err } - w := writer{ - repo: repo, - client: &http.Client{Transport: tr}, - backoff: o.retryBackoff, - predicate: o.retryPredicate, - } - - if o.updates != nil { - w.progress = &progress{updates: o.updates} - w.progress.lastUpdate = &v1.Update{} - - defer close(o.updates) - defer func() { w.progress.err(rerr) }() - - // TODO: support streaming layers which update the total count as they write. - if _, ok := layer.(*stream.Layer); ok { - return errors.New("cannot use stream.Layer and WithProgress") - } - size, err := layer.Size() - if err != nil { - return err - } - w.progress.total(size) + if o.progress != nil { + defer func() { o.progress.Close(rerr) }() } - return w.uploadOne(o.context, layer) + return newPusher(o).Upload(o.context, repo, layer) } // Tag adds a tag to the given Taggable via PUT /v2/.../manifests/ @@ -976,28 +692,9 @@ func Tag(tag name.Tag, t Taggable, options ...Option) error { // should ensure that all blobs or manifests that are referenced by t exist // in the target registry. func Put(ref name.Reference, t Taggable, options ...Option) error { - o, err := makeOptions(ref.Context(), options...) - if err != nil { - return err - } - scopes := []string{ref.Scope(transport.PushScope)} - - // TODO: This *always* does a token exchange. For some registries, - // that's pretty slow. Some ideas; - // * Tag could take a list of tags. - // * Allow callers to pass in a transport.Transport, typecheck - // it to allow them to reuse the transport across multiple calls. - // * WithTag option to do multiple manifest PUTs in commitManifest. - tr, err := transport.NewWithContext(o.context, ref.Context().Registry, o.auth, o.transport, scopes) + o, err := makeOptions(options...) if err != nil { return err } - w := writer{ - repo: ref.Context(), - client: &http.Client{Transport: tr}, - backoff: o.retryBackoff, - predicate: o.retryPredicate, - } - - return w.commitManifest(o.context, t, ref) + return newPusher(o).Push(o.context, ref, t) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go b/vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go index d6f2df8f0..2b0354479 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go @@ -130,6 +130,8 @@ func (l *Layer) Uncompressed() (io.ReadCloser, error) { // Compressed implements v1.Layer. func (l *Layer) Compressed() (io.ReadCloser, error) { + l.mu.Lock() + defer l.mu.Unlock() if l.consumed { return nil, ErrConsumed } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go index 1f977e16a..c984f3c8f 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go @@ -223,9 +223,9 @@ func extractFileFromTar(opener Opener, filePath string) (io.ReadCloser, error) { if err != nil { return nil, err } - close := true + needClose := true defer func() { - if close { + if needClose { f.Close() } }() @@ -244,7 +244,7 @@ func extractFileFromTar(opener Opener, filePath string) (io.ReadCloser, error) { currentDir := filepath.Dir(filePath) return extractFileFromTar(opener, path.Join(currentDir, path.Clean(hdr.Linkname))) } - close = false + needClose = false return tarFile{ Reader: tf, Closer: f, diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/layer.go b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/layer.go index a344e9206..8a2630961 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/layer.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/layer.go @@ -160,6 +160,8 @@ func WithCompressedCaching(l *layer) { // WithEstargzOptions is a functional option that allow the caller to pass // through estargz.Options to the underlying compression layer. This is // only meaningful when estargz is enabled. +// +// Deprecated: WithEstargz is deprecated, and will be removed in a future release. func WithEstargzOptions(opts ...estargz.Option) LayerOption { return func(l *layer) { l.estgzopts = opts @@ -167,6 +169,8 @@ func WithEstargzOptions(opts ...estargz.Option) LayerOption { } // WithEstargz is a functional option that explicitly enables estargz support. +// +// Deprecated: WithEstargz is deprecated, and will be removed in a future release. func WithEstargz(l *layer) { oguncompressed := l.uncompressedopener estargz := func() (io.ReadCloser, error) { @@ -238,6 +242,7 @@ func LayerFromOpener(opener Opener, opts ...LayerOption) (v1.Layer, error) { } if estgz := os.Getenv("GGCR_EXPERIMENT_ESTARGZ"); estgz == "1" { + logs.Warn.Println("GGCR_EXPERIMENT_ESTARGZ is deprecated, and will be removed in a future release.") opts = append([]LayerOption{WithEstargz}, opts...) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/types/types.go b/vendor/github.com/google/go-containerregistry/pkg/v1/types/types.go index efc6bd6b9..c86657d7b 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/types/types.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/types/types.go @@ -80,3 +80,19 @@ func (m MediaType) IsConfig() bool { } return false } + +func (m MediaType) IsSchema1() bool { + switch m { + case DockerManifestSchema1, DockerManifestSchema1Signed: + return true + } + return false +} + +func (m MediaType) IsLayer() bool { + switch m { + case DockerLayer, DockerUncompressedLayer, OCILayer, OCILayerZStd, OCIUncompressedLayer, DockerForeignLayer, OCIRestrictedLayer, OCIUncompressedRestrictedLayer: + return true + } + return false +} diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 958666ed8..efab55e65 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -16,6 +16,30 @@ This package provides various compression algorithms. # changelog +* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4) + * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784 + * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792 + * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785 + * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795 + * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779 + * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780 + * gzhttp: Suppport ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799 + +* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1) + * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776 + * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767 + * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766 + * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773 + * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774 + +* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0) + * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685 + * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752 + * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755 + * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748 + * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747 + * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746 + * Jan 21st, 2023 (v1.15.15) * deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739 * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728 @@ -600,6 +624,8 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv * [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression. * [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression. * [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer. +* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression. +* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression. # license diff --git a/vendor/github.com/klauspost/compress/fse/decompress.go b/vendor/github.com/klauspost/compress/fse/decompress.go index 926f5f153..cc05d0f7e 100644 --- a/vendor/github.com/klauspost/compress/fse/decompress.go +++ b/vendor/github.com/klauspost/compress/fse/decompress.go @@ -260,7 +260,9 @@ func (s *Scratch) buildDtable() error { // If the buffer is over-read an error is returned. func (s *Scratch) decompress() error { br := &s.bits - br.init(s.br.unread()) + if err := br.init(s.br.unread()); err != nil { + return err + } var s1, s2 decoder // Initialize and decode first state and symbol. diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go index ec71f7a34..aed2347ce 100644 --- a/vendor/github.com/klauspost/compress/huff0/bitwriter.go +++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go @@ -60,6 +60,22 @@ func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) { b.nBits += encA.nBits + encB.nBits } +// encFourSymbols adds up to 32 bits from four symbols. +// It will not check if there is space for them, +// so the caller must ensure that b has been flushed recently. +func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) { + bitsA := encA.nBits + bitsB := bitsA + encB.nBits + bitsC := bitsB + encC.nBits + bitsD := bitsC + encD.nBits + combined := uint64(encA.val) | + (uint64(encB.val) << (bitsA & 63)) | + (uint64(encC.val) << (bitsB & 63)) | + (uint64(encD.val) << (bitsC & 63)) + b.bitContainer |= combined << (b.nBits & 63) + b.nBits += bitsD +} + // flush32 will flush out, so there are at least 32 bits available for writing. func (b *bitWriter) flush32() { if b.nBits < 32 { diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go index cdc94856f..4ee4fa18d 100644 --- a/vendor/github.com/klauspost/compress/huff0/compress.go +++ b/vendor/github.com/klauspost/compress/huff0/compress.go @@ -248,8 +248,7 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) { tmp := src[n : n+4] // tmp should be len 4 bw.flush32() - bw.encTwoSymbols(cTable, tmp[3], tmp[2]) - bw.encTwoSymbols(cTable, tmp[1], tmp[0]) + bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]]) } } else { for ; n >= 0; n -= 4 { diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 2445bb4fe..5f272d87f 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -9,6 +9,7 @@ import ( "encoding/binary" "errors" "fmt" + "hash/crc32" "io" "os" "path/filepath" @@ -442,6 +443,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err } } var err error + if debugDecoder { + println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals)) + } huff, literals, err = huff0.ReadTable(literals, huff) if err != nil { println("reading huffman table:", err) diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go index 12e8f6f0b..fd4a36f73 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockenc.go +++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go @@ -473,7 +473,7 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { return b.encodeLits(b.literals, rawAllLits) } // We want some difference to at least account for the headers. - saved := b.size - len(b.literals) - (b.size >> 5) + saved := b.size - len(b.literals) - (b.size >> 6) if saved < 16 { if org == nil { return errIncompressible @@ -779,10 +779,13 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { } b.output = wr.out + // Maybe even add a bigger margin. if len(b.output)-3-bhOffset >= b.size { - // Maybe even add a bigger margin. + // Discard and encode as raw block. + b.output = b.encodeRawTo(b.output[:bhOffset], org) + b.popOffsets() b.litEnc.Reuse = huff0.ReusePolicyNone - return errIncompressible + return nil } // Size is output minus block header. diff --git a/vendor/github.com/klauspost/compress/zstd/bytebuf.go b/vendor/github.com/klauspost/compress/zstd/bytebuf.go index 176788f25..55a388553 100644 --- a/vendor/github.com/klauspost/compress/zstd/bytebuf.go +++ b/vendor/github.com/klauspost/compress/zstd/bytebuf.go @@ -54,7 +54,7 @@ func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) { func (b *byteBuf) readByte() (byte, error) { bb := *b if len(bb) < 1 { - return 0, nil + return 0, io.ErrUnexpectedEOF } r := bb[0] *b = bb[1:] @@ -109,7 +109,7 @@ func (r *readerWrapper) readBig(n int, dst []byte) ([]byte, error) { } func (r *readerWrapper) readByte() (byte, error) { - n2, err := r.r.Read(r.tmp[:1]) + n2, err := io.ReadFull(r.r, r.tmp[:1]) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index 7113e69ee..f04aaa21e 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -455,12 +455,7 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) { } if len(next.b) > 0 { - n, err := d.current.crc.Write(next.b) - if err == nil { - if n != len(next.b) { - d.current.err = io.ErrShortWrite - } - } + d.current.crc.Write(next.b) } if next.err == nil && next.d != nil && next.d.hasCRC { got := uint32(d.current.crc.Sum64()) diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go index 830f5ba74..9819d4145 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_best.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go @@ -32,10 +32,9 @@ type match struct { length int32 rep int32 est int32 - _ [12]byte // Aligned size to cache line: 4+4+4+4+4 bytes + 12 bytes padding = 32 bytes } -const highScore = 25000 +const highScore = maxMatchLen * 8 // estBits will estimate output bits from predefined tables. func (m *match) estBits(bitsPerByte int32) { @@ -160,7 +159,6 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) { // nextEmit is where in src the next emitLiteral should start from. nextEmit := s - cv := load6432(src, s) // Relative offsets offset1 := int32(blk.recentOffsets[0]) @@ -174,7 +172,6 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) { blk.literals = append(blk.literals, src[nextEmit:until]...) s.litLen = uint32(until - nextEmit) } - _ = addLiterals if debugEncoder { println("recent offsets:", blk.recentOffsets) @@ -189,53 +186,96 @@ encodeLoop: panic("offset0 was 0") } - bestOf := func(a, b *match) *match { - if a.est-b.est+(a.s-b.s)*bitsPerByte>>10 < 0 { - return a - } - return b - } - const goodEnough = 100 + const goodEnough = 250 + + cv := load6432(src, s) nextHashL := hashLen(cv, bestLongTableBits, bestLongLen) nextHashS := hashLen(cv, bestShortTableBits, bestShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] - matchAt := func(offset int32, s int32, first uint32, rep int32) match { + // Set m to a match at offset if it looks like that will improve compression. + improve := func(m *match, offset int32, s int32, first uint32, rep int32) { if s-offset >= e.maxMatchOff || load3232(src, offset) != first { - return match{s: s, est: highScore} + return } if debugAsserts { + if offset <= 0 { + panic(offset) + } if !bytes.Equal(src[s:s+4], src[offset:offset+4]) { panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) } } - m := match{offset: offset, s: s, length: 4 + e.matchlen(s+4, offset+4, src), rep: rep} - m.estBits(bitsPerByte) - return m + // Try to quick reject if we already have a long match. + if m.length > 16 { + left := len(src) - int(m.s+m.length) + // If we are too close to the end, keep as is. + if left <= 0 { + return + } + checkLen := m.length - (s - m.s) - 8 + if left > 2 && checkLen > 4 { + // Check 4 bytes, 4 bytes from the end of the current match. + a := load3232(src, offset+checkLen) + b := load3232(src, s+checkLen) + if a != b { + return + } + } + } + l := 4 + e.matchlen(s+4, offset+4, src) + if rep < 0 { + // Extend candidate match backwards as far as possible. + tMin := s - e.maxMatchOff + if tMin < 0 { + tMin = 0 + } + for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength { + s-- + offset-- + l++ + } + } + + cand := match{offset: offset, s: s, length: l, rep: rep} + cand.estBits(bitsPerByte) + if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 { + *m = cand + } } - m1 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1) - m2 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1) - m3 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1) - m4 := matchAt(candidateS.prev-e.cur, s, uint32(cv), -1) - best := bestOf(bestOf(&m1, &m2), bestOf(&m3, &m4)) + best := match{s: s, est: highScore} + improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1) + improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1) + improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1) + improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1) if canRepeat && best.length < goodEnough { - cv32 := uint32(cv >> 8) - spp := s + 1 - m1 := matchAt(spp-offset1, spp, cv32, 1) - m2 := matchAt(spp-offset2, spp, cv32, 2) - m3 := matchAt(spp-offset3, spp, cv32, 3) - best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3)) - if best.length > 0 { - cv32 = uint32(cv >> 24) - spp += 2 - m1 := matchAt(spp-offset1, spp, cv32, 1) - m2 := matchAt(spp-offset2, spp, cv32, 2) - m3 := matchAt(spp-offset3, spp, cv32, 3) - best = bestOf(bestOf(best, &m1), bestOf(&m2, &m3)) + if s == nextEmit { + // Check repeats straight after a match. + improve(&best, s-offset2, s, uint32(cv), 1|4) + improve(&best, s-offset3, s, uint32(cv), 2|4) + if offset1 > 1 { + improve(&best, s-(offset1-1), s, uint32(cv), 3|4) + } + } + + // If either no match or a non-repeat match, check at + 1 + if best.rep <= 0 { + cv32 := uint32(cv >> 8) + spp := s + 1 + improve(&best, spp-offset1, spp, cv32, 1) + improve(&best, spp-offset2, spp, cv32, 2) + improve(&best, spp-offset3, spp, cv32, 3) + if best.rep < 0 { + cv32 = uint32(cv >> 24) + spp += 2 + improve(&best, spp-offset1, spp, cv32, 1) + improve(&best, spp-offset2, spp, cv32, 2) + improve(&best, spp-offset3, spp, cv32, 3) + } } } // Load next and check... @@ -250,47 +290,45 @@ encodeLoop: if s >= sLimit { break encodeLoop } - cv = load6432(src, s) continue } - s++ candidateS = e.table[hashLen(cv>>8, bestShortTableBits, bestShortLen)] - cv = load6432(src, s) - cv2 := load6432(src, s+1) + cv = load6432(src, s+1) + cv2 := load6432(src, s+2) candidateL = e.longTable[hashLen(cv, bestLongTableBits, bestLongLen)] candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)] // Short at s+1 - m1 := matchAt(candidateS.offset-e.cur, s, uint32(cv), -1) + improve(&best, candidateS.offset-e.cur, s+1, uint32(cv), -1) // Long at s+1, s+2 - m2 := matchAt(candidateL.offset-e.cur, s, uint32(cv), -1) - m3 := matchAt(candidateL.prev-e.cur, s, uint32(cv), -1) - m4 := matchAt(candidateL2.offset-e.cur, s+1, uint32(cv2), -1) - m5 := matchAt(candidateL2.prev-e.cur, s+1, uint32(cv2), -1) - best = bestOf(bestOf(bestOf(best, &m1), &m2), bestOf(bestOf(&m3, &m4), &m5)) + improve(&best, candidateL.offset-e.cur, s+1, uint32(cv), -1) + improve(&best, candidateL.prev-e.cur, s+1, uint32(cv), -1) + improve(&best, candidateL2.offset-e.cur, s+2, uint32(cv2), -1) + improve(&best, candidateL2.prev-e.cur, s+2, uint32(cv2), -1) if false { // Short at s+3. // Too often worse... - m := matchAt(e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+2, uint32(cv2>>8), -1) - best = bestOf(best, &m) + improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+3, uint32(cv2>>8), -1) } - // See if we can find a better match by checking where the current best ends. - // Use that offset to see if we can find a better full match. - if sAt := best.s + best.length; sAt < sLimit { - nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen) - candidateEnd := e.longTable[nextHashL] - // Start check at a fixed offset to allow for a few mismatches. - // For this compression level 2 yields the best results. - const skipBeginning = 2 - if pos := candidateEnd.offset - e.cur - best.length + skipBeginning; pos >= 0 { - m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) - bestEnd := bestOf(best, &m) - if pos := candidateEnd.prev - e.cur - best.length + skipBeginning; pos >= 0 { - m := matchAt(pos, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) - bestEnd = bestOf(bestEnd, &m) + + // Start check at a fixed offset to allow for a few mismatches. + // For this compression level 2 yields the best results. + // We cannot do this if we have already indexed this position. + const skipBeginning = 2 + if best.s > s-skipBeginning { + // See if we can find a better match by checking where the current best ends. + // Use that offset to see if we can find a better full match. + if sAt := best.s + best.length; sAt < sLimit { + nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen) + candidateEnd := e.longTable[nextHashL] + + if off := candidateEnd.offset - e.cur - best.length + skipBeginning; off >= 0 { + improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) + if off := candidateEnd.prev - e.cur - best.length + skipBeginning; off >= 0 { + improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) + } } - best = bestEnd } } } @@ -303,51 +341,34 @@ encodeLoop: // We have a match, we can store the forward value if best.rep > 0 { - s = best.s var seq seq seq.matchLen = uint32(best.length - zstdMinMatch) - - // We might be able to match backwards. - // Extend as long as we can. - start := best.s - // We end the search early, so we don't risk 0 literals - // and have to do special offset treatment. - startLimit := nextEmit + 1 - - tMin := s - e.maxMatchOff - if tMin < 0 { - tMin = 0 - } - repIndex := best.offset - for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { - repIndex-- - start-- - seq.matchLen++ + if debugAsserts && s <= nextEmit { + panic("s <= nextEmit") } - addLiterals(&seq, start) + addLiterals(&seq, best.s) - // rep 0 - seq.offset = uint32(best.rep) + // Repeat. If bit 4 is set, this is a non-lit repeat. + seq.offset = uint32(best.rep & 3) if debugSequences { println("repeat sequence", seq, "next s:", s) } blk.sequences = append(blk.sequences, seq) - // Index match start+1 (long) -> s - 1 - index0 := s + // Index old s + 1 -> s - 1 + index0 := s + 1 s = best.s + best.length nextEmit = s if s >= sLimit { if debugEncoder { println("repeat ended", s, best.length) - } break encodeLoop } // Index skipped... off := index0 + e.cur - for index0 < s-1 { + for index0 < s { cv0 := load6432(src, index0) h0 := hashLen(cv0, bestLongTableBits, bestLongLen) h1 := hashLen(cv0, bestShortTableBits, bestShortLen) @@ -357,17 +378,19 @@ encodeLoop: index0++ } switch best.rep { - case 2: + case 2, 4 | 1: offset1, offset2 = offset2, offset1 - case 3: + case 3, 4 | 2: offset1, offset2, offset3 = offset3, offset1, offset2 + case 4 | 3: + offset1, offset2, offset3 = offset1-1, offset1, offset2 } - cv = load6432(src, s) continue } // A 4-byte match has been found. Update recent offsets. // We'll later see if more than 4 bytes. + index0 := s + 1 s = best.s t := best.offset offset1, offset2, offset3 = s-t, offset1, offset2 @@ -380,22 +403,9 @@ encodeLoop: panic("invalid offset") } - // Extend the n-byte match as long as possible. - l := best.length - - // Extend backwards - tMin := s - e.maxMatchOff - if tMin < 0 { - tMin = 0 - } - for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { - s-- - t-- - l++ - } - // Write our sequence var seq seq + l := best.length seq.litLen = uint32(s - nextEmit) seq.matchLen = uint32(l - zstdMinMatch) if seq.litLen > 0 { @@ -412,10 +422,8 @@ encodeLoop: break encodeLoop } - // Index match start+1 (long) -> s - 1 - index0 := s - l + 1 - // every entry - for index0 < s-1 { + // Index old s + 1 -> s - 1 + for index0 < s { cv0 := load6432(src, index0) h0 := hashLen(cv0, bestLongTableBits, bestLongLen) h1 := hashLen(cv0, bestShortTableBits, bestShortLen) @@ -424,50 +432,6 @@ encodeLoop: e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset} index0++ } - - cv = load6432(src, s) - if !canRepeat { - continue - } - - // Check offset 2 - for { - o2 := s - offset2 - if load3232(src, o2) != uint32(cv) { - // Do regular search - break - } - - // Store this, since we have it. - nextHashS := hashLen(cv, bestShortTableBits, bestShortLen) - nextHashL := hashLen(cv, bestLongTableBits, bestLongLen) - - // We have at least 4 byte match. - // No need to check backwards. We come straight from a match - l := 4 + e.matchlen(s+4, o2+4, src) - - e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset} - e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: e.table[nextHashS].offset} - seq.matchLen = uint32(l) - zstdMinMatch - seq.litLen = 0 - - // Since litlen is always 0, this is offset 1. - seq.offset = 1 - s += l - nextEmit = s - if debugSequences { - println("sequence", seq, "next s:", s) - } - blk.sequences = append(blk.sequences, seq) - - // Swap offset 1 and 2. - offset1, offset2 = offset2, offset1 - if s >= sLimit { - // Finished - break encodeLoop - } - cv = load6432(src, s) - } } if int(nextEmit) < len(src) { diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go index 65c6c36dc..4de0aed0d 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder.go @@ -277,23 +277,9 @@ func (e *Encoder) nextBlock(final bool) error { s.eofWritten = true } - err := errIncompressible - // If we got the exact same number of literals as input, - // assume the literals cannot be compressed. - if len(src) != len(blk.literals) || len(src) != e.o.blockSize { - err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) - } - switch err { - case errIncompressible: - if debugEncoder { - println("Storing incompressible block as raw") - } - blk.encodeRaw(src) - // In fast mode, we do not transfer offsets, so we don't have to deal with changing the. - case nil: - default: - s.err = err - return err + s.err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if s.err != nil { + return s.err } _, s.err = s.w.Write(blk.output) s.nWritten += int64(len(blk.output)) @@ -343,22 +329,8 @@ func (e *Encoder) nextBlock(final bool) error { } s.wWg.Done() }() - err := errIncompressible - // If we got the exact same number of literals as input, - // assume the literals cannot be compressed. - if len(src) != len(blk.literals) || len(src) != e.o.blockSize { - err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) - } - switch err { - case errIncompressible: - if debugEncoder { - println("Storing incompressible block as raw") - } - blk.encodeRaw(src) - // In fast mode, we do not transfer offsets, so we don't have to deal with changing the. - case nil: - default: - s.writeErr = err + s.writeErr = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if s.writeErr != nil { return } _, s.writeErr = s.w.Write(blk.output) @@ -568,25 +540,15 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte { // If we got the exact same number of literals as input, // assume the literals cannot be compressed. - err := errIncompressible oldout := blk.output - if len(blk.literals) != len(src) || len(src) != e.o.blockSize { - // Output directly to dst - blk.output = dst - err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) - } + // Output directly to dst + blk.output = dst - switch err { - case errIncompressible: - if debugEncoder { - println("Storing incompressible block as raw") - } - dst = blk.encodeRawTo(dst, src) - case nil: - dst = blk.output - default: + err := blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if err != nil { panic(err) } + dst = blk.output blk.output = oldout } else { enc.Reset(e.o.dict, false) @@ -605,25 +567,11 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte { if len(src) == 0 { blk.last = true } - err := errIncompressible - // If we got the exact same number of literals as input, - // assume the literals cannot be compressed. - if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize { - err = blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy) - } - - switch err { - case errIncompressible: - if debugEncoder { - println("Storing incompressible block as raw") - } - dst = blk.encodeRawTo(dst, todo) - blk.popOffsets() - case nil: - dst = append(dst, blk.output...) - default: + err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy) + if err != nil { panic(err) } + dst = append(dst, blk.output...) blk.reset(nil) } } diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go index 8e15be2f7..50f70533b 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go @@ -39,7 +39,7 @@ func (o *encoderOptions) setDefault() { blockSize: maxCompressedBlockSize, windowSize: 8 << 20, level: SpeedDefault, - allLitEntropy: true, + allLitEntropy: false, lowMem: false, } } @@ -238,7 +238,7 @@ func WithEncoderLevel(l EncoderLevel) EOption { } } if !o.customALEntropy { - o.allLitEntropy = l > SpeedFastest + o.allLitEntropy = l > SpeedDefault } return nil diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go index d8e8a05bd..cc0aa2274 100644 --- a/vendor/github.com/klauspost/compress/zstd/framedec.go +++ b/vendor/github.com/klauspost/compress/zstd/framedec.go @@ -293,13 +293,9 @@ func (d *frameDec) next(block *blockDec) error { return nil } -// checkCRC will check the checksum if the frame has one. +// checkCRC will check the checksum, assuming the frame has one. // Will return ErrCRCMismatch if crc check failed, otherwise nil. func (d *frameDec) checkCRC() error { - if !d.HasCheckSum { - return nil - } - // We can overwrite upper tmp now buf, err := d.rawInput.readSmall(4) if err != nil { @@ -307,10 +303,6 @@ func (d *frameDec) checkCRC() error { return err } - if d.o.ignoreChecksum { - return nil - } - want := binary.LittleEndian.Uint32(buf[:4]) got := uint32(d.crc.Sum64()) @@ -326,17 +318,13 @@ func (d *frameDec) checkCRC() error { return nil } -// consumeCRC reads the checksum data if the frame has one. +// consumeCRC skips over the checksum, assuming the frame has one. func (d *frameDec) consumeCRC() error { - if d.HasCheckSum { - _, err := d.rawInput.readSmall(4) - if err != nil { - println("CRC missing?", err) - return err - } + _, err := d.rawInput.readSmall(4) + if err != nil { + println("CRC missing?", err) } - - return nil + return err } // runDecoder will run the decoder for the remainder of the frame. @@ -415,15 +403,8 @@ func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) { if d.o.ignoreChecksum { err = d.consumeCRC() } else { - var n int - n, err = d.crc.Write(dst[crcStart:]) - if err == nil { - if n != len(dst)-crcStart { - err = io.ErrShortWrite - } else { - err = d.checkCRC() - } - } + d.crc.Write(dst[crcStart:]) + err = d.checkCRC() } } } diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go index f833d1541..9405fcf10 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go @@ -236,9 +236,12 @@ func (s *sequenceDecs) decodeSync(hist []byte) error { maxBlockSize = s.windowSize } + if debugDecoder { + println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream") + } for i := seqs - 1; i >= 0; i-- { if br.overread() { - printf("reading sequence %d, exceeded available data\n", seqs-i) + printf("reading sequence %d, exceeded available data. Overread by %d\n", seqs-i, -br.remain()) return io.ErrUnexpectedEOF } var ll, mo, ml int @@ -314,9 +317,6 @@ func (s *sequenceDecs) decodeSync(hist []byte) error { } size := ll + ml + len(out) if size-startSize > maxBlockSize { - if size-startSize == 424242 { - panic("here") - } return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) } if size > cap(out) { @@ -427,8 +427,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error { } } - // Check if space for literals - if size := len(s.literals) + len(s.out) - startSize; size > maxBlockSize { + if size := len(s.literals) + len(out) - startSize; size > maxBlockSize { return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) } diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go index 191384adf..8adabd828 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go @@ -5,6 +5,7 @@ package zstd import ( "fmt" + "io" "github.com/klauspost/compress/internal/cpuinfo" ) @@ -134,6 +135,9 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ctx.ll, ctx.litRemain+ctx.ll) + case errorOverread: + return true, io.ErrUnexpectedEOF + case errorNotEnoughSpace: size := ctx.outPosition + ctx.ll + ctx.ml if debugDecoder { @@ -148,7 +152,6 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { s.seqSize += ctx.litRemain if s.seqSize > maxBlockSize { return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) - } err := br.close() if err != nil { @@ -203,6 +206,9 @@ const errorNotEnoughLiterals = 4 // error reported when capacity of `out` is too small const errorNotEnoughSpace = 5 +// error reported when bits are overread. +const errorOverread = 6 + // sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm. // // Please refer to seqdec_generic.go for the reference implementation. @@ -248,6 +254,10 @@ func (s *sequenceDecs) decode(seqs []seqVals) error { litRemain: len(s.literals), } + if debugDecoder { + println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream") + } + s.seqSize = 0 lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56 var errCode int @@ -278,6 +288,8 @@ func (s *sequenceDecs) decode(seqs []seqVals) error { case errorNotEnoughLiterals: ll := ctx.seqs[i].ll return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll) + case errorOverread: + return io.ErrUnexpectedEOF } return fmt.Errorf("sequenceDecs_decode_amd64 returned erronous code %d", errCode) @@ -292,6 +304,9 @@ func (s *sequenceDecs) decode(seqs []seqVals) error { if s.seqSize > maxBlockSize { return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) } + if debugDecoder { + println("decode: ", br.remain(), "bits remain on stream. code:", errCode) + } err := br.close() if err != nil { printf("Closing sequences: %v, %+v\n", err, *br) diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index b94993a07..b6f4ba6fc 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -38,7 +38,7 @@ sequenceDecs_decode_amd64_main_loop: sequenceDecs_decode_amd64_fill_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decode_amd64_fill_end + JLE sequenceDecs_decode_amd64_fill_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decode_amd64_fill_end SHLQ $0x08, DX @@ -49,6 +49,10 @@ sequenceDecs_decode_amd64_fill_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decode_amd64_fill_byte_by_byte +sequenceDecs_decode_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decode_amd64_fill_end: // Update offset MOVQ R9, AX @@ -105,7 +109,7 @@ sequenceDecs_decode_amd64_ml_update_zero: sequenceDecs_decode_amd64_fill_2_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decode_amd64_fill_2_end + JLE sequenceDecs_decode_amd64_fill_2_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decode_amd64_fill_2_end SHLQ $0x08, DX @@ -116,6 +120,10 @@ sequenceDecs_decode_amd64_fill_2_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte +sequenceDecs_decode_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decode_amd64_fill_2_end: // Update literal length MOVQ DI, AX @@ -320,6 +328,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: CMOV TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32 @@ -356,7 +369,7 @@ sequenceDecs_decode_56_amd64_main_loop: sequenceDecs_decode_56_amd64_fill_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decode_56_amd64_fill_end + JLE sequenceDecs_decode_56_amd64_fill_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decode_56_amd64_fill_end SHLQ $0x08, DX @@ -367,6 +380,10 @@ sequenceDecs_decode_56_amd64_fill_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte +sequenceDecs_decode_56_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decode_56_amd64_fill_end: // Update offset MOVQ R9, AX @@ -613,6 +630,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: BMI, BMI2, CMOV TEXT ·sequenceDecs_decode_bmi2(SB), $8-32 @@ -649,7 +671,7 @@ sequenceDecs_decode_bmi2_main_loop: sequenceDecs_decode_bmi2_fill_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decode_bmi2_fill_end + JLE sequenceDecs_decode_bmi2_fill_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decode_bmi2_fill_end SHLQ $0x08, AX @@ -660,6 +682,10 @@ sequenceDecs_decode_bmi2_fill_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decode_bmi2_fill_byte_by_byte +sequenceDecs_decode_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decode_bmi2_fill_end: // Update offset MOVQ $0x00000808, CX @@ -700,7 +726,7 @@ sequenceDecs_decode_bmi2_fill_end: sequenceDecs_decode_bmi2_fill_2_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decode_bmi2_fill_2_end + JLE sequenceDecs_decode_bmi2_fill_2_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decode_bmi2_fill_2_end SHLQ $0x08, AX @@ -711,6 +737,10 @@ sequenceDecs_decode_bmi2_fill_2_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decode_bmi2_fill_2_byte_by_byte +sequenceDecs_decode_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decode_bmi2_fill_2_end: // Update literal length MOVQ $0x00000808, CX @@ -889,6 +919,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int // Requires: BMI, BMI2, CMOV TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32 @@ -925,7 +960,7 @@ sequenceDecs_decode_56_bmi2_main_loop: sequenceDecs_decode_56_bmi2_fill_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decode_56_bmi2_fill_end + JLE sequenceDecs_decode_56_bmi2_fill_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decode_56_bmi2_fill_end SHLQ $0x08, AX @@ -936,6 +971,10 @@ sequenceDecs_decode_56_bmi2_fill_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decode_56_bmi2_fill_byte_by_byte +sequenceDecs_decode_56_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decode_56_bmi2_fill_end: // Update offset MOVQ $0x00000808, CX @@ -1140,6 +1179,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool // Requires: SSE TEXT ·sequenceDecs_executeSimple_amd64(SB), $8-9 @@ -1804,7 +1848,7 @@ sequenceDecs_decodeSync_amd64_main_loop: sequenceDecs_decodeSync_amd64_fill_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decodeSync_amd64_fill_end + JLE sequenceDecs_decodeSync_amd64_fill_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decodeSync_amd64_fill_end SHLQ $0x08, DX @@ -1815,6 +1859,10 @@ sequenceDecs_decodeSync_amd64_fill_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte +sequenceDecs_decodeSync_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decodeSync_amd64_fill_end: // Update offset MOVQ R9, AX @@ -1871,7 +1919,7 @@ sequenceDecs_decodeSync_amd64_ml_update_zero: sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decodeSync_amd64_fill_2_end + JLE sequenceDecs_decodeSync_amd64_fill_2_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decodeSync_amd64_fill_2_end SHLQ $0x08, DX @@ -1882,6 +1930,10 @@ sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte +sequenceDecs_decodeSync_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decodeSync_amd64_fill_2_end: // Update literal length MOVQ DI, AX @@ -2291,6 +2343,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX @@ -2356,7 +2413,7 @@ sequenceDecs_decodeSync_bmi2_main_loop: sequenceDecs_decodeSync_bmi2_fill_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decodeSync_bmi2_fill_end + JLE sequenceDecs_decodeSync_bmi2_fill_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decodeSync_bmi2_fill_end SHLQ $0x08, AX @@ -2367,6 +2424,10 @@ sequenceDecs_decodeSync_bmi2_fill_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decodeSync_bmi2_fill_byte_by_byte +sequenceDecs_decodeSync_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decodeSync_bmi2_fill_end: // Update offset MOVQ $0x00000808, CX @@ -2407,7 +2468,7 @@ sequenceDecs_decodeSync_bmi2_fill_end: sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decodeSync_bmi2_fill_2_end + JLE sequenceDecs_decodeSync_bmi2_fill_2_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decodeSync_bmi2_fill_2_end SHLQ $0x08, AX @@ -2418,6 +2479,10 @@ sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte +sequenceDecs_decodeSync_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decodeSync_bmi2_fill_2_end: // Update literal length MOVQ $0x00000808, CX @@ -2801,6 +2866,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX @@ -2866,7 +2936,7 @@ sequenceDecs_decodeSync_safe_amd64_main_loop: sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decodeSync_safe_amd64_fill_end + JLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decodeSync_safe_amd64_fill_end SHLQ $0x08, DX @@ -2877,6 +2947,10 @@ sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte +sequenceDecs_decodeSync_safe_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decodeSync_safe_amd64_fill_end: // Update offset MOVQ R9, AX @@ -2933,7 +3007,7 @@ sequenceDecs_decodeSync_safe_amd64_ml_update_zero: sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte: CMPQ SI, $0x00 - JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end + JLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread CMPQ BX, $0x07 JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end SHLQ $0x08, DX @@ -2944,6 +3018,10 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte: ORQ AX, DX JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte +sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + sequenceDecs_decodeSync_safe_amd64_fill_2_end: // Update literal length MOVQ DI, AX @@ -3455,6 +3533,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX @@ -3520,7 +3603,7 @@ sequenceDecs_decodeSync_safe_bmi2_main_loop: sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decodeSync_safe_bmi2_fill_end + JLE sequenceDecs_decodeSync_safe_bmi2_fill_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decodeSync_safe_bmi2_fill_end SHLQ $0x08, AX @@ -3531,6 +3614,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte +sequenceDecs_decodeSync_safe_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decodeSync_safe_bmi2_fill_end: // Update offset MOVQ $0x00000808, CX @@ -3571,7 +3658,7 @@ sequenceDecs_decodeSync_safe_bmi2_fill_end: sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte: CMPQ BX, $0x00 - JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end + JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread CMPQ DX, $0x07 JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end SHLQ $0x08, AX @@ -3582,6 +3669,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte: ORQ CX, AX JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte +sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + sequenceDecs_decodeSync_safe_bmi2_fill_2_end: // Update literal length MOVQ $0x00000808, CX @@ -4067,6 +4158,11 @@ error_not_enough_literals: MOVQ $0x00000004, ret+24(FP) RET + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + // Return with not enough output space error error_not_enough_space: MOVQ ctx+16(FP), AX diff --git a/vendor/github.com/klauspost/compress/zstd/zstd.go b/vendor/github.com/klauspost/compress/zstd/zstd.go index 5ffa82f5a..89396673d 100644 --- a/vendor/github.com/klauspost/compress/zstd/zstd.go +++ b/vendor/github.com/klauspost/compress/zstd/zstd.go @@ -128,11 +128,11 @@ func matchLen(a, b []byte) (n int) { } func load3232(b []byte, i int32) uint32 { - return binary.LittleEndian.Uint32(b[i:]) + return binary.LittleEndian.Uint32(b[:len(b):len(b)][i:]) } func load6432(b []byte, i int32) uint64 { - return binary.LittleEndian.Uint64(b[i:]) + return binary.LittleEndian.Uint64(b[:len(b):len(b)][i:]) } type byter interface { diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go index 6f9e6fd3a..e62892046 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go @@ -65,7 +65,4 @@ const ( // AnnotationArtifactDescription is the annotation key for the human readable description for the artifact. AnnotationArtifactDescription = "org.opencontainers.artifact.description" - - // AnnotationReferrersFiltersApplied is the annotation key for the comma separated list of filters applied by the registry in the referrers listing. - AnnotationReferrersFiltersApplied = "org.opencontainers.referrers.filtersApplied" ) diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go deleted file mode 100644 index 03d76ce43..000000000 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 The Linux Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package v1 - -// Artifact describes an artifact manifest. -// This structure provides `application/vnd.oci.artifact.manifest.v1+json` mediatype when marshalled to JSON. -type Artifact struct { - // MediaType is the media type of the object this schema refers to. - MediaType string `json:"mediaType"` - - // ArtifactType is the IANA media type of the artifact this schema refers to. - ArtifactType string `json:"artifactType"` - - // Blobs is a collection of blobs referenced by this manifest. - Blobs []Descriptor `json:"blobs,omitempty"` - - // Subject (reference) is an optional link from the artifact to another manifest forming an association between the artifact and the other manifest. - Subject *Descriptor `json:"subject,omitempty"` - - // Annotations contains arbitrary metadata for the artifact manifest. - Annotations map[string]string `json:"annotations,omitempty"` -} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go index ffff4b6d1..36b0aeb8f 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go @@ -48,6 +48,17 @@ type ImageConfig struct { // StopSignal contains the system call signal that will be sent to the container to exit. StopSignal string `json:"StopSignal,omitempty"` + + // ArgsEscaped + // + // Deprecated: This field is present only for legacy compatibility with + // Docker and should not be used by new image builders. It is used by Docker + // for Windows images to indicate that the `Entrypoint` or `Cmd` or both, + // contains only a single element array, that is a pre-escaped, and combined + // into a single string `CommandLine`. If `true` the value in `Entrypoint` or + // `Cmd` should be used as-is to avoid double escaping. + // https://github.com/opencontainers/image-spec/pull/892 + ArgsEscaped bool `json:"ArgsEscaped,omitempty"` } // RootFS describes a layer content addresses @@ -86,22 +97,8 @@ type Image struct { // Author defines the name and/or email address of the person or entity which created and is responsible for maintaining the image. Author string `json:"author,omitempty"` - // Architecture is the CPU architecture which the binaries in this image are built to run on. - Architecture string `json:"architecture"` - - // Variant is the variant of the specified CPU architecture which image binaries are intended to run on. - Variant string `json:"variant,omitempty"` - - // OS is the name of the operating system which the image is built to run on. - OS string `json:"os"` - - // OSVersion is an optional field specifying the operating system - // version, for example on Windows `10.0.14393.1066`. - OSVersion string `json:"os.version,omitempty"` - - // OSFeatures is an optional field specifying an array of strings, - // each listing a required OS feature (for example on Windows `win32k`). - OSFeatures []string `json:"os.features,omitempty"` + // Platform describes the platform which the image in the manifest runs on. + Platform // Config defines the execution parameters which should be used as a base when running a container using the image. Config ImageConfig `json:"config,omitempty"` diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go index 730a09359..4ce7b54cc 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go @@ -23,6 +23,9 @@ type Manifest struct { // MediaType specifies the type of this document data structure e.g. `application/vnd.oci.image.manifest.v1+json` MediaType string `json:"mediaType,omitempty"` + // ArtifactType specifies the IANA media type of artifact when the manifest is used for an artifact. + ArtifactType string `json:"artifactType,omitempty"` + // Config references a configuration object for a container, by digest. // The referenced configuration object is a JSON blob that the runtime uses to set up the container. Config Descriptor `json:"config"` @@ -36,3 +39,11 @@ type Manifest struct { // Annotations contains arbitrary metadata for the image manifest. Annotations map[string]string `json:"annotations,omitempty"` } + +// ScratchDescriptor is the descriptor of a blob with content of `{}`. +var ScratchDescriptor = Descriptor{ + MediaType: MediaTypeScratch, + Digest: `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a`, + Size: 2, + Data: []byte(`{}`), +} diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go index 935b481e3..5dd31255e 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go @@ -40,21 +40,36 @@ const ( // MediaTypeImageLayerNonDistributable is the media type for layers referenced by // the manifest but with distribution restrictions. + // + // Deprecated: Non-distributable layers are deprecated, and not recommended + // for future use. Implementations SHOULD NOT produce new non-distributable + // layers. + // https://github.com/opencontainers/image-spec/pull/965 MediaTypeImageLayerNonDistributable = "application/vnd.oci.image.layer.nondistributable.v1.tar" // MediaTypeImageLayerNonDistributableGzip is the media type for // gzipped layers referenced by the manifest but with distribution // restrictions. + // + // Deprecated: Non-distributable layers are deprecated, and not recommended + // for future use. Implementations SHOULD NOT produce new non-distributable + // layers. + // https://github.com/opencontainers/image-spec/pull/965 MediaTypeImageLayerNonDistributableGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip" // MediaTypeImageLayerNonDistributableZstd is the media type for zstd // compressed layers referenced by the manifest but with distribution // restrictions. + // + // Deprecated: Non-distributable layers are deprecated, and not recommended + // for future use. Implementations SHOULD NOT produce new non-distributable + // layers. + // https://github.com/opencontainers/image-spec/pull/965 MediaTypeImageLayerNonDistributableZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd" // MediaTypeImageConfig specifies the media type for the image configuration. MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json" - // MediaTypeArtifactManifest specifies the media type for a content descriptor. - MediaTypeArtifactManifest = "application/vnd.oci.artifact.manifest.v1+json" + // MediaTypeScratch specifies the media type for an unused blob containing the value `{}` + MediaTypeScratch = "application/vnd.oci.scratch.v1+json" ) diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go index d27903579..3d4119b44 100644 --- a/vendor/github.com/opencontainers/image-spec/specs-go/version.go +++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go @@ -25,7 +25,7 @@ const ( VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "-rc2" + VersionDev = "-rc.3" ) // Version is the specification version that the package types support. diff --git a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go index ea64a3820..fcf321553 100644 --- a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go +++ b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go @@ -41,7 +41,7 @@ type fileReader interface { // RawBytes accesses the raw bytes of the archive, apart from the file payload itself. // This includes the header and padding. // -// This call resets the current rawbytes buffer +// # This call resets the current rawbytes buffer // // Only when RawAccounting is enabled, otherwise this returns nil func (tr *Reader) RawBytes() []byte { @@ -126,7 +126,9 @@ func (tr *Reader) next() (*Header, error) { return nil, err } if hdr.Typeflag == TypeXGlobalHeader { - mergePAX(hdr, paxHdrs) + if err = mergePAX(hdr, paxHdrs); err != nil { + return nil, err + } return &Header{ Name: hdr.Name, Typeflag: hdr.Typeflag, @@ -381,9 +383,9 @@ func parsePAX(r io.Reader) (map[string]string, error) { // header in case further processing is required. // // The err will be set to io.EOF only when one of the following occurs: -// * Exactly 0 bytes are read and EOF is hit. -// * Exactly 1 block of zeros is read and EOF is hit. -// * At least 2 blocks of zeros are read. +// - Exactly 0 bytes are read and EOF is hit. +// - Exactly 1 block of zeros is read and EOF is hit. +// - At least 2 blocks of zeros are read. func (tr *Reader) readHeader() (*Header, *block, error) { // Two blocks of zero bytes marks the end of the archive. n, err := io.ReadFull(tr.r, tr.blk[:]) diff --git a/vendor/golang.org/x/oauth2/README.md b/vendor/golang.org/x/oauth2/README.md index 1473e1296..781770c20 100644 --- a/vendor/golang.org/x/oauth2/README.md +++ b/vendor/golang.org/x/oauth2/README.md @@ -19,7 +19,7 @@ See pkg.go.dev for further documentation and examples. * [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2) * [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google) -## Policy for new packages +## Policy for new endpoints We no longer accept new provider-specific packages in this repo if all they do is add a single endpoint variable. If you just want to add a @@ -29,8 +29,12 @@ package. ## Report Issues / Send Patches -This repository uses Gerrit for code changes. To learn how to submit changes to -this repository, see https://golang.org/doc/contribute.html. - The main issue tracker for the oauth2 repository is located at https://github.com/golang/oauth2/issues. + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. In particular: + +* Excluding trivial changes, all contributions should be connected to an existing issue. +* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted. +* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2). diff --git a/vendor/golang.org/x/oauth2/google/default.go b/vendor/golang.org/x/oauth2/google/default.go index db6b19e93..b3e8783cc 100644 --- a/vendor/golang.org/x/oauth2/google/default.go +++ b/vendor/golang.org/x/oauth2/google/default.go @@ -13,12 +13,15 @@ import ( "os" "path/filepath" "runtime" + "time" "cloud.google.com/go/compute/metadata" "golang.org/x/oauth2" "golang.org/x/oauth2/authhandler" ) +const adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc" + // Credentials holds Google credentials, including "Application Default Credentials". // For more details, see: // https://developers.google.com/accounts/docs/application-default-credentials @@ -66,6 +69,14 @@ type CredentialsParams struct { // The OAuth2 TokenURL default override. This value overrides the default TokenURL, // unless explicitly specified by the credentials config file. Optional. TokenURL string + + // EarlyTokenRefresh is the amount of time before a token expires that a new + // token will be preemptively fetched. If unset the default value is 10 + // seconds. + // + // Note: This option is currently only respected when using credentials + // fetched from the GCE metadata server. + EarlyTokenRefresh time.Duration } func (params CredentialsParams) deepCopy() CredentialsParams { @@ -153,13 +164,12 @@ func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsPar id, _ := metadata.ProjectID() return &Credentials{ ProjectID: id, - TokenSource: ComputeTokenSource("", params.Scopes...), + TokenSource: computeTokenSource("", params.EarlyTokenRefresh, params.Scopes...), }, nil } // None are found; return helpful error. - const url = "https://developers.google.com/accounts/docs/application-default-credentials" - return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) + return nil, fmt.Errorf("google: could not find default credentials. See %v for more information", adcSetupURL) } // FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes. diff --git a/vendor/golang.org/x/oauth2/google/doc.go b/vendor/golang.org/x/oauth2/google/doc.go index 8a3349fc2..ca717634a 100644 --- a/vendor/golang.org/x/oauth2/google/doc.go +++ b/vendor/golang.org/x/oauth2/google/doc.go @@ -26,7 +26,7 @@ // // Using workload identity federation, your application can access Google Cloud // resources from Amazon Web Services (AWS), Microsoft Azure or any identity -// provider that supports OpenID Connect (OIDC). +// provider that supports OpenID Connect (OIDC) or SAML 2.0. // Traditionally, applications running outside Google Cloud have used service // account keys to access Google Cloud resources. Using identity federation, // you can allow your workload to impersonate a service account. @@ -36,26 +36,70 @@ // Follow the detailed instructions on how to configure Workload Identity Federation // in various platforms: // -// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws -// Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure -// OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc +// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#aws +// Microsoft Azure: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#azure +// OIDC identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#oidc +// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#saml // // For OIDC and SAML providers, the library can retrieve tokens in three ways: // from a local file location (file-sourced credentials), from a server // (URL-sourced credentials), or from a local executable (executable-sourced // credentials). // For file-sourced credentials, a background process needs to be continuously -// refreshing the file location with a new OIDC token prior to expiration. +// refreshing the file location with a new OIDC/SAML token prior to expiration. // For tokens with one hour lifetimes, the token needs to be updated in the file // every hour. The token can be stored directly as plain text or in JSON format. // For URL-sourced credentials, a local server needs to host a GET endpoint to -// return the OIDC token. The response can be in plain text or JSON. +// return the OIDC/SAML token. The response can be in plain text or JSON. // Additional required request headers can also be specified. // For executable-sourced credentials, an application needs to be available to -// output the OIDC token and other information in a JSON format. +// output the OIDC/SAML token and other information in a JSON format. // For more information on how these work (and how to implement // executable-sourced credentials), please check out: -// https://cloud.google.com/iam/docs/using-workload-identity-federation#oidc +// https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create_a_credential_configuration +// +// Note that this library does not perform any validation on the token_url, token_info_url, +// or service_account_impersonation_url fields of the credential configuration. +// It is not recommended to use a credential configuration that you did not generate with +// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain. +// +// # Workforce Identity Federation +// +// Workforce identity federation lets you use an external identity provider (IdP) to +// authenticate and authorize a workforce—a group of users, such as employees, partners, +// and contractors—using IAM, so that the users can access Google Cloud services. +// Workforce identity federation extends Google Cloud's identity capabilities to support +// syncless, attribute-based single sign on. +// +// With workforce identity federation, your workforce can access Google Cloud resources +// using an external identity provider (IdP) that supports OpenID Connect (OIDC) or +// SAML 2.0 such as Azure Active Directory (Azure AD), Active Directory Federation +// Services (AD FS), Okta, and others. +// +// Follow the detailed instructions on how to configure Workload Identity Federation +// in various platforms: +// +// Azure AD: https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad +// Okta: https://cloud.google.com/iam/docs/workforce-sign-in-okta +// OIDC identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#oidc +// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#saml +// +// For workforce identity federation, the library can retrieve tokens in three ways: +// from a local file location (file-sourced credentials), from a server +// (URL-sourced credentials), or from a local executable (executable-sourced +// credentials). +// For file-sourced credentials, a background process needs to be continuously +// refreshing the file location with a new OIDC/SAML token prior to expiration. +// For tokens with one hour lifetimes, the token needs to be updated in the file +// every hour. The token can be stored directly as plain text or in JSON format. +// For URL-sourced credentials, a local server needs to host a GET endpoint to +// return the OIDC/SAML token. The response can be in plain text or JSON. +// Additional required request headers can also be specified. +// For executable-sourced credentials, an application needs to be available to +// output the OIDC/SAML token and other information in a JSON format. +// For more information on how these work (and how to implement +// executable-sourced credentials), please check out: +// https://cloud.google.com/iam/docs/workforce-obtaining-short-lived-credentials#generate_a_configuration_file_for_non-interactive_sign-in // // Note that this library does not perform any validation on the token_url, token_info_url, // or service_account_impersonation_url fields of the credential configuration. @@ -86,5 +130,4 @@ // same as the one obtained from the oauth2.Config returned from ConfigFromJSON or // JWTConfigFromJSON, but the Credentials may contain additional information // that is useful is some circumstances. -// package google // import "golang.org/x/oauth2/google" diff --git a/vendor/golang.org/x/oauth2/google/google.go b/vendor/golang.org/x/oauth2/google/google.go index a1b629a2e..cc1223889 100644 --- a/vendor/golang.org/x/oauth2/google/google.go +++ b/vendor/golang.org/x/oauth2/google/google.go @@ -231,7 +231,11 @@ func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsPar // Further information about retrieving access tokens from the GCE metadata // server can be found at https://cloud.google.com/compute/docs/authentication. func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource { - return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope}) + return computeTokenSource(account, 0, scope...) +} + +func computeTokenSource(account string, earlyExpiry time.Duration, scope ...string) oauth2.TokenSource { + return oauth2.ReuseTokenSourceWithExpiry(nil, computeSource{account: account, scopes: scope}, earlyExpiry) } type computeSource struct { diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go index 291df5c83..9085fabe3 100644 --- a/vendor/golang.org/x/oauth2/oauth2.go +++ b/vendor/golang.org/x/oauth2/oauth2.go @@ -16,6 +16,7 @@ import ( "net/url" "strings" "sync" + "time" "golang.org/x/oauth2/internal" ) @@ -140,7 +141,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption { // // State is a token to protect the user from CSRF attacks. You must // always provide a non-empty string and validate that it matches the -// the state query parameter on your redirect callback. +// state query parameter on your redirect callback. // See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. // // Opts may include AccessTypeOnline or AccessTypeOffline, as well @@ -290,6 +291,8 @@ type reuseTokenSource struct { mu sync.Mutex // guards t t *Token + + expiryDelta time.Duration } // Token returns the current token if it's still valid, else will @@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) { if err != nil { return nil, err } + t.expiryDelta = s.expiryDelta s.t = t return t, nil } @@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource { new: src, } } + +// ReuseTokenSource returns a TokenSource that acts in the same manner as the +// TokenSource returned by ReuseTokenSource, except the expiry buffer is +// configurable. The expiration time of a token is calculated as +// t.Expiry.Add(-earlyExpiry). +func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource { + // Don't wrap a reuseTokenSource in itself. That would work, + // but cause an unnecessary number of mutex operations. + // Just build the equivalent one. + if rt, ok := src.(*reuseTokenSource); ok { + if t == nil { + // Just use it directly, but set the expiryDelta to earlyExpiry, + // so the behavior matches what the user expects. + rt.expiryDelta = earlyExpiry + return rt + } + src = rt.new + } + if t != nil { + t.expiryDelta = earlyExpiry + } + return &reuseTokenSource{ + t: t, + new: src, + expiryDelta: earlyExpiry, + } +} diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go index 822720341..7c64006de 100644 --- a/vendor/golang.org/x/oauth2/token.go +++ b/vendor/golang.org/x/oauth2/token.go @@ -16,10 +16,10 @@ import ( "golang.org/x/oauth2/internal" ) -// expiryDelta determines how earlier a token should be considered +// defaultExpiryDelta determines how earlier a token should be considered // expired than its actual expiration time. It is used to avoid late // expirations due to client-server time mismatches. -const expiryDelta = 10 * time.Second +const defaultExpiryDelta = 10 * time.Second // Token represents the credentials used to authorize // the requests to access protected resources on the OAuth 2.0 @@ -52,6 +52,11 @@ type Token struct { // raw optionally contains extra metadata from the server // when updating a token. raw interface{} + + // expiryDelta is used to calculate when a token is considered + // expired, by subtracting from Expiry. If zero, defaultExpiryDelta + // is used. + expiryDelta time.Duration } // Type returns t.TokenType if non-empty, else "Bearer". @@ -127,6 +132,11 @@ func (t *Token) expired() bool { if t.Expiry.IsZero() { return false } + + expiryDelta := defaultExpiryDelta + if t.expiryDelta != 0 { + expiryDelta = t.expiryDelta + } return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow()) } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index ba53cdcdd..a0dc0b5e2 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -44,12 +44,12 @@ func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { return out.Bytes(), err } -// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow -// in the same executable. This function cannot import data from +// IImportShallow decodes "shallow" types.Package data encoded by +// IExportShallow in the same executable. This function cannot import data from // cmd/compile or gcexportdata.Write. -func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) { +func IImportShallow(fset *token.FileSet, getPackage GetPackageFunc, data []byte, path string, insert InsertType) (*types.Package, error) { const bundle = false - pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert) + pkgs, err := iimportCommon(fset, getPackage, data, bundle, path, insert) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 448f903e8..be6dace15 100644 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -85,7 +85,7 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { - pkgs, err := iimportCommon(fset, imports, data, false, path, nil) + pkgs, err := iimportCommon(fset, GetPackageFromMap(imports), data, false, path, nil) if err != nil { return 0, nil, err } @@ -94,10 +94,33 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // IImportBundle imports a set of packages from the serialized package bundle. func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { - return iimportCommon(fset, imports, data, true, "", nil) + return iimportCommon(fset, GetPackageFromMap(imports), data, true, "", nil) } -func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { +// A GetPackageFunc is a function that gets the package with the given path +// from the importer state, creating it (with the specified name) if necessary. +// It is an abstraction of the map historically used to memoize package creation. +// +// Two calls with the same path must return the same package. +// +// If the given getPackage func returns nil, the import will fail. +type GetPackageFunc = func(path, name string) *types.Package + +// GetPackageFromMap returns a GetPackageFunc that retrieves packages from the +// given map of package path -> package. +// +// The resulting func may mutate m: if a requested package is not found, a new +// package will be inserted into m. +func GetPackageFromMap(m map[string]*types.Package) GetPackageFunc { + return func(path, name string) *types.Package { + if _, ok := m[path]; !ok { + m[path] = types.NewPackage(path, name) + } + return m[path] + } +} + +func iimportCommon(fset *token.FileSet, getPackage GetPackageFunc, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { const currentVersion = iexportVersionCurrent version := int64(-1) if !debug { @@ -195,10 +218,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data if pkgPath == "" { pkgPath = path } - pkg := imports[pkgPath] + pkg := getPackage(pkgPath, pkgName) if pkg == nil { - pkg = types.NewPackage(pkgPath, pkgName) - imports[pkgPath] = pkg + errorf("internal error: getPackage returned nil package for %s", pkgPath) } else if pkg.Name() != pkgName { errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) } diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go index a3fb2d4f2..7e638ec24 100644 --- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go +++ b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go @@ -7,7 +7,9 @@ package tokeninternal import ( + "fmt" "go/token" + "sort" "sync" "unsafe" ) @@ -57,3 +59,93 @@ func GetLines(file *token.File) []int { panic("unexpected token.File size") } } + +// AddExistingFiles adds the specified files to the FileSet if they +// are not already present. It panics if any pair of files in the +// resulting FileSet would overlap. +func AddExistingFiles(fset *token.FileSet, files []*token.File) { + // Punch through the FileSet encapsulation. + type tokenFileSet struct { + // This type remained essentially consistent from go1.16 to go1.21. + mutex sync.RWMutex + base int + files []*token.File + _ *token.File // changed to atomic.Pointer[token.File] in go1.19 + } + + // If the size of token.FileSet changes, this will fail to compile. + const delta = int64(unsafe.Sizeof(tokenFileSet{})) - int64(unsafe.Sizeof(token.FileSet{})) + var _ [-delta * delta]int + + type uP = unsafe.Pointer + var ptr *tokenFileSet + *(*uP)(uP(&ptr)) = uP(fset) + ptr.mutex.Lock() + defer ptr.mutex.Unlock() + + // Merge and sort. + newFiles := append(ptr.files, files...) + sort.Slice(newFiles, func(i, j int) bool { + return newFiles[i].Base() < newFiles[j].Base() + }) + + // Reject overlapping files. + // Discard adjacent identical files. + out := newFiles[:0] + for i, file := range newFiles { + if i > 0 { + prev := newFiles[i-1] + if file == prev { + continue + } + if prev.Base()+prev.Size()+1 > file.Base() { + panic(fmt.Sprintf("file %s (%d-%d) overlaps with file %s (%d-%d)", + prev.Name(), prev.Base(), prev.Base()+prev.Size(), + file.Name(), file.Base(), file.Base()+file.Size())) + } + } + out = append(out, file) + } + newFiles = out + + ptr.files = newFiles + + // Advance FileSet.Base(). + if len(newFiles) > 0 { + last := newFiles[len(newFiles)-1] + newBase := last.Base() + last.Size() + 1 + if ptr.base < newBase { + ptr.base = newBase + } + } +} + +// FileSetFor returns a new FileSet containing a sequence of new Files with +// the same base, size, and line as the input files, for use in APIs that +// require a FileSet. +// +// Precondition: the input files must be non-overlapping, and sorted in order +// of their Base. +func FileSetFor(files ...*token.File) *token.FileSet { + fset := token.NewFileSet() + for _, f := range files { + f2 := fset.AddFile(f.Name(), f.Base(), f.Size()) + lines := GetLines(f) + f2.SetLines(lines) + } + return fset +} + +// CloneFileSet creates a new FileSet holding all files in fset. It does not +// create copies of the token.Files in fset: they are added to the resulting +// FileSet unmodified. +func CloneFileSet(fset *token.FileSet) *token.FileSet { + var files []*token.File + fset.Iterate(func(f *token.File) bool { + files = append(files, f) + return true + }) + newFileSet := token.NewFileSet() + AddExistingFiles(newFileSet, files) + return newFileSet +} diff --git a/vendor/google.golang.org/protobuf/internal/version/version.go b/vendor/google.golang.org/protobuf/internal/version/version.go index daefe1105..f7014cd51 100644 --- a/vendor/google.golang.org/protobuf/internal/version/version.go +++ b/vendor/google.golang.org/protobuf/internal/version/version.go @@ -51,8 +51,8 @@ import ( // 10. Send out the CL for review and submit it. const ( Major = 1 - Minor = 29 - Patch = 1 + Minor = 30 + Patch = 0 PreRelease = "" ) diff --git a/vendor/modules.txt b/vendor/modules.txt index 7e3fe6a30..65070ae11 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -151,7 +151,7 @@ github.com/davecgh/go-spew/spew # github.com/dimchansky/utfbom v1.1.0 ## explicit github.com/dimchansky/utfbom -# github.com/docker/cli v23.0.1+incompatible +# github.com/docker/cli v23.0.5+incompatible ## explicit github.com/docker/cli/cli/config github.com/docker/cli/cli/config/configfile @@ -160,7 +160,7 @@ github.com/docker/cli/cli/config/types # github.com/docker/distribution v2.8.2+incompatible ## explicit github.com/docker/distribution/registry/client/auth/challenge -# github.com/docker/docker v23.0.3+incompatible +# github.com/docker/docker v23.0.5+incompatible ## explicit github.com/docker/docker/pkg/homedir # github.com/docker/docker-credential-helpers v0.7.0 @@ -176,7 +176,7 @@ github.com/form3tech-oss/jwt-go # github.com/golang/protobuf v1.5.3 ## explicit; go 1.9 github.com/golang/protobuf/proto -# github.com/google/go-containerregistry v0.14.0 +# github.com/google/go-containerregistry v0.15.2 ## explicit; go 1.18 github.com/google/go-containerregistry/internal/and github.com/google/go-containerregistry/internal/compression @@ -211,7 +211,7 @@ github.com/inconshreveable/mousetrap # github.com/jmespath/go-jmespath v0.4.0 ## explicit; go 1.14 github.com/jmespath/go-jmespath -# github.com/klauspost/compress v1.16.0 +# github.com/klauspost/compress v1.16.5 ## explicit; go 1.18 github.com/klauspost/compress github.com/klauspost/compress/fse @@ -241,8 +241,8 @@ github.com/mitchellh/go-homedir # github.com/opencontainers/go-digest v1.0.0 ## explicit; go 1.13 github.com/opencontainers/go-digest -# github.com/opencontainers/image-spec v1.1.0-rc2 -## explicit; go 1.17 +# github.com/opencontainers/image-spec v1.1.0-rc3 +## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 # github.com/pkg/errors v0.9.1 @@ -267,7 +267,7 @@ github.com/spf13/pflag ## explicit; go 1.20 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/vbatts/tar-split v0.11.2 +# github.com/vbatts/tar-split v0.11.3 ## explicit; go 1.15 github.com/vbatts/tar-split/archive/tar # github.com/vito/go-interact v1.0.1 @@ -277,15 +277,15 @@ github.com/vito/go-interact/interact ## explicit; go 1.17 golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12/internal/rc2 -# golang.org/x/mod v0.9.0 +# golang.org/x/mod v0.10.0 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.8.0 +# golang.org/x/net v0.9.0 ## explicit; go 1.17 golang.org/x/net/context -# golang.org/x/oauth2 v0.6.0 +# golang.org/x/oauth2 v0.7.0 ## explicit; go 1.17 golang.org/x/oauth2 golang.org/x/oauth2/authhandler @@ -304,10 +304,10 @@ golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.6.0 +# golang.org/x/term v0.7.0 ## explicit; go 1.17 golang.org/x/term -# golang.org/x/tools v0.7.0 +# golang.org/x/tools v0.8.0 ## explicit; go 1.18 golang.org/x/tools/go/ast/astutil golang.org/x/tools/go/gcexportdata @@ -342,7 +342,7 @@ google.golang.org/appengine/internal/modules google.golang.org/appengine/internal/remote_api google.golang.org/appengine/internal/urlfetch google.golang.org/appengine/urlfetch -# google.golang.org/protobuf v1.29.1 +# google.golang.org/protobuf v1.30.0 ## explicit; go 1.11 google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire From dfebd8f6b076c8ae105b641a016fb0dc4523635c Mon Sep 17 00:00:00 2001 From: Joao Pereira Date: Fri, 16 Jun 2023 16:40:56 -0500 Subject: [PATCH 2/2] Fix issues with imgpkg tests Signed-off-by: Joao Pereira --- pkg/imgpkg/cmd/copy_repo_src_test.go | 2 ++ test/helpers/image_factory.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/imgpkg/cmd/copy_repo_src_test.go b/pkg/imgpkg/cmd/copy_repo_src_test.go index 7f5c34f0f..e740e6ac5 100644 --- a/pkg/imgpkg/cmd/copy_repo_src_test.go +++ b/pkg/imgpkg/cmd/copy_repo_src_test.go @@ -196,6 +196,8 @@ func TestToTarBundleContainingNonDistributableLayers(t *testing.T) { assets := &helpers.Assets{T: t} bundleBuilder := helpers.NewBundleDir(t, assets) defer assets.CleanCreatedFolders() + + fakeRegistry := helpers.NewFakeRegistry(t, &helpers.Logger{LogLevel: helpers.LogDebug}) imageLockYAML := fmt.Sprintf(`--- apiVersion: imgpkg.carvel.dev/v1alpha1 kind: ImagesLock diff --git a/test/helpers/image_factory.go b/test/helpers/image_factory.go index fb338fd03..606d973e5 100644 --- a/test/helpers/image_factory.go +++ b/test/helpers/image_factory.go @@ -56,7 +56,7 @@ func (i *ImageFactory) PushImageWithANonDistributableLayer(imgRef string, mediaT }) require.NoError(i.T, err) - err = remote.WriteLayer(imageRef.Context(), layer, remote.WithAuthFromKeychain(authn.DefaultKeychain)) + err = remote.WriteLayer(imageRef.Context(), layer, remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithNondistributable) require.NoError(i.T, err) err = remote.Write(imageRef, image, remote.WithAuthFromKeychain(authn.DefaultKeychain)) require.NoError(i.T, err)