Bump c/storage to v1.53.0, c/image to v5.30.0

As the title says.  The third step in the vendor dance.
Bumps c/storage v1.53.0 and c/image to v5.30.0 all in
preparation of Podman v5.0

[NO NEW TESTS NEEDED]

Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
This commit is contained in:
tomsweeneyredhat 2024-03-05 09:40:16 -05:00
parent 27a4ef1396
commit 7ef6b56fd2
77 changed files with 1536 additions and 678 deletions

View File

@ -7,9 +7,9 @@ require (
github.com/containerd/containerd v1.7.13 github.com/containerd/containerd v1.7.13
github.com/containernetworking/cni v1.1.2 github.com/containernetworking/cni v1.1.2
github.com/containernetworking/plugins v1.4.0 github.com/containernetworking/plugins v1.4.0
github.com/containers/image/v5 v5.29.3-0.20240227090231-5bef5e1e1506 github.com/containers/image/v5 v5.30.0
github.com/containers/ocicrypt v1.1.9 github.com/containers/ocicrypt v1.1.9
github.com/containers/storage v1.52.1-0.20240227215008-a083950a778f github.com/containers/storage v1.53.0
github.com/coreos/go-systemd/v22 v22.5.0 github.com/coreos/go-systemd/v22 v22.5.0
github.com/cyphar/filepath-securejoin v0.2.4 github.com/cyphar/filepath-securejoin v0.2.4
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
@ -41,7 +41,7 @@ require (
github.com/vishvananda/netlink v1.2.1-beta.2 github.com/vishvananda/netlink v1.2.1-beta.2
go.etcd.io/bbolt v1.3.9 go.etcd.io/bbolt v1.3.9
golang.org/x/crypto v0.21.0 golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
golang.org/x/sync v0.6.0 golang.org/x/sync v0.6.0
golang.org/x/sys v0.18.0 golang.org/x/sys v0.18.0
golang.org/x/term v0.18.0 golang.org/x/term v0.18.0
@ -69,28 +69,28 @@ require (
github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect
github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-connections v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-jose/go-jose/v3 v3.0.2 // indirect
github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.21.0 // indirect github.com/go-openapi/errors v0.21.1 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/loads v0.21.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect
github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/runtime v0.26.0 // indirect
github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/strfmt v0.22.0 // indirect github.com/go-openapi/strfmt v0.22.2 // indirect
github.com/go-openapi/swag v0.22.9 // indirect github.com/go-openapi/swag v0.22.10 // indirect
github.com/go-openapi/validate v0.22.1 // indirect github.com/go-openapi/validate v0.22.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.17.0 // indirect github.com/google/go-containerregistry v0.19.0 // indirect
github.com/google/go-intervals v0.0.2 // indirect github.com/google/go-intervals v0.0.2 // indirect
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
github.com/google/uuid v1.5.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -120,7 +120,7 @@ require (
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
github.com/sigstore/fulcio v1.4.3 // indirect github.com/sigstore/fulcio v1.4.3 // indirect
github.com/sigstore/rekor v1.2.2 // indirect github.com/sigstore/rekor v1.2.2 // indirect
github.com/sigstore/sigstore v1.8.1 // indirect github.com/sigstore/sigstore v1.8.2 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
github.com/sylabs/sif/v2 v2.15.1 // indirect github.com/sylabs/sif/v2 v2.15.1 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect
@ -129,17 +129,17 @@ require (
github.com/vbatts/tar-split v0.11.5 // indirect github.com/vbatts/tar-split v0.11.5 // indirect
github.com/vbauerster/mpb/v8 v8.7.2 // indirect github.com/vbauerster/mpb/v8 v8.7.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect github.com/vishvananda/netns v0.0.4 // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect go.opentelemetry.io/otel/trace v1.19.0 // indirect
golang.org/x/mod v0.14.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect golang.org/x/net v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect golang.org/x/tools v0.18.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
google.golang.org/grpc v1.59.0 // indirect google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/protobuf v1.31.0 // indirect

View File

@ -53,14 +53,14 @@ github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl3
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic= github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic=
github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0= github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0=
github.com/containers/image/v5 v5.29.3-0.20240227090231-5bef5e1e1506 h1:Wdkl9fdxXYp2zaiw0GWC7fF8DSqD72B5jhILY0qK/sU= github.com/containers/image/v5 v5.30.0 h1:CmHeSwI6W2kTRWnUsxATDFY5TEX4b58gPkaQcEyrLIA=
github.com/containers/image/v5 v5.29.3-0.20240227090231-5bef5e1e1506/go.mod h1:2/7sa5zJsx3Gl4v2MHkBrSMxsQePJcx9EDehbxmxlKE= github.com/containers/image/v5 v5.30.0/go.mod h1:gSD8MVOyqBspc0ynLsuiMR9qmt8UQ4jpVImjmK0uXfk=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.1.9 h1:2Csfba4jse85Raxk5HIyEk8OwZNjRvfkhEGijOjIdEM= github.com/containers/ocicrypt v1.1.9 h1:2Csfba4jse85Raxk5HIyEk8OwZNjRvfkhEGijOjIdEM=
github.com/containers/ocicrypt v1.1.9/go.mod h1:dTKx1918d8TDkxXvarscpNVY+lyPakPNFN4jwA9GBys= github.com/containers/ocicrypt v1.1.9/go.mod h1:dTKx1918d8TDkxXvarscpNVY+lyPakPNFN4jwA9GBys=
github.com/containers/storage v1.52.1-0.20240227215008-a083950a778f h1:1praFMNpAwJWq5usBh1T8FkXoRsHTJ4rhU/2NpNhvhI= github.com/containers/storage v1.53.0 h1:VSES3C/u1pxjTJIXvLrSmyP7OBtDky04oGu07UvdTEA=
github.com/containers/storage v1.52.1-0.20240227215008-a083950a778f/go.mod h1:mFA6QpUoT9qTa3q2DD1CvSo3Az3syNkw1P9X+4nUYdY= github.com/containers/storage v1.53.0/go.mod h1:pujcoOSc+upx15Jirdkebhtd8uJiLwbSd/mYT6zDJK8=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -99,8 +99,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= github.com/go-jose/go-jose/v3 v3.0.2 h1:2Edjn8Nrb44UvTdp84KU0bBPs1cO7noRCybtS3eJEUQ=
github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-jose/go-jose/v3 v3.0.2/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@ -112,8 +112,8 @@ github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9Qy
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= github.com/go-openapi/errors v0.21.1 h1:rVisxQPdETctjlYntm0Ek4dKf68nAQocCloCT50vWuI=
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho= github.com/go-openapi/errors v0.21.1/go.mod h1:LyiY9bgc7AVVh6wtVvMYEyoj3KJYNoRw92mmvnMWgj8=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
@ -134,14 +134,14 @@ github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= github.com/go-openapi/strfmt v0.22.2 h1:DPYOrm6gexCfZZfXUaXFS4+Jw6HAaIIG0SZ5630f8yw=
github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= github.com/go-openapi/strfmt v0.22.2/go.mod h1:HB/b7TCm91rno75Dembc1dFW/0FPLk5CEXsoF9ReNc4=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= github.com/go-openapi/swag v0.22.10 h1:4y86NVn7Z2yYd6pfS4Z+Nyh3aAUL3Nul+LMbhFKy0gA=
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-openapi/swag v0.22.10/go.mod h1:Cnn8BYtRlx6BNE3DPN86f/xkapGIcLWzh3CLEb4C1jI=
github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -209,8 +209,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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk= github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic=
github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM= github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y= github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -220,8 +220,8 @@ github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHa
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
@ -367,8 +367,8 @@ github.com/sigstore/fulcio v1.4.3 h1:9JcUCZjjVhRF9fmhVuz6i1RyhCc/EGCD7MOl+iqCJLQ
github.com/sigstore/fulcio v1.4.3/go.mod h1:BQPWo7cfxmJwgaHlphUHUpFkp5+YxeJes82oo39m5og= github.com/sigstore/fulcio v1.4.3/go.mod h1:BQPWo7cfxmJwgaHlphUHUpFkp5+YxeJes82oo39m5og=
github.com/sigstore/rekor v1.2.2 h1:5JK/zKZvcQpL/jBmHvmFj3YbpDMBQnJQ6ygp8xdF3bY= github.com/sigstore/rekor v1.2.2 h1:5JK/zKZvcQpL/jBmHvmFj3YbpDMBQnJQ6ygp8xdF3bY=
github.com/sigstore/rekor v1.2.2/go.mod h1:FGnWBGWzeNceJnp0x9eDFd41mI8aQqCjj+Zp0IEs0Qg= github.com/sigstore/rekor v1.2.2/go.mod h1:FGnWBGWzeNceJnp0x9eDFd41mI8aQqCjj+Zp0IEs0Qg=
github.com/sigstore/sigstore v1.8.1 h1:mAVposMb14oplk2h/bayPmIVdzbq2IhCgy4g6R0ZSjo= github.com/sigstore/sigstore v1.8.2 h1:0Ttjcn3V0fVQXlYq7+oHaaHkGFIt3ywm7SF4JTU/l8c=
github.com/sigstore/sigstore v1.8.1/go.mod h1:02SL1158BSj15bZyOFz7m+/nJzLZfFd9A8ab3Kz7w/E= github.com/sigstore/sigstore v1.8.2/go.mod h1:CHVcSyknCcjI4K2ZhS1SI28r0tcQyBlwtALG536x1DY=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -419,10 +419,8 @@ github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZla
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
@ -435,8 +433,8 @@ go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
@ -456,26 +454,27 @@ go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lI
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -493,8 +492,10 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -505,6 +506,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -536,11 +538,17 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -548,9 +556,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
@ -568,8 +576,9 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -23,9 +23,9 @@ var (
// compressionBufferSize is the buffer size used to compress a blob // compressionBufferSize is the buffer size used to compress a blob
compressionBufferSize = 1048576 compressionBufferSize = 1048576
// expectedCompressionFormats is used to check if a blob with a specified media type is compressed // expectedBaseCompressionFormats is used to check if a blob with a specified media type is compressed
// using the algorithm that the media type says it should be compressed with // using the algorithm that the media type says it should be compressed with
expectedCompressionFormats = map[string]*compressiontypes.Algorithm{ expectedBaseCompressionFormats = map[string]*compressiontypes.Algorithm{
imgspecv1.MediaTypeImageLayerGzip: &compression.Gzip, imgspecv1.MediaTypeImageLayerGzip: &compression.Gzip,
imgspecv1.MediaTypeImageLayerZstd: &compression.Zstd, imgspecv1.MediaTypeImageLayerZstd: &compression.Zstd,
manifest.DockerV2Schema2LayerMediaType: &compression.Gzip, manifest.DockerV2Schema2LayerMediaType: &compression.Gzip,
@ -62,8 +62,8 @@ func blobPipelineDetectCompressionStep(stream *sourceStream, srcInfo types.BlobI
res.srcCompressorName = internalblobinfocache.Uncompressed res.srcCompressorName = internalblobinfocache.Uncompressed
} }
if expectedFormat, known := expectedCompressionFormats[stream.info.MediaType]; known && res.isCompressed && format.Name() != expectedFormat.Name() { if expectedBaseFormat, known := expectedBaseCompressionFormats[stream.info.MediaType]; known && res.isCompressed && format.BaseVariantName() != expectedBaseFormat.Name() {
logrus.Debugf("blob %s with type %s should be compressed with %s, but compressor appears to be %s", srcInfo.Digest.String(), srcInfo.MediaType, expectedFormat.Name(), format.Name()) logrus.Debugf("blob %s with type %s should be compressed with %s, but compressor appears to be %s", srcInfo.Digest.String(), srcInfo.MediaType, expectedBaseFormat.Name(), format.Name())
} }
return res, nil return res, nil
} }
@ -172,7 +172,8 @@ func (ic *imageCopier) bpcCompressUncompressed(stream *sourceStream, detected bp
// bpcRecompressCompressed checks if we should be recompressing a compressed input to another format, and returns a *bpCompressionStepData if so. // bpcRecompressCompressed checks if we should be recompressing a compressed input to another format, and returns a *bpCompressionStepData if so.
func (ic *imageCopier) bpcRecompressCompressed(stream *sourceStream, detected bpDetectCompressionStepData) (*bpCompressionStepData, error) { func (ic *imageCopier) bpcRecompressCompressed(stream *sourceStream, detected bpDetectCompressionStepData) (*bpCompressionStepData, error) {
if ic.c.dest.DesiredLayerCompression() == types.Compress && detected.isCompressed && if ic.c.dest.DesiredLayerCompression() == types.Compress && detected.isCompressed &&
ic.compressionFormat != nil && ic.compressionFormat.Name() != detected.format.Name() { ic.compressionFormat != nil &&
(ic.compressionFormat.Name() != detected.format.Name() && ic.compressionFormat.Name() != detected.format.BaseVariantName()) {
// When the blob is compressed, but the desired format is different, it first needs to be decompressed and finally // When the blob is compressed, but the desired format is different, it first needs to be decompressed and finally
// re-compressed using the desired format. // re-compressed using the desired format.
logrus.Debugf("Blob will be converted") logrus.Debugf("Blob will be converted")

View File

@ -23,11 +23,11 @@ type digestingReader struct {
func newDigestingReader(source io.Reader, expectedDigest digest.Digest) (*digestingReader, error) { func newDigestingReader(source io.Reader, expectedDigest digest.Digest) (*digestingReader, error) {
var digester digest.Digester var digester digest.Digester
if err := expectedDigest.Validate(); err != nil { if err := expectedDigest.Validate(); err != nil {
return nil, fmt.Errorf("Invalid digest specification %s", expectedDigest) return nil, fmt.Errorf("invalid digest specification %q: %w", expectedDigest, err)
} }
digestAlgorithm := expectedDigest.Algorithm() digestAlgorithm := expectedDigest.Algorithm()
if !digestAlgorithm.Available() { if !digestAlgorithm.Available() {
return nil, fmt.Errorf("Invalid digest specification %s: unsupported digest algorithm %s", expectedDigest, digestAlgorithm) return nil, fmt.Errorf("invalid digest specification %q: unsupported digest algorithm %q", expectedDigest, digestAlgorithm)
} }
digester = digestAlgorithm.Digester() digester = digestAlgorithm.Digester()

View File

@ -383,7 +383,11 @@ func (ic *imageCopier) compareImageDestinationManifestEqual(ctx context.Context,
compressionAlgos := set.New[string]() compressionAlgos := set.New[string]()
for _, srcInfo := range ic.src.LayerInfos() { for _, srcInfo := range ic.src.LayerInfos() {
if _, c := compressionEditsFromMIMEType(srcInfo); c != nil { _, c, err := compressionEditsFromBlobInfo(srcInfo)
if err != nil {
return nil, err
}
if c != nil {
compressionAlgos.Add(c.Name()) compressionAlgos.Add(c.Name())
} }
} }
@ -636,21 +640,28 @@ type diffIDResult struct {
err error err error
} }
// compressionEditsFromMIMEType returns a (CompressionOperation, CompressionAlgorithm) value pair suitable // compressionEditsFromBlobInfo returns a (CompressionOperation, CompressionAlgorithm) value pair suitable
// for types.BlobInfo, based on a MIME type of srcInfo. // for types.BlobInfo.
func compressionEditsFromMIMEType(srcInfo types.BlobInfo) (types.LayerCompression, *compressiontypes.Algorithm) { func compressionEditsFromBlobInfo(srcInfo types.BlobInfo) (types.LayerCompression, *compressiontypes.Algorithm, error) {
// This MIME type → compression mapping belongs in manifest-specific code in our manifest // This MIME type → compression mapping belongs in manifest-specific code in our manifest
// package (but we should preferably replace/change UpdatedImage instead of productizing // package (but we should preferably replace/change UpdatedImage instead of productizing
// this workaround). // this workaround).
switch srcInfo.MediaType { switch srcInfo.MediaType {
case manifest.DockerV2Schema2LayerMediaType, imgspecv1.MediaTypeImageLayerGzip: case manifest.DockerV2Schema2LayerMediaType, imgspecv1.MediaTypeImageLayerGzip:
return types.PreserveOriginal, &compression.Gzip return types.PreserveOriginal, &compression.Gzip, nil
case imgspecv1.MediaTypeImageLayerZstd: case imgspecv1.MediaTypeImageLayerZstd:
return types.PreserveOriginal, &compression.Zstd tocDigest, err := chunkedToc.GetTOCDigest(srcInfo.Annotations)
if err != nil {
return types.PreserveOriginal, nil, err
}
if tocDigest != nil {
return types.PreserveOriginal, &compression.ZstdChunked, nil
}
return types.PreserveOriginal, &compression.Zstd, nil
case manifest.DockerV2SchemaLayerMediaTypeUncompressed, imgspecv1.MediaTypeImageLayer: case manifest.DockerV2SchemaLayerMediaTypeUncompressed, imgspecv1.MediaTypeImageLayer:
return types.Decompress, nil return types.Decompress, nil, nil
default: default:
return types.PreserveOriginal, nil return types.PreserveOriginal, nil, nil
} }
} }
@ -666,7 +677,12 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
// (Sadly UpdatedImage() is documented to not update MediaTypes from // (Sadly UpdatedImage() is documented to not update MediaTypes from
// ManifestUpdateOptions.LayerInfos[].MediaType, so we are doing it indirectly.) // ManifestUpdateOptions.LayerInfos[].MediaType, so we are doing it indirectly.)
if srcInfo.CompressionOperation == types.PreserveOriginal && srcInfo.CompressionAlgorithm == nil { if srcInfo.CompressionOperation == types.PreserveOriginal && srcInfo.CompressionAlgorithm == nil {
srcInfo.CompressionOperation, srcInfo.CompressionAlgorithm = compressionEditsFromMIMEType(srcInfo) op, algo, err := compressionEditsFromBlobInfo(srcInfo)
if err != nil {
return types.BlobInfo{}, "", err
}
srcInfo.CompressionOperation = op
srcInfo.CompressionAlgorithm = algo
} }
ic.c.printCopyInfo("blob", srcInfo) ic.c.printCopyInfo("blob", srcInfo)

View File

@ -978,13 +978,10 @@ func (c *dockerClient) fetchManifest(ctx context.Context, ref dockerReference, t
// This function can return nil reader when no url is supported by this function. In this case, the caller // This function can return nil reader when no url is supported by this function. In this case, the caller
// should fallback to fetch the non-external blob (i.e. pull from the registry). // should fallback to fetch the non-external blob (i.e. pull from the registry).
func (c *dockerClient) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) { func (c *dockerClient) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
var (
resp *http.Response
err error
)
if len(urls) == 0 { if len(urls) == 0 {
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs") return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
} }
var remoteErrors []error
for _, u := range urls { for _, u := range urls {
blobURL, err := url.Parse(u) blobURL, err := url.Parse(u)
if err != nil || (blobURL.Scheme != "http" && blobURL.Scheme != "https") { if err != nil || (blobURL.Scheme != "http" && blobURL.Scheme != "https") {
@ -993,24 +990,28 @@ func (c *dockerClient) getExternalBlob(ctx context.Context, urls []string) (io.R
// NOTE: we must not authenticate on additional URLs as those // NOTE: we must not authenticate on additional URLs as those
// can be abused to leak credentials or tokens. Please // can be abused to leak credentials or tokens. Please
// refer to CVE-2020-15157 for more information. // refer to CVE-2020-15157 for more information.
resp, err = c.makeRequestToResolvedURL(ctx, http.MethodGet, blobURL, nil, nil, -1, noAuth, nil) resp, err := c.makeRequestToResolvedURL(ctx, http.MethodGet, blobURL, nil, nil, -1, noAuth, nil)
if err == nil { if err != nil {
remoteErrors = append(remoteErrors, err)
continue
}
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("error fetching external blob from %q: %d (%s)", u, resp.StatusCode, http.StatusText(resp.StatusCode)) err := fmt.Errorf("error fetching external blob from %q: %d (%s)", u, resp.StatusCode, http.StatusText(resp.StatusCode))
remoteErrors = append(remoteErrors, err)
logrus.Debug(err) logrus.Debug(err)
resp.Body.Close() resp.Body.Close()
continue continue
} }
break return resp.Body, getBlobSize(resp), nil
} }
} if remoteErrors == nil {
if resp == nil && err == nil {
return nil, 0, nil // fallback to non-external blob return nil, 0, nil // fallback to non-external blob
} }
if err != nil { err := fmt.Errorf("failed fetching external blob from all urls: %w", remoteErrors[0])
return nil, 0, err for _, e := range remoteErrors[1:] {
err = fmt.Errorf("%s, %w", err, e)
} }
return resp.Body, getBlobSize(resp), nil return nil, 0, err
} }
func getBlobSize(resp *http.Response) int64 { func getBlobSize(resp *http.Response) int64 {

View File

@ -17,7 +17,8 @@ func CandidateMatchesTryReusingBlobOptions(options private.TryReusingBlobOptions
// The caller must re-compress to build those annotations. // The caller must re-compress to build those annotations.
return false return false
} }
if candidateCompression == nil || (options.RequiredCompression.Name() != candidateCompression.Name()) { if candidateCompression == nil ||
(options.RequiredCompression.Name() != candidateCompression.Name() && options.RequiredCompression.Name() != candidateCompression.BaseVariantName()) {
return false return false
} }
} }

View File

@ -169,7 +169,8 @@ func NormalizedMIMEType(input string) string {
// CompressionAlgorithmIsUniversallySupported returns true if MIMETypeSupportsCompressionAlgorithm(mimeType, algo) returns true for all mimeType values. // CompressionAlgorithmIsUniversallySupported returns true if MIMETypeSupportsCompressionAlgorithm(mimeType, algo) returns true for all mimeType values.
func CompressionAlgorithmIsUniversallySupported(algo compressiontypes.Algorithm) bool { func CompressionAlgorithmIsUniversallySupported(algo compressiontypes.Algorithm) bool {
switch algo.Name() { // Should this use InternalUnstableUndocumentedMIMEQuestionMark() ? // Compare the discussion about BaseVariantName in MIMETypeSupportsCompressionAlgorithm().
switch algo.Name() {
case compressiontypes.GzipAlgorithmName: case compressiontypes.GzipAlgorithmName:
return true return true
default: default:
@ -182,7 +183,9 @@ func MIMETypeSupportsCompressionAlgorithm(mimeType string, algo compressiontypes
if CompressionAlgorithmIsUniversallySupported(algo) { if CompressionAlgorithmIsUniversallySupported(algo) {
return true return true
} }
switch algo.Name() { // Should this use InternalUnstableUndocumentedMIMEQuestionMark() ? // This does not use BaseVariantName: Plausibly a manifest format might support zstd but not have annotation fields.
// The logic might have to be more complex (and more ad-hoc) if more manifest formats, with more capabilities, emerge.
switch algo.Name() {
case compressiontypes.ZstdAlgorithmName, compressiontypes.ZstdChunkedAlgorithmName: case compressiontypes.ZstdAlgorithmName, compressiontypes.ZstdChunkedAlgorithmName:
return mimeType == imgspecv1.MediaTypeImageManifest return mimeType == imgspecv1.MediaTypeImageManifest
default: // Includes Bzip2AlgorithmName and XzAlgorithmName, which are defined names but are not supported anywhere default: // Includes Bzip2AlgorithmName and XzAlgorithmName, which are defined names but are not supported anywhere

View File

@ -103,8 +103,8 @@ func addCompressionAnnotations(compressionAlgorithms []compression.Algorithm, an
*annotationsMap = map[string]string{} *annotationsMap = map[string]string{}
} }
for _, algo := range compressionAlgorithms { for _, algo := range compressionAlgorithms {
switch algo.Name() { switch algo.BaseVariantName() {
case compression.ZstdAlgorithmName, compression.ZstdChunkedAlgorithmName: // Should this use InternalUnstableUndocumentedMIMEQuestionMark() ? case compression.ZstdAlgorithmName:
(*annotationsMap)[OCI1InstanceAnnotationCompressionZSTD] = OCI1InstanceAnnotationCompressionZSTDValue (*annotationsMap)[OCI1InstanceAnnotationCompressionZSTD] = OCI1InstanceAnnotationCompressionZSTDValue
default: default:
continue continue

View File

@ -55,7 +55,7 @@ func compressionVariantMIMEType(variantTable []compressionMIMETypeSet, mimeType
if variants != nil { if variants != nil {
name := mtsUncompressed name := mtsUncompressed
if algorithm != nil { if algorithm != nil {
name = algorithm.InternalUnstableUndocumentedMIMEQuestionMark() name = algorithm.BaseVariantName()
} }
if res, ok := variants[name]; ok { if res, ok := variants[name]; ok {
if res != mtsUnsupportedMIMEType { if res != mtsUnsupportedMIMEType {

View File

@ -19,19 +19,19 @@ type Algorithm = types.Algorithm
var ( var (
// Gzip compression. // Gzip compression.
Gzip = internal.NewAlgorithm(types.GzipAlgorithmName, types.GzipAlgorithmName, Gzip = internal.NewAlgorithm(types.GzipAlgorithmName, "",
[]byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor) []byte{0x1F, 0x8B, 0x08}, GzipDecompressor, gzipCompressor)
// Bzip2 compression. // Bzip2 compression.
Bzip2 = internal.NewAlgorithm(types.Bzip2AlgorithmName, types.Bzip2AlgorithmName, Bzip2 = internal.NewAlgorithm(types.Bzip2AlgorithmName, "",
[]byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor) []byte{0x42, 0x5A, 0x68}, Bzip2Decompressor, bzip2Compressor)
// Xz compression. // Xz compression.
Xz = internal.NewAlgorithm(types.XzAlgorithmName, types.XzAlgorithmName, Xz = internal.NewAlgorithm(types.XzAlgorithmName, "",
[]byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor) []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}, XzDecompressor, xzCompressor)
// Zstd compression. // Zstd compression.
Zstd = internal.NewAlgorithm(types.ZstdAlgorithmName, types.ZstdAlgorithmName, Zstd = internal.NewAlgorithm(types.ZstdAlgorithmName, "",
[]byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor) []byte{0x28, 0xb5, 0x2f, 0xfd}, ZstdDecompressor, zstdCompressor)
// ZstdChunked is a Zstd compression with chunk metadta which allows random access to individual files. // ZstdChunked is a Zstd compression with chunk metadata which allows random access to individual files.
ZstdChunked = internal.NewAlgorithm(types.ZstdChunkedAlgorithmName, types.ZstdAlgorithmName, /* Note: InternalUnstableUndocumentedMIMEQuestionMark is not ZstdChunkedAlgorithmName */ ZstdChunked = internal.NewAlgorithm(types.ZstdChunkedAlgorithmName, types.ZstdAlgorithmName,
nil, ZstdDecompressor, compressor.ZstdCompressor) nil, ZstdDecompressor, compressor.ZstdCompressor)
compressionAlgorithms = map[string]Algorithm{ compressionAlgorithms = map[string]Algorithm{

View File

@ -13,19 +13,24 @@ type DecompressorFunc func(io.Reader) (io.ReadCloser, error)
// Algorithm is a compression algorithm that can be used for CompressStream. // Algorithm is a compression algorithm that can be used for CompressStream.
type Algorithm struct { type Algorithm struct {
name string name string
mime string baseVariantName string
prefix []byte // Initial bytes of a stream compressed using this algorithm, or empty to disable detection. prefix []byte // Initial bytes of a stream compressed using this algorithm, or empty to disable detection.
decompressor DecompressorFunc decompressor DecompressorFunc
compressor CompressorFunc compressor CompressorFunc
} }
// NewAlgorithm creates an Algorithm instance. // NewAlgorithm creates an Algorithm instance.
// nontrivialBaseVariantName is typically "".
// This function exists so that Algorithm instances can only be created by code that // This function exists so that Algorithm instances can only be created by code that
// is allowed to import this internal subpackage. // is allowed to import this internal subpackage.
func NewAlgorithm(name, mime string, prefix []byte, decompressor DecompressorFunc, compressor CompressorFunc) Algorithm { func NewAlgorithm(name, nontrivialBaseVariantName string, prefix []byte, decompressor DecompressorFunc, compressor CompressorFunc) Algorithm {
baseVariantName := name
if nontrivialBaseVariantName != "" {
baseVariantName = nontrivialBaseVariantName
}
return Algorithm{ return Algorithm{
name: name, name: name,
mime: mime, baseVariantName: baseVariantName,
prefix: prefix, prefix: prefix,
decompressor: decompressor, decompressor: decompressor,
compressor: compressor, compressor: compressor,
@ -37,10 +42,11 @@ func (c Algorithm) Name() string {
return c.name return c.name
} }
// InternalUnstableUndocumentedMIMEQuestionMark ??? // BaseVariantName returns the name of the “base variant” of the compression algorithm.
// DO NOT USE THIS anywhere outside of c/image until it is properly documented. // It is either equal to Name() of the same algorithm, or equal to Name() of some other Algorithm (the “base variant”).
func (c Algorithm) InternalUnstableUndocumentedMIMEQuestionMark() string { // This supports a single level of “is-a” relationship between compression algorithms, e.g. where "zstd:chunked" data is valid "zstd" data.
return c.mime func (c Algorithm) BaseVariantName() string {
return c.baseVariantName
} }
// AlgorithmCompressor returns the compressor field of algo. // AlgorithmCompressor returns the compressor field of algo.

View File

@ -11,7 +11,7 @@ const (
VersionPatch = 0 VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string. // VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev" VersionDev = ""
) )
// Version is the specification version that the package types support. // Version is the specification version that the package types support.

View File

@ -1 +1 @@
1.52.1-dev 1.53.0

View File

@ -310,16 +310,6 @@ func isNetworkFileSystem(fsMagic graphdriver.FsMagic) bool {
// If overlay filesystem is not supported on the host, a wrapped graphdriver.ErrNotSupported is returned as error. // If overlay filesystem is not supported on the host, a wrapped graphdriver.ErrNotSupported is returned as error.
// If an overlay filesystem is not supported over an existing filesystem then a wrapped graphdriver.ErrIncompatibleFS is returned. // If an overlay filesystem is not supported over an existing filesystem then a wrapped graphdriver.ErrIncompatibleFS is returned.
func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) { func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
// If custom --imagestore is selected never
// ditch the original graphRoot, instead add it as
// additionalImageStore so its images can still be
// read and used.
if options.ImageStore != "" {
graphRootAsAdditionalStore := fmt.Sprintf("AdditionalImageStore=%s", options.ImageStore)
options.DriverOptions = append(options.DriverOptions, graphRootAsAdditionalStore)
// complete base name with driver name included
options.ImageStore = filepath.Join(options.ImageStore, "overlay")
}
opts, err := parseOptions(options.DriverOptions) opts, err := parseOptions(options.DriverOptions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -863,22 +853,15 @@ func (d *Driver) Status() [][2]string {
// Metadata returns meta data about the overlay driver such as // Metadata returns meta data about the overlay driver such as
// LowerDir, UpperDir, WorkDir and MergeDir used to store data. // LowerDir, UpperDir, WorkDir and MergeDir used to store data.
func (d *Driver) Metadata(id string) (map[string]string, error) { func (d *Driver) Metadata(id string) (map[string]string, error) {
dir, imagestore, _ := d.dir2(id) dir := d.dir(id)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return nil, err return nil, err
} }
workDirBase := dir
if imagestore != "" {
if _, err := os.Stat(dir); err != nil {
return nil, err
}
workDirBase = imagestore
}
metadata := map[string]string{ metadata := map[string]string{
"WorkDir": path.Join(workDirBase, "work"), "WorkDir": path.Join(dir, "work"),
"MergedDir": path.Join(workDirBase, "merged"), "MergedDir": path.Join(dir, "merged"),
"UpperDir": path.Join(workDirBase, "diff"), "UpperDir": path.Join(dir, "diff"),
} }
lowerDirs, err := d.getLowerDirs(id) lowerDirs, err := d.getLowerDirs(id)
@ -896,7 +879,7 @@ func (d *Driver) Metadata(id string) (map[string]string, error) {
// is being shutdown. For now, we just have to unmount the bind mounted // is being shutdown. For now, we just have to unmount the bind mounted
// we had created. // we had created.
func (d *Driver) Cleanup() error { func (d *Driver) Cleanup() error {
_ = os.RemoveAll(d.getStagingDir()) _ = os.RemoveAll(filepath.Join(d.home, stagingDir))
return mount.Unmount(d.home) return mount.Unmount(d.home)
} }
@ -992,8 +975,10 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
return d.create(id, parent, opts, true) return d.create(id, parent, opts, true)
} }
func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disableQuota bool) (retErr error) { func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnly bool) (retErr error) {
dir, imageStore, _ := d.dir2(id) dir, homedir, _ := d.dir2(id, readOnly)
disableQuota := readOnly
uidMaps := d.uidMaps uidMaps := d.uidMaps
gidMaps := d.gidMaps gidMaps := d.gidMaps
@ -1004,7 +989,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
} }
// Make the link directory if it does not exist // Make the link directory if it does not exist
if err := idtools.MkdirAllAs(path.Join(d.home, linkDir), 0o755, 0, 0); err != nil { if err := idtools.MkdirAllAs(path.Join(homedir, linkDir), 0o755, 0, 0); err != nil {
return err return err
} }
@ -1021,20 +1006,8 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
if err := idtools.MkdirAllAndChownNew(path.Dir(dir), 0o755, idPair); err != nil { if err := idtools.MkdirAllAndChownNew(path.Dir(dir), 0o755, idPair); err != nil {
return err return err
} }
workDirBase := dir
if imageStore != "" {
workDirBase = imageStore
if err := idtools.MkdirAllAndChownNew(path.Dir(imageStore), 0o755, idPair); err != nil {
return err
}
}
if parent != "" { if parent != "" {
parentBase, parentImageStore, inAdditionalStore := d.dir2(parent) parentBase := d.dir(parent)
// If parentBase path is additional image store, select the image contained in parentBase.
// See https://github.com/containers/podman/issues/19748
if parentImageStore != "" && !inAdditionalStore {
parentBase = parentImageStore
}
st, err := system.Stat(filepath.Join(parentBase, "diff")) st, err := system.Stat(filepath.Join(parentBase, "diff"))
if err != nil { if err != nil {
return err return err
@ -1055,11 +1028,6 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
if err := idtools.MkdirAllAndChownNew(dir, 0o700, idPair); err != nil { if err := idtools.MkdirAllAndChownNew(dir, 0o700, idPair); err != nil {
return err return err
} }
if imageStore != "" {
if err := idtools.MkdirAllAndChownNew(imageStore, 0o700, idPair); err != nil {
return err
}
}
defer func() { defer func() {
// Clean up on failure // Clean up on failure
@ -1067,11 +1035,6 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
if err2 := os.RemoveAll(dir); err2 != nil { if err2 := os.RemoveAll(dir); err2 != nil {
logrus.Errorf("While recovering from a failure creating a layer, error deleting %#v: %v", dir, err2) logrus.Errorf("While recovering from a failure creating a layer, error deleting %#v: %v", dir, err2)
} }
if imageStore != "" {
if err2 := os.RemoveAll(workDirBase); err2 != nil {
logrus.Errorf("While recovering from a failure creating a layer, error deleting %#v: %v", workDirBase, err2)
}
}
} }
}() }()
@ -1094,11 +1057,6 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
if err := d.quotaCtl.SetQuota(dir, quota); err != nil { if err := d.quotaCtl.SetQuota(dir, quota); err != nil {
return err return err
} }
if imageStore != "" {
if err := d.quotaCtl.SetQuota(imageStore, quota); err != nil {
return err
}
}
} }
perms := defaultPerms perms := defaultPerms
@ -1107,12 +1065,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
} }
if parent != "" { if parent != "" {
parentBase, parentImageStore, inAdditionalStore := d.dir2(parent) parentBase := d.dir(parent)
// If parentBase path is additional image store, select the image contained in parentBase.
// See https://github.com/containers/podman/issues/19748
if parentImageStore != "" && !inAdditionalStore {
parentBase = parentImageStore
}
st, err := system.Stat(filepath.Join(parentBase, "diff")) st, err := system.Stat(filepath.Join(parentBase, "diff"))
if err != nil { if err != nil {
return err return err
@ -1120,17 +1073,14 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
perms = os.FileMode(st.Mode()) perms = os.FileMode(st.Mode())
} }
if err := idtools.MkdirAs(path.Join(workDirBase, "diff"), perms, rootUID, rootGID); err != nil { if err := idtools.MkdirAs(path.Join(dir, "diff"), perms, rootUID, rootGID); err != nil {
return err return err
} }
lid := generateID(idLength) lid := generateID(idLength)
linkBase := path.Join("..", id, "diff") linkBase := path.Join("..", id, "diff")
if imageStore != "" { if err := os.Symlink(linkBase, path.Join(homedir, linkDir, lid)); err != nil {
linkBase = path.Join(imageStore, "diff")
}
if err := os.Symlink(linkBase, path.Join(d.home, linkDir, lid)); err != nil {
return err return err
} }
@ -1139,10 +1089,10 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disable
return err return err
} }
if err := idtools.MkdirAs(path.Join(workDirBase, "work"), 0o700, rootUID, rootGID); err != nil { if err := idtools.MkdirAs(path.Join(dir, "work"), 0o700, rootUID, rootGID); err != nil {
return err return err
} }
if err := idtools.MkdirAs(path.Join(workDirBase, "merged"), 0o700, rootUID, rootGID); err != nil { if err := idtools.MkdirAs(path.Join(dir, "merged"), 0o700, rootUID, rootGID); err != nil {
return err return err
} }
@ -1224,26 +1174,39 @@ func (d *Driver) getLower(parent string) (string, error) {
} }
func (d *Driver) dir(id string) string { func (d *Driver) dir(id string) string {
p, _, _ := d.dir2(id) p, _, _ := d.dir2(id, false)
return p return p
} }
func (d *Driver) dir2(id string) (string, string, bool) { func (d *Driver) getAllImageStores() []string {
newpath := path.Join(d.home, id) additionalImageStores := d.AdditionalImageStores()
imageStore := ""
if d.imageStore != "" { if d.imageStore != "" {
imageStore = path.Join(d.imageStore, id) additionalImageStores = append([]string{d.imageStore}, additionalImageStores...)
} }
return additionalImageStores
}
func (d *Driver) dir2(id string, useImageStore bool) (string, string, bool) {
var homedir string
if useImageStore && d.imageStore != "" {
homedir = path.Join(d.imageStore, d.name)
} else {
homedir = d.home
}
newpath := path.Join(homedir, id)
if _, err := os.Stat(newpath); err != nil { if _, err := os.Stat(newpath); err != nil {
for _, p := range d.AdditionalImageStores() { for _, p := range d.getAllImageStores() {
l := path.Join(p, d.name, id) l := path.Join(p, d.name, id)
_, err = os.Stat(l) _, err = os.Stat(l)
if err == nil { if err == nil {
return l, imageStore, true return l, homedir, true
} }
} }
} }
return newpath, imageStore, false return newpath, homedir, false
} }
func (d *Driver) getLowerDirs(id string) ([]string, error) { func (d *Driver) getLowerDirs(id string) ([]string, error) {
@ -1453,14 +1416,11 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
} }
func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountOpts) (_ string, retErr error) { func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountOpts) (_ string, retErr error) {
dir, imageStore, inAdditionalStore := d.dir2(id) dir, _, inAdditionalStore := d.dir2(id, false)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return "", err return "", err
} }
workDirBase := dir
if imageStore != "" {
workDirBase = imageStore
}
readWrite := !inAdditionalStore readWrite := !inAdditionalStore
if !d.SupportsShifting() || options.DisableShifting { if !d.SupportsShifting() || options.DisableShifting {
@ -1565,7 +1525,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
}() }()
composeFsLayers := []string{} composeFsLayers := []string{}
composeFsLayersDir := filepath.Join(workDirBase, "composefs-layers") composeFsLayersDir := filepath.Join(dir, "composefs-layers")
maybeAddComposefsMount := func(lowerID string, i int, readWrite bool) (string, error) { maybeAddComposefsMount := func(lowerID string, i int, readWrite bool) (string, error) {
composefsBlob := d.getComposefsData(lowerID) composefsBlob := d.getComposefsData(lowerID)
_, err = os.Stat(composefsBlob) _, err = os.Stat(composefsBlob)
@ -1599,7 +1559,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
return dest, nil return dest, nil
} }
diffDir := path.Join(workDirBase, "diff") diffDir := path.Join(dir, "diff")
if dest, err := maybeAddComposefsMount(id, 0, readWrite); err != nil { if dest, err := maybeAddComposefsMount(id, 0, readWrite); err != nil {
return "", err return "", err
@ -1617,7 +1577,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
lower := "" lower := ""
newpath := path.Join(d.home, l) newpath := path.Join(d.home, l)
if st, err := os.Stat(newpath); err != nil { if st, err := os.Stat(newpath); err != nil {
for _, p := range d.AdditionalImageStores() { for _, p := range d.getAllImageStores() {
lower = path.Join(p, d.name, l) lower = path.Join(p, d.name, l)
if st2, err2 := os.Stat(lower); err2 == nil { if st2, err2 := os.Stat(lower); err2 == nil {
if !permsKnown { if !permsKnown {
@ -1685,16 +1645,16 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
optsList = append(optsList, "metacopy=on", "redirect_dir=on") optsList = append(optsList, "metacopy=on", "redirect_dir=on")
} }
if len(absLowers) == 0 {
absLowers = append(absLowers, path.Join(dir, "empty"))
}
// user namespace requires this to move a directory from lower to upper. // user namespace requires this to move a directory from lower to upper.
rootUID, rootGID, err := idtools.GetRootUIDGID(options.UidMaps, options.GidMaps) rootUID, rootGID, err := idtools.GetRootUIDGID(options.UidMaps, options.GidMaps)
if err != nil { if err != nil {
return "", err return "", err
} }
if len(absLowers) == 0 {
absLowers = append(absLowers, path.Join(dir, "empty"))
}
if err := idtools.MkdirAllAs(diffDir, perms, rootUID, rootGID); err != nil { if err := idtools.MkdirAllAs(diffDir, perms, rootUID, rootGID); err != nil {
if !inAdditionalStore { if !inAdditionalStore {
return "", err return "", err
@ -1705,7 +1665,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
} }
} }
mergedDir := path.Join(workDirBase, "merged") mergedDir := path.Join(dir, "merged")
// Create the driver merged dir
if err := idtools.MkdirAs(mergedDir, 0o700, rootUID, rootGID); err != nil && !os.IsExist(err) {
return "", err
}
if count := d.ctr.Increment(mergedDir); count > 1 { if count := d.ctr.Increment(mergedDir); count > 1 {
return mergedDir, nil return mergedDir, nil
} }
@ -1719,7 +1683,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
} }
}() }()
workdir := path.Join(workDirBase, "work") workdir := path.Join(dir, "work")
if d.options.mountProgram == "" && unshare.IsRootless() { if d.options.mountProgram == "" && unshare.IsRootless() {
optsList = append(optsList, "userxattr") optsList = append(optsList, "userxattr")
@ -1869,7 +1833,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
// Put unmounts the mount path created for the give id. // Put unmounts the mount path created for the give id.
func (d *Driver) Put(id string) error { func (d *Driver) Put(id string) error {
dir, _, inAdditionalStore := d.dir2(id) dir, _, inAdditionalStore := d.dir2(id, false)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {
return err return err
} }
@ -2038,8 +2002,9 @@ func (g *overlayFileGetter) Close() error {
return nil return nil
} }
func (d *Driver) getStagingDir() string { func (d *Driver) getStagingDir(id string) string {
return filepath.Join(d.home, stagingDir) _, homedir, _ := d.dir2(id, d.imageStore != "")
return filepath.Join(homedir, stagingDir)
} }
// DiffGetter returns a FileGetCloser that can read files from the directory that // DiffGetter returns a FileGetCloser that can read files from the directory that
@ -2096,11 +2061,12 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
var applyDir string var applyDir string
if id == "" { if id == "" {
err := os.MkdirAll(d.getStagingDir(), 0o700) stagingDir := d.getStagingDir(id)
err := os.MkdirAll(stagingDir, 0o700)
if err != nil && !os.IsExist(err) { if err != nil && !os.IsExist(err) {
return graphdriver.DriverWithDifferOutput{}, err return graphdriver.DriverWithDifferOutput{}, err
} }
applyDir, err = os.MkdirTemp(d.getStagingDir(), "") applyDir, err = os.MkdirTemp(stagingDir, "")
if err != nil { if err != nil {
return graphdriver.DriverWithDifferOutput{}, err return graphdriver.DriverWithDifferOutput{}, err
} }
@ -2144,7 +2110,7 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
// ApplyDiffFromStagingDirectory applies the changes using the specified staging directory. // ApplyDiffFromStagingDirectory applies the changes using the specified staging directory.
func (d *Driver) ApplyDiffFromStagingDirectory(id, parent string, diffOutput *graphdriver.DriverWithDifferOutput, options *graphdriver.ApplyDiffWithDifferOpts) error { func (d *Driver) ApplyDiffFromStagingDirectory(id, parent string, diffOutput *graphdriver.DriverWithDifferOutput, options *graphdriver.ApplyDiffWithDifferOpts) error {
stagingDirectory := diffOutput.Target stagingDirectory := diffOutput.Target
if filepath.Dir(stagingDirectory) != d.getStagingDir() { if filepath.Dir(stagingDirectory) != d.getStagingDir(id) {
return fmt.Errorf("%q is not a staging directory", stagingDirectory) return fmt.Errorf("%q is not a staging directory", stagingDirectory)
} }
diffPath, err := d.getDiffPath(id) diffPath, err := d.getDiffPath(id)
@ -2230,12 +2196,8 @@ func (d *Driver) getComposefsData(id string) string {
} }
func (d *Driver) getDiffPath(id string) (string, error) { func (d *Driver) getDiffPath(id string) (string, error) {
dir, imagestore, _ := d.dir2(id) dir := d.dir(id)
base := dir return redirectDiffIfAdditionalLayer(path.Join(dir, "diff"))
if imagestore != "" {
base = imagestore
}
return redirectDiffIfAdditionalLayer(path.Join(base, "diff"))
} }
func (d *Driver) getLowerDiffPaths(id string) ([]string, error) { func (d *Driver) getLowerDiffPaths(id string) ([]string, error) {
@ -2326,12 +2288,8 @@ func (d *Driver) AdditionalImageStores() []string {
// by toContainer to those specified by toHost. // by toContainer to those specified by toHost.
func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error { func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
var err error var err error
dir, imagestore, _ := d.dir2(id) dir := d.dir(id)
base := dir diffDir := filepath.Join(dir, "diff")
if imagestore != "" {
base = imagestore
}
diffDir := filepath.Join(base, "diff")
rootUID, rootGID := 0, 0 rootUID, rootGID := 0, 0
if toHost != nil { if toHost != nil {

View File

@ -31,8 +31,9 @@ func init() {
func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) { func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) {
d := &Driver{ d := &Driver{
name: "vfs", name: "vfs",
homes: []string{home}, home: home,
idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps), idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
imageStore: options.ImageStore,
} }
rootIDs := d.idMappings.RootPair() rootIDs := d.idMappings.RootPair()
@ -47,7 +48,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
key = strings.ToLower(key) key = strings.ToLower(key)
switch key { switch key {
case "vfs.imagestore", ".imagestore": case "vfs.imagestore", ".imagestore":
d.homes = append(d.homes, strings.Split(val, ",")...) d.additionalHomes = append(d.additionalHomes, strings.Split(val, ",")...)
continue continue
case "vfs.mountopt": case "vfs.mountopt":
return nil, fmt.Errorf("vfs driver does not support mount options") return nil, fmt.Errorf("vfs driver does not support mount options")
@ -62,12 +63,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
return nil, fmt.Errorf("vfs driver does not support %s options", key) return nil, fmt.Errorf("vfs driver does not support %s options", key)
} }
} }
// If --imagestore is provided, lets add writable graphRoot
// to vfs's additional image store, as it is done for
// `overlay` driver.
if options.ImageStore != "" {
d.homes = append(d.homes, options.ImageStore)
}
d.updater = graphdriver.NewNaiveLayerIDMapUpdater(d) d.updater = graphdriver.NewNaiveLayerIDMapUpdater(d)
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, d.updater) d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, d.updater)
@ -80,11 +76,13 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver // Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver
type Driver struct { type Driver struct {
name string name string
homes []string home string
additionalHomes []string
idMappings *idtools.IDMappings idMappings *idtools.IDMappings
ignoreChownErrors bool ignoreChownErrors bool
naiveDiff graphdriver.DiffDriver naiveDiff graphdriver.DiffDriver
updater graphdriver.LayerIDMapUpdater updater graphdriver.LayerIDMapUpdater
imageStore string
} }
func (d *Driver) String() string { func (d *Driver) String() string {
@ -158,7 +156,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool
idMappings = opts.IDMappings idMappings = opts.IDMappings
} }
dir := d.dir(id) dir := d.dir2(id, ro)
rootIDs := idMappings.RootPair() rootIDs := idMappings.RootPair()
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0o700, rootIDs); err != nil { if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0o700, rootIDs); err != nil {
return err return err
@ -204,18 +202,32 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool
return nil return nil
} }
func (d *Driver) dir(id string) string { func (d *Driver) dir2(id string, useImageStore bool) string {
for i, home := range d.homes { var homedir string
if i > 0 {
home = filepath.Join(home, d.String()) if useImageStore && d.imageStore != "" {
homedir = filepath.Join(d.imageStore, d.String(), "dir", filepath.Base(id))
} else {
homedir = filepath.Join(d.home, "dir", filepath.Base(id))
} }
candidate := filepath.Join(home, "dir", filepath.Base(id)) if _, err := os.Stat(homedir); err != nil {
additionalHomes := d.additionalHomes[:]
if d.imageStore != "" {
additionalHomes = append(additionalHomes, d.imageStore)
}
for _, home := range additionalHomes {
candidate := filepath.Join(home, d.String(), "dir", filepath.Base(id))
fi, err := os.Stat(candidate) fi, err := os.Stat(candidate)
if err == nil && fi.IsDir() { if err == nil && fi.IsDir() {
return candidate return candidate
} }
} }
return filepath.Join(d.homes[0], "dir", filepath.Base(id)) }
return homedir
}
func (d *Driver) dir(id string) string {
return d.dir2(id, false)
} }
// Remove deletes the content from the directory for a given id. // Remove deletes the content from the directory for a given id.
@ -263,7 +275,7 @@ func (d *Driver) Exists(id string) bool {
// List layers (not including additional image stores) // List layers (not including additional image stores)
func (d *Driver) ListLayers() ([]string, error) { func (d *Driver) ListLayers() ([]string, error) {
entries, err := os.ReadDir(filepath.Join(d.homes[0], "dir")) entries, err := os.ReadDir(filepath.Join(d.home, "dir"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,8 +297,8 @@ func (d *Driver) ListLayers() ([]string, error) {
// AdditionalImageStores returns additional image stores supported by the driver // AdditionalImageStores returns additional image stores supported by the driver
func (d *Driver) AdditionalImageStores() []string { func (d *Driver) AdditionalImageStores() []string {
if len(d.homes) > 1 { if len(d.additionalHomes) > 0 {
return d.homes[1:] return d.additionalHomes
} }
return nil return nil
} }

View File

@ -334,10 +334,71 @@ type rwLayerStore interface {
GarbageCollect() error GarbageCollect() error
} }
type multipleLockFile struct {
lockfiles []*lockfile.LockFile
}
func (l multipleLockFile) Lock() {
for _, lock := range l.lockfiles {
lock.Lock()
}
}
func (l multipleLockFile) RLock() {
for _, lock := range l.lockfiles {
lock.RLock()
}
}
func (l multipleLockFile) Unlock() {
for _, lock := range l.lockfiles {
lock.Unlock()
}
}
func (l multipleLockFile) ModifiedSince(lastWrite lockfile.LastWrite) (lockfile.LastWrite, bool, error) {
// Look up only the first lockfile, since this is the value returned by RecordWrite().
return l.lockfiles[0].ModifiedSince(lastWrite)
}
func (l multipleLockFile) AssertLockedForWriting() {
for _, lock := range l.lockfiles {
lock.AssertLockedForWriting()
}
}
func (l multipleLockFile) GetLastWrite() (lockfile.LastWrite, error) {
return l.lockfiles[0].GetLastWrite()
}
func (l multipleLockFile) RecordWrite() (lockfile.LastWrite, error) {
var lastWrite *lockfile.LastWrite
for _, lock := range l.lockfiles {
lw, err := lock.RecordWrite()
if err != nil {
return lw, err
}
// Return the first value we get so we know that
// all the locks have a write time >= to this one.
if lastWrite == nil {
lastWrite = &lw
}
}
return *lastWrite, nil
}
func (l multipleLockFile) IsReadWrite() bool {
return l.lockfiles[0].IsReadWrite()
}
func newMultipleLockFile(l ...*lockfile.LockFile) *multipleLockFile {
return &multipleLockFile{lockfiles: l}
}
type layerStore struct { type layerStore struct {
// The following fields are only set when constructing layerStore, and must never be modified afterwards. // The following fields are only set when constructing layerStore, and must never be modified afterwards.
// They are safe to access without any other locking. // They are safe to access without any other locking.
lockfile *lockfile.LockFile // lockfile.IsReadWrite can be used to distinguish between read-write and read-only layer stores. lockfile *multipleLockFile // lockfile.IsReadWrite can be used to distinguish between read-write and read-only layer stores.
mountsLockfile *lockfile.LockFile // Can _only_ be obtained with inProcessLock held. mountsLockfile *lockfile.LockFile // Can _only_ be obtained with inProcessLock held.
rundir string rundir string
jsonPath [numLayerLocationIndex]string jsonPath [numLayerLocationIndex]string
@ -1023,22 +1084,37 @@ func (r *layerStore) saveMounts() error {
return r.loadMounts() return r.loadMounts()
} }
func (s *store) newLayerStore(rundir string, layerdir string, driver drivers.Driver, transient bool) (rwLayerStore, error) { func (s *store) newLayerStore(rundir, layerdir, imagedir string, driver drivers.Driver, transient bool) (rwLayerStore, error) {
if err := os.MkdirAll(rundir, 0o700); err != nil { if err := os.MkdirAll(rundir, 0o700); err != nil {
return nil, err return nil, err
} }
if err := os.MkdirAll(layerdir, 0o700); err != nil { if err := os.MkdirAll(layerdir, 0o700); err != nil {
return nil, err return nil, err
} }
if imagedir != "" {
if err := os.MkdirAll(imagedir, 0o700); err != nil {
return nil, err
}
}
// Note: While the containers.lock file is in rundir for transient stores // Note: While the containers.lock file is in rundir for transient stores
// we don't want to do this here, because the non-transient layers in // we don't want to do this here, because the non-transient layers in
// layers.json might be used externally as a read-only layer (using e.g. // layers.json might be used externally as a read-only layer (using e.g.
// additionalimagestores), and that would look for the lockfile in the // additionalimagestores), and that would look for the lockfile in the
// same directory // same directory
var lockFiles []*lockfile.LockFile
lockFile, err := lockfile.GetLockFile(filepath.Join(layerdir, "layers.lock")) lockFile, err := lockfile.GetLockFile(filepath.Join(layerdir, "layers.lock"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
lockFiles = append(lockFiles, lockFile)
if imagedir != "" {
lockFile, err := lockfile.GetLockFile(filepath.Join(imagedir, "layers.lock"))
if err != nil {
return nil, err
}
lockFiles = append(lockFiles, lockFile)
}
mountsLockfile, err := lockfile.GetLockFile(filepath.Join(rundir, "mountpoints.lock")) mountsLockfile, err := lockfile.GetLockFile(filepath.Join(rundir, "mountpoints.lock"))
if err != nil { if err != nil {
return nil, err return nil, err
@ -1048,7 +1124,7 @@ func (s *store) newLayerStore(rundir string, layerdir string, driver drivers.Dri
volatileDir = rundir volatileDir = rundir
} }
rlstore := layerStore{ rlstore := layerStore{
lockfile: lockFile, lockfile: newMultipleLockFile(lockFiles...),
mountsLockfile: mountsLockfile, mountsLockfile: mountsLockfile,
rundir: rundir, rundir: rundir,
jsonPath: [numLayerLocationIndex]string{ jsonPath: [numLayerLocationIndex]string{
@ -1085,7 +1161,7 @@ func newROLayerStore(rundir string, layerdir string, driver drivers.Driver) (roL
return nil, err return nil, err
} }
rlstore := layerStore{ rlstore := layerStore{
lockfile: lockfile, lockfile: newMultipleLockFile(lockfile),
mountsLockfile: nil, mountsLockfile: nil,
rundir: rundir, rundir: rundir,
jsonPath: [numLayerLocationIndex]string{ jsonPath: [numLayerLocationIndex]string{

View File

@ -416,7 +416,7 @@ func ReadUserXattrToTarHeader(path string, hdr *tar.Header) error {
return err return err
} }
for _, key := range xattrs { for _, key := range xattrs {
if strings.HasPrefix(key, "user.") { if strings.HasPrefix(key, "user.") && !strings.HasPrefix(key, "user.overlay.") {
value, err := system.Lgetxattr(path, key) value, err := system.Lgetxattr(path, key)
if err != nil { if err != nil {
if errors.Is(err, system.E2BIG) { if errors.Is(err, system.E2BIG) {

View File

@ -41,6 +41,7 @@ import (
const ( const (
maxNumberMissingChunks = 1024 maxNumberMissingChunks = 1024
autoMergePartsThreshold = 128 // if the gap between two ranges is below this threshold, automatically merge them.
newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY) newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY)
containersOverrideXattr = "user.containers.override_stat" containersOverrideXattr = "user.containers.override_stat"
bigDataKey = "zstd-chunked-manifest" bigDataKey = "zstd-chunked-manifest"
@ -1180,22 +1181,12 @@ func (c *chunkedDiffer) storeMissingFiles(streams chan io.ReadCloser, errs chan
} }
func mergeMissingChunks(missingParts []missingPart, target int) []missingPart { func mergeMissingChunks(missingParts []missingPart, target int) []missingPart {
getGap := func(missingParts []missingPart, i int) int { getGap := func(missingParts []missingPart, i int) uint64 {
prev := missingParts[i-1].SourceChunk.Offset + missingParts[i-1].SourceChunk.Length prev := missingParts[i-1].SourceChunk.Offset + missingParts[i-1].SourceChunk.Length
return int(missingParts[i].SourceChunk.Offset - prev) return missingParts[i].SourceChunk.Offset - prev
}
getCost := func(missingParts []missingPart, i int) int {
cost := getGap(missingParts, i)
if missingParts[i-1].OriginFile != nil {
cost += int(missingParts[i-1].SourceChunk.Length)
}
if missingParts[i].OriginFile != nil {
cost += int(missingParts[i].SourceChunk.Length)
}
return cost
} }
// simple case: merge chunks from the same file. // simple case: merge chunks from the same file. Useful to reduce the number of parts to work with later.
newMissingParts := missingParts[0:1] newMissingParts := missingParts[0:1]
prevIndex := 0 prevIndex := 0
for i := 1; i < len(missingParts); i++ { for i := 1; i < len(missingParts); i++ {
@ -1215,28 +1206,50 @@ func mergeMissingChunks(missingParts []missingPart, target int) []missingPart {
} }
missingParts = newMissingParts missingParts = newMissingParts
if len(missingParts) <= target { type gap struct {
return missingParts from int
to int
cost uint64
} }
var requestGaps []gap
// this implementation doesn't account for duplicates, so it could merge lastOffset := int(-1)
// more than necessary to reach the specified target. Since target itself numberSourceChunks := 0
// is a heuristic value, it doesn't matter. for i, c := range missingParts {
costs := make([]int, len(missingParts)-1) if c.OriginFile != nil || c.Hole {
for i := 1; i < len(missingParts); i++ { // it does not require a network request
costs[i-1] = getCost(missingParts, i) continue
} }
sort.Ints(costs) numberSourceChunks++
if lastOffset >= 0 {
toShrink := len(missingParts) - target prevEnd := missingParts[lastOffset].SourceChunk.Offset + missingParts[lastOffset].SourceChunk.Length
if toShrink >= len(costs) { cost := c.SourceChunk.Offset - prevEnd
toShrink = len(costs) - 1 g := gap{
from: lastOffset,
to: i,
cost: cost,
}
requestGaps = append(requestGaps, g)
}
lastOffset = i
}
sort.Slice(requestGaps, func(i, j int) bool {
return requestGaps[i].cost < requestGaps[j].cost
})
toMergeMap := make([]bool, len(missingParts))
remainingToMerge := numberSourceChunks - target
for _, g := range requestGaps {
if remainingToMerge < 0 && g.cost > autoMergePartsThreshold {
continue
}
for i := g.from + 1; i <= g.to; i++ {
toMergeMap[i] = true
}
remainingToMerge--
} }
targetValue := costs[toShrink]
newMissingParts = missingParts[0:1] newMissingParts = missingParts[0:1]
for i := 1; i < len(missingParts); i++ { for i := 1; i < len(missingParts); i++ {
if getCost(missingParts, i) > targetValue { if !toMergeMap[i] {
newMissingParts = append(newMissingParts, missingParts[i]) newMissingParts = append(newMissingParts, missingParts[i])
} else { } else {
gap := getGap(missingParts, i) gap := getGap(missingParts, i)
@ -1268,6 +1281,7 @@ func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dest st
} }
} }
missingParts = mergeMissingChunks(missingParts, maxNumberMissingChunks)
calculateChunksToRequest() calculateChunksToRequest()
// There are some missing files. Prepare a multirange request for the missing chunks. // There are some missing files. Prepare a multirange request for the missing chunks.
@ -1281,14 +1295,13 @@ func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dest st
} }
if _, ok := err.(ErrBadRequest); ok { if _, ok := err.(ErrBadRequest); ok {
requested := len(missingParts)
// If the server cannot handle at least 64 chunks in a single request, just give up. // If the server cannot handle at least 64 chunks in a single request, just give up.
if requested < 64 { if len(chunksToRequest) < 64 {
return err return err
} }
// Merge more chunks to request // Merge more chunks to request
missingParts = mergeMissingChunks(missingParts, requested/2) missingParts = mergeMissingChunks(missingParts, len(chunksToRequest)/2)
calculateChunksToRequest() calculateChunksToRequest()
continue continue
} }
@ -1999,7 +2012,6 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
} }
// There are some missing files. Prepare a multirange request for the missing chunks. // There are some missing files. Prepare a multirange request for the missing chunks.
if len(missingParts) > 0 { if len(missingParts) > 0 {
missingParts = mergeMissingChunks(missingParts, maxNumberMissingChunks)
if err := c.retrieveMissingFiles(stream, dest, dirfd, missingParts, options); err != nil { if err := c.retrieveMissingFiles(stream, dest, dirfd, missingParts, options); err != nil {
return output, err return output, err
} }

View File

@ -972,11 +972,13 @@ func (s *store) load() error {
if err := os.MkdirAll(gipath, 0o700); err != nil { if err := os.MkdirAll(gipath, 0o700); err != nil {
return err return err
} }
ris, err := newImageStore(gipath) imageStore, err := newImageStore(gipath)
if err != nil { if err != nil {
return err return err
} }
s.imageStore = ris s.imageStore = imageStore
s.rwImageStores = []rwImageStore{imageStore}
gcpath := filepath.Join(s.graphRoot, driverPrefix+"containers") gcpath := filepath.Join(s.graphRoot, driverPrefix+"containers")
if err := os.MkdirAll(gcpath, 0o700); err != nil { if err := os.MkdirAll(gcpath, 0o700); err != nil {
@ -994,13 +996,16 @@ func (s *store) load() error {
s.containerStore = rcs s.containerStore = rcs
for _, store := range driver.AdditionalImageStores() { additionalImageStores := s.graphDriver.AdditionalImageStores()
if s.imageStoreDir != "" {
additionalImageStores = append([]string{s.graphRoot}, additionalImageStores...)
}
for _, store := range additionalImageStores {
gipath := filepath.Join(store, driverPrefix+"images") gipath := filepath.Join(store, driverPrefix+"images")
var ris roImageStore var ris roImageStore
if s.imageStoreDir != "" && store == s.graphRoot { // both the graphdriver and the imagestore must be used read-write.
// If --imagestore was set and current store if store == s.imageStoreDir || store == s.graphRoot {
// is `graphRoot` then mount it as a `rw` additional
// store instead of `readonly` additional store.
imageStore, err := newImageStore(gipath) imageStore, err := newImageStore(gipath)
if err != nil { if err != nil {
return err return err
@ -1085,15 +1090,9 @@ func (s *store) stopUsingGraphDriver() {
// Almost all users should use startUsingGraphDriver instead. // Almost all users should use startUsingGraphDriver instead.
// The caller must hold s.graphLock. // The caller must hold s.graphLock.
func (s *store) createGraphDriverLocked() (drivers.Driver, error) { func (s *store) createGraphDriverLocked() (drivers.Driver, error) {
driverRoot := s.imageStoreDir
imageStoreBase := s.graphRoot
if driverRoot == "" {
driverRoot = s.graphRoot
imageStoreBase = ""
}
config := drivers.Options{ config := drivers.Options{
Root: driverRoot, Root: s.graphRoot,
ImageStore: imageStoreBase, ImageStore: s.imageStoreDir,
RunRoot: s.runRoot, RunRoot: s.runRoot,
DriverPriority: s.graphDriverPriority, DriverPriority: s.graphDriverPriority,
DriverOptions: s.graphOptions, DriverOptions: s.graphOptions,
@ -1123,15 +1122,15 @@ func (s *store) getLayerStoreLocked() (rwLayerStore, error) {
if err := os.MkdirAll(rlpath, 0o700); err != nil { if err := os.MkdirAll(rlpath, 0o700); err != nil {
return nil, err return nil, err
} }
imgStoreRoot := s.imageStoreDir glpath := filepath.Join(s.graphRoot, driverPrefix+"layers")
if imgStoreRoot == "" {
imgStoreRoot = s.graphRoot
}
glpath := filepath.Join(imgStoreRoot, driverPrefix+"layers")
if err := os.MkdirAll(glpath, 0o700); err != nil { if err := os.MkdirAll(glpath, 0o700); err != nil {
return nil, err return nil, err
} }
rls, err := s.newLayerStore(rlpath, glpath, s.graphDriver, s.transientStore) ilpath := ""
if s.imageStoreDir != "" {
ilpath = filepath.Join(s.imageStoreDir, driverPrefix+"layers")
}
rls, err := s.newLayerStore(rlpath, glpath, ilpath, s.graphDriver, s.transientStore)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1162,8 +1161,10 @@ func (s *store) getROLayerStoresLocked() ([]roLayerStore, error) {
if err := os.MkdirAll(rlpath, 0o700); err != nil { if err := os.MkdirAll(rlpath, 0o700); err != nil {
return nil, err return nil, err
} }
for _, store := range s.graphDriver.AdditionalImageStores() { for _, store := range s.graphDriver.AdditionalImageStores() {
glpath := filepath.Join(store, driverPrefix+"layers") glpath := filepath.Join(store, driverPrefix+"layers")
rls, err := newROLayerStore(rlpath, glpath, s.graphDriver) rls, err := newROLayerStore(rlpath, glpath, s.graphDriver)
if err != nil { if err != nil {
return nil, err return nil, err
@ -2590,7 +2591,7 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
if err := s.writeToAllStores(func(rlstore rwLayerStore) error { if err := s.writeToAllStores(func(rlstore rwLayerStore) error {
// Delete image from all available imagestores configured to be used. // Delete image from all available imagestores configured to be used.
imageFound := false imageFound := false
for _, is := range append([]rwImageStore{s.imageStore}, s.rwImageStores...) { for _, is := range s.rwImageStores {
if is != s.imageStore { if is != s.imageStore {
// This is an additional writeable image store // This is an additional writeable image store
// so we must perform lock // so we must perform lock

View File

@ -1,10 +0,0 @@
Serious about security
======================
Square recognizes the important contributions the security research community
can make. We therefore encourage reporting security issues with the code
contained in this repository.
If you believe you have discovered a security vulnerability, please follow the
guidelines at <https://bugcrowd.com/squareopensource>.

View File

@ -1,6 +1,23 @@
# v3.0.2
## Fixed
- DecryptMulti: handle decompression error (#19)
## Changed
- jwe/CompactSerialize: improve performance (#67)
- Increase the default number of PBKDF2 iterations to 600k (#48)
- Return the proper algorithm for ECDSA keys (#45)
## Added
- Add Thumbprint support for opaque signers (#38)
# v3.0.1 # v3.0.1
Fixed: ## Fixed
- Security issue: an attacker specifying a large "p2c" value can cause - Security issue: an attacker specifying a large "p2c" value can cause
JSONWebEncryption.Decrypt and JSONWebEncryption.DecryptMulti to consume large JSONWebEncryption.Decrypt and JSONWebEncryption.DecryptMulti to consume large
amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the

View File

@ -1,15 +1,18 @@
# Go JOSE # Go JOSE
[![godoc](http://img.shields.io/badge/godoc-jose_package-blue.svg?style=flat)](https://godoc.org/gopkg.in/go-jose/go-jose.v2) [![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v3.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v3)
[![godoc](http://img.shields.io/badge/godoc-jwt_package-blue.svg?style=flat)](https://godoc.org/gopkg.in/go-jose/go-jose.v2/jwt) [![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v3/jwt.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v3/jwt)
[![license](http://img.shields.io/badge/license-apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE) [![license](https://img.shields.io/badge/license-apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE)
[![build](https://travis-ci.org/go-jose/go-jose.svg?branch=master)](https://travis-ci.org/go-jose/go-jose) [![test](https://img.shields.io/github/checks-status/go-jose/go-jose/v3)](https://github.com/go-jose/go-jose/actions)
[![coverage](https://coveralls.io/repos/github/go-jose/go-jose/badge.svg?branch=master)](https://coveralls.io/r/go-jose/go-jose)
Package jose aims to provide an implementation of the Javascript Object Signing Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption, and Encryption set of standards. This includes support for JSON Web Encryption,
JSON Web Signature, and JSON Web Token standards. JSON Web Signature, and JSON Web Token standards.
**Help Wanted!** If you'd like to help us develop this library please reach
out to css (at) css.bio. While I'm still working on keeping this maintained,
I have limited time for in-depth development and could use some additional help.
**Disclaimer**: This library contains encryption software that is subject to **Disclaimer**: This library contains encryption software that is subject to
the U.S. Export Administration Regulations. You may not export, re-export, the U.S. Export Administration Regulations. You may not export, re-export,
transfer or download this code or any part of it in violation of any United transfer or download this code or any part of it in violation of any United
@ -21,13 +24,13 @@ US maintained blocked list.
## Overview ## Overview
The implementation follows the The implementation follows the
[JSON Web Encryption](http://dx.doi.org/10.17487/RFC7516) (RFC 7516), [JSON Web Encryption](https://dx.doi.org/10.17487/RFC7516) (RFC 7516),
[JSON Web Signature](http://dx.doi.org/10.17487/RFC7515) (RFC 7515), and [JSON Web Signature](https://dx.doi.org/10.17487/RFC7515) (RFC 7515), and
[JSON Web Token](http://dx.doi.org/10.17487/RFC7519) (RFC 7519) specifications. [JSON Web Token](https://dx.doi.org/10.17487/RFC7519) (RFC 7519) specifications.
Tables of supported algorithms are shown below. The library supports both Tables of supported algorithms are shown below. The library supports both
the compact and JWS/JWE JSON Serialization formats, and has optional support for the compact and JWS/JWE JSON Serialization formats, and has optional support for
multiple recipients. It also comes with a small command-line utility multiple recipients. It also comes with a small command-line utility
([`jose-util`](https://github.com/go-jose/go-jose/tree/master/jose-util)) ([`jose-util`](https://pkg.go.dev/github.com/go-jose/go-jose/jose-util))
for dealing with JOSE messages in a shell. for dealing with JOSE messages in a shell.
**Note**: We use a forked version of the `encoding/json` package from the Go **Note**: We use a forked version of the `encoding/json` package from the Go
@ -38,29 +41,19 @@ libraries in other languages.
### Versions ### Versions
[Version 2](https://gopkg.in/go-jose/go-jose.v2)
([branch](https://github.com/go-jose/go-jose/tree/v2),
[doc](https://godoc.org/gopkg.in/go-jose/go-jose.v2)) is the current stable version:
import "gopkg.in/go-jose/go-jose.v2"
[Version 3](https://github.com/go-jose/go-jose) [Version 3](https://github.com/go-jose/go-jose)
([branch](https://github.com/go-jose/go-jose/tree/master), ([branch](https://github.com/go-jose/go-jose/tree/v3),
[doc](https://godoc.org/github.com/go-jose/go-jose)) is the under development/unstable version (not released yet): [doc](https://pkg.go.dev/github.com/go-jose/go-jose/v3), [releases](https://github.com/go-jose/go-jose/releases)) is the current stable version:
import "github.com/go-jose/go-jose/v3" import "github.com/go-jose/go-jose/v3"
All new feature development takes place on the `master` branch, which we are The old [square/go-jose](https://github.com/square/go-jose) repo contains the prior v1 and v2 versions, which
preparing to release as version 3 soon. Version 2 will continue to receive are still useable but not actively developed anymore.
critical bug and security fixes. Note that starting with version 3 we are
using Go modules for versioning instead of `gopkg.in` as before. Version 3 also will require Go version 1.13 or higher.
Version 1 (on the `v1` branch) is frozen and not supported anymore.
### Supported algorithms ### Supported algorithms
See below for a table of supported algorithms. Algorithm identifiers match See below for a table of supported algorithms. Algorithm identifiers match
the names in the [JSON Web Algorithms](http://dx.doi.org/10.17487/RFC7518) the names in the [JSON Web Algorithms](https://dx.doi.org/10.17487/RFC7518)
standard where possible. The Godoc reference has a list of constants. standard where possible. The Godoc reference has a list of constants.
Key encryption | Algorithm identifier(s) Key encryption | Algorithm identifier(s)
@ -103,20 +96,20 @@ allows attaching a key id.
Algorithm(s) | Corresponding types Algorithm(s) | Corresponding types
:------------------------- | ------------------------------- :------------------------- | -------------------------------
RSA | *[rsa.PublicKey](http://golang.org/pkg/crypto/rsa/#PublicKey), *[rsa.PrivateKey](http://golang.org/pkg/crypto/rsa/#PrivateKey) RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey)
ECDH, ECDSA | *[ecdsa.PublicKey](http://golang.org/pkg/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](http://golang.org/pkg/crypto/ecdsa/#PrivateKey) ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey)
EdDSA<sup>1</sup> | [ed25519.PublicKey](https://godoc.org/pkg/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://godoc.org/pkg/crypto/ed25519#PrivateKey) EdDSA<sup>1</sup> | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey)
AES, HMAC | []byte AES, HMAC | []byte
<sup>1. Only available in version 2 or later of the package</sup> <sup>1. Only available in version 2 or later of the package</sup>
## Examples ## Examples
[![godoc](http://img.shields.io/badge/godoc-jose_package-blue.svg?style=flat)](https://godoc.org/gopkg.in/go-jose/go-jose.v2) [![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v3.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v3)
[![godoc](http://img.shields.io/badge/godoc-jwt_package-blue.svg?style=flat)](https://godoc.org/gopkg.in/go-jose/go-jose.v2/jwt) [![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v3/jwt.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v3/jwt)
Examples can be found in the Godoc Examples can be found in the Godoc
reference for this package. The reference for this package. The
[`jose-util`](https://github.com/go-jose/go-jose/tree/master/jose-util) [`jose-util`](https://github.com/go-jose/go-jose/tree/v3/jose-util)
subdirectory also contains a small command-line utility which might be useful subdirectory also contains a small command-line utility which might be useful
as an example as well. as an example as well.

View File

@ -0,0 +1,13 @@
# Security Policy
This document explains how to contact the Let's Encrypt security team to report security vulnerabilities.
## Supported Versions
| Version | Supported |
| ------- | ----------|
| >= v3 | &check; |
| v2 | &cross; |
| v1 | &cross; |
## Reporting a vulnerability
Please see [https://letsencrypt.org/contact/#security](https://letsencrypt.org/contact/#security) for the email address to report a vulnerability. Ensure that the subject line for your report contains the word `vulnerability` and is descriptive. Your email should be acknowledged within 24 hours. If you do not receive a response within 24 hours, please follow-up again with another email.

View File

@ -285,6 +285,9 @@ func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm
switch alg { switch alg {
case RS256, RS384, RS512: case RS256, RS384, RS512:
// TODO(https://github.com/go-jose/go-jose/issues/40): As of go1.20, the
// random parameter is legacy and ignored, and it can be nil.
// https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/crypto/rsa/pkcs1v15.go;l=263;bpv=0;bpt=1
out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed) out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed)
case PS256, PS384, PS512: case PS256, PS384, PS512:
out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{ out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{

View File

@ -21,7 +21,6 @@ import (
"crypto/rsa" "crypto/rsa"
"errors" "errors"
"fmt" "fmt"
"reflect"
"github.com/go-jose/go-jose/v3/json" "github.com/go-jose/go-jose/v3/json"
) )
@ -76,14 +75,24 @@ type recipientKeyInfo struct {
type EncrypterOptions struct { type EncrypterOptions struct {
Compression CompressionAlgorithm Compression CompressionAlgorithm
// Optional map of additional keys to be inserted into the protected header // Optional map of name/value pairs to be inserted into the protected
// of a JWS object. Some specifications which make use of JWS like to insert // header of a JWS object. Some specifications which make use of
// additional values here. All values must be JSON-serializable. // JWS require additional values here.
//
// Values will be serialized by [json.Marshal] and must be valid inputs to
// that function.
//
// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
ExtraHeaders map[HeaderKey]interface{} ExtraHeaders map[HeaderKey]interface{}
} }
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it // WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
// if necessary. It returns itself and so can be used in a fluent style. // if necessary, and returns the updated EncrypterOptions.
//
// The v parameter will be serialized by [json.Marshal] and must be a valid
// input to that function.
//
// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions { func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions {
if eo.ExtraHeaders == nil { if eo.ExtraHeaders == nil {
eo.ExtraHeaders = map[HeaderKey]interface{}{} eo.ExtraHeaders = map[HeaderKey]interface{}{}
@ -112,6 +121,16 @@ func (eo *EncrypterOptions) WithType(typ ContentType) *EncrypterOptions {
// be generated. // be generated.
type Recipient struct { type Recipient struct {
Algorithm KeyAlgorithm Algorithm KeyAlgorithm
// Key must have one of these types:
// - ed25519.PublicKey
// - *ecdsa.PublicKey
// - *rsa.PublicKey
// - *JSONWebKey
// - JSONWebKey
// - []byte (a symmetric key)
// - Any type that satisfies the OpaqueKeyEncrypter interface
//
// The type of Key must match the value of Algorithm.
Key interface{} Key interface{}
KeyID string KeyID string
PBES2Count int PBES2Count int
@ -150,16 +169,17 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions)
switch rcpt.Algorithm { switch rcpt.Algorithm {
case DIRECT: case DIRECT:
// Direct encryption mode must be treated differently // Direct encryption mode must be treated differently
if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) { keyBytes, ok := rawKey.([]byte)
if !ok {
return nil, ErrUnsupportedKeyType return nil, ErrUnsupportedKeyType
} }
if encrypter.cipher.keySize() != len(rawKey.([]byte)) { if encrypter.cipher.keySize() != len(keyBytes) {
return nil, ErrInvalidKeySize return nil, ErrInvalidKeySize
} }
encrypter.keyGenerator = staticKeyGenerator{ encrypter.keyGenerator = staticKeyGenerator{
key: rawKey.([]byte), key: keyBytes,
} }
recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, rawKey.([]byte)) recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, keyBytes)
recipientInfo.keyID = keyID recipientInfo.keyID = keyID
if rcpt.KeyID != "" { if rcpt.KeyID != "" {
recipientInfo.keyID = rcpt.KeyID recipientInfo.keyID = rcpt.KeyID
@ -168,16 +188,16 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions)
return encrypter, nil return encrypter, nil
case ECDH_ES: case ECDH_ES:
// ECDH-ES (w/o key wrapping) is similar to DIRECT mode // ECDH-ES (w/o key wrapping) is similar to DIRECT mode
typeOf := reflect.TypeOf(rawKey) keyDSA, ok := rawKey.(*ecdsa.PublicKey)
if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) { if !ok {
return nil, ErrUnsupportedKeyType return nil, ErrUnsupportedKeyType
} }
encrypter.keyGenerator = ecKeyGenerator{ encrypter.keyGenerator = ecKeyGenerator{
size: encrypter.cipher.keySize(), size: encrypter.cipher.keySize(),
algID: string(enc), algID: string(enc),
publicKey: rawKey.(*ecdsa.PublicKey), publicKey: keyDSA,
} }
recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, rawKey.(*ecdsa.PublicKey)) recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, keyDSA)
recipientInfo.keyID = keyID recipientInfo.keyID = keyID
if rcpt.KeyID != "" { if rcpt.KeyID != "" {
recipientInfo.keyID = rcpt.KeyID recipientInfo.keyID = rcpt.KeyID
@ -270,9 +290,8 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey
recipient, err := makeJWERecipient(alg, encryptionKey.Key) recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID recipient.keyID = encryptionKey.KeyID
return recipient, err return recipient, err
} case OpaqueKeyEncrypter:
if encrypter, ok := encryptionKey.(OpaqueKeyEncrypter); ok { return newOpaqueKeyEncrypter(alg, encryptionKey)
return newOpaqueKeyEncrypter(alg, encrypter)
} }
return recipientKeyInfo{}, ErrUnsupportedKeyType return recipientKeyInfo{}, ErrUnsupportedKeyType
} }
@ -300,12 +319,12 @@ func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) {
return newDecrypter(decryptionKey.Key) return newDecrypter(decryptionKey.Key)
case *JSONWebKey: case *JSONWebKey:
return newDecrypter(decryptionKey.Key) return newDecrypter(decryptionKey.Key)
} case OpaqueKeyDecrypter:
if okd, ok := decryptionKey.(OpaqueKeyDecrypter); ok { return &opaqueKeyDecrypter{decrypter: decryptionKey}, nil
return &opaqueKeyDecrypter{decrypter: okd}, nil default:
}
return nil, ErrUnsupportedKeyType return nil, ErrUnsupportedKeyType
} }
}
// Implementation of encrypt method producing a JWE object. // Implementation of encrypt method producing a JWE object.
func (ctx *genericEncrypter) Encrypt(plaintext []byte) (*JSONWebEncryption, error) { func (ctx *genericEncrypter) Encrypt(plaintext []byte) (*JSONWebEncryption, error) {
@ -403,9 +422,24 @@ func (ctx *genericEncrypter) Options() EncrypterOptions {
} }
} }
// Decrypt and validate the object and return the plaintext. Note that this // Decrypt and validate the object and return the plaintext. This
// function does not support multi-recipient, if you desire multi-recipient // function does not support multi-recipient. If you desire multi-recipient
// decryption use DecryptMulti instead. // decryption use DecryptMulti instead.
//
// The decryptionKey argument must contain a private or symmetric key
// and must have one of these types:
// - *ecdsa.PrivateKey
// - *rsa.PrivateKey
// - *JSONWebKey
// - JSONWebKey
// - *JSONWebKeySet
// - JSONWebKeySet
// - []byte (a symmetric key)
// - string (a symmetric key)
// - Any type that satisfies the OpaqueKeyDecrypter interface.
//
// Note that ed25519 is only available for signatures, not encryption, so is
// not an option here.
func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) { func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) {
headers := obj.mergedHeaders(nil) headers := obj.mergedHeaders(nil)
@ -462,15 +496,21 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
// The "zip" header parameter may only be present in the protected header. // The "zip" header parameter may only be present in the protected header.
if comp := obj.protected.getCompression(); comp != "" { if comp := obj.protected.getCompression(); comp != "" {
plaintext, err = decompress(comp, plaintext) plaintext, err = decompress(comp, plaintext)
if err != nil {
return nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
}
} }
return plaintext, err return plaintext, nil
} }
// DecryptMulti decrypts and validates the object and returns the plaintexts, // DecryptMulti decrypts and validates the object and returns the plaintexts,
// with support for multiple recipients. It returns the index of the recipient // with support for multiple recipients. It returns the index of the recipient
// for which the decryption was successful, the merged headers for that recipient, // for which the decryption was successful, the merged headers for that recipient,
// and the plaintext. // and the plaintext.
//
// The decryptionKey argument must have one of the types allowed for the
// decryptionKey argument of Decrypt().
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) { func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
globalHeaders := obj.mergedHeaders(nil) globalHeaders := obj.mergedHeaders(nil)
@ -532,7 +572,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
// The "zip" header parameter may only be present in the protected header. // The "zip" header parameter may only be present in the protected header.
if comp := obj.protected.getCompression(); comp != "" { if comp := obj.protected.getCompression(); comp != "" {
plaintext, _ = decompress(comp, plaintext) plaintext, err = decompress(comp, plaintext)
if err != nil {
return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err)
}
} }
sanitized, err := headers.sanitized() sanitized, err := headers.sanitized()

View File

@ -15,13 +15,11 @@
*/ */
/* /*
Package jose aims to provide an implementation of the Javascript Object Signing Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. It implements encryption and signing based on and Encryption set of standards. It implements encryption and signing based on
the JSON Web Encryption and JSON Web Signature standards, with optional JSON Web the JSON Web Encryption and JSON Web Signature standards, with optional JSON Web
Token support available in a sub-package. The library supports both the compact Token support available in a sub-package. The library supports both the compact
and JWS/JWE JSON Serialization formats, and has optional support for multiple and JWS/JWE JSON Serialization formats, and has optional support for multiple
recipients. recipients.
*/ */
package jose package jose

View File

@ -189,3 +189,36 @@ func base64URLDecode(value string) ([]byte, error) {
value = strings.TrimRight(value, "=") value = strings.TrimRight(value, "=")
return base64.RawURLEncoding.DecodeString(value) return base64.RawURLEncoding.DecodeString(value)
} }
func base64EncodeLen(sl []byte) int {
return base64.RawURLEncoding.EncodedLen(len(sl))
}
func base64JoinWithDots(inputs ...[]byte) string {
if len(inputs) == 0 {
return ""
}
// Count of dots.
totalCount := len(inputs) - 1
for _, input := range inputs {
totalCount += base64EncodeLen(input)
}
out := make([]byte, totalCount)
startEncode := 0
for i, input := range inputs {
base64.RawURLEncoding.Encode(out[startEncode:], input)
if i == len(inputs)-1 {
continue
}
startEncode += base64EncodeLen(input)
out[startEncode] = '.'
startEncode++
}
return string(out)
}

View File

@ -75,14 +75,13 @@ import (
// //
// The JSON null value unmarshals into an interface, map, pointer, or slice // The JSON null value unmarshals into an interface, map, pointer, or slice
// by setting that Go value to nil. Because null is often used in JSON to mean // by setting that Go value to nil. Because null is often used in JSON to mean
// ``not present,'' unmarshaling a JSON null into any other Go type has no effect // “not present,” unmarshaling a JSON null into any other Go type has no effect
// on the value and produces no error. // on the value and produces no error.
// //
// When unmarshaling quoted strings, invalid UTF-8 or // When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error. // invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement // Instead, they are replaced by the Unicode replacement
// character U+FFFD. // character U+FFFD.
//
func Unmarshal(data []byte, v interface{}) error { func Unmarshal(data []byte, v interface{}) error {
// Check for well-formedness. // Check for well-formedness.
// Avoids filling out half a data structure // Avoids filling out half a data structure

View File

@ -58,6 +58,7 @@ import (
// becomes a member of the object unless // becomes a member of the object unless
// - the field's tag is "-", or // - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option. // - the field is empty and its tag specifies the "omitempty" option.
//
// The empty values are false, 0, any // The empty values are false, 0, any
// nil pointer or interface value, and any array, slice, map, or string of // nil pointer or interface value, and any array, slice, map, or string of
// length zero. The object's default key string is the struct field name // length zero. The object's default key string is the struct field name
@ -133,7 +134,6 @@ import (
// JSON cannot represent cyclic data structures and Marshal does not // JSON cannot represent cyclic data structures and Marshal does not
// handle them. Passing cyclic structures to Marshal will result in // handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion. // an infinite recursion.
//
func Marshal(v interface{}) ([]byte, error) { func Marshal(v interface{}) ([]byte, error) {
e := &encodeState{} e := &encodeState{}
err := e.marshal(v) err := e.marshal(v)

View File

@ -240,7 +240,6 @@ var _ Unmarshaler = (*RawMessage)(nil)
// Number, for JSON numbers // Number, for JSON numbers
// string, for JSON string literals // string, for JSON string literals
// nil, for JSON null // nil, for JSON null
//
type Token interface{} type Token interface{}
const ( const (

View File

@ -252,13 +252,13 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
serializedProtected := mustSerializeJSON(obj.protected) serializedProtected := mustSerializeJSON(obj.protected)
return fmt.Sprintf( return base64JoinWithDots(
"%s.%s.%s.%s.%s", serializedProtected,
base64.RawURLEncoding.EncodeToString(serializedProtected), obj.recipients[0].encryptedKey,
base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey), obj.iv,
base64.RawURLEncoding.EncodeToString(obj.iv), obj.ciphertext,
base64.RawURLEncoding.EncodeToString(obj.ciphertext), obj.tag,
base64.RawURLEncoding.EncodeToString(obj.tag)), nil ), nil
} }
// FullSerialize serializes an object using the full JSON serialization format. // FullSerialize serializes an object using the full JSON serialization format.

View File

@ -67,9 +67,21 @@ type rawJSONWebKey struct {
X5tSHA256 string `json:"x5t#S256,omitempty"` X5tSHA256 string `json:"x5t#S256,omitempty"`
} }
// JSONWebKey represents a public or private key in JWK format. // JSONWebKey represents a public or private key in JWK format. It can be
// marshaled into JSON and unmarshaled from JSON.
type JSONWebKey struct { type JSONWebKey struct {
// Cryptographic key, can be a symmetric or asymmetric key. // Key is the Go in-memory representation of this key. It must have one
// of these types:
// - ed25519.PublicKey
// - ed25519.PrivateKey
// - *ecdsa.PublicKey
// - *ecdsa.PrivateKey
// - *rsa.PublicKey
// - *rsa.PrivateKey
// - []byte (a symmetric key)
//
// When marshaling this JSONWebKey into JSON, the "kty" header parameter
// will be automatically set based on the type of this field.
Key interface{} Key interface{}
// Key identifier, parsed from `kid` header. // Key identifier, parsed from `kid` header.
KeyID string KeyID string
@ -389,6 +401,8 @@ func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) {
input, err = rsaThumbprintInput(key.N, key.E) input, err = rsaThumbprintInput(key.N, key.E)
case ed25519.PrivateKey: case ed25519.PrivateKey:
input, err = edThumbprintInput(ed25519.PublicKey(key[32:])) input, err = edThumbprintInput(ed25519.PublicKey(key[32:]))
case OpaqueSigner:
return key.Public().Thumbprint(hash)
default: default:
return nil, fmt.Errorf("go-jose/go-jose: unknown key type '%s'", reflect.TypeOf(key)) return nil, fmt.Errorf("go-jose/go-jose: unknown key type '%s'", reflect.TypeOf(key))
} }

View File

@ -314,15 +314,18 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
return "", ErrNotSupported return "", ErrNotSupported
} }
serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected)) serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
payload := ""
signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)
var payload []byte
if !detached { if !detached {
payload = base64.RawURLEncoding.EncodeToString(obj.payload) payload = obj.payload
} }
return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil return base64JoinWithDots(
serializedProtected,
payload,
obj.Signatures[0].Signature,
), nil
} }
// CompactSerialize serializes an object using the compact serialization format. // CompactSerialize serializes an object using the compact serialization format.

View File

@ -183,8 +183,13 @@ type Header struct {
// Unverified certificate chain parsed from x5c header. // Unverified certificate chain parsed from x5c header.
certificates []*x509.Certificate certificates []*x509.Certificate
// Any headers not recognised above get unmarshalled // At parse time, each header parameter with a name other than "kid",
// from JSON in a generic manner and placed in this map. // "jwk", "alg", "nonce", or "x5c" will have its value passed to
// [json.Unmarshal] to unmarshal it into an interface value.
// The resulting value will be stored in this map, with the header
// parameter name as the key.
//
// [json.Unmarshal]: https://pkg.go.dev/encoding/json#Unmarshal
ExtraHeaders map[HeaderKey]interface{} ExtraHeaders map[HeaderKey]interface{}
} }

View File

@ -40,6 +40,15 @@ type Signer interface {
} }
// SigningKey represents an algorithm/key used to sign a message. // SigningKey represents an algorithm/key used to sign a message.
//
// Key must have one of these types:
// - ed25519.PrivateKey
// - *ecdsa.PrivateKey
// - *rsa.PrivateKey
// - *JSONWebKey
// - JSONWebKey
// - []byte (an HMAC key)
// - Any type that satisfies the OpaqueSigner interface
type SigningKey struct { type SigningKey struct {
Algorithm SignatureAlgorithm Algorithm SignatureAlgorithm
Key interface{} Key interface{}
@ -52,12 +61,22 @@ type SignerOptions struct {
// Optional map of additional keys to be inserted into the protected header // Optional map of additional keys to be inserted into the protected header
// of a JWS object. Some specifications which make use of JWS like to insert // of a JWS object. Some specifications which make use of JWS like to insert
// additional values here. All values must be JSON-serializable. // additional values here.
//
// Values will be serialized by [json.Marshal] and must be valid inputs to
// that function.
//
// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
ExtraHeaders map[HeaderKey]interface{} ExtraHeaders map[HeaderKey]interface{}
} }
// WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it // WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it
// if necessary. It returns itself and so can be used in a fluent style. // if necessary, and returns the updated SignerOptions.
//
// The v argument will be serialized by [json.Marshal] and must be a valid
// input to that function.
//
// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal
func (so *SignerOptions) WithHeader(k HeaderKey, v interface{}) *SignerOptions { func (so *SignerOptions) WithHeader(k HeaderKey, v interface{}) *SignerOptions {
if so.ExtraHeaders == nil { if so.ExtraHeaders == nil {
so.ExtraHeaders = map[HeaderKey]interface{}{} so.ExtraHeaders = map[HeaderKey]interface{}{}
@ -173,12 +192,12 @@ func newVerifier(verificationKey interface{}) (payloadVerifier, error) {
return newVerifier(verificationKey.Key) return newVerifier(verificationKey.Key)
case *JSONWebKey: case *JSONWebKey:
return newVerifier(verificationKey.Key) return newVerifier(verificationKey.Key)
} case OpaqueVerifier:
if ov, ok := verificationKey.(OpaqueVerifier); ok { return &opaqueVerifier{verifier: verificationKey}, nil
return &opaqueVerifier{verifier: ov}, nil default:
}
return nil, ErrUnsupportedKeyType return nil, ErrUnsupportedKeyType
} }
}
func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error { func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error {
recipient, err := makeJWSRecipient(alg, signingKey) recipient, err := makeJWSRecipient(alg, signingKey)
@ -204,12 +223,12 @@ func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipient
return newJWKSigner(alg, signingKey) return newJWKSigner(alg, signingKey)
case *JSONWebKey: case *JSONWebKey:
return newJWKSigner(alg, *signingKey) return newJWKSigner(alg, *signingKey)
} case OpaqueSigner:
if signer, ok := signingKey.(OpaqueSigner); ok { return newOpaqueSigner(alg, signingKey)
return newOpaqueSigner(alg, signer) default:
}
return recipientSigInfo{}, ErrUnsupportedKeyType return recipientSigInfo{}, ErrUnsupportedKeyType
} }
}
func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) { func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) {
recipient, err := makeJWSRecipient(alg, signingKey.Key) recipient, err := makeJWSRecipient(alg, signingKey.Key)
@ -321,12 +340,21 @@ func (ctx *genericSigner) Options() SignerOptions {
} }
// Verify validates the signature on the object and returns the payload. // Verify validates the signature on the object and returns the payload.
// This function does not support multi-signature, if you desire multi-sig // This function does not support multi-signature. If you desire multi-signature
// verification use VerifyMulti instead. // verification use VerifyMulti instead.
// //
// Be careful when verifying signatures based on embedded JWKs inside the // Be careful when verifying signatures based on embedded JWKs inside the
// payload header. You cannot assume that the key received in a payload is // payload header. You cannot assume that the key received in a payload is
// trusted. // trusted.
//
// The verificationKey argument must have one of these types:
// - ed25519.PublicKey
// - *ecdsa.PublicKey
// - *rsa.PublicKey
// - *JSONWebKey
// - JSONWebKey
// - []byte (an HMAC key)
// - Any type that implements the OpaqueVerifier interface.
func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) { func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) {
err := obj.DetachedVerify(obj.payload, verificationKey) err := obj.DetachedVerify(obj.payload, verificationKey)
if err != nil { if err != nil {
@ -346,6 +374,9 @@ func (obj JSONWebSignature) UnsafePayloadWithoutVerification() []byte {
// most cases, you will probably want to use Verify instead. DetachedVerify // most cases, you will probably want to use Verify instead. DetachedVerify
// is only useful if you have a payload and signature that are separated from // is only useful if you have a payload and signature that are separated from
// each other. // each other.
//
// The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error { func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error {
key := tryJWKS(verificationKey, obj.headers()...) key := tryJWKS(verificationKey, obj.headers()...)
verifier, err := newVerifier(key) verifier, err := newVerifier(key)
@ -388,6 +419,9 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
// returns the index of the signature that was verified, along with the signature // returns the index of the signature that was verified, along with the signature
// object and the payload. We return the signature and index to guarantee that // object and the payload. We return the signature and index to guarantee that
// callers are getting the verified value. // callers are getting the verified value.
//
// The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) { func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) {
idx, sig, err := obj.DetachedVerifyMulti(obj.payload, verificationKey) idx, sig, err := obj.DetachedVerifyMulti(obj.payload, verificationKey)
if err != nil { if err != nil {
@ -405,6 +439,9 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa
// DetachedVerifyMulti is only useful if you have a payload and signature that are // DetachedVerifyMulti is only useful if you have a payload and signature that are
// separated from each other, and the signature can have multiple signers at the // separated from each other, and the signature can have multiple signers at the
// same time. // same time.
//
// The verificationKey argument must have one of the types allowed for the
// verificationKey argument of JSONWebSignature.Verify().
func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) { func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) {
key := tryJWKS(verificationKey, obj.headers()...) key := tryJWKS(verificationKey, obj.headers()...)
verifier, err := newVerifier(key) verifier, err := newVerifier(key)

View File

@ -40,12 +40,17 @@ var RandReader = rand.Reader
const ( const (
// RFC7518 recommends a minimum of 1,000 iterations: // RFC7518 recommends a minimum of 1,000 iterations:
// https://tools.ietf.org/html/rfc7518#section-4.8.1.2 // - https://tools.ietf.org/html/rfc7518#section-4.8.1.2
//
// NIST recommends a minimum of 10,000: // NIST recommends a minimum of 10,000:
// https://pages.nist.gov/800-63-3/sp800-63b.html // - https://pages.nist.gov/800-63-3/sp800-63b.html
// 1Password uses 100,000: //
// https://support.1password.com/pbkdf2/ // 1Password increased in 2023 from 100,000 to 650,000:
defaultP2C = 100000 // - https://support.1password.com/pbkdf2/
//
// OWASP recommended 600,000 in Dec 2022:
// - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2
defaultP2C = 600000
// Default salt size: 128 bits // Default salt size: 128 bits
defaultP2SSize = 16 defaultP2SSize = 16
) )

View File

@ -16,6 +16,7 @@ package strfmt
import ( import (
"encoding" "encoding"
stderrors "errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -117,7 +118,7 @@ func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
case "datetime": case "datetime":
input := data input := data
if len(input) == 0 { if len(input) == 0 {
return nil, fmt.Errorf("empty string is an invalid datetime format") return nil, stderrors.New("empty string is an invalid datetime format")
} }
return ParseDateTime(input) return ParseDateTime(input)
case "duration": case "duration":

View File

@ -176,7 +176,7 @@ func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
func (m *indexOfInitialisms) sorted() (result []string) { func (m *indexOfInitialisms) sorted() (result []string) {
m.sortMutex.Lock() m.sortMutex.Lock()
defer m.sortMutex.Unlock() defer m.sortMutex.Unlock()
m.index.Range(func(key, value interface{}) bool { m.index.Range(func(key, _ interface{}) bool {
k := key.(string) k := key.(string)
result = append(result, k) result = append(result, k)
return true return true

View File

@ -16,6 +16,7 @@ package swag
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -50,7 +51,7 @@ func BytesToYAMLDoc(data []byte) (interface{}, error) {
return nil, err return nil, err
} }
if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode { if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
return nil, fmt.Errorf("only YAML documents that are objects are supported") return nil, errors.New("only YAML documents that are objects are supported")
} }
return &document, nil return &document, nil
} }

View File

@ -1,5 +1,18 @@
# Changelog # Changelog
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
### Features
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
### Bug Fixes
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) ## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)

View File

@ -17,6 +17,12 @@ var (
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros Nil UUID // empty UUID, all zeros
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
Max = UUID{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
}
) )
// NewHash returns a new UUID derived from the hash of space concatenated with // NewHash returns a new UUID derived from the hash of space concatenated with

View File

@ -52,7 +52,7 @@ func makeV7(uuid []byte) {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | | unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a | | unix_ts_ms | ver | rand_a (12 bit seq) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b | |var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@ -61,7 +61,7 @@ func makeV7(uuid []byte) {
*/ */
_ = uuid[15] // bounds check _ = uuid[15] // bounds check
t := timeNow().UnixMilli() t, s := getV7Time()
uuid[0] = byte(t >> 40) uuid[0] = byte(t >> 40)
uuid[1] = byte(t >> 32) uuid[1] = byte(t >> 32)
@ -70,6 +70,35 @@ func makeV7(uuid []byte) {
uuid[4] = byte(t >> 8) uuid[4] = byte(t >> 8)
uuid[5] = byte(t) uuid[5] = byte(t)
uuid[6] = 0x70 | (uuid[6] & 0x0F) uuid[6] = 0x70 | (0x0F & byte(s>>8))
// uuid[8] has already has right version uuid[7] = byte(s)
}
// lastV7time is the last time we returned stored as:
//
// 52 bits of time in milliseconds since epoch
// 12 bits of (fractional nanoseconds) >> 8
var lastV7time int64
const nanoPerMilli = 1000000
// getV7Time returns the time in milliseconds and nanoseconds / 256.
// The returned (milli << 12 + seq) is guarenteed to be greater than
// (milli << 12 + seq) returned by any previous call to getV7Time.
func getV7Time() (milli, seq int64) {
timeMu.Lock()
defer timeMu.Unlock()
nano := timeNow().UnixNano()
milli = nano / nanoPerMilli
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
seq = (nano - milli*nanoPerMilli) >> 8
now := milli<<12 + seq
if now <= lastV7time {
now = lastV7time + 1
milli = now >> 12
seq = now & 0xfff
}
lastV7time = now
return milli, seq
} }

View File

@ -0,0 +1,211 @@
//
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package signature
import (
"crypto"
"crypto/ed25519"
"crypto/rand"
"errors"
"fmt"
"io"
"github.com/sigstore/sigstore/pkg/signature/options"
)
var ed25519phSupportedHashFuncs = []crypto.Hash{
crypto.SHA512,
}
// ED25519phSigner is a signature.Signer that uses the Ed25519 public-key signature system with pre-hashing
type ED25519phSigner struct {
priv ed25519.PrivateKey
}
// LoadED25519phSigner calculates signatures using the specified private key.
func LoadED25519phSigner(priv ed25519.PrivateKey) (*ED25519phSigner, error) {
if priv == nil {
return nil, errors.New("invalid ED25519 private key specified")
}
return &ED25519phSigner{
priv: priv,
}, nil
}
// ToED25519SignerVerifier creates a ED25519SignerVerifier from a ED25519phSignerVerifier
//
// Clients that use ED25519phSignerVerifier should use this method to get a
// SignerVerifier that uses the same ED25519 private key, but with the Pure
// Ed25519 algorithm. This might be necessary to interact with Fulcio, which
// only supports the Pure Ed25519 algorithm.
func (e ED25519phSignerVerifier) ToED25519SignerVerifier() (*ED25519SignerVerifier, error) {
return LoadED25519SignerVerifier(e.priv)
}
// SignMessage signs the provided message. If the message is provided,
// this method will compute the digest according to the hash function specified
// when the ED25519phSigner was created.
//
// This function recognizes the following Options listed in order of preference:
//
// - WithDigest()
//
// All other options are ignored if specified.
func (e ED25519phSigner) SignMessage(message io.Reader, opts ...SignOption) ([]byte, error) {
digest, _, err := ComputeDigestForSigning(message, crypto.SHA512, ed25519phSupportedHashFuncs, opts...)
if err != nil {
return nil, err
}
return e.priv.Sign(nil, digest, crypto.SHA512)
}
// Public returns the public key that can be used to verify signatures created by
// this signer.
func (e ED25519phSigner) Public() crypto.PublicKey {
if e.priv == nil {
return nil
}
return e.priv.Public()
}
// PublicKey returns the public key that can be used to verify signatures created by
// this signer. As this value is held in memory, all options provided in arguments
// to this method are ignored.
func (e ED25519phSigner) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) {
return e.Public(), nil
}
// Sign computes the signature for the specified message; the first and third arguments to this
// function are ignored as they are not used by the ED25519ph algorithm.
func (e ED25519phSigner) Sign(_ io.Reader, digest []byte, _ crypto.SignerOpts) ([]byte, error) {
return e.SignMessage(nil, options.WithDigest(digest))
}
// ED25519phVerifier is a signature.Verifier that uses the Ed25519 public-key signature system
type ED25519phVerifier struct {
publicKey ed25519.PublicKey
}
// LoadED25519phVerifier returns a Verifier that verifies signatures using the
// specified ED25519 public key.
func LoadED25519phVerifier(pub ed25519.PublicKey) (*ED25519phVerifier, error) {
if pub == nil {
return nil, errors.New("invalid ED25519 public key specified")
}
return &ED25519phVerifier{
publicKey: pub,
}, nil
}
// PublicKey returns the public key that is used to verify signatures by
// this verifier. As this value is held in memory, all options provided in arguments
// to this method are ignored.
func (e *ED25519phVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) {
return e.publicKey, nil
}
// VerifySignature verifies the signature for the given message. Unless provided
// in an option, the digest of the message will be computed using the hash function specified
// when the ED25519phVerifier was created.
//
// This function returns nil if the verification succeeded, and an error message otherwise.
//
// This function recognizes the following Options listed in order of preference:
//
// - WithDigest()
//
// All other options are ignored if specified.
func (e *ED25519phVerifier) VerifySignature(signature, message io.Reader, opts ...VerifyOption) error {
if signature == nil {
return errors.New("nil signature passed to VerifySignature")
}
digest, _, err := ComputeDigestForVerifying(message, crypto.SHA512, ed25519phSupportedHashFuncs, opts...)
if err != nil {
return err
}
sigBytes, err := io.ReadAll(signature)
if err != nil {
return fmt.Errorf("reading signature: %w", err)
}
if err := ed25519.VerifyWithOptions(e.publicKey, digest, sigBytes, &ed25519.Options{Hash: crypto.SHA512}); err != nil {
return fmt.Errorf("failed to verify signature: %w", err)
}
return nil
}
// ED25519phSignerVerifier is a signature.SignerVerifier that uses the Ed25519 public-key signature system
type ED25519phSignerVerifier struct {
*ED25519phSigner
*ED25519phVerifier
}
// LoadED25519phSignerVerifier creates a combined signer and verifier. This is
// a convenience object that simply wraps an instance of ED25519phSigner and ED25519phVerifier.
func LoadED25519phSignerVerifier(priv ed25519.PrivateKey) (*ED25519phSignerVerifier, error) {
signer, err := LoadED25519phSigner(priv)
if err != nil {
return nil, fmt.Errorf("initializing signer: %w", err)
}
pub, ok := priv.Public().(ed25519.PublicKey)
if !ok {
return nil, fmt.Errorf("given key is not ed25519.PublicKey")
}
verifier, err := LoadED25519phVerifier(pub)
if err != nil {
return nil, fmt.Errorf("initializing verifier: %w", err)
}
return &ED25519phSignerVerifier{
ED25519phSigner: signer,
ED25519phVerifier: verifier,
}, nil
}
// NewDefaultED25519phSignerVerifier creates a combined signer and verifier using ED25519.
// This creates a new ED25519 key using crypto/rand as an entropy source.
func NewDefaultED25519phSignerVerifier() (*ED25519phSignerVerifier, ed25519.PrivateKey, error) {
return NewED25519phSignerVerifier(rand.Reader)
}
// NewED25519phSignerVerifier creates a combined signer and verifier using ED25519.
// This creates a new ED25519 key using the specified entropy source.
func NewED25519phSignerVerifier(rand io.Reader) (*ED25519phSignerVerifier, ed25519.PrivateKey, error) {
_, priv, err := ed25519.GenerateKey(rand)
if err != nil {
return nil, nil, err
}
sv, err := LoadED25519phSignerVerifier(priv)
if err != nil {
return nil, nil, err
}
return sv, priv, nil
}
// PublicKey returns the public key that is used to verify signatures by
// this verifier. As this value is held in memory, all options provided in arguments
// to this method are ignored.
func (e ED25519phSignerVerifier) PublicKey(_ ...PublicKeyOption) (crypto.PublicKey, error) {
return e.publicKey, nil
}

View File

@ -18,6 +18,7 @@ package signature
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/rsa"
"io" "io"
"github.com/sigstore/sigstore/pkg/signature/options" "github.com/sigstore/sigstore/pkg/signature/options"
@ -55,3 +56,10 @@ type VerifyOption interface {
RPCOption RPCOption
MessageOption MessageOption
} }
// LoadOption specifies options to be used when creating a Signer/Verifier
type LoadOption interface {
ApplyHash(*crypto.Hash)
ApplyED25519ph(*bool)
ApplyRSAPSS(**rsa.PSSOptions)
}

View File

@ -0,0 +1,76 @@
//
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package options
import (
"crypto"
"crypto/rsa"
)
// RequestHash implements the functional option pattern for setting a Hash
// function when loading a signer or verifier
type RequestHash struct {
NoOpOptionImpl
hashFunc crypto.Hash
}
// ApplyHash sets the hash as requested by the functional option
func (r RequestHash) ApplyHash(hash *crypto.Hash) {
*hash = r.hashFunc
}
// WithHash specifies that the given hash function should be used when loading a signer or verifier
func WithHash(hash crypto.Hash) RequestHash {
return RequestHash{hashFunc: hash}
}
// RequestED25519ph implements the functional option pattern for specifying
// ED25519ph (pre-hashed) should be used when loading a signer or verifier and a
// ED25519 key is
type RequestED25519ph struct {
NoOpOptionImpl
useED25519ph bool
}
// ApplyED25519ph sets the ED25519ph flag as requested by the functional option
func (r RequestED25519ph) ApplyED25519ph(useED25519ph *bool) {
*useED25519ph = r.useED25519ph
}
// WithED25519ph specifies that the ED25519ph algorithm should be used when a ED25519 key is used
func WithED25519ph() RequestED25519ph {
return RequestED25519ph{useED25519ph: true}
}
// RequestPSSOptions implements the functional option pattern for specifying RSA
// PSS should be used when loading a signer or verifier and a RSA key is
// detected
type RequestPSSOptions struct {
NoOpOptionImpl
opts *rsa.PSSOptions
}
// ApplyRSAPSS sets the RSAPSS options as requested by the functional option
func (r RequestPSSOptions) ApplyRSAPSS(opts **rsa.PSSOptions) {
*opts = r.opts
}
// WithRSAPSS specifies that the RSAPSS algorithm should be used when a RSA key is used
// Note that the RSA PSSOptions contains an hash algorithm, which will override
// the hash function specified with WithHash.
func WithRSAPSS(opts *rsa.PSSOptions) RequestPSSOptions {
return RequestPSSOptions{opts: opts}
}

View File

@ -18,6 +18,7 @@ package options
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/rsa"
"io" "io"
) )
@ -47,3 +48,12 @@ func (NoOpOptionImpl) ApplyKeyVersion(_ *string) {}
// ApplyKeyVersionUsed is a no-op required to fully implement the requisite interfaces // ApplyKeyVersionUsed is a no-op required to fully implement the requisite interfaces
func (NoOpOptionImpl) ApplyKeyVersionUsed(_ **string) {} func (NoOpOptionImpl) ApplyKeyVersionUsed(_ **string) {}
// ApplyHash is a no-op required to fully implement the requisite interfaces
func (NoOpOptionImpl) ApplyHash(_ *crypto.Hash) {}
// ApplyED25519ph is a no-op required to fully implement the requisite interfaces
func (NoOpOptionImpl) ApplyED25519ph(_ *bool) {}
// ApplyRSAPSS is a no-op required to fully implement the requisite interfaces
func (NoOpOptionImpl) ApplyRSAPSS(_ **rsa.PSSOptions) {}

View File

@ -30,6 +30,7 @@ import (
_ "crypto/sha512" _ "crypto/sha512"
"github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature/options"
// these ensure we have the implementations loaded // these ensure we have the implementations loaded
_ "golang.org/x/crypto/sha3" _ "golang.org/x/crypto/sha3"
@ -59,12 +60,33 @@ func (s SignerOpts) HashFunc() crypto.Hash {
// If privateKey is an RSA key, a RSAPKCS1v15Signer will be returned. If a // If privateKey is an RSA key, a RSAPKCS1v15Signer will be returned. If a
// RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() method directly. // RSAPSSSigner is desired instead, use the LoadRSAPSSSigner() method directly.
func LoadSigner(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (Signer, error) { func LoadSigner(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (Signer, error) {
return LoadSignerWithOpts(privateKey, options.WithHash(hashFunc))
}
// LoadSignerWithOpts returns a signature.Signer based on the algorithm of the private key
// provided.
func LoadSignerWithOpts(privateKey crypto.PrivateKey, opts ...LoadOption) (Signer, error) {
var rsaPSSOptions *rsa.PSSOptions
var useED25519ph bool
hashFunc := crypto.SHA256
for _, o := range opts {
o.ApplyED25519ph(&useED25519ph)
o.ApplyHash(&hashFunc)
o.ApplyRSAPSS(&rsaPSSOptions)
}
switch pk := privateKey.(type) { switch pk := privateKey.(type) {
case *rsa.PrivateKey: case *rsa.PrivateKey:
if rsaPSSOptions != nil {
return LoadRSAPSSSigner(pk, hashFunc, rsaPSSOptions)
}
return LoadRSAPKCS1v15Signer(pk, hashFunc) return LoadRSAPKCS1v15Signer(pk, hashFunc)
case *ecdsa.PrivateKey: case *ecdsa.PrivateKey:
return LoadECDSASigner(pk, hashFunc) return LoadECDSASigner(pk, hashFunc)
case ed25519.PrivateKey: case ed25519.PrivateKey:
if useED25519ph {
return LoadED25519phSigner(pk)
}
return LoadED25519Signer(pk) return LoadED25519Signer(pk)
} }
return nil, errors.New("unsupported public key type") return nil, errors.New("unsupported public key type")
@ -87,3 +109,17 @@ func LoadSignerFromPEMFile(path string, hashFunc crypto.Hash, pf cryptoutils.Pas
} }
return LoadSigner(priv, hashFunc) return LoadSigner(priv, hashFunc)
} }
// LoadSignerFromPEMFileWithOpts returns a signature.Signer based on the algorithm of the private key
// in the file. The Signer will use the hash function specified in the options when computing digests.
func LoadSignerFromPEMFileWithOpts(path string, pf cryptoutils.PassFunc, opts ...LoadOption) (Signer, error) {
fileBytes, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return nil, err
}
priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf)
if err != nil {
return nil, err
}
return LoadSignerWithOpts(priv, opts...)
}

View File

@ -25,6 +25,7 @@ import (
"path/filepath" "path/filepath"
"github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature/options"
) )
// SignerVerifier creates and verifies digital signatures over a message using a specified key pair // SignerVerifier creates and verifies digital signatures over a message using a specified key pair
@ -39,12 +40,33 @@ type SignerVerifier interface {
// If privateKey is an RSA key, a RSAPKCS1v15SignerVerifier will be returned. If a // If privateKey is an RSA key, a RSAPKCS1v15SignerVerifier will be returned. If a
// RSAPSSSignerVerifier is desired instead, use the LoadRSAPSSSignerVerifier() method directly. // RSAPSSSignerVerifier is desired instead, use the LoadRSAPSSSignerVerifier() method directly.
func LoadSignerVerifier(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (SignerVerifier, error) { func LoadSignerVerifier(privateKey crypto.PrivateKey, hashFunc crypto.Hash) (SignerVerifier, error) {
return LoadSignerVerifierWithOpts(privateKey, options.WithHash(hashFunc))
}
// LoadSignerVerifierWithOpts returns a signature.SignerVerifier based on the
// algorithm of the private key provided and the user's choice.
func LoadSignerVerifierWithOpts(privateKey crypto.PrivateKey, opts ...LoadOption) (SignerVerifier, error) {
var rsaPSSOptions *rsa.PSSOptions
var useED25519ph bool
hashFunc := crypto.SHA256
for _, o := range opts {
o.ApplyED25519ph(&useED25519ph)
o.ApplyHash(&hashFunc)
o.ApplyRSAPSS(&rsaPSSOptions)
}
switch pk := privateKey.(type) { switch pk := privateKey.(type) {
case *rsa.PrivateKey: case *rsa.PrivateKey:
if rsaPSSOptions != nil {
return LoadRSAPSSSignerVerifier(pk, hashFunc, rsaPSSOptions)
}
return LoadRSAPKCS1v15SignerVerifier(pk, hashFunc) return LoadRSAPKCS1v15SignerVerifier(pk, hashFunc)
case *ecdsa.PrivateKey: case *ecdsa.PrivateKey:
return LoadECDSASignerVerifier(pk, hashFunc) return LoadECDSASignerVerifier(pk, hashFunc)
case ed25519.PrivateKey: case ed25519.PrivateKey:
if useED25519ph {
return LoadED25519phSignerVerifier(pk)
}
return LoadED25519SignerVerifier(pk) return LoadED25519SignerVerifier(pk)
} }
return nil, errors.New("unsupported public key type") return nil, errors.New("unsupported public key type")
@ -67,3 +89,17 @@ func LoadSignerVerifierFromPEMFile(path string, hashFunc crypto.Hash, pf cryptou
} }
return LoadSignerVerifier(priv, hashFunc) return LoadSignerVerifier(priv, hashFunc)
} }
// LoadSignerVerifierFromPEMFileWithOpts returns a signature.SignerVerifier based on the algorithm of the private key
// in the file. The SignerVerifier will use the hash function specified in the options when computing digests.
func LoadSignerVerifierFromPEMFileWithOpts(path string, pf cryptoutils.PassFunc, opts ...LoadOption) (SignerVerifier, error) {
fileBytes, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return nil, err
}
priv, err := cryptoutils.UnmarshalPEMToPrivateKey(fileBytes, pf)
if err != nil {
return nil, err
}
return LoadSignerVerifierWithOpts(priv, opts...)
}

View File

@ -26,6 +26,7 @@ import (
"path/filepath" "path/filepath"
"github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature/options"
) )
// Verifier verifies the digital signature using a specified public key // Verifier verifies the digital signature using a specified public key
@ -40,12 +41,33 @@ type Verifier interface {
// If publicKey is an RSA key, a RSAPKCS1v15Verifier will be returned. If a // If publicKey is an RSA key, a RSAPKCS1v15Verifier will be returned. If a
// RSAPSSVerifier is desired instead, use the LoadRSAPSSVerifier() method directly. // RSAPSSVerifier is desired instead, use the LoadRSAPSSVerifier() method directly.
func LoadVerifier(publicKey crypto.PublicKey, hashFunc crypto.Hash) (Verifier, error) { func LoadVerifier(publicKey crypto.PublicKey, hashFunc crypto.Hash) (Verifier, error) {
return LoadVerifierWithOpts(publicKey, options.WithHash(hashFunc))
}
// LoadVerifierWithOpts returns a signature.Verifier based on the algorithm of the public key
// provided that will use the hash function specified when computing digests.
func LoadVerifierWithOpts(publicKey crypto.PublicKey, opts ...LoadOption) (Verifier, error) {
var rsaPSSOptions *rsa.PSSOptions
var useED25519ph bool
hashFunc := crypto.SHA256
for _, o := range opts {
o.ApplyED25519ph(&useED25519ph)
o.ApplyHash(&hashFunc)
o.ApplyRSAPSS(&rsaPSSOptions)
}
switch pk := publicKey.(type) { switch pk := publicKey.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
if rsaPSSOptions != nil {
return LoadRSAPSSVerifier(pk, hashFunc, rsaPSSOptions)
}
return LoadRSAPKCS1v15Verifier(pk, hashFunc) return LoadRSAPKCS1v15Verifier(pk, hashFunc)
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
return LoadECDSAVerifier(pk, hashFunc) return LoadECDSAVerifier(pk, hashFunc)
case ed25519.PublicKey: case ed25519.PublicKey:
if useED25519ph {
return LoadED25519phVerifier(pk)
}
return LoadED25519Verifier(pk) return LoadED25519Verifier(pk)
} }
return nil, errors.New("unsupported public key type") return nil, errors.New("unsupported public key type")
@ -98,3 +120,19 @@ func LoadVerifierFromPEMFile(path string, hashFunc crypto.Hash) (Verifier, error
return LoadVerifier(pubKey, hashFunc) return LoadVerifier(pubKey, hashFunc)
} }
// LoadVerifierFromPEMFileWithOpts returns a signature.Verifier based on the contents of a
// file located at path. The Verifier wil use the hash function specified in the options when computing digests.
func LoadVerifierFromPEMFileWithOpts(path string, opts ...LoadOption) (Verifier, error) {
fileBytes, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return nil, err
}
pubKey, err := cryptoutils.UnmarshalPEMToPublicKey(fileBytes)
if err != nil {
return nil, err
}
return LoadVerifierWithOpts(pubKey, opts...)
}

View File

@ -15,16 +15,15 @@ import (
// ArrayCodec is the Codec used for bsoncore.Array values. // ArrayCodec is the Codec used for bsoncore.Array values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: ArrayCodec will not be directly accessible in Go Driver 2.0.
// ArrayCodec registered.
type ArrayCodec struct{} type ArrayCodec struct{}
var defaultArrayCodec = NewArrayCodec() var defaultArrayCodec = NewArrayCodec()
// NewArrayCodec returns an ArrayCodec. // NewArrayCodec returns an ArrayCodec.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewArrayCodec will not be available in Go Driver 2.0. See
// ArrayCodec registered. // [ArrayCodec] for more details.
func NewArrayCodec() *ArrayCodec { func NewArrayCodec() *ArrayCodec {
return &ArrayCodec{} return &ArrayCodec{}
} }

View File

@ -17,13 +17,28 @@ import (
// ByteSliceCodec is the Codec used for []byte values. // ByteSliceCodec is the Codec used for []byte values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: ByteSliceCodec will not be directly configurable in Go Driver
// ByteSliceCodec registered. // 2.0. To configure the byte slice encode and decode behavior, use the
// configuration methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the byte slice
// encode and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to encode nil byte slices as empty
// BSON binary values, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilByteSliceAsEmpty: true,
// })
//
// See the deprecation notice for each field in ByteSliceCodec for the
// corresponding settings.
type ByteSliceCodec struct { type ByteSliceCodec struct {
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go byte slices as empty BSON binary values // EncodeNilAsEmpty causes EncodeValue to marshal nil Go byte slices as empty BSON binary values
// instead of BSON null. // instead of BSON null.
// //
// Deprecated: Use bson.Encoder.NilByteSliceAsEmpty instead. // Deprecated: Use bson.Encoder.NilByteSliceAsEmpty or options.BSONOptions.NilByteSliceAsEmpty
// instead.
EncodeNilAsEmpty bool EncodeNilAsEmpty bool
} }
@ -38,8 +53,8 @@ var (
// NewByteSliceCodec returns a ByteSliceCodec with options opts. // NewByteSliceCodec returns a ByteSliceCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewByteSliceCodec will not be available in Go Driver 2.0. See
// ByteSliceCodec registered. // [ByteSliceCodec] for more details.
func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec { func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec {
byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...) byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...)
codec := ByteSliceCodec{} codec := ByteSliceCodec{}

View File

@ -41,7 +41,7 @@ func newDefaultStructCodec() *StructCodec {
if err != nil { if err != nil {
// This function is called from the codec registration path, so errors can't be propagated. If there's an error // This function is called from the codec registration path, so errors can't be propagated. If there's an error
// constructing the StructCodec, we panic to avoid losing it. // constructing the StructCodec, we panic to avoid losing it.
panic(fmt.Errorf("error creating default StructCodec: %v", err)) panic(fmt.Errorf("error creating default StructCodec: %w", err))
} }
return codec return codec
} }
@ -178,7 +178,7 @@ func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueRe
for { for {
key, elemVr, err := dr.ReadElement() key, elemVr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} else if err != nil { } else if err != nil {
return err return err
@ -1379,7 +1379,7 @@ func (dvd DefaultValueDecoders) MapDecodeValue(dc DecodeContext, vr bsonrw.Value
keyType := val.Type().Key() keyType := val.Type().Key()
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -1675,7 +1675,7 @@ func (dvd DefaultValueDecoders) decodeDefault(dc DecodeContext, vr bsonrw.ValueR
idx := 0 idx := 0
for { for {
vr, err := ar.ReadValue() vr, err := ar.ReadValue()
if err == bsonrw.ErrEOA { if errors.Is(err, bsonrw.ErrEOA) {
break break
} }
if err != nil { if err != nil {
@ -1787,7 +1787,7 @@ func (DefaultValueDecoders) decodeElemsFromDocumentReader(dc DecodeContext, dr b
elems := make([]reflect.Value, 0) elems := make([]reflect.Value, 0)
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {

View File

@ -343,7 +343,7 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
} }
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.MapIndex(key)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.MapIndex(key))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -352,7 +352,7 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -418,7 +418,7 @@ func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.Val
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -427,7 +427,7 @@ func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.Val
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -487,7 +487,7 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -496,7 +496,7 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err

View File

@ -17,13 +17,27 @@ import (
// EmptyInterfaceCodec is the Codec used for interface{} values. // EmptyInterfaceCodec is the Codec used for interface{} values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: EmptyInterfaceCodec will not be directly configurable in Go
// EmptyInterfaceCodec registered. // Driver 2.0. To configure the empty interface encode and decode behavior, use
// the configuration methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the empty interface
// encode and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to unmarshal BSON binary field
// values as a Go byte slice, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// BinaryAsSlice: true,
// })
//
// See the deprecation notice for each field in EmptyInterfaceCodec for the
// corresponding settings.
type EmptyInterfaceCodec struct { type EmptyInterfaceCodec struct {
// DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the // DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the
// "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary. // "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
// //
// Deprecated: Use bson.Decoder.BinaryAsSlice instead. // Deprecated: Use bson.Decoder.BinaryAsSlice or options.BSONOptions.BinaryAsSlice instead.
DecodeBinaryAsSlice bool DecodeBinaryAsSlice bool
} }
@ -38,8 +52,8 @@ var (
// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts. // NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewEmptyInterfaceCodec will not be available in Go Driver 2.0. See
// EmptyInterfaceCodec registered. // [EmptyInterfaceCodec] for more details.
func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec { func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec {
interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...) interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...)

View File

@ -8,6 +8,7 @@ package bsoncodec
import ( import (
"encoding" "encoding"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
@ -21,25 +22,40 @@ var defaultMapCodec = NewMapCodec()
// MapCodec is the Codec used for map values. // MapCodec is the Codec used for map values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: MapCodec will not be directly configurable in Go Driver 2.0. To
// MapCodec registered. // configure the map encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the map encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal nil Go maps as empty BSON
// documents, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilMapAsEmpty: true,
// })
//
// See the deprecation notice for each field in MapCodec for the corresponding
// settings.
type MapCodec struct { type MapCodec struct {
// DecodeZerosMap causes DecodeValue to delete any existing values from Go maps in the destination // DecodeZerosMap causes DecodeValue to delete any existing values from Go maps in the destination
// value passed to Decode before unmarshaling BSON documents into them. // value passed to Decode before unmarshaling BSON documents into them.
// //
// Deprecated: Use bson.Decoder.ZeroMaps instead. // Deprecated: Use bson.Decoder.ZeroMaps or options.BSONOptions.ZeroMaps instead.
DecodeZerosMap bool DecodeZerosMap bool
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go maps as empty BSON documents instead of // EncodeNilAsEmpty causes EncodeValue to marshal nil Go maps as empty BSON documents instead of
// BSON null. // BSON null.
// //
// Deprecated: Use bson.Encoder.NilMapAsEmpty instead. // Deprecated: Use bson.Encoder.NilMapAsEmpty or options.BSONOptions.NilMapAsEmpty instead.
EncodeNilAsEmpty bool EncodeNilAsEmpty bool
// EncodeKeysWithStringer causes the Encoder to convert Go map keys to BSON document field name // EncodeKeysWithStringer causes the Encoder to convert Go map keys to BSON document field name
// strings using fmt.Sprintf() instead of the default string conversion logic. // strings using fmt.Sprintf() instead of the default string conversion logic.
// //
// Deprecated: Use bson.Encoder.StringifyMapKeysWithFmt instead. // Deprecated: Use bson.Encoder.StringifyMapKeysWithFmt or
// options.BSONOptions.StringifyMapKeysWithFmt instead.
EncodeKeysWithStringer bool EncodeKeysWithStringer bool
} }
@ -61,8 +77,8 @@ type KeyUnmarshaler interface {
// NewMapCodec returns a MapCodec with options opts. // NewMapCodec returns a MapCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewMapCodec will not be available in Go Driver 2.0. See
// MapCodec registered. // [MapCodec] for more details.
func NewMapCodec(opts ...*bsonoptions.MapCodecOptions) *MapCodec { func NewMapCodec(opts ...*bsonoptions.MapCodecOptions) *MapCodec {
mapOpt := bsonoptions.MergeMapCodecOptions(opts...) mapOpt := bsonoptions.MergeMapCodecOptions(opts...)
@ -128,7 +144,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, v
} }
currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.MapIndex(key)) currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.MapIndex(key))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -137,7 +153,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, v
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -200,7 +216,7 @@ func (mc *MapCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val ref
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -313,7 +329,7 @@ func (mc *MapCodec) decodeKey(key string, keyType reflect.Type) (reflect.Value,
if mc.EncodeKeysWithStringer { if mc.EncodeKeysWithStringer {
parsed, err := strconv.ParseFloat(key, 64) parsed, err := strconv.ParseFloat(key, 64)
if err != nil { if err != nil {
return keyVal, fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %v", keyType.Kind(), err) return keyVal, fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %w", keyType.Kind(), err)
} }
keyVal = reflect.ValueOf(parsed) keyVal = reflect.ValueOf(parsed)
break break

View File

@ -18,8 +18,16 @@ var _ ValueDecoder = &PointerCodec{}
// PointerCodec is the Codec used for pointers. // PointerCodec is the Codec used for pointers.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: PointerCodec will not be directly accessible in Go Driver 2.0. To
// PointerCodec registered. // override the default pointer encode and decode behavior, create a new registry
// with [go.mongodb.org/mongo-driver/bson.NewRegistry] and register a new
// encoder and decoder for pointers.
//
// For example,
//
// reg := bson.NewRegistry()
// reg.RegisterKindEncoder(reflect.Ptr, myPointerEncoder)
// reg.RegisterKindDecoder(reflect.Ptr, myPointerDecoder)
type PointerCodec struct { type PointerCodec struct {
ecache typeEncoderCache ecache typeEncoderCache
dcache typeDecoderCache dcache typeDecoderCache
@ -27,8 +35,8 @@ type PointerCodec struct {
// NewPointerCodec returns a PointerCodec that has been initialized. // NewPointerCodec returns a PointerCodec that has been initialized.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewPointerCodec will not be available in Go Driver 2.0. See
// PointerCodec registered. // [PointerCodec] for more details.
func NewPointerCodec() *PointerCodec { func NewPointerCodec() *PointerCodec {
return &PointerCodec{} return &PointerCodec{}
} }

View File

@ -7,6 +7,7 @@
package bsoncodec package bsoncodec
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
@ -20,8 +21,22 @@ var defaultSliceCodec = NewSliceCodec()
// SliceCodec is the Codec used for slice values. // SliceCodec is the Codec used for slice values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: SliceCodec will not be directly configurable in Go Driver 2.0. To
// SliceCodec registered. // configure the slice encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the slice encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal nil Go slices as empty
// BSON arrays, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilSliceAsEmpty: true,
// })
//
// See the deprecation notice for each field in SliceCodec for the corresponding
// settings.
type SliceCodec struct { type SliceCodec struct {
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go slices as empty BSON arrays instead of // EncodeNilAsEmpty causes EncodeValue to marshal nil Go slices as empty BSON arrays instead of
// BSON null. // BSON null.
@ -32,8 +47,8 @@ type SliceCodec struct {
// NewSliceCodec returns a MapCodec with options opts. // NewSliceCodec returns a MapCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewSliceCodec will not be available in Go Driver 2.0. See
// SliceCodec registered. // [SliceCodec] for more details.
func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec { func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec {
sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...) sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...)
@ -93,7 +108,7 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val re
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -102,7 +117,7 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val re
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err

View File

@ -17,8 +17,16 @@ import (
// StringCodec is the Codec used for string values. // StringCodec is the Codec used for string values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: StringCodec will not be directly accessible in Go Driver 2.0. To
// StringCodec registered. // override the default string encode and decode behavior, create a new registry
// with [go.mongodb.org/mongo-driver/bson.NewRegistry] and register a new
// encoder and decoder for strings.
//
// For example,
//
// reg := bson.NewRegistry()
// reg.RegisterKindEncoder(reflect.String, myStringEncoder)
// reg.RegisterKindDecoder(reflect.String, myStringDecoder)
type StringCodec struct { type StringCodec struct {
// DecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation. // DecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation.
// If false, a string made from the raw object ID bytes will be used. Defaults to true. // If false, a string made from the raw object ID bytes will be used. Defaults to true.
@ -38,8 +46,8 @@ var (
// NewStringCodec returns a StringCodec with options opts. // NewStringCodec returns a StringCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewStringCodec will not be available in Go Driver 2.0. See
// StringCodec registered. // [StringCodec] for more details.
func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec { func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec {
stringOpt := bsonoptions.MergeStringCodecOptions(opts...) stringOpt := bsonoptions.MergeStringCodecOptions(opts...)
return &StringCodec{*stringOpt.DecodeObjectIDAsHex} return &StringCodec{*stringOpt.DecodeObjectIDAsHex}

View File

@ -60,8 +60,22 @@ type Zeroer interface {
// StructCodec is the Codec used for struct values. // StructCodec is the Codec used for struct values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: StructCodec will not be directly configurable in Go Driver 2.0.
// StructCodec registered. // To configure the struct encode and decode behavior, use the configuration
// methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the struct encode
// and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to omit zero-value structs when
// using the "omitempty" struct tag, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// OmitZeroStruct: true,
// })
//
// See the deprecation notice for each field in StructCodec for the corresponding
// settings.
type StructCodec struct { type StructCodec struct {
cache sync.Map // map[reflect.Type]*structDescription cache sync.Map // map[reflect.Type]*structDescription
parser StructTagParser parser StructTagParser
@ -69,7 +83,7 @@ type StructCodec struct {
// DecodeZeroStruct causes DecodeValue to delete any existing values from Go structs in the // DecodeZeroStruct causes DecodeValue to delete any existing values from Go structs in the
// destination value passed to Decode before unmarshaling BSON documents into them. // destination value passed to Decode before unmarshaling BSON documents into them.
// //
// Deprecated: Use bson.Decoder.ZeroStructs instead. // Deprecated: Use bson.Decoder.ZeroStructs or options.BSONOptions.ZeroStructs instead.
DecodeZeroStruct bool DecodeZeroStruct bool
// DecodeDeepZeroInline causes DecodeValue to delete any existing values from Go structs in the // DecodeDeepZeroInline causes DecodeValue to delete any existing values from Go structs in the
@ -82,7 +96,7 @@ type StructCodec struct {
// MyStruct{}) as empty and omit it from the marshaled BSON when the "omitempty" struct tag // MyStruct{}) as empty and omit it from the marshaled BSON when the "omitempty" struct tag
// option is set. // option is set.
// //
// Deprecated: Use bson.Encoder.OmitZeroStruct instead. // Deprecated: Use bson.Encoder.OmitZeroStruct or options.BSONOptions.OmitZeroStruct instead.
EncodeOmitDefaultStruct bool EncodeOmitDefaultStruct bool
// AllowUnexportedFields allows encoding and decoding values from un-exported struct fields. // AllowUnexportedFields allows encoding and decoding values from un-exported struct fields.
@ -95,7 +109,8 @@ type StructCodec struct {
// a duplicate field in the marshaled BSON when the "inline" struct tag option is set. The // a duplicate field in the marshaled BSON when the "inline" struct tag option is set. The
// default value is true. // default value is true.
// //
// Deprecated: Use bson.Encoder.ErrorOnInlineDuplicates instead. // Deprecated: Use bson.Encoder.ErrorOnInlineDuplicates or
// options.BSONOptions.ErrorOnInlineDuplicates instead.
OverwriteDuplicatedInlinedFields bool OverwriteDuplicatedInlinedFields bool
} }
@ -104,8 +119,8 @@ var _ ValueDecoder = &StructCodec{}
// NewStructCodec returns a StructCodec that uses p for struct tag parsing. // NewStructCodec returns a StructCodec that uses p for struct tag parsing.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewStructCodec will not be available in Go Driver 2.0. See
// StructCodec registered. // [StructCodec] for more details.
func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) { func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) {
if p == nil { if p == nil {
return nil, errors.New("a StructTagParser must be provided to NewStructCodec") return nil, errors.New("a StructTagParser must be provided to NewStructCodec")
@ -164,11 +179,11 @@ func (sc *StructCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val
desc.encoder, rv, err = defaultValueEncoders.lookupElementEncoder(ec, desc.encoder, rv) desc.encoder, rv, err = defaultValueEncoders.lookupElementEncoder(ec, desc.encoder, rv)
if err != nil && err != errInvalidValue { if err != nil && !errors.Is(err, errInvalidValue) {
return err return err
} }
if err == errInvalidValue { if errors.Is(err, errInvalidValue) {
if desc.omitEmpty { if desc.omitEmpty {
continue continue
} }
@ -189,17 +204,17 @@ func (sc *StructCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val
encoder := desc.encoder encoder := desc.encoder
var zero bool var empty bool
if cz, ok := encoder.(CodecZeroer); ok { if cz, ok := encoder.(CodecZeroer); ok {
zero = cz.IsTypeZero(rv.Interface()) empty = cz.IsTypeZero(rv.Interface())
} else if rv.Kind() == reflect.Interface { } else if rv.Kind() == reflect.Interface {
// isZero will not treat an interface rv as an interface, so we need to check for the // isEmpty will not treat an interface rv as an interface, so we need to check for the
// zero interface separately. // nil interface separately.
zero = rv.IsNil() empty = rv.IsNil()
} else { } else {
zero = isZero(rv, sc.EncodeOmitDefaultStruct || ec.omitZeroStruct) empty = isEmpty(rv, sc.EncodeOmitDefaultStruct || ec.omitZeroStruct)
} }
if desc.omitEmpty && zero { if desc.omitEmpty && empty {
continue continue
} }
@ -239,8 +254,8 @@ func (sc *StructCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val
} }
func newDecodeError(key string, original error) error { func newDecodeError(key string, original error) error {
de, ok := original.(*DecodeError) var de *DecodeError
if !ok { if !errors.As(original, &de) {
return &DecodeError{ return &DecodeError{
keys: []string{key}, keys: []string{key},
wrapped: original, wrapped: original,
@ -308,7 +323,7 @@ func (sc *StructCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val
for { for {
name, vr, err := dr.ReadElement() name, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -391,12 +406,15 @@ func (sc *StructCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val
return nil return nil
} }
func isZero(v reflect.Value, omitZeroStruct bool) bool { func isEmpty(v reflect.Value, omitZeroStruct bool) bool {
kind := v.Kind() kind := v.Kind()
if (kind != reflect.Ptr || !v.IsNil()) && v.Type().Implements(tZeroer) { if (kind != reflect.Ptr || !v.IsNil()) && v.Type().Implements(tZeroer) {
return v.Interface().(Zeroer).IsZero() return v.Interface().(Zeroer).IsZero()
} }
if kind == reflect.Struct { switch kind {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Struct:
if !omitZeroStruct { if !omitZeroStruct {
return false return false
} }
@ -410,7 +428,7 @@ func isZero(v reflect.Value, omitZeroStruct bool) bool {
if ff.PkgPath != "" && !ff.Anonymous { if ff.PkgPath != "" && !ff.Anonymous {
continue // Private field continue // Private field
} }
if !isZero(v.Field(i), omitZeroStruct) { if !isEmpty(v.Field(i), omitZeroStruct) {
return false return false
} }
} }

View File

@ -23,12 +23,26 @@ const (
// TimeCodec is the Codec used for time.Time values. // TimeCodec is the Codec used for time.Time values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: TimeCodec will not be directly configurable in Go Driver 2.0.
// TimeCodec registered. // To configure the time.Time encode and decode behavior, use the configuration
// methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the time.Time encode
// and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to ..., use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// UseLocalTimeZone: true,
// })
//
// See the deprecation notice for each field in TimeCodec for the corresponding
// settings.
type TimeCodec struct { type TimeCodec struct {
// UseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false. // UseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false.
// //
// Deprecated: Use bson.Decoder.UseLocalTimeZone instead. // Deprecated: Use bson.Decoder.UseLocalTimeZone or options.BSONOptions.UseLocalTimeZone
// instead.
UseLocalTimeZone bool UseLocalTimeZone bool
} }
@ -42,8 +56,8 @@ var (
// NewTimeCodec returns a TimeCodec with options opts. // NewTimeCodec returns a TimeCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewTimeCodec will not be available in Go Driver 2.0. See
// TimeCodec registered. // [TimeCodec] for more details.
func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec { func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec {
timeOpt := bsonoptions.MergeTimeCodecOptions(opts...) timeOpt := bsonoptions.MergeTimeCodecOptions(opts...)

View File

@ -18,13 +18,27 @@ import (
// UIntCodec is the Codec used for uint values. // UIntCodec is the Codec used for uint values.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: UIntCodec will not be directly configurable in Go Driver 2.0. To
// UIntCodec registered. // configure the uint encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the uint encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal Go uint values as the
// minimum BSON int size that can represent the value, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// IntMinSize: true,
// })
//
// See the deprecation notice for each field in UIntCodec for the corresponding
// settings.
type UIntCodec struct { type UIntCodec struct {
// EncodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the // EncodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the
// minimum BSON int size (either 32-bit or 64-bit) that can represent the integer value. // minimum BSON int size (either 32-bit or 64-bit) that can represent the integer value.
// //
// Deprecated: Use bson.Encoder.IntMinSize instead. // Deprecated: Use bson.Encoder.IntMinSize or options.BSONOptions.IntMinSize instead.
EncodeToMinSize bool EncodeToMinSize bool
} }
@ -38,8 +52,8 @@ var (
// NewUIntCodec returns a UIntCodec with options opts. // NewUIntCodec returns a UIntCodec with options opts.
// //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the // Deprecated: NewUIntCodec will not be available in Go Driver 2.0. See
// UIntCodec registered. // [UIntCodec] for more details.
func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec { func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec {
uintOpt := bsonoptions.MergeUIntCodecOptions(opts...) uintOpt := bsonoptions.MergeUIntCodecOptions(opts...)

View File

@ -7,6 +7,7 @@
package bsonrw package bsonrw
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
@ -442,7 +443,7 @@ func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
for { for {
vr, err := ar.ReadValue() vr, err := ar.ReadValue()
if err == ErrEOA { if errors.Is(err, ErrEOA) {
break break
} }
if err != nil { if err != nil {
@ -466,7 +467,7 @@ func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error { func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error {
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == ErrEOD { if errors.Is(err, ErrEOD) {
break break
} }
if err != nil { if err != nil {

View File

@ -313,7 +313,7 @@ func (ejp *extJSONParser) readValue(t bsontype.Type) (*extJSONValue, error) {
// convert hex to bytes // convert hex to bytes
bytes, err := hex.DecodeString(uuidNoHyphens) bytes, err := hex.DecodeString(uuidNoHyphens)
if err != nil { if err != nil {
return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding hex bytes: %v", err) return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding hex bytes: %w", err)
} }
ejp.advanceState() ejp.advanceState()

View File

@ -7,6 +7,7 @@
package bsonrw package bsonrw
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"sync" "sync"
@ -613,7 +614,7 @@ func (ejvr *extJSONValueReader) ReadElement() (string, ValueReader, error) {
name, t, err := ejvr.p.readKey() name, t, err := ejvr.p.readKey()
if err != nil { if err != nil {
if err == ErrEOD { if errors.Is(err, ErrEOD) {
if ejvr.stack[ejvr.frame].mode == mCodeWithScope { if ejvr.stack[ejvr.frame].mode == mCodeWithScope {
_, err := ejvr.p.peekType() _, err := ejvr.p.peekType()
if err != nil { if err != nil {
@ -640,7 +641,7 @@ func (ejvr *extJSONValueReader) ReadValue() (ValueReader, error) {
t, err := ejvr.p.peekType() t, err := ejvr.p.peekType()
if err != nil { if err != nil {
if err == ErrEOA { if errors.Is(err, ErrEOA) {
ejvr.pop() ejvr.pop()
} }

View File

@ -58,7 +58,7 @@ func (js *jsonScanner) nextToken() (*jsonToken, error) {
c, err = js.readNextByte() c, err = js.readNextByte()
} }
if err == io.EOF { if errors.Is(err, io.EOF) {
return &jsonToken{t: jttEOF}, nil return &jsonToken{t: jttEOF}, nil
} else if err != nil { } else if err != nil {
return nil, err return nil, err
@ -198,7 +198,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
for { for {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -209,7 +209,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
case '\\': case '\\':
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -248,7 +248,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
if utf16.IsSurrogate(rn) { if utf16.IsSurrogate(rn) {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -264,7 +264,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -325,17 +325,17 @@ func (js *jsonScanner) scanLiteral(first byte) (*jsonToken, error) {
c5, err := js.readNextByte() c5, err := js.readNextByte()
if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || err == io.EOF) { if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttBool, v: true, p: p}, nil return &jsonToken{t: jttBool, v: true, p: p}, nil
} else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || err == io.EOF) { } else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttNull, v: nil, p: p}, nil return &jsonToken{t: jttNull, v: nil, p: p}, nil
} else if bytes.Equal([]byte("fals"), lit) { } else if bytes.Equal([]byte("fals"), lit) {
if c5 == 'e' { if c5 == 'e' {
c5, err = js.readNextByte() c5, err = js.readNextByte()
if isValueTerminator(c5) || err == io.EOF { if isValueTerminator(c5) || errors.Is(err, io.EOF) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttBool, v: false, p: p}, nil return &jsonToken{t: jttBool, v: false, p: p}, nil
} }
@ -384,7 +384,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
for { for {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil && err != io.EOF { if err != nil && !errors.Is(err, io.EOF) {
return nil, err return nil, err
} }
@ -413,7 +413,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else { } else {
s = nssInvalid s = nssInvalid
@ -430,7 +430,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawIntegerDigits s = nssSawIntegerDigits
@ -455,7 +455,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawFractionDigits s = nssSawFractionDigits
@ -490,7 +490,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawExponentDigits s = nssSawExponentDigits

View File

@ -6,9 +6,9 @@
// Package bson is a library for reading, writing, and manipulating BSON. BSON is a binary serialization format used to // Package bson is a library for reading, writing, and manipulating BSON. BSON is a binary serialization format used to
// store documents and make remote procedure calls in MongoDB. The BSON specification is located at https://bsonspec.org. // store documents and make remote procedure calls in MongoDB. The BSON specification is located at https://bsonspec.org.
// The BSON library handles marshalling and unmarshalling of values through a configurable codec system. For a description // The BSON library handles marshaling and unmarshaling of values through a configurable codec system. For a description
// of the codec system and examples of registering custom codecs, see the bsoncodec package. For additional information and // of the codec system and examples of registering custom codecs, see the bsoncodec package. For additional information
// usage examples, check out the [Work with BSON] page in the Go Driver docs site. // and usage examples, check out the [Work with BSON] page in the Go Driver docs site.
// //
// # Raw BSON // # Raw BSON
// //
@ -38,7 +38,7 @@
// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} // bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} // bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
// //
// When decoding BSON to a D or M, the following type mappings apply when unmarshalling: // When decoding BSON to a D or M, the following type mappings apply when unmarshaling:
// //
// 1. BSON int32 unmarshals to an int32. // 1. BSON int32 unmarshals to an int32.
// 2. BSON int64 unmarshals to an int64. // 2. BSON int64 unmarshals to an int64.
@ -62,83 +62,78 @@
// 20. BSON DBPointer unmarshals to a primitive.DBPointer. // 20. BSON DBPointer unmarshals to a primitive.DBPointer.
// 21. BSON symbol unmarshals to a primitive.Symbol. // 21. BSON symbol unmarshals to a primitive.Symbol.
// //
// The above mappings also apply when marshalling a D or M to BSON. Some other useful marshalling mappings are: // The above mappings also apply when marshaling a D or M to BSON. Some other useful marshaling mappings are:
// //
// 1. time.Time marshals to a BSON datetime. // 1. time.Time marshals to a BSON datetime.
// 2. int8, int16, and int32 marshal to a BSON int32. // 2. int8, int16, and int32 marshal to a BSON int32.
// 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64 // 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64
// otherwise. // otherwise.
// 4. int64 marshals to BSON int64. // 4. int64 marshals to BSON int64 (unless [Encoder.IntMinSize] is set).
// 5. uint8 and uint16 marshal to a BSON int32. // 5. uint8 and uint16 marshal to a BSON int32.
// 6. uint, uint32, and uint64 marshal to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, // 6. uint, uint32, and uint64 marshal to a BSON int64 (unless [Encoder.IntMinSize] is set).
// inclusive, and BSON int64 otherwise. // 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshaling a BSON null or
// 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshalling a BSON null or
// undefined value into a string will yield the empty string.). // undefined value into a string will yield the empty string.).
// //
// # Structs // # Structs
// //
// Structs can be marshalled/unmarshalled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended // Structs can be marshaled/unmarshaled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended
// JSON, the following rules apply: // JSON, the following rules apply:
// //
// 1. Only exported fields in structs will be marshalled or unmarshalled. // 1. Only exported fields in structs will be marshaled or unmarshaled.
// //
// 2. When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element. // 2. When marshaling a struct, each field will be lowercased to generate the key for the corresponding BSON element.
// For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g. // For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g.
// `bson:"fooField"` to generate key "fooField" instead). // `bson:"fooField"` to generate key "fooField" instead).
// //
// 3. An embedded struct field is marshalled as a subdocument. The key will be the lowercased name of the field's type. // 3. An embedded struct field is marshaled as a subdocument. The key will be the lowercased name of the field's type.
// //
// 4. A pointer field is marshalled as the underlying type if the pointer is non-nil. If the pointer is nil, it is // 4. A pointer field is marshaled as the underlying type if the pointer is non-nil. If the pointer is nil, it is
// marshalled as a BSON null value. // marshaled as a BSON null value.
// //
// 5. When unmarshalling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents // 5. When unmarshaling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents
// unmarshalled into an interface{} field will be unmarshalled as a D. // unmarshaled into an interface{} field will be unmarshaled as a D.
// //
// The encoding of each struct field can be customized by the "bson" struct tag. // The encoding of each struct field can be customized by the "bson" struct tag.
// //
// This tag behavior is configurable, and different struct tag behavior can be configured by initializing a new // This tag behavior is configurable, and different struct tag behavior can be configured by initializing a new
// bsoncodec.StructCodec with the desired tag parser and registering that StructCodec onto the Registry. By default, JSON tags // bsoncodec.StructCodec with the desired tag parser and registering that StructCodec onto the Registry. By default, JSON
// are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below: // tags are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below:
// //
// Example: // Example:
// //
// structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser) // structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser)
// //
// The bson tag gives the name of the field, possibly followed by a comma-separated list of options. // The bson tag gives the name of the field, possibly followed by a comma-separated list of options.
// The name may be empty in order to specify options without overriding the default field name. The following options can be used // The name may be empty in order to specify options without overriding the default field name. The following options can
// to configure behavior: // be used to configure behavior:
// //
// 1. omitempty: If the omitempty struct tag is specified on a field, the field will not be marshalled if it is set to // 1. omitempty: If the omitempty struct tag is specified on a field, the field will be omitted from the marshaling if
// the zero value. Fields with language primitive types such as integers, booleans, and strings are considered empty if // the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array,
// their value is equal to the zero value for the type (i.e. 0 for integers, false for booleans, and "" for strings). // slice, map, or string.
// Slices, maps, and arrays are considered empty if they are of length zero. Interfaces and pointers are considered
// empty if their value is nil. By default, structs are only considered empty if the struct type implements the
// bsoncodec.Zeroer interface and the IsZero method returns true. Struct fields whose types do not implement Zeroer are
// never considered empty and will be marshalled as embedded documents.
// NOTE: It is recommended that this tag be used for all slice and map fields. // NOTE: It is recommended that this tag be used for all slice and map fields.
// //
// 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of // 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of
// the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For other // the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For
// types, this tag is ignored. // other types, this tag is ignored.
// //
// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled // 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles
// into that field will be truncated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int, // unmarshaled into that field will be truncated at the decimal point. For example, if 3.14 is unmarshaled into a
// it will be unmarshalled as 3. If this tag is not specified, the decoder will throw an error if the value cannot be // field of type int, it will be unmarshaled as 3. If this tag is not specified, the decoder will throw an error if
// decoded without losing precision. For float64 or non-numeric types, this tag is ignored. // the value cannot be decoded without losing precision. For float64 or non-numeric types, this tag is ignored.
// //
// 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when // 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when
// marshalling and "un-flattened" when unmarshalling. This means that all of the fields in that struct/map will be // marshaling and "un-flattened" when unmarshaling. This means that all of the fields in that struct/map will be
// pulled up one level and will become top-level fields rather than being fields in a nested document. For example, if a // pulled up one level and will become top-level fields rather than being fields in a nested document. For example,
// map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will be // if a map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will
// {"foo": "bar"} instead of {"map": {"foo": "bar"}}. There can only be one inlined map field in a struct. If there are // be {"foo": "bar"} instead of {"map": {"foo": "bar"}}. There can only be one inlined map field in a struct. If
// duplicated fields in the resulting document when an inlined struct is marshalled, the inlined field will be overwritten. // there are duplicated fields in the resulting document when an inlined struct is marshaled, the inlined field will
// If there are duplicated fields in the resulting document when an inlined map is marshalled, an error will be returned. // be overwritten. If there are duplicated fields in the resulting document when an inlined map is marshaled, an
// This tag can be used with fields that are pointers to structs. If an inlined pointer field is nil, it will not be // error will be returned. This tag can be used with fields that are pointers to structs. If an inlined pointer field
// marshalled. For fields that are not maps or structs, this tag is ignored. // is nil, it will not be marshaled. For fields that are not maps or structs, this tag is ignored.
// //
// # Marshalling and Unmarshalling // # Marshaling and Unmarshaling
// //
// Manually marshalling and unmarshalling can be done with the Marshal and Unmarshal family of functions. // Manually marshaling and unmarshaling can be done with the Marshal and Unmarshal family of functions.
// //
// [Work with BSON]: https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/ // [Work with BSON]: https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/
package bson package bson

View File

@ -164,9 +164,6 @@ func (d Decimal128) BigInt() (*big.Int, int, error) {
// Would be handled by the logic below, but that's trivial and common. // Would be handled by the logic below, but that's trivial and common.
if high == 0 && low == 0 && exp == 0 { if high == 0 && low == 0 && exp == 0 {
if posSign {
return new(big.Int), 0, nil
}
return new(big.Int), 0, nil return new(big.Int), 0, nil
} }

View File

@ -183,7 +183,7 @@ func processUniqueBytes() [5]byte {
var b [5]byte var b [5]byte
_, err := io.ReadFull(rand.Reader, b[:]) _, err := io.ReadFull(rand.Reader, b[:])
if err != nil { if err != nil {
panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))
} }
return b return b
@ -193,7 +193,7 @@ func readRandomUint32() uint32 {
var b [4]byte var b [4]byte
_, err := io.ReadFull(rand.Reader, b[:]) _, err := io.ReadFull(rand.Reader, b[:])
if err != nil { if err != nil {
panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))
} }
return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)

View File

@ -2911,6 +2911,15 @@ func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
fl = &cs.flow fl = &cs.flow
} }
if !fl.add(int32(f.Increment)) { if !fl.add(int32(f.Increment)) {
// For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR
if cs != nil {
rl.endStreamError(cs, StreamError{
StreamID: f.StreamID,
Code: ErrCodeFlowControl,
})
return nil
}
return ConnectionError(ErrCodeFlowControl) return ConnectionError(ErrCodeFlowControl)
} }
cc.cond.Broadcast() cc.cond.Broadcast()

View File

@ -15,22 +15,10 @@ Load passes most patterns directly to the underlying build tool.
The default build tool is the go command. The default build tool is the go command.
Its supported patterns are described at Its supported patterns are described at
https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns. https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns.
Other build systems may be supported by providing a "driver";
see [The driver protocol].
Load may be used in Go projects that use alternative build systems, by All patterns with the prefix "query=", where query is a
installing an appropriate "driver" program for the build system and
specifying its location in the GOPACKAGESDRIVER environment variable.
For example,
https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration
explains how to use the driver for Bazel.
The driver program is responsible for interpreting patterns in its
preferred notation and reporting information about the packages that
they identify.
(See driverRequest and driverResponse types for the JSON
schema used by the protocol.
Though the protocol is supported, these types are currently unexported;
see #64608 for a proposal to publish them.)
Regardless of driver, all patterns with the prefix "query=", where query is a
non-empty string of letters from [a-z], are reserved and may be non-empty string of letters from [a-z], are reserved and may be
interpreted as query operators. interpreted as query operators.
@ -86,7 +74,29 @@ for details.
Most tools should pass their command-line arguments (after any flags) Most tools should pass their command-line arguments (after any flags)
uninterpreted to [Load], so that it can interpret them uninterpreted to [Load], so that it can interpret them
according to the conventions of the underlying build system. according to the conventions of the underlying build system.
See the Example function for typical usage. See the Example function for typical usage.
# The driver protocol
[Load] may be used to load Go packages even in Go projects that use
alternative build systems, by installing an appropriate "driver"
program for the build system and specifying its location in the
GOPACKAGESDRIVER environment variable.
For example,
https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration
explains how to use the driver for Bazel.
The driver program is responsible for interpreting patterns in its
preferred notation and reporting information about the packages that
those patterns identify. Drivers must also support the special "file="
and "pattern=" patterns described above.
The patterns are provided as positional command-line arguments. A
JSON-encoded [DriverRequest] message providing additional information
is written to the driver's standard input. The driver must write a
JSON-encoded [DriverResponse] message to its standard output. (This
message differs from the JSON schema produced by 'go list'.)
*/ */
package packages // import "golang.org/x/tools/go/packages" package packages // import "golang.org/x/tools/go/packages"

View File

@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file enables an external tool to intercept package requests.
// If the tool is present then its results are used in preference to
// the go list command.
package packages package packages
// This file defines the protocol that enables an external "driver"
// tool to supply package metadata in place of 'go list'.
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
@ -17,31 +16,71 @@ import (
"strings" "strings"
) )
// The Driver Protocol // DriverRequest defines the schema of a request for package metadata
// from an external driver program. The JSON-encoded DriverRequest
// message is provided to the driver program's standard input. The
// query patterns are provided as command-line arguments.
// //
// The driver, given the inputs to a call to Load, returns metadata about the packages specified. // See the package documentation for an overview.
// This allows for different build systems to support go/packages by telling go/packages how the type DriverRequest struct {
// packages' source is organized.
// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
// documentation in doc.go for the full description of the patterns that need to be supported.
// A driver receives as a JSON-serialized driverRequest struct in standard input and will
// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
// driverRequest is used to provide the portion of Load's Config that is needed by a driver.
type driverRequest struct {
Mode LoadMode `json:"mode"` Mode LoadMode `json:"mode"`
// Env specifies the environment the underlying build system should be run in. // Env specifies the environment the underlying build system should be run in.
Env []string `json:"env"` Env []string `json:"env"`
// BuildFlags are flags that should be passed to the underlying build system. // BuildFlags are flags that should be passed to the underlying build system.
BuildFlags []string `json:"build_flags"` BuildFlags []string `json:"build_flags"`
// Tests specifies whether the patterns should also return test packages. // Tests specifies whether the patterns should also return test packages.
Tests bool `json:"tests"` Tests bool `json:"tests"`
// Overlay maps file paths (relative to the driver's working directory) to the byte contents // Overlay maps file paths (relative to the driver's working directory) to the byte contents
// of overlay files. // of overlay files.
Overlay map[string][]byte `json:"overlay"` Overlay map[string][]byte `json:"overlay"`
} }
// DriverResponse defines the schema of a response from an external
// driver program, providing the results of a query for package
// metadata. The driver program must write a JSON-encoded
// DriverResponse message to its standard output.
//
// See the package documentation for an overview.
type DriverResponse struct {
// NotHandled is returned if the request can't be handled by the current
// driver. If an external driver returns a response with NotHandled, the
// rest of the DriverResponse is ignored, and go/packages will fallback
// to the next driver. If go/packages is extended in the future to support
// lists of multiple drivers, go/packages will fall back to the next driver.
NotHandled bool
// Compiler and Arch are the arguments pass of types.SizesFor
// to get a types.Sizes to use when type checking.
Compiler string
Arch string
// Roots is the set of package IDs that make up the root packages.
// We have to encode this separately because when we encode a single package
// we cannot know if it is one of the roots as that requires knowledge of the
// graph it is part of.
Roots []string `json:",omitempty"`
// Packages is the full set of packages in the graph.
// The packages are not connected into a graph.
// The Imports if populated will be stubs that only have their ID set.
// Imports will be connected and then type and syntax information added in a
// later pass (see refine).
Packages []*Package
// GoVersion is the minor version number used by the driver
// (e.g. the go command on the PATH) when selecting .go files.
// Zero means unknown.
GoVersion int
}
// driver is the type for functions that query the build system for the
// packages named by the patterns.
type driver func(cfg *Config, patterns ...string) (*DriverResponse, error)
// findExternalDriver returns the file path of a tool that supplies // findExternalDriver returns the file path of a tool that supplies
// the build system package structure, or "" if not found." // the build system package structure, or "" if not found."
// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
@ -64,8 +103,8 @@ func findExternalDriver(cfg *Config) driver {
return nil return nil
} }
} }
return func(cfg *Config, words ...string) (*driverResponse, error) { return func(cfg *Config, words ...string) (*DriverResponse, error) {
req, err := json.Marshal(driverRequest{ req, err := json.Marshal(DriverRequest{
Mode: cfg.Mode, Mode: cfg.Mode,
Env: cfg.Env, Env: cfg.Env,
BuildFlags: cfg.BuildFlags, BuildFlags: cfg.BuildFlags,
@ -92,7 +131,7 @@ func findExternalDriver(cfg *Config) driver {
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr) fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)
} }
var response driverResponse var response DriverResponse
if err := json.Unmarshal(buf.Bytes(), &response); err != nil { if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
return nil, err return nil, err
} }

View File

@ -35,23 +35,23 @@ type goTooOldError struct {
error error
} }
// responseDeduper wraps a driverResponse, deduplicating its contents. // responseDeduper wraps a DriverResponse, deduplicating its contents.
type responseDeduper struct { type responseDeduper struct {
seenRoots map[string]bool seenRoots map[string]bool
seenPackages map[string]*Package seenPackages map[string]*Package
dr *driverResponse dr *DriverResponse
} }
func newDeduper() *responseDeduper { func newDeduper() *responseDeduper {
return &responseDeduper{ return &responseDeduper{
dr: &driverResponse{}, dr: &DriverResponse{},
seenRoots: map[string]bool{}, seenRoots: map[string]bool{},
seenPackages: map[string]*Package{}, seenPackages: map[string]*Package{},
} }
} }
// addAll fills in r with a driverResponse. // addAll fills in r with a DriverResponse.
func (r *responseDeduper) addAll(dr *driverResponse) { func (r *responseDeduper) addAll(dr *DriverResponse) {
for _, pkg := range dr.Packages { for _, pkg := range dr.Packages {
r.addPackage(pkg) r.addPackage(pkg)
} }
@ -128,7 +128,7 @@ func (state *golistState) mustGetEnv() map[string]string {
// goListDriver uses the go list command to interpret the patterns and produce // goListDriver uses the go list command to interpret the patterns and produce
// the build system package structure. // the build system package structure.
// See driver for more details. // See driver for more details.
func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error) {
// Make sure that any asynchronous go commands are killed when we return. // Make sure that any asynchronous go commands are killed when we return.
parentCtx := cfg.Context parentCtx := cfg.Context
if parentCtx == nil { if parentCtx == nil {
@ -146,16 +146,18 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
} }
// Fill in response.Sizes asynchronously if necessary. // Fill in response.Sizes asynchronously if necessary.
var sizeserr error
var sizeswg sync.WaitGroup
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 { if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
sizeswg.Add(1) errCh := make(chan error)
go func() { go func() {
compiler, arch, err := packagesdriver.GetSizesForArgsGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner) compiler, arch, err := packagesdriver.GetSizesForArgsGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner)
sizeserr = err
response.dr.Compiler = compiler response.dr.Compiler = compiler
response.dr.Arch = arch response.dr.Arch = arch
sizeswg.Done() errCh <- err
}()
defer func() {
if sizesErr := <-errCh; sizesErr != nil {
err = sizesErr
}
}() }()
} }
@ -208,10 +210,7 @@ extractQueries:
} }
} }
sizeswg.Wait() // (We may yet return an error due to defer.)
if sizeserr != nil {
return nil, sizeserr
}
return response.dr, nil return response.dr, nil
} }
@ -266,7 +265,7 @@ func (state *golistState) runContainsQueries(response *responseDeduper, queries
// adhocPackage attempts to load or construct an ad-hoc package for a given // adhocPackage attempts to load or construct an ad-hoc package for a given
// query, if the original call to the driver produced inadequate results. // query, if the original call to the driver produced inadequate results.
func (state *golistState) adhocPackage(pattern, query string) (*driverResponse, error) { func (state *golistState) adhocPackage(pattern, query string) (*DriverResponse, error) {
response, err := state.createDriverResponse(query) response, err := state.createDriverResponse(query)
if err != nil { if err != nil {
return nil, err return nil, err
@ -357,7 +356,7 @@ func otherFiles(p *jsonPackage) [][]string {
// createDriverResponse uses the "go list" command to expand the pattern // createDriverResponse uses the "go list" command to expand the pattern
// words and return a response for the specified packages. // words and return a response for the specified packages.
func (state *golistState) createDriverResponse(words ...string) (*driverResponse, error) { func (state *golistState) createDriverResponse(words ...string) (*DriverResponse, error) {
// go list uses the following identifiers in ImportPath and Imports: // go list uses the following identifiers in ImportPath and Imports:
// //
// "p" -- importable package or main (command) // "p" -- importable package or main (command)
@ -384,7 +383,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
pkgs := make(map[string]*Package) pkgs := make(map[string]*Package)
additionalErrors := make(map[string][]Error) additionalErrors := make(map[string][]Error)
// Decode the JSON and convert it to Package form. // Decode the JSON and convert it to Package form.
response := &driverResponse{ response := &DriverResponse{
GoVersion: goVersion, GoVersion: goVersion,
} }
for dec := json.NewDecoder(buf); dec.More(); { for dec := json.NewDecoder(buf); dec.More(); {

View File

@ -206,43 +206,6 @@ type Config struct {
Overlay map[string][]byte Overlay map[string][]byte
} }
// driver is the type for functions that query the build system for the
// packages named by the patterns.
type driver func(cfg *Config, patterns ...string) (*driverResponse, error)
// driverResponse contains the results for a driver query.
type driverResponse struct {
// NotHandled is returned if the request can't be handled by the current
// driver. If an external driver returns a response with NotHandled, the
// rest of the driverResponse is ignored, and go/packages will fallback
// to the next driver. If go/packages is extended in the future to support
// lists of multiple drivers, go/packages will fall back to the next driver.
NotHandled bool
// Compiler and Arch are the arguments pass of types.SizesFor
// to get a types.Sizes to use when type checking.
Compiler string
Arch string
// Roots is the set of package IDs that make up the root packages.
// We have to encode this separately because when we encode a single package
// we cannot know if it is one of the roots as that requires knowledge of the
// graph it is part of.
Roots []string `json:",omitempty"`
// Packages is the full set of packages in the graph.
// The packages are not connected into a graph.
// The Imports if populated will be stubs that only have their ID set.
// Imports will be connected and then type and syntax information added in a
// later pass (see refine).
Packages []*Package
// GoVersion is the minor version number used by the driver
// (e.g. the go command on the PATH) when selecting .go files.
// Zero means unknown.
GoVersion int
}
// Load loads and returns the Go packages named by the given patterns. // Load loads and returns the Go packages named by the given patterns.
// //
// Config specifies loading options; // Config specifies loading options;
@ -291,7 +254,7 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) {
// no external driver, or the driver returns a response with NotHandled set, // no external driver, or the driver returns a response with NotHandled set,
// defaultDriver will fall back to the go list driver. // defaultDriver will fall back to the go list driver.
// The boolean result indicates that an external driver handled the request. // The boolean result indicates that an external driver handled the request.
func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, bool, error) { func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, error) {
if driver := findExternalDriver(cfg); driver != nil { if driver := findExternalDriver(cfg); driver != nil {
response, err := driver(cfg, patterns...) response, err := driver(cfg, patterns...)
if err != nil { if err != nil {
@ -303,7 +266,10 @@ func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, bool, erro
} }
response, err := goListDriver(cfg, patterns...) response, err := goListDriver(cfg, patterns...)
return response, false, err if err != nil {
return nil, false, err
}
return response, false, nil
} }
// A Package describes a loaded Go package. // A Package describes a loaded Go package.
@ -648,7 +614,7 @@ func newLoader(cfg *Config) *loader {
// refine connects the supplied packages into a graph and then adds type // refine connects the supplied packages into a graph and then adds type
// and syntax information as requested by the LoadMode. // and syntax information as requested by the LoadMode.
func (ld *loader) refine(response *driverResponse) ([]*Package, error) { func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
roots := response.Roots roots := response.Roots
rootMap := make(map[string]int, len(roots)) rootMap := make(map[string]int, len(roots))
for i, root := range roots { for i, root := range roots {

View File

@ -224,6 +224,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
// Gather the relevant packages from the manifest. // Gather the relevant packages from the manifest.
items := make([]GetPackagesItem, r.uint64()) items := make([]GetPackagesItem, r.uint64())
uniquePkgPaths := make(map[string]bool)
for i := range items { for i := range items {
pkgPathOff := r.uint64() pkgPathOff := r.uint64()
pkgPath := p.stringAt(pkgPathOff) pkgPath := p.stringAt(pkgPathOff)
@ -248,6 +249,12 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
} }
items[i].nameIndex = nameIndex items[i].nameIndex = nameIndex
uniquePkgPaths[pkgPath] = true
}
// Debugging #63822; hypothesis: there are duplicate PkgPaths.
if len(uniquePkgPaths) != len(items) {
reportf("found duplicate PkgPaths while reading export data manifest: %v", items)
} }
// Request packages all at once from the client, // Request packages all at once from the client,

View File

@ -97,7 +97,7 @@ github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.4.0 # github.com/containernetworking/plugins v1.4.0
## explicit; go 1.20 ## explicit; go 1.20
github.com/containernetworking/plugins/pkg/ns github.com/containernetworking/plugins/pkg/ns
# github.com/containers/image/v5 v5.29.3-0.20240227090231-5bef5e1e1506 # github.com/containers/image/v5 v5.30.0
## explicit; go 1.19 ## explicit; go 1.19
github.com/containers/image/v5/copy github.com/containers/image/v5/copy
github.com/containers/image/v5/directory github.com/containers/image/v5/directory
@ -182,7 +182,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7
github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/spec
github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils
github.com/containers/ocicrypt/utils/keyprovider github.com/containers/ocicrypt/utils/keyprovider
# github.com/containers/storage v1.52.1-0.20240227215008-a083950a778f # github.com/containers/storage v1.53.0
## explicit; go 1.20 ## explicit; go 1.20
github.com/containers/storage github.com/containers/storage
github.com/containers/storage/drivers github.com/containers/storage/drivers
@ -299,7 +299,7 @@ github.com/felixge/httpsnoop
# github.com/fsnotify/fsnotify v1.7.0 # github.com/fsnotify/fsnotify v1.7.0
## explicit; go 1.17 ## explicit; go 1.17
github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify
# github.com/go-jose/go-jose/v3 v3.0.1 # github.com/go-jose/go-jose/v3 v3.0.2
## explicit; go 1.12 ## explicit; go 1.12
github.com/go-jose/go-jose/v3 github.com/go-jose/go-jose/v3
github.com/go-jose/go-jose/v3/cipher github.com/go-jose/go-jose/v3/cipher
@ -320,7 +320,7 @@ github.com/go-openapi/analysis/internal/flatten/operations
github.com/go-openapi/analysis/internal/flatten/replace github.com/go-openapi/analysis/internal/flatten/replace
github.com/go-openapi/analysis/internal/flatten/schutils github.com/go-openapi/analysis/internal/flatten/schutils
github.com/go-openapi/analysis/internal/flatten/sortref github.com/go-openapi/analysis/internal/flatten/sortref
# github.com/go-openapi/errors v0.21.0 # github.com/go-openapi/errors v0.21.1
## explicit; go 1.19 ## explicit; go 1.19
github.com/go-openapi/errors github.com/go-openapi/errors
# github.com/go-openapi/jsonpointer v0.19.6 # github.com/go-openapi/jsonpointer v0.19.6
@ -339,10 +339,10 @@ github.com/go-openapi/runtime
# github.com/go-openapi/spec v0.20.9 # github.com/go-openapi/spec v0.20.9
## explicit; go 1.13 ## explicit; go 1.13
github.com/go-openapi/spec github.com/go-openapi/spec
# github.com/go-openapi/strfmt v0.22.0 # github.com/go-openapi/strfmt v0.22.2
## explicit; go 1.19 ## explicit; go 1.19
github.com/go-openapi/strfmt github.com/go-openapi/strfmt
# github.com/go-openapi/swag v0.22.9 # github.com/go-openapi/swag v0.22.10
## explicit; go 1.19 ## explicit; go 1.19
github.com/go-openapi/swag github.com/go-openapi/swag
# github.com/go-openapi/validate v0.22.1 # github.com/go-openapi/validate v0.22.1
@ -375,7 +375,7 @@ github.com/google/go-cmp/cmp/internal/diff
github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/flags
github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/function
github.com/google/go-cmp/cmp/internal/value github.com/google/go-cmp/cmp/internal/value
# github.com/google/go-containerregistry v0.17.0 # github.com/google/go-containerregistry v0.19.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/google/go-containerregistry/pkg/name github.com/google/go-containerregistry/pkg/name
github.com/google/go-containerregistry/pkg/v1 github.com/google/go-containerregistry/pkg/v1
@ -386,7 +386,7 @@ github.com/google/go-intervals/intervalset
# github.com/google/pprof v0.0.0-20230323073829-e72429f035bd # github.com/google/pprof v0.0.0-20230323073829-e72429f035bd
## explicit; go 1.19 ## explicit; go 1.19
github.com/google/pprof/profile github.com/google/pprof/profile
# github.com/google/uuid v1.5.0 # github.com/google/uuid v1.6.0
## explicit ## explicit
github.com/google/uuid github.com/google/uuid
# github.com/gorilla/mux v1.8.1 # github.com/gorilla/mux v1.8.1
@ -581,7 +581,7 @@ github.com/sigstore/fulcio/pkg/certificate
# github.com/sigstore/rekor v1.2.2 # github.com/sigstore/rekor v1.2.2
## explicit; go 1.19 ## explicit; go 1.19
github.com/sigstore/rekor/pkg/generated/models github.com/sigstore/rekor/pkg/generated/models
# github.com/sigstore/sigstore v1.8.1 # github.com/sigstore/sigstore v1.8.2
## explicit; go 1.20 ## explicit; go 1.20
github.com/sigstore/sigstore/pkg/cryptoutils github.com/sigstore/sigstore/pkg/cryptoutils
github.com/sigstore/sigstore/pkg/signature github.com/sigstore/sigstore/pkg/signature
@ -642,8 +642,8 @@ github.com/vishvananda/netns
# go.etcd.io/bbolt v1.3.9 # go.etcd.io/bbolt v1.3.9
## explicit; go 1.17 ## explicit; go 1.17
go.etcd.io/bbolt go.etcd.io/bbolt
# go.mongodb.org/mongo-driver v1.13.1 # go.mongodb.org/mongo-driver v1.14.0
## explicit; go 1.13 ## explicit; go 1.18
go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson
go.mongodb.org/mongo-driver/bson/bsoncodec go.mongodb.org/mongo-driver/bson/bsoncodec
go.mongodb.org/mongo-driver/bson/bsonoptions go.mongodb.org/mongo-driver/bson/bsonoptions
@ -710,15 +710,15 @@ golang.org/x/crypto/ssh
golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/knownhosts
# golang.org/x/exp v0.0.0-20240119083558-1b970713d09a # golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
## explicit; go 1.20 ## explicit; go 1.20
golang.org/x/exp/constraints golang.org/x/exp/constraints
golang.org/x/exp/maps golang.org/x/exp/maps
golang.org/x/exp/slices golang.org/x/exp/slices
# golang.org/x/mod v0.14.0 # golang.org/x/mod v0.15.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/mod/semver golang.org/x/mod/semver
# golang.org/x/net v0.21.0 # golang.org/x/net v0.22.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/net/context golang.org/x/net/context
golang.org/x/net/html golang.org/x/net/html
@ -766,7 +766,7 @@ golang.org/x/text/secure/bidirule
golang.org/x/text/transform golang.org/x/text/transform
golang.org/x/text/unicode/bidi golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm golang.org/x/text/unicode/norm
# golang.org/x/tools v0.17.0 # golang.org/x/tools v0.18.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/tools/cmd/stringer golang.org/x/tools/cmd/stringer
golang.org/x/tools/go/ast/inspector golang.org/x/tools/go/ast/inspector