diff --git a/go.mod b/go.mod
index 5840f955..d0125f25 100644
--- a/go.mod
+++ b/go.mod
@@ -9,17 +9,17 @@ require (
github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65
github.com/cppforlife/go-cli-ui v0.0.0-20220425131040-94f26b16bc14
github.com/gogo/protobuf v1.3.2
- github.com/google/go-containerregistry v0.20.6
+ github.com/google/go-containerregistry v0.20.8
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-querystring v1.1.0 // indirect
- github.com/hashicorp/go-version v1.2.1
+ github.com/hashicorp/go-version v1.7.0
github.com/mitchellh/go-homedir v1.1.0
github.com/otiai10/copy v1.2.0
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
golang.org/x/crypto v0.49.0
- golang.org/x/oauth2 v0.30.0
+ golang.org/x/oauth2 v0.35.0
golang.org/x/tools v0.43.0
gopkg.in/inf.v0 v0.9.1
k8s.io/apimachinery v0.24.3
@@ -60,11 +60,11 @@ require (
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0 // indirect
github.com/cheggaaa/pb/v3 v3.1.7 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect
- github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
+ github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
github.com/cppforlife/color v1.9.1-0.20200716202919-6706ac40b835 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.0 // indirect
- github.com/docker/cli v29.2.0+incompatible // indirect
+ github.com/docker/cli v29.2.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.5 // indirect
github.com/emicklei/go-restful v2.16.0+incompatible // indirect
@@ -78,7 +78,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
+ github.com/klauspost/compress v1.18.4 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -93,7 +93,7 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/spf13/pflag v1.0.9 // indirect
- github.com/vbatts/tar-split v0.12.1 // indirect
+ github.com/vbatts/tar-split v0.12.2 // indirect
github.com/vito/go-interact v1.0.1 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/net v0.52.0 // indirect
diff --git a/go.sum b/go.sum
index 2788aaf8..a412d1cf 100644
--- a/go.sum
+++ b/go.sum
@@ -86,8 +86,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8=
-github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
+github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=
+github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=
github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65 h1:+3J1K6yQFRPKDEl5Py68c1q0FjaCkeMcB1nb7uzmpSw=
github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65/go.mod h1:2w+qxVu2KSGW78Ex/XaIqfh/OvBgjEsmN53S4T8vEyA=
github.com/cppforlife/color v1.9.1-0.20200716202919-6706ac40b835 h1:mYQweUIBD+TBRjIeQnJmXr0GSVMpI6O0takyb/aaOgo=
@@ -106,8 +106,8 @@ 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 v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM=
-github.com/docker/cli v29.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
+github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
@@ -182,8 +182,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
-github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
+github.com/google/go-containerregistry v0.20.8 h1:UMDTaJFeV9yFOL+lAiwrJkAu1sQTgRo3HFsqCZTsPyA=
+github.com/google/go-containerregistry v0.20.8/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@@ -197,8 +197,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
-github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -213,8 +213,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
+github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -317,8 +317,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
-github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
+github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
+github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -366,8 +366,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
+golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
index 6aba0ef1..a9e1b72b 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/build.go
@@ -35,6 +35,7 @@ import (
"runtime"
"strings"
"sync"
+ "sync/atomic"
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
"github.com/klauspost/compress/zstd"
@@ -42,6 +43,8 @@ import (
"golang.org/x/sync/errgroup"
)
+type GzipHelperFunc func(io.Reader) (io.ReadCloser, error)
+
type options struct {
chunkSize int
compressionLevel int
@@ -50,6 +53,7 @@ type options struct {
compression Compression
ctx context.Context
minChunkSize int
+ gzipHelperFunc GzipHelperFunc
}
type Option func(o *options) error
@@ -127,11 +131,25 @@ func WithMinChunkSize(minChunkSize int) Option {
}
}
+// WithGzipHelperFunc option specifies a custom function to decompress gzip-compressed layers.
+// When a gzip-compressed layer is detected, this function will be used instead of the
+// Go standard library gzip decompression for better performance.
+// The function should take an io.Reader as input and return an io.ReadCloser.
+// If nil, the Go standard library gzip.NewReader will be used.
+func WithGzipHelperFunc(gzipHelperFunc GzipHelperFunc) Option {
+ return func(o *options) error {
+ o.gzipHelperFunc = gzipHelperFunc
+ return nil
+ }
+}
+
// Blob is an eStargz blob.
type Blob struct {
io.ReadCloser
- diffID digest.Digester
- tocDigest digest.Digest
+ diffID digest.Digester
+ tocDigest digest.Digest
+ readCompleted *atomic.Bool
+ uncompressedSize *atomic.Int64
}
// DiffID returns the digest of uncompressed blob.
@@ -145,6 +163,19 @@ func (b *Blob) TOCDigest() digest.Digest {
return b.tocDigest
}
+// UncompressedSize returns the size of uncompressed blob.
+// UncompressedSize should only be called after the blob has been fully read.
+func (b *Blob) UncompressedSize() (int64, error) {
+ switch {
+ case b.uncompressedSize == nil || b.readCompleted == nil:
+ return -1, fmt.Errorf("readCompleted or uncompressedSize is not initialized")
+ case !b.readCompleted.Load():
+ return -1, fmt.Errorf("called UncompressedSize before the blob has been fully read")
+ default:
+ return b.uncompressedSize.Load(), nil
+ }
+}
+
// Build builds an eStargz blob which is an extended version of stargz, from a blob (gzip, zstd
// or plain tar) passed through the argument. If there are some prioritized files are listed in
// the option, these files are grouped as "prioritized" and can be used for runtime optimization
@@ -186,7 +217,7 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
rErr = fmt.Errorf("error from context %q: %w", cErr, rErr)
}
}()
- tarBlob, err := decompressBlob(tarBlob, layerFiles)
+ tarBlob, err := decompressBlob(tarBlob, layerFiles, opts.gzipHelperFunc)
if err != nil {
return nil, err
}
@@ -252,17 +283,28 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
}
diffID := digest.Canonical.Digester()
pr, pw := io.Pipe()
+ readCompleted := new(atomic.Bool)
+ uncompressedSize := new(atomic.Int64)
go func() {
- r, err := opts.compression.Reader(io.TeeReader(io.MultiReader(append(rs, tocAndFooter)...), pw))
+ var size int64
+ var decompressFunc func(io.Reader) (io.ReadCloser, error)
+ if _, ok := opts.compression.(*gzipCompression); ok && opts.gzipHelperFunc != nil {
+ decompressFunc = opts.gzipHelperFunc
+ } else {
+ decompressFunc = opts.compression.Reader
+ }
+ decompressR, err := decompressFunc(io.TeeReader(io.MultiReader(append(rs, tocAndFooter)...), pw))
if err != nil {
pw.CloseWithError(err)
return
}
- defer r.Close()
- if _, err := io.Copy(diffID.Hash(), r); err != nil {
+ defer decompressR.Close()
+ if size, err = io.Copy(diffID.Hash(), decompressR); err != nil {
pw.CloseWithError(err)
return
}
+ uncompressedSize.Store(size)
+ readCompleted.Store(true)
pw.Close()
}()
return &Blob{
@@ -270,8 +312,10 @@ func Build(tarBlob *io.SectionReader, opt ...Option) (_ *Blob, rErr error) {
Reader: pr,
closeFunc: layerFiles.CleanupAll,
},
- tocDigest: tocDgst,
- diffID: diffID,
+ tocDigest: tocDgst,
+ diffID: diffID,
+ readCompleted: readCompleted,
+ uncompressedSize: uncompressedSize,
}, nil
}
@@ -366,8 +410,9 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
// Sort the tar file respecting to the prioritized files list.
sorted := &tarFile{}
+ picked := make(map[string]struct{})
for _, l := range prioritized {
- if err := moveRec(l, intar, sorted); err != nil {
+ if err := moveRec(l, intar, sorted, picked); err != nil {
if errors.Is(err, errNotFound) && missedPrioritized != nil {
*missedPrioritized = append(*missedPrioritized, l)
continue // allow not found
@@ -395,8 +440,8 @@ func sortEntries(in io.ReaderAt, prioritized []string, missedPrioritized *[]stri
})
}
- // Dump all entry and concatinate them.
- return append(sorted.dump(), intar.dump()...), nil
+ // Dump prioritized entries followed by the rest entries while skipping picked ones.
+ return append(sorted.dump(nil), intar.dump(picked)...), nil
}
// readerFromEntries returns a reader of tar archive that contains entries passed
@@ -408,11 +453,11 @@ func readerFromEntries(entries ...*entry) io.Reader {
defer tw.Close()
for _, entry := range entries {
if err := tw.WriteHeader(entry.header); err != nil {
- pw.CloseWithError(fmt.Errorf("Failed to write tar header: %v", err))
+ pw.CloseWithError(fmt.Errorf("failed to write tar header: %v", err))
return
}
if _, err := io.Copy(tw, entry.payload); err != nil {
- pw.CloseWithError(fmt.Errorf("Failed to write tar payload: %v", err))
+ pw.CloseWithError(fmt.Errorf("failed to write tar payload: %v", err))
return
}
}
@@ -458,36 +503,42 @@ func importTar(in io.ReaderAt) (*tarFile, error) {
return tf, nil
}
-func moveRec(name string, in *tarFile, out *tarFile) error {
+func moveRec(name string, in *tarFile, out *tarFile, picked map[string]struct{}) error {
name = cleanEntryName(name)
if name == "" { // root directory. stop recursion.
if e, ok := in.get(name); ok {
// entry of the root directory exists. we should move it as well.
// this case will occur if tar entries are prefixed with "./", "/", etc.
- out.add(e)
- in.remove(name)
+ if _, done := picked[name]; !done {
+ out.add(e)
+ picked[name] = struct{}{}
+ }
}
return nil
}
_, okIn := in.get(name)
_, okOut := out.get(name)
- if !okIn && !okOut {
+ _, okPicked := picked[name]
+ if !okIn && !okOut && !okPicked {
return fmt.Errorf("file: %q: %w", name, errNotFound)
}
parent, _ := path.Split(strings.TrimSuffix(name, "/"))
- if err := moveRec(parent, in, out); err != nil {
+ if err := moveRec(parent, in, out, picked); err != nil {
return err
}
if e, ok := in.get(name); ok && e.header.Typeflag == tar.TypeLink {
- if err := moveRec(e.header.Linkname, in, out); err != nil {
+ if err := moveRec(e.header.Linkname, in, out, picked); err != nil {
return err
}
}
+ if _, done := picked[name]; done {
+ return nil
+ }
if e, ok := in.get(name); ok {
out.add(e)
- in.remove(name)
+ picked[name] = struct{}{}
}
return nil
}
@@ -533,8 +584,18 @@ func (f *tarFile) get(name string) (e *entry, ok bool) {
return
}
-func (f *tarFile) dump() []*entry {
- return f.stream
+func (f *tarFile) dump(skip map[string]struct{}) []*entry {
+ if len(skip) == 0 {
+ return f.stream
+ }
+ var out []*entry
+ for _, e := range f.stream {
+ if _, ok := skip[cleanEntryName(e.header.Name)]; ok {
+ continue
+ }
+ out = append(out, e)
+ }
+ return out
}
type readCloser struct {
@@ -627,12 +688,12 @@ func (cr *countReadSeeker) Seek(offset int64, whence int) (int64, error) {
switch whence {
default:
- return 0, fmt.Errorf("Unknown whence: %v", whence)
+ return 0, fmt.Errorf("unknown whence: %v", whence)
case io.SeekStart:
case io.SeekCurrent:
offset += *cr.cPos
case io.SeekEnd:
- return 0, fmt.Errorf("Unsupported whence: %v", whence)
+ return 0, fmt.Errorf("unsupported whence: %v", whence)
}
if offset < 0 {
@@ -649,7 +710,7 @@ func (cr *countReadSeeker) currentPos() int64 {
return *cr.cPos
}
-func decompressBlob(org *io.SectionReader, tmp *tempFiles) (*io.SectionReader, error) {
+func decompressBlob(org *io.SectionReader, tmp *tempFiles, gzipHelperFunc GzipHelperFunc) (*io.SectionReader, error) {
if org.Size() < 4 {
return org, nil
}
@@ -660,7 +721,13 @@ func decompressBlob(org *io.SectionReader, tmp *tempFiles) (*io.SectionReader, e
var dR io.Reader
if bytes.Equal([]byte{0x1F, 0x8B, 0x08}, src[:3]) {
// gzip
- dgR, err := gzip.NewReader(io.NewSectionReader(org, 0, org.Size()))
+ var dgR io.ReadCloser
+ var err error
+ if gzipHelperFunc != nil {
+ dgR, err = gzipHelperFunc(io.NewSectionReader(org, 0, org.Size()))
+ } else {
+ dgR, err = gzip.NewReader(io.NewSectionReader(org, 0, org.Size()))
+ }
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
index f4d55465..69373042 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
@@ -237,7 +237,7 @@ func (r *Reader) initFields() error {
if ent.Gname != "" {
gname[ent.GID] = ent.Gname
} else {
- ent.Gname = uname[ent.GID]
+ ent.Gname = gname[ent.GID]
}
ent.modTime, _ = time.Parse(time.RFC3339, ent.ModTime3339)
@@ -307,6 +307,15 @@ func (r *Reader) initFields() error {
}
}
+ if len(r.m) == 0 {
+ r.m[""] = &TOCEntry{
+ Name: "",
+ Type: "dir",
+ Mode: 0755,
+ NumLink: 1,
+ }
+ }
+
return nil
}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
index f24afe32..88fa13b1 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
@@ -109,7 +109,7 @@ func gzipFooterBytes(tocOff int64) []byte {
header[0], header[1] = 'S', 'G'
subfield := fmt.Sprintf("%016xSTARGZ", tocOff)
binary.LittleEndian.PutUint16(header[2:4], uint16(len(subfield))) // little-endian per RFC1952
- gz.Header.Extra = append(header, []byte(subfield)...)
+ gz.Extra = append(header, []byte(subfield)...)
gz.Close()
if buf.Len() != FooterSize {
panic(fmt.Sprintf("footer buffer = %d, not %d", buf.Len(), FooterSize))
@@ -136,7 +136,7 @@ func (gz *GzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, t
return 0, 0, 0, err
}
defer zr.Close()
- extra := zr.Header.Extra
+ extra := zr.Extra
si1, si2, subfieldlen, subfield := extra[0], extra[1], extra[2:4], extra[4:]
if si1 != 'S' || si2 != 'G' {
return 0, 0, 0, fmt.Errorf("invalid subfield IDs: %q, %q; want E, S", si1, si2)
@@ -181,7 +181,7 @@ func (gz *LegacyGzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOff
return 0, 0, 0, fmt.Errorf("legacy: failed to get footer gzip reader: %w", err)
}
defer zr.Close()
- extra := zr.Header.Extra
+ extra := zr.Extra
if len(extra) != 16+len("STARGZ") {
return 0, 0, 0, fmt.Errorf("legacy: invalid stargz's extra field size")
}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
index ba650b4d..ff165e09 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
@@ -38,7 +38,6 @@ import (
"reflect"
"sort"
"strings"
- "testing"
"time"
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
@@ -49,16 +48,48 @@ import (
// TestingController is Compression with some helper methods necessary for testing.
type TestingController interface {
Compression
- TestStreams(t *testing.T, b []byte, streams []int64)
- DiffIDOf(*testing.T, []byte) string
+ TestStreams(t TestingT, b []byte, streams []int64)
+ DiffIDOf(TestingT, []byte) string
String() string
}
+// TestingT is the minimal set of testing.T required to run the
+// tests defined in CompressionTestSuite. This interface exists to prevent
+// leaking the testing package from being exposed outside tests.
+type TestingT interface {
+ Errorf(format string, args ...any)
+ FailNow()
+ Failed() bool
+ Fatal(args ...any)
+ Fatalf(format string, args ...any)
+ Logf(format string, args ...any)
+ Parallel()
+}
+
+// Runner allows running subtests of TestingT. This exists instead of adding
+// a Run method to TestingT interface because the Run implementation of
+// testing.T would not satisfy the interface.
+type Runner func(t TestingT, name string, fn func(t TestingT))
+
+type TestRunner struct {
+ TestingT
+ Runner Runner
+}
+
+func (r *TestRunner) Run(name string, run func(*TestRunner)) {
+ r.Runner(r.TestingT, name, func(t TestingT) {
+ run(&TestRunner{TestingT: t, Runner: r.Runner})
+ })
+}
+
// CompressionTestSuite tests this pkg with controllers can build valid eStargz blobs and parse them.
-func CompressionTestSuite(t *testing.T, controllers ...TestingControllerFactory) {
- t.Run("testBuild", func(t *testing.T) { t.Parallel(); testBuild(t, controllers...) })
- t.Run("testDigestAndVerify", func(t *testing.T) { t.Parallel(); testDigestAndVerify(t, controllers...) })
- t.Run("testWriteAndOpen", func(t *testing.T) { t.Parallel(); testWriteAndOpen(t, controllers...) })
+func CompressionTestSuite(t *TestRunner, controllers ...TestingControllerFactory) {
+ t.Run("testBuild", func(t *TestRunner) { t.Parallel(); testBuild(t, controllers...) })
+ t.Run("testDigestAndVerify", func(t *TestRunner) {
+ t.Parallel()
+ testDigestAndVerify(t, controllers...)
+ })
+ t.Run("testWriteAndOpen", func(t *TestRunner) { t.Parallel(); testWriteAndOpen(t, controllers...) })
}
type TestingControllerFactory func() TestingController
@@ -79,7 +110,7 @@ var allowedPrefix = [4]string{"", "./", "/", "../"}
// testBuild tests the resulting stargz blob built by this pkg has the same
// contents as the normal stargz blob.
-func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
+func testBuild(t *TestRunner, controllers ...TestingControllerFactory) {
tests := []struct {
name string
chunkSize int
@@ -165,7 +196,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
prefix := prefix
for _, minChunkSize := range tt.minChunkSize {
minChunkSize := minChunkSize
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *testing.T) {
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *TestRunner) {
tarBlob := buildTar(t, tt.in, prefix, srcTarFormat)
// Test divideEntries()
entries, err := sortEntries(tarBlob, nil, nil) // identical order
@@ -265,7 +296,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
}
}
-func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
+func isSameTarGz(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
aGz, err := cla.Reader(bytes.NewReader(a))
if err != nil {
t.Fatalf("failed to read A")
@@ -325,7 +356,7 @@ func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingContr
return true
}
-func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool {
+func isSameVersion(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
aJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(a), 0, int64(len(a))), cla)
if err != nil {
t.Fatalf("failed to parse A: %v", err)
@@ -339,7 +370,7 @@ func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingCon
return aJTOC.Version == bJTOC.Version
}
-func isSameEntries(t *testing.T, a, b *Reader) bool {
+func isSameEntries(t TestingT, a, b *Reader) bool {
aroot, ok := a.Lookup("")
if !ok {
t.Fatalf("failed to get root of A")
@@ -353,18 +384,19 @@ func isSameEntries(t *testing.T, a, b *Reader) bool {
return contains(t, aEntry, bEntry) && contains(t, bEntry, aEntry)
}
-func compressBlob(t *testing.T, src *io.SectionReader, srcCompression int) *io.SectionReader {
+func compressBlob(t TestingT, src *io.SectionReader, srcCompression int) *io.SectionReader {
buf := new(bytes.Buffer)
var w io.WriteCloser
var err error
- if srcCompression == gzipType {
+ switch srcCompression {
+ case gzipType:
w = gzip.NewWriter(buf)
- } else if srcCompression == zstdType {
+ case zstdType:
w, err = zstd.NewWriter(buf)
if err != nil {
t.Fatalf("failed to init zstd writer: %v", err)
}
- } else {
+ default:
return src
}
src.Seek(0, io.SeekStart)
@@ -386,7 +418,7 @@ type stargzEntry struct {
// contains checks if all child entries in "b" are also contained in "a".
// This function also checks if the files/chunks contain the same contents among "a" and "b".
-func contains(t *testing.T, a, b stargzEntry) bool {
+func contains(t TestingT, a, b stargzEntry) bool {
ae, ar := a.e, a.r
be, br := b.e, b.r
t.Logf("Comparing: %q vs %q", ae.Name, be.Name)
@@ -445,7 +477,7 @@ func contains(t *testing.T, a, b stargzEntry) bool {
bbytes, bnext, bok := readOffset(t, bf, nr, b)
if !aok && !bok {
break
- } else if !(aok && bok) || anext != bnext {
+ } else if !aok || !bok || anext != bnext {
t.Logf("%q != %q (offset=%d): chunk existence a=%v vs b=%v, anext=%v vs bnext=%v",
ae.Name, be.Name, nr, aok, bok, anext, bnext)
return false
@@ -497,7 +529,7 @@ func equalEntry(a, b *TOCEntry) bool {
a.Digest == b.Digest
}
-func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
+func readOffset(t TestingT, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
ce, ok := e.r.ChunkEntryForOffset(e.e.Name, offset)
if !ok {
return nil, 0, false
@@ -516,7 +548,7 @@ func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry)
return data[:n], offset + ce.ChunkSize, true
}
-func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
+func dumpTOCJSON(t TestingT, tocJSON *JTOC) string {
jtocData, err := json.Marshal(*tocJSON)
if err != nil {
t.Fatalf("failed to marshal TOC JSON: %v", err)
@@ -530,20 +562,19 @@ func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
const chunkSize = 3
-// type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, compressionLevel int)
-type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
+type check func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
// testDigestAndVerify runs specified checks against sample stargz blobs.
-func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory) {
+func testDigestAndVerify(t *TestRunner, controllers ...TestingControllerFactory) {
tests := []struct {
name string
- tarInit func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry)
+ tarInit func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry)
checks []check
minChunkSize []int
}{
{
name: "no-regfile",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
+ tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf(
dir("test/"),
)
@@ -558,7 +589,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
},
{
name: "small-files",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
+ tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf(
regDigest(t, "baz.txt", "", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap),
@@ -582,7 +613,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
},
{
name: "big-files",
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
+ tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf(
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap),
@@ -606,7 +637,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
{
name: "with-non-regfiles",
minChunkSize: []int{0, 64000},
- tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) {
+ tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf(
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap),
@@ -653,7 +684,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
srcTarFormat := srcTarFormat
for _, minChunkSize := range tt.minChunkSize {
minChunkSize := minChunkSize
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *testing.T) {
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *TestRunner) {
// Get original tar file and chunk digests
dgstMap := make(map[string]digest.Digest)
tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat)
@@ -689,7 +720,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
// checkStargzTOC checks the TOC JSON of the passed stargz has the expected
// digest and contains valid chunks. It walks all entries in the stargz and
// checks all chunk digests stored to the TOC JSON match the actual contents.
-func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
+func checkStargzTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
WithDecompressors(controller),
@@ -800,7 +831,7 @@ func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
// checkVerifyTOC checks the verification works for the TOC JSON of the passed
// stargz. It walks all entries in the stargz and checks the verifications for
// all chunks work.
-func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
+func checkVerifyTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
WithDecompressors(controller),
@@ -881,9 +912,9 @@ func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
// checkVerifyInvalidTOCEntryFail checks if misconfigured TOC JSON can be
// detected during the verification and the verification returns an error.
func checkVerifyInvalidTOCEntryFail(filename string) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
+ return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
funcs := map[string]rewriteFunc{
- "lost digest in a entry": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
+ "lost digest in a entry": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
var found bool
for _, e := range toc.Entries {
if cleanEntryName(e.Name) == filename {
@@ -901,7 +932,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
t.Fatalf("rewrite target not found")
}
},
- "duplicated entry offset": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) {
+ "duplicated entry offset": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
var (
sampleEntry *TOCEntry
targetEntry *TOCEntry
@@ -928,7 +959,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
}
for name, rFunc := range funcs {
- t.Run(name, func(t *testing.T) {
+ t.Run(name, func(t *TestRunner) {
newSgz, newTocDigest := rewriteTOCJSON(t, io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), rFunc, controller)
buf := new(bytes.Buffer)
if _, err := io.Copy(buf, newSgz); err != nil {
@@ -957,7 +988,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
// checkVerifyInvalidStargzFail checks if the verification detects that the
// given stargz file doesn't match to the expected digest and returns error.
func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
+ return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
cl := newController()
rc, err := Build(invalid, WithChunkSize(chunkSize), WithCompression(cl))
if err != nil {
@@ -989,7 +1020,7 @@ func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
// checkVerifyBrokenContentFail checks if the verifier detects broken contents
// that doesn't match to the expected digest and returns error.
func checkVerifyBrokenContentFail(filename string) check {
- return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
+ return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
// Parse stargz file
sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
@@ -1046,9 +1077,9 @@ func chunkID(name string, offset, size int64) string {
return fmt.Sprintf("%s-%d-%d", cleanEntryName(name), offset, size)
}
-type rewriteFunc func(t *testing.T, toc *JTOC, sgz *io.SectionReader)
+type rewriteFunc func(t TestingT, toc *JTOC, sgz *io.SectionReader)
-func rewriteTOCJSON(t *testing.T, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
+func rewriteTOCJSON(t TestingT, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
decodedJTOC, jtocOffset, err := parseStargz(sgz, controller)
if err != nil {
t.Fatalf("failed to extract TOC JSON: %v", err)
@@ -1119,7 +1150,7 @@ func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJT
return decodedJTOC, tocOffset, nil
}
-func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
+func testWriteAndOpen(t *TestRunner, controllers ...TestingControllerFactory) {
const content = "Some contents"
invalidUtf8 := "\xff\xfe\xfd"
@@ -1463,7 +1494,7 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
srcTarFormat := srcTarFormat
for _, lossless := range []bool{true, false} {
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *testing.T) {
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *TestRunner) {
var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat)
origTarDgstr := digest.Canonical.Digester()
tr = io.TeeReader(tr, origTarDgstr.Hash())
@@ -1529,6 +1560,9 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
if err != nil {
t.Fatalf("stargz.Open: %v", err)
}
+ if _, ok := r.Lookup(""); !ok {
+ t.Fatalf("failed to lookup rootdir: %v", err)
+ }
wantTOCVersion := 1
if tt.wantTOCVersion > 0 {
wantTOCVersion = tt.wantTOCVersion
@@ -1627,7 +1661,7 @@ func digestFor(content string) string {
type numTOCEntries int
-func (n numTOCEntries) check(t *testing.T, r *Reader) {
+func (n numTOCEntries) check(t TestingT, r *Reader) {
if r.toc == nil {
t.Fatal("nil TOC")
}
@@ -1647,15 +1681,15 @@ func (n numTOCEntries) check(t *testing.T, r *Reader) {
func checks(s ...stargzCheck) []stargzCheck { return s }
type stargzCheck interface {
- check(t *testing.T, r *Reader)
+ check(t TestingT, r *Reader)
}
-type stargzCheckFn func(*testing.T, *Reader)
+type stargzCheckFn func(TestingT, *Reader)
-func (f stargzCheckFn) check(t *testing.T, r *Reader) { f(t, r) }
+func (f stargzCheckFn) check(t TestingT, r *Reader) { f(t, r) }
func maxDepth(max int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
e, ok := r.Lookup("")
if !ok {
t.Fatal("root directory not found")
@@ -1672,7 +1706,7 @@ func maxDepth(max int) stargzCheck {
})
}
-func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr error) {
+func getMaxDepth(t TestingT, e *TOCEntry, current, limit int) (max int, rErr error) {
if current > limit {
return -1, fmt.Errorf("walkMaxDepth: exceeds limit: current:%d > limit:%d",
current, limit)
@@ -1694,7 +1728,7 @@ func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr e
}
func hasFileLen(file string, wantLen int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == file {
if ent.Type != "reg" {
@@ -1710,7 +1744,7 @@ func hasFileLen(file string, wantLen int) stargzCheck {
}
func hasFileXattrs(file, name, value string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == file {
if ent.Type != "reg" {
@@ -1737,7 +1771,7 @@ func hasFileXattrs(file, name, value string) stargzCheck {
}
func hasFileDigest(file string, digest string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(file)
if !ok {
t.Fatalf("didn't find TOCEntry for file %q", file)
@@ -1749,7 +1783,7 @@ func hasFileDigest(file string, digest string) stargzCheck {
}
func hasFileContentsWithPreRead(file string, offset int, want string, extra ...chunkInfo) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
extraMap := make(map[string]chunkInfo)
for _, e := range extra {
extraMap[e.name] = e
@@ -1796,7 +1830,7 @@ func hasFileContentsWithPreRead(file string, offset int, want string, extra ...c
}
func hasFileContentsRange(file string, offset int, want string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
f, err := r.OpenFile(file)
if err != nil {
t.Fatal(err)
@@ -1813,7 +1847,7 @@ func hasFileContentsRange(file string, offset int, want string) stargzCheck {
}
func hasChunkEntries(file string, wantChunks int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(file)
if !ok {
t.Fatalf("no file for %q", file)
@@ -1857,7 +1891,7 @@ func hasChunkEntries(file string, wantChunks int) stargzCheck {
}
func entryHasChildren(dir string, want ...string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
want := append([]string(nil), want...)
var got []string
ent, ok := r.Lookup(dir)
@@ -1876,7 +1910,7 @@ func entryHasChildren(dir string, want ...string) stargzCheck {
}
func hasDir(file string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) {
if ent.Type != "dir" {
@@ -1890,7 +1924,7 @@ func hasDir(file string) stargzCheck {
}
func hasDirLinkCount(file string, count int) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) {
if ent.Type != "dir" {
@@ -1908,7 +1942,7 @@ func hasDirLinkCount(file string, count int) stargzCheck {
}
func hasMode(file string, mode os.FileMode) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) {
if ent.Stat().Mode() != mode {
@@ -1923,7 +1957,7 @@ func hasMode(file string, mode os.FileMode) stargzCheck {
}
func hasSymlink(file, target string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries {
if ent.Name == file {
if ent.Type != "symlink" {
@@ -1939,7 +1973,7 @@ func hasSymlink(file, target string) stargzCheck {
}
func lookupMatch(name string, want *TOCEntry) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
e, ok := r.Lookup(name)
if !ok {
t.Fatalf("failed to Lookup entry %q", name)
@@ -1952,7 +1986,7 @@ func lookupMatch(name string, want *TOCEntry) stargzCheck {
}
func hasEntryOwner(entry string, owner owner) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(strings.TrimSuffix(entry, "/"))
if !ok {
t.Errorf("entry %q not found", entry)
@@ -1966,7 +2000,7 @@ func hasEntryOwner(entry string, owner owner) stargzCheck {
}
func mustSameEntry(files ...string) stargzCheck {
- return stargzCheckFn(func(t *testing.T, r *Reader) {
+ return stargzCheckFn(func(t TestingT, r *Reader) {
var first *TOCEntry
for _, f := range files {
if first == nil {
@@ -2038,7 +2072,7 @@ func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string, format tar.Format
return f(tw, prefix, format)
}
-func buildTar(t *testing.T, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
+func buildTar(t TestingT, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
format := tar.FormatUnknown
for _, opt := range opts {
switch v := opt.(type) {
@@ -2247,7 +2281,7 @@ func noPrefetchLandmark() tarEntry {
})
}
-func regDigest(t *testing.T, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
+func regDigest(t TestingT, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
if digestMap == nil {
t.Fatalf("digest map mustn't be nil")
}
@@ -2317,7 +2351,7 @@ func (f fileInfoOnlyMode) ModTime() time.Time { return time.Now() }
func (f fileInfoOnlyMode) IsDir() bool { return os.FileMode(f).IsDir() }
func (f fileInfoOnlyMode) Sys() interface{} { return nil }
-func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
+func CheckGzipHasStreams(t TestingT, b []byte, streams []int64) {
if len(streams) == 0 {
return // nop
}
@@ -2346,8 +2380,8 @@ func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
t.Fatalf("countStreams(gzip), Copy: %v", err)
}
var extra string
- if len(zr.Header.Extra) > 0 {
- extra = fmt.Sprintf("; extra=%q", zr.Header.Extra)
+ if len(zr.Extra) > 0 {
+ extra = fmt.Sprintf("; extra=%q", zr.Extra)
}
t.Logf(" [%d] at %d in stargz, uncompressed length %d%s", numStreams, zoff, n, extra)
delete(wants, int64(zoff))
@@ -2355,7 +2389,7 @@ func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
}
}
-func GzipDiffIDOf(t *testing.T, b []byte) string {
+func GzipDiffIDOf(t TestingT, b []byte) string {
h := sha256.New()
zr, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
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 6e8814d8..6f08460b 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go
@@ -117,8 +117,8 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A
if err != nil {
return nil, err
}
- } else if fileExists(os.Getenv("REGISTRY_AUTH_FILE")) {
- f, err := os.Open(os.Getenv("REGISTRY_AUTH_FILE"))
+ } else if path := filepath.Clean(os.Getenv("REGISTRY_AUTH_FILE")); fileExists(path) {
+ f, err := os.Open(path)
if err != nil {
return nil, err
}
@@ -127,8 +127,8 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A
if err != nil {
return nil, err
}
- } else if fileExists(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json")) {
- f, err := os.Open(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json"))
+ } else if path := filepath.Clean(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json")); fileExists(path) {
+ f, err := os.Open(path)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/config.go b/vendor/github.com/google/go-containerregistry/pkg/v1/config.go
index 960c93b5..b62d8482 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/v1/config.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/v1/config.go
@@ -27,10 +27,11 @@ import (
// docker_version and os.version are not part of the spec but included
// for backwards compatibility.
type ConfigFile struct {
- Architecture string `json:"architecture"`
- Author string `json:"author,omitempty"`
- Container string `json:"container,omitempty"`
- Created Time `json:"created,omitempty"`
+ Architecture string `json:"architecture"`
+ Author string `json:"author,omitempty"`
+ Container string `json:"container,omitempty"`
+ Created Time `json:"created,omitempty"`
+ // Deprecated: This field is deprecated and will be removed in the next release.
DockerVersion string `json:"docker_version,omitempty"`
History []History `json:"history,omitempty"`
OS string `json:"os"`
diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/hash.go b/vendor/github.com/google/go-containerregistry/pkg/v1/hash.go
index d81593bd..bbb600ed 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/v1/hash.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/v1/hash.go
@@ -84,27 +84,35 @@ func Hasher(name string) (hash.Hash, error) {
}
func (h *Hash) parse(unquoted string) error {
- parts := strings.Split(unquoted, ":")
- if len(parts) != 2 {
+ algo, body, ok := strings.Cut(unquoted, ":")
+ if !ok || algo == "" || body == "" {
return fmt.Errorf("cannot parse hash: %q", unquoted)
}
- rest := strings.TrimLeft(parts[1], "0123456789abcdef")
+ rest := strings.TrimLeft(body, "0123456789abcdef")
if len(rest) != 0 {
return fmt.Errorf("found non-hex character in hash: %c", rest[0])
}
- hasher, err := Hasher(parts[0])
- if err != nil {
- return err
+ var wantBytes int
+ switch algo {
+ case "sha256":
+ wantBytes = crypto.SHA256.Size()
+ default:
+ hasher, err := Hasher(algo)
+ if err != nil {
+ return err
+ }
+ wantBytes = hasher.Size()
}
+
// Compare the hex to the expected size (2 hex characters per byte)
- if len(parts[1]) != hasher.Size()*2 {
- return fmt.Errorf("wrong number of hex digits for %s: %s", parts[0], parts[1])
+ if len(body) != hex.EncodedLen(wantBytes) {
+ return fmt.Errorf("wrong number of hex digits for %s: %s", algo, body)
}
- h.Algorithm = parts[0]
- h.Hex = parts[1]
+ h.Algorithm = algo
+ h.Hex = body
return nil
}
diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
index c0447960..bf1113c9 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
@@ -317,7 +317,7 @@ func extract(img v1.Image, w io.Writer) error {
name = filepath.Join(dirname, basename)
}
- if _, ok := fileMap[name]; ok {
+ if _, ok := fileMap[name]; ok && !tombstone {
continue
}
@@ -514,7 +514,7 @@ func Canonical(img v1.Image) (v1.Image, error) {
cfg.Container = ""
cfg.Config.Hostname = ""
- cfg.DockerVersion = ""
+ cfg.DockerVersion = "" //nolint:staticcheck // Field will be removed in next release
return ConfigFile(img, cfg)
}
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 99a2bb2e..15b7da1e 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
@@ -162,9 +162,14 @@ func makeOptions(opts ...Option) (*options, error) {
o.transport = transport.NewLogger(o.transport)
}
- // Wrap the transport in something that can retry network flakes.
- o.transport = transport.NewRetry(o.transport, transport.WithRetryPredicate(defaultRetryPredicate), transport.WithRetryStatusCodes(o.retryStatusCodes...))
+ // Using customized retry predicate if provided, and fallback to default if not.
+ predicate := o.retryPredicate
+ if predicate == nil {
+ predicate = defaultRetryPredicate
+ }
+ // Wrap the transport in something that can retry network flakes.
+ o.transport = transport.NewRetry(o.transport, transport.WithRetryBackoff(o.retryBackoff), transport.WithRetryPredicate(predicate), transport.WithRetryStatusCodes(o.retryStatusCodes...))
// Wrap this last to prevent transport.New from double-wrapping.
if o.userAgent != "" {
o.transport = transport.NewUserAgent(o.transport, o.userAgent)
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 482a4ade..d38e6762 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
@@ -25,7 +25,7 @@ import (
)
// Error implements error to support the following error specification:
-// https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors
+// https://github.com/distribution/distribution/blob/aac2f6c8b7c5a6c60190848bab5cbeed2b5ba0a9/docs/spec/api.md#errors
type Error struct {
Errors []Diagnostic `json:"errors,omitempty"`
// The http status code returned.
@@ -111,7 +111,7 @@ func (d Diagnostic) String() string {
type ErrorCode string
// The set of error conditions a registry may return:
-// https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors-2
+// https://github.com/distribution/distribution/blob/aac2f6c8b7c5a6c60190848bab5cbeed2b5ba0a9/docs/spec/api.md#errors-2
const (
BlobUnknownErrorCode ErrorCode = "BLOB_UNKNOWN"
BlobUploadInvalidErrorCode ErrorCode = "BLOB_UPLOAD_INVALID"
@@ -170,7 +170,7 @@ func CheckError(resp *http.Response, codes ...int) error {
}
func makeError(resp *http.Response, body []byte) *Error {
- // https://github.com/docker/distribution/blob/master/docs/spec/api.md#errors
+ // https://github.com/distribution/distribution/blob/aac2f6c8b7c5a6c60190848bab5cbeed2b5ba0a9/docs/spec/api.md#errors
structuredError := &Error{}
// This can fail if e.g. the response body is not valid JSON. That's fine,
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 94d207de..58adfd8d 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
@@ -634,7 +634,7 @@ func scopesForUploadingImage(repo name.Repository, layers []v1.Layer) []string {
}
}
- scopes := make([]string, 0)
+ scopes := make([]string, 0, len(scopeSet)+1)
// Push scope should be the first element because a few registries just look at the first scope to determine access.
scopes = append(scopes, repo.Scope(transport.PushScope))
diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/zz_deepcopy_generated.go b/vendor/github.com/google/go-containerregistry/pkg/v1/zz_deepcopy_generated.go
index a47b7475..36102da2 100644
--- a/vendor/github.com/google/go-containerregistry/pkg/v1/zz_deepcopy_generated.go
+++ b/vendor/github.com/google/go-containerregistry/pkg/v1/zz_deepcopy_generated.go
@@ -1,5 +1,4 @@
//go:build !ignore_autogenerated
-// +build !ignore_autogenerated
// Copyright 2018 Google LLC All Rights Reserved.
//
diff --git a/vendor/github.com/hashicorp/go-version/CHANGELOG.md b/vendor/github.com/hashicorp/go-version/CHANGELOG.md
new file mode 100644
index 00000000..6d48174b
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-version/CHANGELOG.md
@@ -0,0 +1,64 @@
+# 1.7.0 (May 24, 2024)
+
+ENHANCEMENTS:
+
+- Remove `reflect` dependency ([#91](https://github.com/hashicorp/go-version/pull/91))
+- Implement the `database/sql.Scanner` and `database/sql/driver.Value` interfaces for `Version` ([#133](https://github.com/hashicorp/go-version/pull/133))
+
+INTERNAL:
+
+- [COMPLIANCE] Add Copyright and License Headers ([#115](https://github.com/hashicorp/go-version/pull/115))
+- [COMPLIANCE] Update MPL-2.0 LICENSE ([#105](https://github.com/hashicorp/go-version/pull/105))
+- Bump actions/cache from 3.0.11 to 3.2.5 ([#116](https://github.com/hashicorp/go-version/pull/116))
+- Bump actions/checkout from 3.2.0 to 3.3.0 ([#111](https://github.com/hashicorp/go-version/pull/111))
+- Bump actions/upload-artifact from 3.1.1 to 3.1.2 ([#112](https://github.com/hashicorp/go-version/pull/112))
+- GHA Migration ([#103](https://github.com/hashicorp/go-version/pull/103))
+- github: Pin external GitHub Actions to hashes ([#107](https://github.com/hashicorp/go-version/pull/107))
+- SEC-090: Automated trusted workflow pinning (2023-04-05) ([#124](https://github.com/hashicorp/go-version/pull/124))
+- update readme ([#104](https://github.com/hashicorp/go-version/pull/104))
+
+# 1.6.0 (June 28, 2022)
+
+FEATURES:
+
+- Add `Prerelease` function to `Constraint` to return true if the version includes a prerelease field ([#100](https://github.com/hashicorp/go-version/pull/100))
+
+# 1.5.0 (May 18, 2022)
+
+FEATURES:
+
+- Use `encoding` `TextMarshaler` & `TextUnmarshaler` instead of JSON equivalents ([#95](https://github.com/hashicorp/go-version/pull/95))
+- Add JSON handlers to allow parsing from/to JSON ([#93](https://github.com/hashicorp/go-version/pull/93))
+
+# 1.4.0 (January 5, 2022)
+
+FEATURES:
+
+ - Introduce `MustConstraints()` ([#87](https://github.com/hashicorp/go-version/pull/87))
+ - `Constraints`: Introduce `Equals()` and `sort.Interface` methods ([#88](https://github.com/hashicorp/go-version/pull/88))
+
+# 1.3.0 (March 31, 2021)
+
+Please note that CHANGELOG.md does not exist in the source code prior to this release.
+
+FEATURES:
+ - Add `Core` function to return a version without prerelease or metadata ([#85](https://github.com/hashicorp/go-version/pull/85))
+
+# 1.2.1 (June 17, 2020)
+
+BUG FIXES:
+ - Prevent `Version.Equal` method from panicking on `nil` encounter ([#73](https://github.com/hashicorp/go-version/pull/73))
+
+# 1.2.0 (April 23, 2019)
+
+FEATURES:
+ - Add `GreaterThanOrEqual` and `LessThanOrEqual` helper methods ([#53](https://github.com/hashicorp/go-version/pull/53))
+
+# 1.1.0 (Jan 07, 2019)
+
+FEATURES:
+ - Add `NewSemver` constructor ([#45](https://github.com/hashicorp/go-version/pull/45))
+
+# 1.0.0 (August 24, 2018)
+
+Initial release.
diff --git a/vendor/github.com/hashicorp/go-version/LICENSE b/vendor/github.com/hashicorp/go-version/LICENSE
index c33dcc7c..1409d6ab 100644
--- a/vendor/github.com/hashicorp/go-version/LICENSE
+++ b/vendor/github.com/hashicorp/go-version/LICENSE
@@ -1,3 +1,5 @@
+Copyright (c) 2014 HashiCorp, Inc.
+
Mozilla Public License, version 2.0
1. Definitions
diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md
index 851a337b..4b7806cd 100644
--- a/vendor/github.com/hashicorp/go-version/README.md
+++ b/vendor/github.com/hashicorp/go-version/README.md
@@ -1,5 +1,5 @@
# Versioning Library for Go
-[](https://circleci.com/gh/hashicorp/go-version/tree/master)
+
[](https://godoc.org/github.com/hashicorp/go-version)
go-version is a library for parsing versions and version constraints,
diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go
index d0557596..29bdc4d2 100644
--- a/vendor/github.com/hashicorp/go-version/constraint.go
+++ b/vendor/github.com/hashicorp/go-version/constraint.go
@@ -1,9 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package version
import (
"fmt"
- "reflect"
"regexp"
+ "sort"
"strings"
)
@@ -11,30 +14,40 @@ import (
// ">= 1.0".
type Constraint struct {
f constraintFunc
+ op operator
check *Version
original string
}
+func (c *Constraint) Equals(con *Constraint) bool {
+ return c.op == con.op && c.check.Equal(con.check)
+}
+
// Constraints is a slice of constraints. We make a custom type so that
// we can add methods to it.
type Constraints []*Constraint
type constraintFunc func(v, c *Version) bool
-var constraintOperators map[string]constraintFunc
+var constraintOperators map[string]constraintOperation
+
+type constraintOperation struct {
+ op operator
+ f constraintFunc
+}
var constraintRegexp *regexp.Regexp
func init() {
- constraintOperators = map[string]constraintFunc{
- "": constraintEqual,
- "=": constraintEqual,
- "!=": constraintNotEqual,
- ">": constraintGreaterThan,
- "<": constraintLessThan,
- ">=": constraintGreaterThanEqual,
- "<=": constraintLessThanEqual,
- "~>": constraintPessimistic,
+ constraintOperators = map[string]constraintOperation{
+ "": {op: equal, f: constraintEqual},
+ "=": {op: equal, f: constraintEqual},
+ "!=": {op: notEqual, f: constraintNotEqual},
+ ">": {op: greaterThan, f: constraintGreaterThan},
+ "<": {op: lessThan, f: constraintLessThan},
+ ">=": {op: greaterThanEqual, f: constraintGreaterThanEqual},
+ "<=": {op: lessThanEqual, f: constraintLessThanEqual},
+ "~>": {op: pessimistic, f: constraintPessimistic},
}
ops := make([]string, 0, len(constraintOperators))
@@ -66,6 +79,16 @@ func NewConstraint(v string) (Constraints, error) {
return Constraints(result), nil
}
+// MustConstraints is a helper that wraps a call to a function
+// returning (Constraints, error) and panics if error is non-nil.
+func MustConstraints(c Constraints, err error) Constraints {
+ if err != nil {
+ panic(err)
+ }
+
+ return c
+}
+
// Check tests if a version satisfies all the constraints.
func (cs Constraints) Check(v *Version) bool {
for _, c := range cs {
@@ -77,6 +100,56 @@ func (cs Constraints) Check(v *Version) bool {
return true
}
+// Equals compares Constraints with other Constraints
+// for equality. This may not represent logical equivalence
+// of compared constraints.
+// e.g. even though '>0.1,>0.2' is logically equivalent
+// to '>0.2' it is *NOT* treated as equal.
+//
+// Missing operator is treated as equal to '=', whitespaces
+// are ignored and constraints are sorted before comaparison.
+func (cs Constraints) Equals(c Constraints) bool {
+ if len(cs) != len(c) {
+ return false
+ }
+
+ // make copies to retain order of the original slices
+ left := make(Constraints, len(cs))
+ copy(left, cs)
+ sort.Stable(left)
+ right := make(Constraints, len(c))
+ copy(right, c)
+ sort.Stable(right)
+
+ // compare sorted slices
+ for i, con := range left {
+ if !con.Equals(right[i]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (cs Constraints) Len() int {
+ return len(cs)
+}
+
+func (cs Constraints) Less(i, j int) bool {
+ if cs[i].op < cs[j].op {
+ return true
+ }
+ if cs[i].op > cs[j].op {
+ return false
+ }
+
+ return cs[i].check.LessThan(cs[j].check)
+}
+
+func (cs Constraints) Swap(i, j int) {
+ cs[i], cs[j] = cs[j], cs[i]
+}
+
// Returns the string format of the constraints
func (cs Constraints) String() string {
csStr := make([]string, len(cs))
@@ -92,6 +165,12 @@ func (c *Constraint) Check(v *Version) bool {
return c.f(v, c.check)
}
+// Prerelease returns true if the version underlying this constraint
+// contains a prerelease field.
+func (c *Constraint) Prerelease() bool {
+ return len(c.check.Prerelease()) > 0
+}
+
func (c *Constraint) String() string {
return c.original
}
@@ -107,8 +186,11 @@ func parseSingle(v string) (*Constraint, error) {
return nil, err
}
+ cop := constraintOperators[matches[1]]
+
return &Constraint{
- f: constraintOperators[matches[1]],
+ f: cop.f,
+ op: cop.op,
check: check,
original: v,
}, nil
@@ -119,7 +201,7 @@ func prereleaseCheck(v, c *Version) bool {
case cPre && vPre:
// A constraint with a pre-release can only match a pre-release version
// with the same base segments.
- return reflect.DeepEqual(c.Segments64(), v.Segments64())
+ return v.equalSegments(c)
case !cPre && vPre:
// A constraint without a pre-release can only match a version without a
@@ -138,6 +220,18 @@ func prereleaseCheck(v, c *Version) bool {
// Constraint functions
//-------------------------------------------------------------------
+type operator rune
+
+const (
+ equal operator = '='
+ notEqual operator = '≠'
+ greaterThan operator = '>'
+ lessThan operator = '<'
+ greaterThanEqual operator = '≥'
+ lessThanEqual operator = '≤'
+ pessimistic operator = '~'
+)
+
func constraintEqual(v, c *Version) bool {
return v.Equal(c)
}
diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go
index 09703e8e..7c683c28 100644
--- a/vendor/github.com/hashicorp/go-version/version.go
+++ b/vendor/github.com/hashicorp/go-version/version.go
@@ -1,9 +1,12 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package version
import (
"bytes"
+ "database/sql/driver"
"fmt"
- "reflect"
"regexp"
"strconv"
"strings"
@@ -64,7 +67,6 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
}
segmentsStr := strings.Split(matches[1], ".")
segments := make([]int64, len(segmentsStr))
- si := 0
for i, str := range segmentsStr {
val, err := strconv.ParseInt(str, 10, 64)
if err != nil {
@@ -72,8 +74,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
"Error parsing version: %s", err)
}
- segments[i] = int64(val)
- si++
+ segments[i] = val
}
// Even though we could support more than three segments, if we
@@ -92,7 +93,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) {
metadata: matches[10],
pre: pre,
segments: segments,
- si: si,
+ si: len(segmentsStr),
original: v,
}, nil
}
@@ -119,11 +120,8 @@ func (v *Version) Compare(other *Version) int {
return 0
}
- segmentsSelf := v.Segments64()
- segmentsOther := other.Segments64()
-
// If the segments are the same, we must compare on prerelease info
- if reflect.DeepEqual(segmentsSelf, segmentsOther) {
+ if v.equalSegments(other) {
preSelf := v.Prerelease()
preOther := other.Prerelease()
if preSelf == "" && preOther == "" {
@@ -139,6 +137,8 @@ func (v *Version) Compare(other *Version) int {
return comparePrereleases(preSelf, preOther)
}
+ segmentsSelf := v.Segments64()
+ segmentsOther := other.Segments64()
// Get the highest specificity (hS), or if they're equal, just use segmentSelf length
lenSelf := len(segmentsSelf)
lenOther := len(segmentsOther)
@@ -162,7 +162,7 @@ func (v *Version) Compare(other *Version) int {
// this means Other had the lower specificity
// Check to see if the remaining segments in Self are all zeros -
if !allZero(segmentsSelf[i:]) {
- //if not, it means that Self has to be greater than Other
+ // if not, it means that Self has to be greater than Other
return 1
}
break
@@ -182,6 +182,21 @@ func (v *Version) Compare(other *Version) int {
return 0
}
+func (v *Version) equalSegments(other *Version) bool {
+ segmentsSelf := v.Segments64()
+ segmentsOther := other.Segments64()
+
+ if len(segmentsSelf) != len(segmentsOther) {
+ return false
+ }
+ for i, v := range segmentsSelf {
+ if v != segmentsOther[i] {
+ return false
+ }
+ }
+ return true
+}
+
func allZero(segs []int64) bool {
for _, s := range segs {
if s != 0 {
@@ -278,6 +293,14 @@ func comparePrereleases(v string, other string) int {
return 0
}
+// Core returns a new version constructed from only the MAJOR.MINOR.PATCH
+// segments of the version, without prerelease or metadata.
+func (v *Version) Core() *Version {
+ segments := v.Segments64()
+ segmentsOnly := fmt.Sprintf("%d.%d.%d", segments[0], segments[1], segments[2])
+ return Must(NewVersion(segmentsOnly))
+}
+
// Equal tests if two versions are equal.
func (v *Version) Equal(o *Version) bool {
if v == nil || o == nil {
@@ -382,3 +405,37 @@ func (v *Version) String() string {
func (v *Version) Original() string {
return v.original
}
+
+// UnmarshalText implements encoding.TextUnmarshaler interface.
+func (v *Version) UnmarshalText(b []byte) error {
+ temp, err := NewVersion(string(b))
+ if err != nil {
+ return err
+ }
+
+ *v = *temp
+
+ return nil
+}
+
+// MarshalText implements encoding.TextMarshaler interface.
+func (v *Version) MarshalText() ([]byte, error) {
+ return []byte(v.String()), nil
+}
+
+// Scan implements the sql.Scanner interface.
+func (v *Version) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case string:
+ return v.UnmarshalText([]byte(src))
+ case nil:
+ return nil
+ default:
+ return fmt.Errorf("cannot scan %T as Version", src)
+ }
+}
+
+// Value implements the driver.Valuer interface.
+func (v *Version) Value() (driver.Value, error) {
+ return v.String(), nil
+}
diff --git a/vendor/github.com/hashicorp/go-version/version_collection.go b/vendor/github.com/hashicorp/go-version/version_collection.go
index cc888d43..83547fe1 100644
--- a/vendor/github.com/hashicorp/go-version/version_collection.go
+++ b/vendor/github.com/hashicorp/go-version/version_collection.go
@@ -1,3 +1,6 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
package version
// Collection is a type that implements the sort.Interface interface
diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md
index 244ee19c..5125c1f2 100644
--- a/vendor/github.com/klauspost/compress/README.md
+++ b/vendor/github.com/klauspost/compress/README.md
@@ -7,7 +7,7 @@ This package provides various compression algorithms.
* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
-* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped requests efficiently.
+* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.
[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
@@ -26,6 +26,22 @@ This package will support the current Go version and 2 versions back.
Use the links above for more information on each.
# changelog
+* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
+ * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).
+
+* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
+ * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
+ * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
+
+* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
+ * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
+ * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
+ * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
+ * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
+ * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
+ * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
+ * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
+ * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
* Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
@@ -36,6 +52,9 @@ Use the links above for more information on each.
* flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
* flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
+
+ See changes to v1.17.x
+
* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
* zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
* s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
@@ -102,7 +121,8 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
* s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
* flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
* gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
-
+
+
See changes to v1.16.x
@@ -589,7 +609,7 @@ While the release has been extensively tested, it is recommended to testing when
# deflate usage
-The packages are drop-in replacements for standard libraries. Simply replace the import path to use them:
+The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:
Typical speed is about 2x of the standard library packages.
@@ -600,17 +620,15 @@ Typical speed is about 2x of the standard library packages.
| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
-* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
+You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
-You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
-
-The packages contains the same as the standard library, so you can use the godoc for that: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
+The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
Currently there is only minor speedup on decompression (mostly CRC32 calculation).
Memory usage is typically 1MB for a Writer. stdlib is in the same range.
If you expect to have a lot of concurrently allocated Writers consider using
-the stateless compress described below.
+the stateless compression described below.
For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
@@ -669,3 +687,7 @@ Here are other packages of good quality and pure Go (no cgo wrappers or autoconv
# license
This code is licensed under the same conditions as the original Go code. See LICENSE file.
+
+
+
+
diff --git a/vendor/github.com/klauspost/compress/fse/bitwriter.go b/vendor/github.com/klauspost/compress/fse/bitwriter.go
index e82fa3bb..d58b3fe4 100644
--- a/vendor/github.com/klauspost/compress/fse/bitwriter.go
+++ b/vendor/github.com/klauspost/compress/fse/bitwriter.go
@@ -143,7 +143,7 @@ func (b *bitWriter) flush32() {
// flushAlign will flush remaining full bytes and align to next byte boundary.
func (b *bitWriter) flushAlign() {
nbBytes := (b.nBits + 7) >> 3
- for i := uint8(0); i < nbBytes; i++ {
+ for i := range nbBytes {
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
}
b.nBits = 0
diff --git a/vendor/github.com/klauspost/compress/fse/compress.go b/vendor/github.com/klauspost/compress/fse/compress.go
index 074018d8..8c8baa4f 100644
--- a/vendor/github.com/klauspost/compress/fse/compress.go
+++ b/vendor/github.com/klauspost/compress/fse/compress.go
@@ -396,7 +396,7 @@ func (s *Scratch) buildCTable() error {
if v > largeLimit {
s.zeroBits = true
}
- for nbOccurrences := int16(0); nbOccurrences < v; nbOccurrences++ {
+ for range v {
tableSymbol[position] = symbol
position = (position + step) & tableMask
for position > highThreshold {
diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
index 0ebc9aaa..41db94cd 100644
--- a/vendor/github.com/klauspost/compress/huff0/bitwriter.go
+++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
@@ -85,7 +85,7 @@ func (b *bitWriter) flush32() {
// flushAlign will flush remaining full bytes and align to next byte boundary.
func (b *bitWriter) flushAlign() {
nbBytes := (b.nBits + 7) >> 3
- for i := uint8(0); i < nbBytes; i++ {
+ for i := range nbBytes {
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
}
b.nBits = 0
diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go
index 84aa3d12..a97cf1b5 100644
--- a/vendor/github.com/klauspost/compress/huff0/compress.go
+++ b/vendor/github.com/klauspost/compress/huff0/compress.go
@@ -276,7 +276,7 @@ func (s *Scratch) compress4X(src []byte) ([]byte, error) {
offsetIdx := len(s.Out)
s.Out = append(s.Out, sixZeros[:]...)
- for i := 0; i < 4; i++ {
+ for i := range 4 {
toDo := src
if len(toDo) > segmentSize {
toDo = toDo[:segmentSize]
@@ -312,7 +312,7 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
segmentSize := (len(src) + 3) / 4
var wg sync.WaitGroup
wg.Add(4)
- for i := 0; i < 4; i++ {
+ for i := range 4 {
toDo := src
if len(toDo) > segmentSize {
toDo = toDo[:segmentSize]
@@ -326,7 +326,7 @@ func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
}(i)
}
wg.Wait()
- for i := 0; i < 4; i++ {
+ for i := range 4 {
o := s.tmpOut[i]
if len(o) > math.MaxUint16 {
// We cannot store the size in the jump table
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
index 0f56b02d..7d0efa88 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -626,7 +626,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
var br [4]bitReaderBytes
start := 6
- for i := 0; i < 3; i++ {
+ for i := range 3 {
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
if start+length >= len(src) {
return nil, errors.New("truncated input (or invalid offset)")
@@ -798,10 +798,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
remainBytes := dstEvery - (decoded / 4)
for i := range br {
offset := dstEvery * i
- endsAt := offset + remainBytes
- if endsAt > len(out) {
- endsAt = len(out)
- }
+ endsAt := min(offset+remainBytes, len(out))
br := &br[i]
bitsLeft := br.remaining()
for bitsLeft > 0 {
@@ -864,7 +861,7 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
var br [4]bitReaderBytes
start := 6
- for i := 0; i < 3; i++ {
+ for i := range 3 {
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
if start+length >= len(src) {
return nil, errors.New("truncated input (or invalid offset)")
@@ -1035,10 +1032,7 @@ func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
remainBytes := dstEvery - (decoded / 4)
for i := range br {
offset := dstEvery * i
- endsAt := offset + remainBytes
- if endsAt > len(out) {
- endsAt = len(out)
- }
+ endsAt := min(offset+remainBytes, len(out))
br := &br[i]
bitsLeft := br.remaining()
for bitsLeft > 0 {
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
index ba7e8e6b..99ddd4af 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
@@ -58,7 +58,7 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
var br [4]bitReaderShifted
// Decode "jump table"
start := 6
- for i := 0; i < 3; i++ {
+ for i := range 3 {
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
if start+length >= len(src) {
return nil, errors.New("truncated input (or invalid offset)")
@@ -109,10 +109,7 @@ func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
remainBytes := dstEvery - (decoded / 4)
for i := range br {
offset := dstEvery * i
- endsAt := offset + remainBytes
- if endsAt > len(out) {
- endsAt = len(out)
- }
+ endsAt := min(offset+remainBytes, len(out))
br := &br[i]
bitsLeft := br.remaining()
for bitsLeft > 0 {
diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go
index 77ecd68e..67d9e05b 100644
--- a/vendor/github.com/klauspost/compress/huff0/huff0.go
+++ b/vendor/github.com/klauspost/compress/huff0/huff0.go
@@ -201,7 +201,7 @@ func (c cTable) write(s *Scratch) error {
for i := range hist[:16] {
hist[i] = 0
}
- for n := uint8(0); n < maxSymbolValue; n++ {
+ for n := range maxSymbolValue {
v := bitsToWeight[c[n].nBits] & 15
huffWeight[n] = v
hist[v]++
@@ -271,7 +271,7 @@ func (c cTable) estTableSize(s *Scratch) (sz int, err error) {
for i := range hist[:16] {
hist[i] = 0
}
- for n := uint8(0); n < maxSymbolValue; n++ {
+ for n := range maxSymbolValue {
v := bitsToWeight[c[n].nBits] & 15
huffWeight[n] = v
hist[v]++
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
index 0cfb5c0e..4f2a0d8c 100644
--- a/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
@@ -37,6 +37,6 @@ func Store32(b []byte, v uint32) {
}
// Store64 will store v at b.
-func Store64(b []byte, v uint64) {
- binary.LittleEndian.PutUint64(b, v)
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ binary.LittleEndian.PutUint64(b[i:], v)
}
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
index ada45cd9..218a38bc 100644
--- a/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
@@ -38,18 +38,15 @@ func Load64[I Indexer](b []byte, i I) uint64 {
// Store16 will store v at b.
func Store16(b []byte, v uint16) {
- //binary.LittleEndian.PutUint16(b, v)
*(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v
}
// Store32 will store v at b.
func Store32(b []byte, v uint32) {
- //binary.LittleEndian.PutUint32(b, v)
*(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v
}
-// Store64 will store v at b.
-func Store64(b []byte, v uint64) {
- //binary.LittleEndian.PutUint64(b, v)
- *(*uint64)(unsafe.Pointer(unsafe.SliceData(b))) = v
+// Store64 will store v at b[i:].
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) = v
}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode.go b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
index 40796a49..a2c82fcd 100644
--- a/vendor/github.com/klauspost/compress/internal/snapref/decode.go
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
@@ -209,7 +209,7 @@ func (r *Reader) fill() error {
if !r.readFull(r.buf[:len(magicBody)], false) {
return r.err
}
- for i := 0; i < len(magicBody); i++ {
+ for i := range len(magicBody) {
if r.buf[i] != magicBody[i] {
r.err = ErrCorrupt
return r.err
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode.go b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
index 13c6040a..860a9941 100644
--- a/vendor/github.com/klauspost/compress/internal/snapref/encode.go
+++ b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
@@ -20,8 +20,10 @@ import (
func Encode(dst, src []byte) []byte {
if n := MaxEncodedLen(len(src)); n < 0 {
panic(ErrTooLarge)
- } else if len(dst) < n {
+ } else if cap(dst) < n {
dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
}
// The block starts with the varint-encoded length of the decompressed bytes.
diff --git a/vendor/github.com/klauspost/compress/zstd/bitwriter.go b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
index 1952f175..b22b297e 100644
--- a/vendor/github.com/klauspost/compress/zstd/bitwriter.go
+++ b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
@@ -88,7 +88,7 @@ func (b *bitWriter) flush32() {
// flushAlign will flush remaining full bytes and align to next byte boundary.
func (b *bitWriter) flushAlign() {
nbBytes := (b.nBits + 7) >> 3
- for i := uint8(0); i < nbBytes; i++ {
+ for i := range nbBytes {
b.out = append(b.out, byte(b.bitContainer>>(i*8)))
}
b.nBits = 0
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index 0dd742fd..2329e996 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -54,11 +54,11 @@ const (
)
var (
- huffDecoderPool = sync.Pool{New: func() interface{} {
+ huffDecoderPool = sync.Pool{New: func() any {
return &huff0.Scratch{}
}}
- fseDecoderPool = sync.Pool{New: func() interface{} {
+ fseDecoderPool = sync.Pool{New: func() any {
return &fseDecoder{}
}}
)
@@ -553,7 +553,7 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
if compMode&3 != 0 {
return errors.New("corrupt block: reserved bits not zero")
}
- for i := uint(0); i < 3; i++ {
+ for i := range uint(3) {
mode := seqCompMode((compMode >> (6 - i*2)) & 3)
if debugDecoder {
println("Table", tableIndex(i), "is", mode)
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index ea2a1937..c7e500f0 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -39,9 +39,6 @@ type Decoder struct {
frame *frameDec
- // Custom dictionaries.
- dicts map[uint32]*dict
-
// streamWg is the waitgroup for all streams
streamWg sync.WaitGroup
}
@@ -101,12 +98,10 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
d.current.err = ErrDecoderNilInput
}
- // Transfer option dicts.
- d.dicts = make(map[uint32]*dict, len(d.o.dicts))
- for _, dc := range d.o.dicts {
- d.dicts[dc.id] = dc
+ // Initialize dict map if needed.
+ if d.o.dicts == nil {
+ d.o.dicts = make(map[uint32]*dict)
}
- d.o.dicts = nil
// Create decoders
d.decoders = make(chan *blockDec, d.o.concurrent)
@@ -238,6 +233,21 @@ func (d *Decoder) Reset(r io.Reader) error {
return nil
}
+// ResetWithOptions will reset the decoder and apply the given options
+// for the next stream or DecodeAll operation.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (d *Decoder) ResetWithOptions(r io.Reader, opts ...DOption) error {
+ d.o.resetOpt = true
+ defer func() { d.o.resetOpt = false }()
+ for _, o := range opts {
+ if err := o(&d.o); err != nil {
+ return err
+ }
+ }
+ return d.Reset(r)
+}
+
// drainOutput will drain the output until errEndOfStream is sent.
func (d *Decoder) drainOutput() {
if d.current.cancel != nil {
@@ -373,11 +383,9 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
if cap(dst) == 0 && !d.o.limitToCap {
// Allocate len(input) * 2 by default if nothing is provided
// and we didn't get frame content size.
- size := len(input) * 2
- // Cap to 1 MB.
- if size > 1<<20 {
- size = 1 << 20
- }
+ size := min(
+ // Cap to 1 MB.
+ len(input)*2, 1<<20)
if uint64(size) > d.o.maxDecodedSize {
size = int(d.o.maxDecodedSize)
}
@@ -932,7 +940,7 @@ decodeStream:
}
func (d *Decoder) setDict(frame *frameDec) (err error) {
- dict, ok := d.dicts[frame.DictionaryID]
+ dict, ok := d.o.dicts[frame.DictionaryID]
if ok {
if debugDecoder {
println("setting dict", frame.DictionaryID)
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
index 774c5f00..537627a0 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
@@ -20,10 +20,11 @@ type decoderOptions struct {
concurrent int
maxDecodedSize uint64
maxWindowSize uint64
- dicts []*dict
+ dicts map[uint32]*dict
ignoreChecksum bool
limitToCap bool
decodeBufsBelow int
+ resetOpt bool
}
func (o *decoderOptions) setDefault() {
@@ -42,8 +43,15 @@ func (o *decoderOptions) setDefault() {
// WithDecoderLowmem will set whether to use a lower amount of memory,
// but possibly have to allocate more while running.
+// Cannot be changed with ResetWithOptions.
func WithDecoderLowmem(b bool) DOption {
- return func(o *decoderOptions) error { o.lowMem = b; return nil }
+ return func(o *decoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithDecoderLowmem cannot be changed on Reset")
+ }
+ o.lowMem = b
+ return nil
+ }
}
// WithDecoderConcurrency sets the number of created decoders.
@@ -53,18 +61,23 @@ func WithDecoderLowmem(b bool) DOption {
// inflight blocks.
// When decoding streams and setting maximum to 1,
// no async decoding will be done.
+// The value supplied must be at least 0.
// When a value of 0 is provided GOMAXPROCS will be used.
// By default this will be set to 4 or GOMAXPROCS, whatever is lower.
+// Cannot be changed with ResetWithOptions.
func WithDecoderConcurrency(n int) DOption {
return func(o *decoderOptions) error {
if n < 0 {
- return errors.New("concurrency must be at least 1")
+ return errors.New("concurrency must be at least 0")
}
+ newVal := n
if n == 0 {
- o.concurrent = runtime.GOMAXPROCS(0)
- } else {
- o.concurrent = n
+ newVal = runtime.GOMAXPROCS(0)
}
+ if o.resetOpt && newVal != o.concurrent {
+ return errors.New("WithDecoderConcurrency cannot be changed on Reset")
+ }
+ o.concurrent = newVal
return nil
}
}
@@ -73,6 +86,7 @@ func WithDecoderConcurrency(n int) DOption {
// non-streaming operations or maximum window size for streaming operations.
// This can be used to control memory usage of potentially hostile content.
// Maximum is 1 << 63 bytes. Default is 64GiB.
+// Can be changed with ResetWithOptions.
func WithDecoderMaxMemory(n uint64) DOption {
return func(o *decoderOptions) error {
if n == 0 {
@@ -92,16 +106,20 @@ func WithDecoderMaxMemory(n uint64) DOption {
// "zstd --train" from the Zstandard reference implementation.
//
// If several dictionaries with the same ID are provided, the last one will be used.
+// Can be changed with ResetWithOptions.
//
// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
func WithDecoderDicts(dicts ...[]byte) DOption {
return func(o *decoderOptions) error {
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
for _, b := range dicts {
d, err := loadDict(b)
if err != nil {
return err
}
- o.dicts = append(o.dicts, d)
+ o.dicts[d.id] = d
}
return nil
}
@@ -109,12 +127,16 @@ func WithDecoderDicts(dicts ...[]byte) DOption {
// WithDecoderDictRaw registers a dictionary that may be used by the decoder.
// The slice content can be arbitrary data.
+// Can be changed with ResetWithOptions.
func WithDecoderDictRaw(id uint32, content []byte) DOption {
return func(o *decoderOptions) error {
if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
}
- o.dicts = append(o.dicts, &dict{id: id, content: content, offsets: [3]int{1, 4, 8}})
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
+ o.dicts[id] = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
return nil
}
}
@@ -124,6 +146,7 @@ func WithDecoderDictRaw(id uint32, content []byte) DOption {
// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.
// If WithDecoderMaxMemory is set to a lower value, that will be used.
// Default is 512MB, Maximum is ~3.75 TB as per zstandard spec.
+// Can be changed with ResetWithOptions.
func WithDecoderMaxWindow(size uint64) DOption {
return func(o *decoderOptions) error {
if size < MinWindowSize {
@@ -141,6 +164,7 @@ func WithDecoderMaxWindow(size uint64) DOption {
// or any size set in WithDecoderMaxMemory.
// This can be used to limit decoding to a specific maximum output size.
// Disabled by default.
+// Can be changed with ResetWithOptions.
func WithDecodeAllCapLimit(b bool) DOption {
return func(o *decoderOptions) error {
o.limitToCap = b
@@ -153,17 +177,37 @@ func WithDecodeAllCapLimit(b bool) DOption {
// This typically uses less allocations but will have the full decompressed object in memory.
// Note that DecodeAllCapLimit will disable this, as well as giving a size of 0 or less.
// Default is 128KiB.
+// Cannot be changed with ResetWithOptions.
func WithDecodeBuffersBelow(size int) DOption {
return func(o *decoderOptions) error {
+ if o.resetOpt && size != o.decodeBufsBelow {
+ return errors.New("WithDecodeBuffersBelow cannot be changed on Reset")
+ }
o.decodeBufsBelow = size
return nil
}
}
// IgnoreChecksum allows to forcibly ignore checksum checking.
+// Can be changed with ResetWithOptions.
func IgnoreChecksum(b bool) DOption {
return func(o *decoderOptions) error {
o.ignoreChecksum = b
return nil
}
}
+
+// WithDecoderDictDelete removes dictionaries by ID.
+// If no ids are passed, all dictionaries are deleted.
+// Should be used with ResetWithOptions.
+func WithDecoderDictDelete(ids ...uint32) DOption {
+ return func(o *decoderOptions) error {
+ if len(ids) == 0 {
+ clear(o.dicts)
+ }
+ for _, id := range ids {
+ delete(o.dicts, id)
+ }
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
index b7b83164..2ffbfdf3 100644
--- a/vendor/github.com/klauspost/compress/zstd/dict.go
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -194,17 +194,17 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
hist := o.History
contents := o.Contents
debug := o.DebugOut != nil
- println := func(args ...interface{}) {
+ println := func(args ...any) {
if o.DebugOut != nil {
fmt.Fprintln(o.DebugOut, args...)
}
}
- printf := func(s string, args ...interface{}) {
+ printf := func(s string, args ...any) {
if o.DebugOut != nil {
fmt.Fprintf(o.DebugOut, s, args...)
}
}
- print := func(args ...interface{}) {
+ print := func(args ...any) {
if o.DebugOut != nil {
fmt.Fprint(o.DebugOut, args...)
}
@@ -424,16 +424,10 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
}
// Literal table
- avgSize := litTotal
- if avgSize > huff0.BlockSizeMax/2 {
- avgSize = huff0.BlockSizeMax / 2
- }
+ avgSize := min(litTotal, huff0.BlockSizeMax/2)
huffBuff := make([]byte, 0, avgSize)
// Target size
- div := litTotal / avgSize
- if div < 1 {
- div = 1
- }
+ div := max(litTotal/avgSize, 1)
if debug {
println("Huffman weights:")
}
@@ -454,7 +448,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
huffBuff = append(huffBuff, 255)
}
scratch := &huff0.Scratch{TableLog: 11}
- for tries := 0; tries < 255; tries++ {
+ for tries := range 255 {
scratch = &huff0.Scratch{TableLog: 11}
_, _, err = huff0.Compress1X(huffBuff, scratch)
if err == nil {
@@ -471,7 +465,7 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
// Bail out.... Just generate something
huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...)
- for i := 0; i < 128; i++ {
+ for i := range 128 {
huffBuff = append(huffBuff, byte(i))
}
continue
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go
index 7d250c67..c1192ec3 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_base.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go
@@ -8,7 +8,7 @@ import (
)
const (
- dictShardBits = 6
+ dictShardBits = 7
)
type fastBase struct {
@@ -41,11 +41,9 @@ func (e *fastBase) AppendCRC(dst []byte) []byte {
// or a window size small enough to contain the input size, if > 0.
func (e *fastBase) WindowSize(size int64) int32 {
if size > 0 && size < int64(e.maxMatchOff) {
- b := int32(1) << uint(bits.Len(uint(size)))
- // Keep minimum window.
- if b < 1024 {
- b = 1024
- }
+ b := max(
+ // Keep minimum window.
+ int32(1)< tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength {
s--
offset--
@@ -382,10 +377,7 @@ encodeLoop:
nextEmit = s
// Index skipped...
- end := s
- if s > sLimit+4 {
- end = sLimit + 4
- }
+ end := min(s, sLimit+4)
off := index0 + e.cur
for index0 < end {
cv0 := load6432(src, index0)
@@ -444,10 +436,7 @@ encodeLoop:
nextEmit = s
// Index old s + 1 -> s - 1 or sLimit
- end := s
- if s > sLimit-4 {
- end = sLimit - 4
- }
+ end := min(s, sLimit-4)
off := index0 + e.cur
for index0 < end {
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go
index 84a79fde..85dcd28c 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_better.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go
@@ -190,10 +190,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -252,10 +249,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -480,10 +474,7 @@ encodeLoop:
l := matched
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
@@ -719,10 +710,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -783,10 +771,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -1005,10 +990,7 @@ encodeLoop:
l := matched
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
index d36be7bd..cf8cad00 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -13,7 +13,7 @@ const (
dFastLongLen = 8 // Bytes used for table hash
dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits) // Number of shards in the table
- dLongTableShardSize = dFastLongTableSize / tableShardCnt // Size of an individual shard
+ dLongTableShardSize = dFastLongTableSize / dLongTableShardCnt // Size of an individual shard
dFastShortTableBits = tableBits // Bits used in the short match table
dFastShortTableSize = 1 << dFastShortTableBits // Size of the table
@@ -149,10 +149,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -266,10 +263,7 @@ encodeLoop:
l := e.matchlen(s+4, t+4, src) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
@@ -462,10 +456,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
repIndex--
start--
@@ -576,10 +567,7 @@ encodeLoop:
l := int32(matchLen(src[s+4:], src[t+4:])) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
s--
t--
@@ -809,10 +797,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
repIndex--
start--
@@ -927,10 +912,7 @@ encodeLoop:
l := e.matchlen(s+4, t+4, src) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
index f45a3da7..9180a3a5 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -143,10 +143,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- sMin := s - e.maxMatchOff
- if sMin < 0 {
- sMin = 0
- }
+ sMin := max(s-e.maxMatchOff, 0)
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
repIndex--
start--
@@ -223,10 +220,7 @@ encodeLoop:
l := e.matchlen(s+4, t+4, src) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
@@ -387,10 +381,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- sMin := s - e.maxMatchOff
- if sMin < 0 {
- sMin = 0
- }
+ sMin := max(s-e.maxMatchOff, 0)
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
repIndex--
start--
@@ -469,10 +460,7 @@ encodeLoop:
l := e.matchlen(s+4, t+4, src) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
s--
t--
@@ -655,10 +643,7 @@ encodeLoop:
// and have to do special offset treatment.
startLimit := nextEmit + 1
- sMin := s - e.maxMatchOff
- if sMin < 0 {
- sMin = 0
- }
+ sMin := max(s-e.maxMatchOff, 0)
for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
repIndex--
start--
@@ -735,10 +720,7 @@ encodeLoop:
l := e.matchlen(s+4, t+4, src) + 4
// Extend backwards
- tMin := s - e.maxMatchOff
- if tMin < 0 {
- tMin = 0
- }
+ tMin := max(s-e.maxMatchOff, 0)
for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
s--
t--
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index 8f8223cd..19e730ac 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -131,6 +131,22 @@ func (e *Encoder) Reset(w io.Writer) {
s.frameContentSize = 0
}
+// ResetWithOptions will re-initialize the writer and apply the given options
+// as a new, independent stream.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error {
+ e.o.resetOpt = true
+ defer func() { e.o.resetOpt = false }()
+ for _, o := range opts {
+ if err := o(&e.o); err != nil {
+ return err
+ }
+ }
+ e.Reset(w)
+ return nil
+}
+
// ResetContentSize will reset and set a content size for the next stream.
// If the bytes written does not match the size given an error will be returned
// when calling Close().
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
index 20671dcb..8e0f5cac 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -14,6 +14,7 @@ type EOption func(*encoderOptions) error
// options retains accumulated state of multiple options.
type encoderOptions struct {
+ resetOpt bool
concurrent int
level EncoderLevel
single *bool
@@ -71,19 +72,28 @@ func (o encoderOptions) encoder() encoder {
// WithEncoderCRC will add CRC value to output.
// Output will be 4 bytes larger.
+// Can be changed with ResetWithOptions.
func WithEncoderCRC(b bool) EOption {
return func(o *encoderOptions) error { o.crc = b; return nil }
}
// WithEncoderConcurrency will set the concurrency,
// meaning the maximum number of encoders to run concurrently.
-// The value supplied must be at least 1.
+// The value supplied must be at least 0.
+// When a value of 0 is provided GOMAXPROCS will be used.
// For streams, setting a value of 1 will disable async compression.
// By default this will be set to GOMAXPROCS.
+// Cannot be changed with ResetWithOptions.
func WithEncoderConcurrency(n int) EOption {
return func(o *encoderOptions) error {
- if n <= 0 {
- return fmt.Errorf("concurrency must be at least 1")
+ if n < 0 {
+ return errors.New("concurrency must at least 0")
+ }
+ if n == 0 {
+ n = runtime.GOMAXPROCS(0)
+ }
+ if o.resetOpt && n != o.concurrent {
+ return errors.New("WithEncoderConcurrency cannot be changed on Reset")
}
o.concurrent = n
return nil
@@ -95,6 +105,7 @@ func WithEncoderConcurrency(n int) EOption {
// A larger value will enable better compression but allocate more memory and,
// for above-default values, take considerably longer.
// The default value is determined by the compression level and max 8MB.
+// Cannot be changed with ResetWithOptions.
func WithWindowSize(n int) EOption {
return func(o *encoderOptions) error {
switch {
@@ -105,6 +116,9 @@ func WithWindowSize(n int) EOption {
case (n & (n - 1)) != 0:
return errors.New("window size must be a power of 2")
}
+ if o.resetOpt && n != o.windowSize {
+ return errors.New("WithWindowSize cannot be changed on Reset")
+ }
o.windowSize = n
o.customWindow = true
@@ -122,6 +136,7 @@ func WithWindowSize(n int) EOption {
// n must be > 0 and <= 1GB, 1<<30 bytes.
// The padded area will be filled with data from crypto/rand.Reader.
// If `EncodeAll` is used with data already in the destination, the total size will be multiple of this.
+// Can be changed with ResetWithOptions.
func WithEncoderPadding(n int) EOption {
return func(o *encoderOptions) error {
if n <= 0 {
@@ -215,12 +230,16 @@ func (e EncoderLevel) String() string {
}
// WithEncoderLevel specifies a predefined compression level.
+// Cannot be changed with ResetWithOptions.
func WithEncoderLevel(l EncoderLevel) EOption {
return func(o *encoderOptions) error {
switch {
case l <= speedNotSet || l >= speedLast:
return fmt.Errorf("unknown encoder level")
}
+ if o.resetOpt && l != o.level {
+ return errors.New("WithEncoderLevel cannot be changed on Reset")
+ }
o.level = l
if !o.customWindow {
switch o.level {
@@ -248,6 +267,7 @@ func WithEncoderLevel(l EncoderLevel) EOption {
// WithZeroFrames will encode 0 length input as full frames.
// This can be needed for compatibility with zstandard usage,
// but is not needed for this package.
+// Can be changed with ResetWithOptions.
func WithZeroFrames(b bool) EOption {
return func(o *encoderOptions) error {
o.fullZero = b
@@ -259,6 +279,7 @@ func WithZeroFrames(b bool) EOption {
// Disabling this will skip incompressible data faster, but in cases with no matches but
// skewed character distribution compression is lost.
// Default value depends on the compression level selected.
+// Can be changed with ResetWithOptions.
func WithAllLitEntropyCompression(b bool) EOption {
return func(o *encoderOptions) error {
o.customALEntropy = true
@@ -270,6 +291,7 @@ func WithAllLitEntropyCompression(b bool) EOption {
// WithNoEntropyCompression will always skip entropy compression of literals.
// This can be useful if content has matches, but unlikely to benefit from entropy
// compression. Usually the slight speed improvement is not worth enabling this.
+// Can be changed with ResetWithOptions.
func WithNoEntropyCompression(b bool) EOption {
return func(o *encoderOptions) error {
o.noEntropy = b
@@ -287,6 +309,7 @@ func WithNoEntropyCompression(b bool) EOption {
// This is only a recommendation, each decoder is free to support higher or lower limits, depending on local limitations.
// If this is not specified, block encodes will automatically choose this based on the input size and the window size.
// This setting has no effect on streamed encodes.
+// Can be changed with ResetWithOptions.
func WithSingleSegment(b bool) EOption {
return func(o *encoderOptions) error {
o.single = &b
@@ -298,8 +321,12 @@ func WithSingleSegment(b bool) EOption {
// slower encoding speed.
// This will not change the window size which is the primary function for reducing
// memory usage. See WithWindowSize.
+// Cannot be changed with ResetWithOptions.
func WithLowerEncoderMem(b bool) EOption {
return func(o *encoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithLowerEncoderMem cannot be changed on Reset")
+ }
o.lowMem = b
return nil
}
@@ -311,6 +338,7 @@ func WithLowerEncoderMem(b bool) EOption {
// "zstd --train" from the Zstandard reference implementation.
//
// The encoder *may* choose to use no dictionary instead for certain payloads.
+// Can be changed with ResetWithOptions.
//
// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
func WithEncoderDict(dict []byte) EOption {
@@ -328,6 +356,7 @@ func WithEncoderDict(dict []byte) EOption {
//
// The slice content may contain arbitrary data. It will be used as an initial
// history.
+// Can be changed with ResetWithOptions.
func WithEncoderDictRaw(id uint32, content []byte) EOption {
return func(o *encoderOptions) error {
if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
@@ -337,3 +366,12 @@ func WithEncoderDictRaw(id uint32, content []byte) EOption {
return nil
}
}
+
+// WithEncoderDictDelete clears the dictionary, so no dictionary will be used.
+// Should be used with ResetWithOptions.
+func WithEncoderDictDelete() EOption {
+ return func(o *encoderOptions) error {
+ o.dict = nil
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go
index e47af66e..d88f067e 100644
--- a/vendor/github.com/klauspost/compress/zstd/framedec.go
+++ b/vendor/github.com/klauspost/compress/zstd/framedec.go
@@ -238,10 +238,7 @@ func (d *frameDec) reset(br byteBuffer) error {
if d.WindowSize == 0 && d.SingleSegment {
// We may not need window in this case.
- d.WindowSize = d.FrameContentSize
- if d.WindowSize < MinWindowSize {
- d.WindowSize = MinWindowSize
- }
+ d.WindowSize = max(d.FrameContentSize, MinWindowSize)
if d.WindowSize > d.o.maxDecodedSize {
if debugDecoder {
printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_encoder.go b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
index ab26326a..3a0f4e7f 100644
--- a/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
@@ -149,7 +149,7 @@ func (s *fseEncoder) buildCTable() error {
if v > largeLimit {
s.zeroBits = true
}
- for nbOccurrences := int16(0); nbOccurrences < v; nbOccurrences++ {
+ for range v {
tableSymbol[position] = symbol
position = (position + step) & tableMask
for position > highThreshold {
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go
index 9a7de82f..0bfb0e43 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go
@@ -231,10 +231,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize]
llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
out := s.out
- maxBlockSize := maxCompressedBlockSize
- if s.windowSize < maxBlockSize {
- maxBlockSize = s.windowSize
- }
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
if debugDecoder {
println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream")
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
index c59f17e0..1f8c3cec 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
@@ -79,10 +79,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
br := s.br
- maxBlockSize := maxCompressedBlockSize
- if s.windowSize < maxBlockSize {
- maxBlockSize = s.windowSize
- }
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
ctx := decodeSyncAsmContext{
llTable: s.litLengths.fse.dt[:maxTablesize],
@@ -237,10 +234,7 @@ func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmC
func (s *sequenceDecs) decode(seqs []seqVals) error {
br := s.br
- maxBlockSize := maxCompressedBlockSize
- if s.windowSize < maxBlockSize {
- maxBlockSize = s.windowSize
- }
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
ctx := decodeAsmContext{
llTable: s.litLengths.fse.dt[:maxTablesize],
diff --git a/vendor/github.com/klauspost/compress/zstd/simple_go124.go b/vendor/github.com/klauspost/compress/zstd/simple_go124.go
new file mode 100644
index 00000000..2efc0497
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/simple_go124.go
@@ -0,0 +1,56 @@
+// Copyright 2025+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+//go:build go1.24
+
+package zstd
+
+import (
+ "errors"
+ "runtime"
+ "sync"
+ "weak"
+)
+
+var weakMu sync.Mutex
+var simpleEnc weak.Pointer[Encoder]
+var simpleDec weak.Pointer[Decoder]
+
+// EncodeTo appends the encoded data from src to dst.
+func EncodeTo(dst []byte, src []byte) []byte {
+ weakMu.Lock()
+ enc := simpleEnc.Value()
+ if enc == nil {
+ var err error
+ enc, err = NewWriter(nil, WithEncoderConcurrency(runtime.NumCPU()), WithWindowSize(1<<20), WithLowerEncoderMem(true), WithZeroFrames(true))
+ if err != nil {
+ panic("failed to create simple encoder: " + err.Error())
+ }
+ simpleEnc = weak.Make(enc)
+ }
+ weakMu.Unlock()
+
+ return enc.EncodeAll(src, dst)
+}
+
+// DecodeTo appends the decoded data from src to dst.
+// The maximum decoded size is 1GiB,
+// not including what may already be in dst.
+func DecodeTo(dst []byte, src []byte) ([]byte, error) {
+ weakMu.Lock()
+ dec := simpleDec.Value()
+ if dec == nil {
+ var err error
+ dec, err = NewReader(nil, WithDecoderConcurrency(runtime.NumCPU()), WithDecoderLowmem(true), WithDecoderMaxMemory(1<<30))
+ if err != nil {
+ weakMu.Unlock()
+ return nil, errors.New("failed to create simple decoder: " + err.Error())
+ }
+ runtime.SetFinalizer(dec, func(d *Decoder) {
+ d.Close()
+ })
+ simpleDec = weak.Make(dec)
+ }
+ weakMu.Unlock()
+ return dec.DecodeAll(src, dst)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go
index a17381b8..336c2889 100644
--- a/vendor/github.com/klauspost/compress/zstd/snappy.go
+++ b/vendor/github.com/klauspost/compress/zstd/snappy.go
@@ -257,7 +257,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
if !r.readFull(r.buf[:len(snappyMagicBody)], false) {
return written, r.err
}
- for i := 0; i < len(snappyMagicBody); i++ {
+ for i := range len(snappyMagicBody) {
if r.buf[i] != snappyMagicBody[i] {
println("r.buf[i] != snappyMagicBody[i]", r.buf[i], snappyMagicBody[i], i)
r.err = ErrSnappyCorrupt
diff --git a/vendor/github.com/klauspost/compress/zstd/zip.go b/vendor/github.com/klauspost/compress/zstd/zip.go
index 29c15c8c..3198d718 100644
--- a/vendor/github.com/klauspost/compress/zstd/zip.go
+++ b/vendor/github.com/klauspost/compress/zstd/zip.go
@@ -19,7 +19,7 @@ const ZipMethodWinZip = 93
const ZipMethodPKWare = 20
// zipReaderPool is the default reader pool.
-var zipReaderPool = sync.Pool{New: func() interface{} {
+var zipReaderPool = sync.Pool{New: func() any {
z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
if err != nil {
panic(err)
diff --git a/vendor/github.com/klauspost/compress/zstd/zstd.go b/vendor/github.com/klauspost/compress/zstd/zstd.go
index 6252b46a..1a869710 100644
--- a/vendor/github.com/klauspost/compress/zstd/zstd.go
+++ b/vendor/github.com/klauspost/compress/zstd/zstd.go
@@ -98,13 +98,13 @@ var (
ErrDecoderNilInput = errors.New("nil input provided as reader")
)
-func println(a ...interface{}) {
+func println(a ...any) {
if debug || debugDecoder || debugEncoder {
log.Println(a...)
}
}
-func printf(format string, a ...interface{}) {
+func printf(format string, a ...any) {
if debug || debugDecoder || debugEncoder {
log.Printf(format, a...)
}
diff --git a/vendor/github.com/vbatts/tar-split/archive/tar/common.go b/vendor/github.com/vbatts/tar-split/archive/tar/common.go
index dee9e47e..e687a08c 100644
--- a/vendor/github.com/vbatts/tar-split/archive/tar/common.go
+++ b/vendor/github.com/vbatts/tar-split/archive/tar/common.go
@@ -34,6 +34,7 @@ var (
errMissData = errors.New("archive/tar: sparse file references non-existent data")
errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
+ errSparseTooLong = errors.New("archive/tar: sparse map too long")
)
type headerError []string
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 248a7ccb..a645c416 100644
--- a/vendor/github.com/vbatts/tar-split/archive/tar/reader.go
+++ b/vendor/github.com/vbatts/tar-split/archive/tar/reader.go
@@ -581,12 +581,17 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
cntNewline int64
buf bytes.Buffer
blk block
+ totalSize int
)
// feedTokens copies data in blocks from r into buf until there are
// at least cnt newlines in buf. It will not read more blocks than needed.
feedTokens := func(n int64) error {
for cntNewline < n {
+ totalSize += len(blk)
+ if totalSize > maxSpecialFileSize {
+ return errSparseTooLong
+ }
if _, err := mustReadFull(r, blk[:]); err != nil {
return err
}
@@ -619,8 +624,8 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
}
// Parse for all member entries.
- // numEntries is trusted after this since a potential attacker must have
- // committed resources proportional to what this library used.
+ // numEntries is trusted after this since feedTokens limits the number of
+ // tokens based on maxSpecialFileSize.
if err := feedTokens(2 * numEntries); err != nil {
return nil, err
}
diff --git a/vendor/golang.org/x/oauth2/deviceauth.go b/vendor/golang.org/x/oauth2/deviceauth.go
index e99c92f3..e783a943 100644
--- a/vendor/golang.org/x/oauth2/deviceauth.go
+++ b/vendor/golang.org/x/oauth2/deviceauth.go
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
+ "mime"
"net/http"
"net/url"
"strings"
@@ -116,10 +117,38 @@ func retrieveDeviceAuth(ctx context.Context, c *Config, v url.Values) (*DeviceAu
return nil, fmt.Errorf("oauth2: cannot auth device: %v", err)
}
if code := r.StatusCode; code < 200 || code > 299 {
- return nil, &RetrieveError{
+ retrieveError := &RetrieveError{
Response: r,
Body: body,
}
+
+ content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
+ switch content {
+ case "application/x-www-form-urlencoded", "text/plain":
+ // some endpoints return a query string
+ vals, err := url.ParseQuery(string(body))
+ if err != nil {
+ return nil, retrieveError
+ }
+ retrieveError.ErrorCode = vals.Get("error")
+ retrieveError.ErrorDescription = vals.Get("error_description")
+ retrieveError.ErrorURI = vals.Get("error_uri")
+ default:
+ var tj struct {
+ // https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+ ErrorCode string `json:"error"`
+ ErrorDescription string `json:"error_description"`
+ ErrorURI string `json:"error_uri"`
+ }
+ if json.Unmarshal(body, &tj) != nil {
+ return nil, retrieveError
+ }
+ retrieveError.ErrorCode = tj.ErrorCode
+ retrieveError.ErrorDescription = tj.ErrorDescription
+ retrieveError.ErrorURI = tj.ErrorURI
+ }
+
+ return nil, retrieveError
}
da := &DeviceAuthResponse{}
diff --git a/vendor/golang.org/x/oauth2/google/default.go b/vendor/golang.org/x/oauth2/google/default.go
index 0260935b..6e572069 100644
--- a/vendor/golang.org/x/oauth2/google/default.go
+++ b/vendor/golang.org/x/oauth2/google/default.go
@@ -153,6 +153,43 @@ func (params CredentialsParams) deepCopy() CredentialsParams {
return paramsCopy
}
+// CredentialsType specifies the type of JSON credentials being provided
+// to a loading function.
+type CredentialsType string
+
+const (
+ // ServiceAccount represents a service account file type.
+ ServiceAccount CredentialsType = "service_account"
+ // AuthorizedUser represents a user credentials file type.
+ AuthorizedUser CredentialsType = "authorized_user"
+ // ExternalAccount represents an external account file type.
+ //
+ // IMPORTANT:
+ // This credential type does not validate the credential configuration. A security
+ // risk occurs when a credential configuration configured with malicious urls
+ // is used.
+ // You should validate credential configurations provided by untrusted sources.
+ // See [Security requirements when using credential configurations from an external
+ // source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
+ // for more details.
+ ExternalAccount CredentialsType = "external_account"
+ // ExternalAccountAuthorizedUser represents an external account authorized user file type.
+ ExternalAccountAuthorizedUser CredentialsType = "external_account_authorized_user"
+ // ImpersonatedServiceAccount represents an impersonated service account file type.
+ //
+ // IMPORTANT:
+ // This credential type does not validate the credential configuration. A security
+ // risk occurs when a credential configuration configured with malicious urls
+ // is used.
+ // You should validate credential configurations provided by untrusted sources.
+ // See [Security requirements when using credential configurations from an external
+ // source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
+ // for more details.
+ ImpersonatedServiceAccount CredentialsType = "impersonated_service_account"
+ // GDCHServiceAccount represents a GDCH service account credentials.
+ GDCHServiceAccount CredentialsType = "gdch_service_account"
+)
+
// DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
@@ -246,17 +283,71 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials
return FindDefaultCredentialsWithParams(ctx, params)
}
-// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
-// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
-// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
-// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
-// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
+// CredentialsFromJSONWithType invokes CredentialsFromJSONWithTypeAndParams with the specified scopes.
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
+func CredentialsFromJSONWithType(ctx context.Context, jsonData []byte, credType CredentialsType, scopes ...string) (*Credentials, error) {
+ var params CredentialsParams
+ params.Scopes = scopes
+ return CredentialsFromJSONWithTypeAndParams(ctx, jsonData, credType, params)
+}
+
+// CredentialsFromJSONWithTypeAndParams obtains Google credentials from a JSON value and
+// validates that the credentials match the specified type.
+//
+// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
+// external source for authentication to Google Cloud Platform, you must validate it before
+// providing it to any Google API or library. Providing an unvalidated credential configuration to
+// Google APIs can compromise the security of your systems and data. For more information, refer to
+// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
+func CredentialsFromJSONWithTypeAndParams(ctx context.Context, jsonData []byte, credType CredentialsType, params CredentialsParams) (*Credentials, error) {
+ var f struct {
+ Type string `json:"type"`
+ }
+ if err := json.Unmarshal(jsonData, &f); err != nil {
+ return nil, err
+ }
+ if CredentialsType(f.Type) != credType {
+ return nil, fmt.Errorf("google: expected credential type %q, found %q", credType, f.Type)
+ }
+ return CredentialsFromJSONWithParams(ctx, jsonData, params)
+}
+
+// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
+// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
+// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
+// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
+// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
+//
+// Deprecated: This function is deprecated because of a potential security risk.
+// It does not validate the credential configuration. The security risk occurs
+// when a credential configuration is accepted from a source that is not
+// under your control and used without validation on your side.
+//
+// If you know that you will be loading credential configurations of a
+// specific type, it is recommended to use a credential-type-specific
+// CredentialsFromJSONWithTypeAndParams method. This will ensure that an unexpected
+// credential type with potential for malicious intent is not loaded
+// unintentionally. You might still have to do validation for certain
+// credential types. Please follow the recommendation for that method. For
+// example, if you want to load only service accounts, you can use
+//
+// creds, err := google.CredentialsFromJSONWithTypeAndParams(ctx, jsonData, google.ServiceAccount, params)
+//
+// If you are loading your credential configuration from an untrusted source
+// and have not mitigated the risks (e.g. by validating the configuration
+// yourself), make these changes as soon as possible to prevent security
+// risks to your environment.
+//
+// Regardless of the method used, it is always your responsibility to
+// validate configurations received from external sources.
+//
+// For more details see:
+// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) {
// Make defensive copy of the slices in params.
params = params.deepCopy()
@@ -301,11 +392,31 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes.
//
-// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
-// external source for authentication to Google Cloud Platform, you must validate it before
-// providing it to any Google API or library. Providing an unvalidated credential configuration to
-// Google APIs can compromise the security of your systems and data. For more information, refer to
-// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
+// Deprecated: This function is deprecated because of a potential security risk.
+// It does not validate the credential configuration. The security risk occurs
+// when a credential configuration is accepted from a source that is not
+// under your control and used without validation on your side.
+//
+// If you know that you will be loading credential configurations of a
+// specific type, it is recommended to use a credential-type-specific
+// CredentialsFromJSONWithType method. This will ensure that an unexpected
+// credential type with potential for malicious intent is not loaded
+// unintentionally. You might still have to do validation for certain
+// credential types. Please follow the recommendation for that method. For
+// example, if you want to load only service accounts, you can use
+//
+// creds, err := google.CredentialsFromJSONWithType(ctx, jsonData, google.ServiceAccount, scopes...)
+//
+// If you are loading your credential configuration from an untrusted source
+// and have not mitigated the risks (e.g. by validating the configuration
+// yourself), make these changes as soon as possible to prevent security
+// risks to your environment.
+//
+// Regardless of the method used, it is always your responsibility to
+// validate configurations received from external sources.
+//
+// For more details see:
+// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var params CredentialsParams
params.Scopes = scopes
diff --git a/vendor/golang.org/x/oauth2/google/externalaccount/aws.go b/vendor/golang.org/x/oauth2/google/externalaccount/aws.go
index e1a735e0..f62ec99a 100644
--- a/vendor/golang.org/x/oauth2/google/externalaccount/aws.go
+++ b/vendor/golang.org/x/oauth2/google/externalaccount/aws.go
@@ -5,7 +5,6 @@
package externalaccount
import (
- "bytes"
"context"
"crypto/hmac"
"crypto/sha256"
@@ -148,13 +147,13 @@ func canonicalHeaders(req *http.Request) (string, string) {
}
sort.Strings(headers)
- var fullHeaders bytes.Buffer
+ var fullHeaders strings.Builder
for _, header := range headers {
headerValue := strings.Join(lowerCaseHeaders[header], ",")
fullHeaders.WriteString(header)
- fullHeaders.WriteRune(':')
+ fullHeaders.WriteByte(':')
fullHeaders.WriteString(headerValue)
- fullHeaders.WriteRune('\n')
+ fullHeaders.WriteByte('\n')
}
return strings.Join(headers, ";"), fullHeaders.String()
diff --git a/vendor/golang.org/x/oauth2/google/google.go b/vendor/golang.org/x/oauth2/google/google.go
index e2eb9c92..14c98eb6 100644
--- a/vendor/golang.org/x/oauth2/google/google.go
+++ b/vendor/golang.org/x/oauth2/google/google.go
@@ -103,6 +103,7 @@ const (
externalAccountKey = "external_account"
externalAccountAuthorizedUserKey = "external_account_authorized_user"
impersonatedServiceAccount = "impersonated_service_account"
+ gdchServiceAccountKey = "gdch_service_account"
)
// credentialsFile is the unmarshalled representation of a credentials file.
@@ -165,7 +166,7 @@ func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config
func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) {
switch f.Type {
- case serviceAccountKey:
+ case serviceAccountKey, gdchServiceAccountKey:
cfg := f.jwtConfig(params.Scopes, params.Subject)
return cfg.TokenSource(ctx), nil
case userCredentialsKey:
@@ -252,7 +253,7 @@ 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 {
- // refresh 3 minutes and 45 seconds early. The shortest MDS cache is currently 4 minutes, so any
+ // Refresh 3 minutes and 45 seconds early. The shortest MDS cache is currently 4 minutes, so any
// refreshes earlier are a waste of compute.
earlyExpirySecs := 225 * time.Second
return computeTokenSource(account, earlyExpirySecs, scope...)
diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go
index de34feb8..5c527d31 100644
--- a/vendor/golang.org/x/oauth2/oauth2.go
+++ b/vendor/golang.org/x/oauth2/oauth2.go
@@ -9,7 +9,6 @@
package oauth2 // import "golang.org/x/oauth2"
import (
- "bytes"
"context"
"errors"
"net/http"
@@ -99,7 +98,7 @@ const (
// in the POST body as application/x-www-form-urlencoded parameters.
AuthStyleInParams AuthStyle = 1
- // AuthStyleInHeader sends the client_id and client_password
+ // AuthStyleInHeader sends the client_id and client_secret
// using HTTP Basic Authorization. This is an optional style
// described in the OAuth2 RFC 6749 section 2.3.1.
AuthStyleInHeader AuthStyle = 2
@@ -158,7 +157,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// PKCE), https://www.oauth.com/oauth2-servers/pkce/ and
// https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches)
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
- var buf bytes.Buffer
+ var buf strings.Builder
buf.WriteString(c.Endpoint.AuthURL)
v := url.Values{
"response_type": {"code"},
diff --git a/vendor/golang.org/x/oauth2/pkce.go b/vendor/golang.org/x/oauth2/pkce.go
index cea8374d..f99384f0 100644
--- a/vendor/golang.org/x/oauth2/pkce.go
+++ b/vendor/golang.org/x/oauth2/pkce.go
@@ -51,7 +51,7 @@ func S256ChallengeFromVerifier(verifier string) string {
return base64.RawURLEncoding.EncodeToString(sha[:])
}
-// S256ChallengeOption derives a PKCE code challenge derived from verifier with
+// S256ChallengeOption derives a PKCE code challenge from the verifier with
// method S256. It should be passed to [Config.AuthCodeURL] or [Config.DeviceAuth]
// only.
func S256ChallengeOption(verifier string) AuthCodeOption {
diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go
index 239ec329..e995eebb 100644
--- a/vendor/golang.org/x/oauth2/token.go
+++ b/vendor/golang.org/x/oauth2/token.go
@@ -103,7 +103,7 @@ func (t *Token) WithExtra(extra any) *Token {
}
// Extra returns an extra field.
-// Extra fields are key-value pairs returned by the server as a
+// Extra fields are key-value pairs returned by the server as
// part of the token retrieval response.
func (t *Token) Extra(key string) any {
if raw, ok := t.raw.(map[string]any); ok {
diff --git a/vendor/golang.org/x/oauth2/transport.go b/vendor/golang.org/x/oauth2/transport.go
index 8bbebbac..9922ec33 100644
--- a/vendor/golang.org/x/oauth2/transport.go
+++ b/vendor/golang.org/x/oauth2/transport.go
@@ -58,7 +58,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
var cancelOnce sync.Once
// CancelRequest does nothing. It used to be a legacy cancellation mechanism
-// but now only it only logs on first use to warn that it's deprecated.
+// but now only logs on first use to warn that it's deprecated.
//
// Deprecated: use contexts for cancellation instead.
func (t *Transport) CancelRequest(req *http.Request) {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a3a66579..95b5c1a9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -195,8 +195,8 @@ github.com/cheggaaa/pb/v3/termutil
github.com/chrismellard/docker-credential-acr-env/pkg/credhelper
github.com/chrismellard/docker-credential-acr-env/pkg/registry
github.com/chrismellard/docker-credential-acr-env/pkg/token
-# github.com/containerd/stargz-snapshotter/estargz v0.16.3
-## explicit; go 1.22.0
+# github.com/containerd/stargz-snapshotter/estargz v0.18.2
+## explicit; go 1.24.0
github.com/containerd/stargz-snapshotter/estargz
github.com/containerd/stargz-snapshotter/estargz/errorutil
# github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65
@@ -216,7 +216,7 @@ github.com/davecgh/go-spew/spew
# github.com/dimchansky/utfbom v1.1.0
## explicit
github.com/dimchansky/utfbom
-# github.com/docker/cli v29.2.0+incompatible
+# github.com/docker/cli v29.2.1+incompatible
## explicit
github.com/docker/cli/cli/config
github.com/docker/cli/cli/config/configfile
@@ -282,8 +282,8 @@ github.com/gogo/protobuf/protoc-gen-gogo/plugin
github.com/gogo/protobuf/sortkeys
github.com/gogo/protobuf/vanity
github.com/gogo/protobuf/vanity/command
-# github.com/google/go-containerregistry v0.20.6
-## explicit; go 1.24
+# github.com/google/go-containerregistry v0.20.8
+## explicit; go 1.25.6
github.com/google/go-containerregistry/internal/and
github.com/google/go-containerregistry/internal/compression
github.com/google/go-containerregistry/internal/estargz
@@ -321,7 +321,7 @@ github.com/google/go-querystring/query
# github.com/google/gofuzz v1.1.0
## explicit; go 1.12
github.com/google/gofuzz
-# github.com/hashicorp/go-version v1.2.1
+# github.com/hashicorp/go-version v1.7.0
## explicit
github.com/hashicorp/go-version
# github.com/inconshreveable/mousetrap v1.1.0
@@ -333,8 +333,8 @@ github.com/josharian/intern
# github.com/json-iterator/go v1.1.12
## explicit; go 1.12
github.com/json-iterator/go
-# github.com/klauspost/compress v1.18.0
-## explicit; go 1.22
+# github.com/klauspost/compress v1.18.4
+## explicit; go 1.23
github.com/klauspost/compress
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
@@ -403,7 +403,7 @@ github.com/spf13/pflag
github.com/stretchr/testify/assert
github.com/stretchr/testify/assert/yaml
github.com/stretchr/testify/require
-# github.com/vbatts/tar-split v0.12.1
+# github.com/vbatts/tar-split v0.12.2
## explicit; go 1.17
github.com/vbatts/tar-split/archive/tar
# github.com/vito/go-interact v1.0.1
@@ -433,8 +433,8 @@ golang.org/x/net/http2/hpack
golang.org/x/net/idna
golang.org/x/net/internal/httpcommon
golang.org/x/net/internal/httpsfv
-# golang.org/x/oauth2 v0.30.0
-## explicit; go 1.23.0
+# golang.org/x/oauth2 v0.35.0
+## explicit; go 1.24.0
golang.org/x/oauth2
golang.org/x/oauth2/authhandler
golang.org/x/oauth2/google