Merge pull request #23278 from rhatdan/VENDOR

Vendor in latest containers(common, storage,image, buildah)
This commit is contained in:
openshift-merge-bot[bot] 2024-07-15 19:19:23 +00:00 committed by GitHub
commit 07f0e4fe04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 1984 additions and 1339 deletions

33
go.mod
View File

@ -1,9 +1,8 @@
module github.com/containers/podman/v5 module github.com/containers/podman/v5
go 1.21
// Warning: Ensure the "go" and "toolchain" versions match exactly to prevent unwanted auto-updates // Warning: Ensure the "go" and "toolchain" versions match exactly to prevent unwanted auto-updates
toolchain go1.21.0
go 1.21.0
require ( require (
github.com/BurntSushi/toml v1.4.0 github.com/BurntSushi/toml v1.4.0
@ -13,15 +12,15 @@ require (
github.com/checkpoint-restore/checkpointctl v1.2.1 github.com/checkpoint-restore/checkpointctl v1.2.1
github.com/checkpoint-restore/go-criu/v7 v7.1.0 github.com/checkpoint-restore/go-criu/v7 v7.1.0
github.com/containernetworking/plugins v1.5.1 github.com/containernetworking/plugins v1.5.1
github.com/containers/buildah v1.36.0 github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382
github.com/containers/common v0.59.1-0.20240603155017-49ad520556e7 github.com/containers/common v0.59.1-0.20240715151621-fdf625dfee0e
github.com/containers/conmon v2.0.20+incompatible github.com/containers/conmon v2.0.20+incompatible
github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70 github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70
github.com/containers/image/v5 v5.31.1-0.20240603155732-aa935041e316 github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516
github.com/containers/libhvee v0.7.1 github.com/containers/libhvee v0.7.1
github.com/containers/ocicrypt v1.2.0 github.com/containers/ocicrypt v1.2.0
github.com/containers/psgo v1.9.0 github.com/containers/psgo v1.9.0
github.com/containers/storage v1.54.1-0.20240712121534-ab74785ce9e8 github.com/containers/storage v1.54.1-0.20240712125645-98ad80d6d165
github.com/containers/winquit v1.1.0 github.com/containers/winquit v1.1.0
github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09 github.com/coreos/go-systemd/v22 v22.5.1-0.20231103132048-7d375ecc2b09
github.com/coreos/stream-metadata-go v0.4.4 github.com/coreos/stream-metadata-go v0.4.4
@ -56,7 +55,7 @@ require (
github.com/onsi/gomega v1.33.1 github.com/onsi/gomega v1.33.1
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/image-spec v1.1.0
github.com/opencontainers/runc v1.1.12 github.com/opencontainers/runc v1.1.13
github.com/opencontainers/runtime-spec v1.2.0 github.com/opencontainers/runtime-spec v1.2.0
github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc github.com/opencontainers/runtime-tools v0.9.1-0.20230914150019-408c51e934dc
github.com/opencontainers/selinux v1.11.0 github.com/opencontainers/selinux v1.11.0
@ -72,7 +71,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.10 go.etcd.io/bbolt v1.3.10
golang.org/x/crypto v0.25.0 golang.org/x/crypto v0.25.0
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
golang.org/x/net v0.27.0 golang.org/x/net v0.27.0
golang.org/x/sync v0.7.0 golang.org/x/sync v0.7.0
golang.org/x/sys v0.22.0 golang.org/x/sys v0.22.0
@ -98,14 +97,14 @@ require (
github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/chzyer/readline v1.5.1 // indirect github.com/chzyer/readline v1.5.1 // indirect
github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect
github.com/containerd/containerd v1.7.17 // indirect github.com/containerd/containerd v1.7.18 // indirect
github.com/containerd/errdefs v0.1.0 // indirect github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containernetworking/cni v1.1.2 // indirect github.com/containernetworking/cni v1.2.2 // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/containers/luksy v0.0.0-20240506205542-84b50f50f3ee // indirect github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c // indirect
github.com/coreos/go-oidc/v3 v3.10.0 // indirect github.com/coreos/go-oidc/v3 v3.10.0 // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
@ -144,7 +143,7 @@ require (
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.4 // indirect github.com/golang/protobuf v1.5.4 // 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.19.1 // indirect github.com/google/go-containerregistry v0.20.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-20240424215950-a892ee059fd6 // indirect github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
@ -195,7 +194,7 @@ require (
github.com/sigstore/sigstore v1.8.4 // indirect github.com/sigstore/sigstore v1.8.4 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect
github.com/sylabs/sif/v2 v2.16.0 // indirect github.com/sylabs/sif/v2 v2.18.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect
@ -215,10 +214,10 @@ require (
go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/arch v0.7.0 // indirect golang.org/x/arch v0.7.0 // indirect
golang.org/x/mod v0.17.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
google.golang.org/grpc v1.64.1 // indirect google.golang.org/grpc v1.64.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect

93
go.sum
View File

@ -63,8 +63,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/containerd v1.7.17 h1:KjNnn0+tAVQHAoaWRjmdak9WlvnFR/8rU1CHHy8Rm2A= github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao=
github.com/containerd/containerd v1.7.17/go.mod h1:vK+hhT4TIv2uejlcDlbVIc8+h/BqtKLIyNrtCZol8lI= github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4=
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
@ -73,32 +73,32 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw+Rbt1vYk=
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/cni v1.2.2/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ= github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ=
github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM= github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM=
github.com/containers/buildah v1.36.0 h1:e369nE9bx0yJtPVRDMsbr0OzkW59XCYAl+5poGhFjcs= github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382 h1:NUScZGjAC6Cd1KuPcnCac10Q/gz01PULzh7Em/VXZOc=
github.com/containers/buildah v1.36.0/go.mod h1:qlEF4RuCnzEUTQhAnCyGr5WoYNZaU0k2mPcZscUR//c= github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382/go.mod h1:HlwJHYRlP5j8siiPY46I8py00hlGxWPC/vCZZ/01EEU=
github.com/containers/common v0.59.1-0.20240603155017-49ad520556e7 h1:Vp0npRNqZJrtMrOeVPyLNDYojSPbkNm3pQVnuBULubs= github.com/containers/common v0.59.1-0.20240715151621-fdf625dfee0e h1:x6PiZObWn9XD9lcvC6ShqDvvoTsRBktY8ycuwhlWWug=
github.com/containers/common v0.59.1-0.20240603155017-49ad520556e7/go.mod h1:G4vF3V1iWu+NxT/pquuJYBcWGsrVKibDhPu9h52nXyI= github.com/containers/common v0.59.1-0.20240715151621-fdf625dfee0e/go.mod h1:KrQ9y5qa7TBVzp7qs7I1MVi6Uxntu0hM5wjd5bmvMnM=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70 h1:aACcXSIgcuPq5QdNZZ8B53BCdhqYvw33/8QmZWJATvg= github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70 h1:aACcXSIgcuPq5QdNZZ8B53BCdhqYvw33/8QmZWJATvg=
github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70/go.mod h1:v2JP4sZFltFJ8smHLVm12Ng3jHetrNh565ZwWpB5pzs= github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70/go.mod h1:v2JP4sZFltFJ8smHLVm12Ng3jHetrNh565ZwWpB5pzs=
github.com/containers/image/v5 v5.31.1-0.20240603155732-aa935041e316 h1:WMekH3CnJOgVwJmvyg1Ucyt5In7BQx2k0mM+FHixg+I= github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516 h1:BVyB11XLbT7s0tMF1qzdc5R04gO2BRAdjbftRwNoLXM=
github.com/containers/image/v5 v5.31.1-0.20240603155732-aa935041e316/go.mod h1:2oAksrXTiV/ArGnq3RlKHK8+6Wsde5jt4qWHfU7hHxI= github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516/go.mod h1:iAUT9Iy/z0QPrYeILorryErMUxm4GlRzBE0Yz65l/uE=
github.com/containers/libhvee v0.7.1 h1:dWGF5GLq9DZvXo3P8aDp3cNieL5eCaSell4UmeA/jY4= github.com/containers/libhvee v0.7.1 h1:dWGF5GLq9DZvXo3P8aDp3cNieL5eCaSell4UmeA/jY4=
github.com/containers/libhvee v0.7.1/go.mod h1:fRKB3AyIqHMvq6xaeYhTpckM2cdoq0oecolyoiuLP7M= github.com/containers/libhvee v0.7.1/go.mod h1:fRKB3AyIqHMvq6xaeYhTpckM2cdoq0oecolyoiuLP7M=
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/luksy v0.0.0-20240506205542-84b50f50f3ee h1:QU6XNrPcxyGejcEYJfpIH7LwB+yXVbb0tWxf7mZxfN4= github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c h1:gJDiBJYc8JFD46IJmr8SqGOcueGSRGnuhW6wgXiAjr0=
github.com/containers/luksy v0.0.0-20240506205542-84b50f50f3ee/go.mod h1:cEhy3LVQzQqf/BHx0WS6CXmZp+RZZaUKmhQaFZ4NiiU= github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c/go.mod h1:Ufusu7xAtl0LSTry0JS6dSxbxR/XJQSEqlhLqTkCaH8=
github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM=
github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U=
github.com/containers/psgo v1.9.0 h1:eJ74jzSaCHnWt26OlKZROSyUyRcGDf+gYBdXnxrMW4g= github.com/containers/psgo v1.9.0 h1:eJ74jzSaCHnWt26OlKZROSyUyRcGDf+gYBdXnxrMW4g=
github.com/containers/psgo v1.9.0/go.mod h1:0YoluUm43Mz2UnBIh1P+6V6NWcbpTL5uRtXyOcH0B5A= github.com/containers/psgo v1.9.0/go.mod h1:0YoluUm43Mz2UnBIh1P+6V6NWcbpTL5uRtXyOcH0B5A=
github.com/containers/storage v1.54.1-0.20240712121534-ab74785ce9e8 h1:Y1kUvxQhjtHIvjVivFqnis9QOWCMPXeehMVb50si/DE= github.com/containers/storage v1.54.1-0.20240712125645-98ad80d6d165 h1:9WbIxink8kCOoMNh9ju4CMdrrxwnbQMV1YJD8sUXt+k=
github.com/containers/storage v1.54.1-0.20240712121534-ab74785ce9e8/go.mod h1:EyuSB0B1ddqXN0pXGNKPrtxzma80jhRCeVl7/J/JAhE= github.com/containers/storage v1.54.1-0.20240712125645-98ad80d6d165/go.mod h1:EyuSB0B1ddqXN0pXGNKPrtxzma80jhRCeVl7/J/JAhE=
github.com/containers/winquit v1.1.0 h1:jArun04BNDQvt2W0Y78kh9TazN2EIEMG5Im6/JY7+pE= github.com/containers/winquit v1.1.0 h1:jArun04BNDQvt2W0Y78kh9TazN2EIEMG5Im6/JY7+pE=
github.com/containers/winquit v1.1.0/go.mod h1:PsPeZlnbkmGGIToMPHF1zhWjBUkd8aHjMOr/vFcPxw8= github.com/containers/winquit v1.1.0/go.mod h1:PsPeZlnbkmGGIToMPHF1zhWjBUkd8aHjMOr/vFcPxw8=
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
@ -132,8 +132,8 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh
github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8= github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc= github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE= github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
@ -158,8 +158,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
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=
@ -213,7 +211,6 @@ github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-rod/rod v0.116.0 h1:ypRryjTys3EnqHskJ/TdgodFMvXV0EHvmy4bSkKZgHM= github.com/go-rod/rod v0.116.0 h1:ypRryjTys3EnqHskJ/TdgodFMvXV0EHvmy4bSkKZgHM=
github.com/go-rod/rod v0.116.0/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= github.com/go-rod/rod v0.116.0/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
@ -238,10 +235,8 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -255,8 +250,8 @@ github.com/google/go-cmp v0.5.6/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.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= github.com/google/go-containerregistry v0.20.0 h1:wRqHpOeVh3DnenOrPy9xDOLdnLatiGuuNRVelR2gSbg=
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/go-containerregistry v0.20.0/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
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=
@ -264,7 +259,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2 h1:CVuJwN34x4xM2aT4sIKhmeib40NeBPhRihNjQmpJsA4= github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2 h1:CVuJwN34x4xM2aT4sIKhmeib40NeBPhRihNjQmpJsA4=
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4= github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@ -292,14 +286,12 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hugelgupf/p9 v0.3.1-0.20230822151754-54f5c5530921 h1:cfYGdNpXGZobTSSDFB+wx2FRfWptM7sCkScJgVx0Tkk= github.com/hugelgupf/p9 v0.3.1-0.20230822151754-54f5c5530921 h1:cfYGdNpXGZobTSSDFB+wx2FRfWptM7sCkScJgVx0Tkk=
github.com/hugelgupf/p9 v0.3.1-0.20230822151754-54f5c5530921/go.mod h1:nMr69J6AmirlSvzeVLK7gj4DUY1oYtSwcSiSJ7BBb0A= github.com/hugelgupf/p9 v0.3.1-0.20230822151754-54f5c5530921/go.mod h1:nMr69J6AmirlSvzeVLK7gj4DUY1oYtSwcSiSJ7BBb0A=
github.com/hugelgupf/socketpair v0.0.0-20230822150718-707395b1939a h1:Nq7wDsqsVBUBfGn8yB1M028ShWTKTtZBcafaTJ35N0s= github.com/hugelgupf/socketpair v0.0.0-20230822150718-707395b1939a h1:Nq7wDsqsVBUBfGn8yB1M028ShWTKTtZBcafaTJ35N0s=
github.com/hugelgupf/socketpair v0.0.0-20230822150718-707395b1939a/go.mod h1:71Bqb5Fh9zPHF8jwdmMEmJObzr25Mx5pWLbDBMMEn6E= github.com/hugelgupf/socketpair v0.0.0-20230822150718-707395b1939a/go.mod h1:71Bqb5Fh9zPHF8jwdmMEmJObzr25Mx5pWLbDBMMEn6E=
github.com/hugelgupf/vmtest v0.0.0-20230810222836-f8c8e381617c h1:4A+BVHylCBQPxlW1NrUITDpRAHCeX6QSZHmzzFQqliU= github.com/hugelgupf/vmtest v0.0.0-20230810222836-f8c8e381617c h1:4A+BVHylCBQPxlW1NrUITDpRAHCeX6QSZHmzzFQqliU=
github.com/hugelgupf/vmtest v0.0.0-20230810222836-f8c8e381617c/go.mod h1:d2FMzS0rIF+3Daufcw660EZfTJihdNPeEwBBJgO4Ap0= github.com/hugelgupf/vmtest v0.0.0-20230810222836-f8c8e381617c/go.mod h1:d2FMzS0rIF+3Daufcw660EZfTJihdNPeEwBBJgO4Ap0=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs=
@ -387,21 +379,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@ -492,7 +475,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -502,8 +484,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/sylabs/sif/v2 v2.16.0 h1:2eqaBaQQsn5DZTzm3QZm0HupZQEjNXfxRnCmtyCihEU= github.com/sylabs/sif/v2 v2.18.0 h1:eXugsS1qx7St2Wu/AJ21KnsQiVCpouPlTigABh+6KYI=
github.com/sylabs/sif/v2 v2.16.0/go.mod h1:d5TxgD/mhMUU3kWLmZmWJQ99Wg0asaTP0bq3ezR1xpg= github.com/sylabs/sif/v2 v2.18.0/go.mod h1:GOQj7LIBqp15fjqH5i8ZEbLp8SXJi9S+xbRO+QQAdRo=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
@ -595,8 +577,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
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-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
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=
@ -605,22 +587,19 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@ -628,8 +607,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
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/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -641,25 +620,17 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.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=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -689,7 +660,6 @@ golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
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=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/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.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=
@ -706,13 +676,12 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
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.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
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=
@ -744,24 +713,18 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,92 +0,0 @@
/*
Copyright The containerd 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 errdefs defines the common errors used throughout containerd
// packages.
//
// Use with fmt.Errorf to add context to an error.
//
// To detect an error class, use the IsXXX functions to tell whether an error
// is of a certain type.
//
// The functions ToGRPC and FromGRPC can be used to map server-side and
// client-side errors to the correct types.
package errdefs
import (
"context"
"errors"
)
// Definitions of common error types used throughout containerd. All containerd
// errors returned by most packages will map into one of these errors classes.
// Packages should return errors of these types when they want to instruct a
// client to take a particular action.
//
// For the most part, we just try to provide local grpc errors. Most conditions
// map very well to those defined by grpc.
var (
ErrUnknown = errors.New("unknown") // used internally to represent a missed mapping.
ErrInvalidArgument = errors.New("invalid argument")
ErrNotFound = errors.New("not found")
ErrAlreadyExists = errors.New("already exists")
ErrFailedPrecondition = errors.New("failed precondition")
ErrUnavailable = errors.New("unavailable")
ErrNotImplemented = errors.New("not implemented") // represents not supported and unimplemented
)
// IsInvalidArgument returns true if the error is due to an invalid argument
func IsInvalidArgument(err error) bool {
return errors.Is(err, ErrInvalidArgument)
}
// IsNotFound returns true if the error is due to a missing object
func IsNotFound(err error) bool {
return errors.Is(err, ErrNotFound)
}
// IsAlreadyExists returns true if the error is due to an already existing
// metadata item
func IsAlreadyExists(err error) bool {
return errors.Is(err, ErrAlreadyExists)
}
// IsFailedPrecondition returns true if an operation could not proceed to the
// lack of a particular condition
func IsFailedPrecondition(err error) bool {
return errors.Is(err, ErrFailedPrecondition)
}
// IsUnavailable returns true if the error is due to a resource being unavailable
func IsUnavailable(err error) bool {
return errors.Is(err, ErrUnavailable)
}
// IsNotImplemented returns true if the error is due to not being implemented
func IsNotImplemented(err error) bool {
return errors.Is(err, ErrNotImplemented)
}
// IsCanceled returns true if the error is due to `context.Canceled`.
func IsCanceled(err error) bool {
return errors.Is(err, context.Canceled)
}
// IsDeadlineExceeded returns true if the error is due to
// `context.DeadlineExceeded`.
func IsDeadlineExceeded(err error) bool {
return errors.Is(err, context.DeadlineExceeded)
}

View File

@ -1,147 +0,0 @@
/*
Copyright The containerd 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 errdefs
import (
"context"
"fmt"
"strings"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// ToGRPC will attempt to map the backend containerd error into a grpc error,
// using the original error message as a description.
//
// Further information may be extracted from certain errors depending on their
// type.
//
// If the error is unmapped, the original error will be returned to be handled
// by the regular grpc error handling stack.
func ToGRPC(err error) error {
if err == nil {
return nil
}
if isGRPCError(err) {
// error has already been mapped to grpc
return err
}
switch {
case IsInvalidArgument(err):
return status.Errorf(codes.InvalidArgument, err.Error())
case IsNotFound(err):
return status.Errorf(codes.NotFound, err.Error())
case IsAlreadyExists(err):
return status.Errorf(codes.AlreadyExists, err.Error())
case IsFailedPrecondition(err):
return status.Errorf(codes.FailedPrecondition, err.Error())
case IsUnavailable(err):
return status.Errorf(codes.Unavailable, err.Error())
case IsNotImplemented(err):
return status.Errorf(codes.Unimplemented, err.Error())
case IsCanceled(err):
return status.Errorf(codes.Canceled, err.Error())
case IsDeadlineExceeded(err):
return status.Errorf(codes.DeadlineExceeded, err.Error())
}
return err
}
// ToGRPCf maps the error to grpc error codes, assembling the formatting string
// and combining it with the target error string.
//
// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
func ToGRPCf(err error, format string, args ...interface{}) error {
return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
}
// FromGRPC returns the underlying error from a grpc service based on the grpc error code
func FromGRPC(err error) error {
if err == nil {
return nil
}
var cls error // divide these into error classes, becomes the cause
switch code(err) {
case codes.InvalidArgument:
cls = ErrInvalidArgument
case codes.AlreadyExists:
cls = ErrAlreadyExists
case codes.NotFound:
cls = ErrNotFound
case codes.Unavailable:
cls = ErrUnavailable
case codes.FailedPrecondition:
cls = ErrFailedPrecondition
case codes.Unimplemented:
cls = ErrNotImplemented
case codes.Canceled:
cls = context.Canceled
case codes.DeadlineExceeded:
cls = context.DeadlineExceeded
default:
cls = ErrUnknown
}
msg := rebaseMessage(cls, err)
if msg != "" {
err = fmt.Errorf("%s: %w", msg, cls)
} else {
err = cls
}
return err
}
// rebaseMessage removes the repeats for an error at the end of an error
// string. This will happen when taking an error over grpc then remapping it.
//
// Effectively, we just remove the string of cls from the end of err if it
// appears there.
func rebaseMessage(cls error, err error) string {
desc := errDesc(err)
clss := cls.Error()
if desc == clss {
return ""
}
return strings.TrimSuffix(desc, ": "+clss)
}
func isGRPCError(err error) bool {
_, ok := status.FromError(err)
return ok
}
func code(err error) codes.Code {
if s, ok := status.FromError(err); ok {
return s.Code()
}
return codes.Unknown
}
func errDesc(err error) string {
if s, ok := status.FromError(err); ok {
return s.Message()
}
return err.Error()
}

View File

@ -1,149 +0,0 @@
/*
Copyright The containerd 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 log
import (
"context"
"github.com/containerd/log"
)
// G is a shorthand for [GetLogger].
//
// Deprecated: use [log.G].
var G = log.G
// L is an alias for the standard logger.
//
// Deprecated: use [log.L].
var L = log.L
// Fields type to pass to "WithFields".
//
// Deprecated: use [log.Fields].
type Fields = log.Fields
// Entry is a logging entry.
//
// Deprecated: use [log.Entry].
type Entry = log.Entry
// RFC3339NanoFixed is [time.RFC3339Nano] with nanoseconds padded using
// zeros to ensure the formatted time is always the same number of
// characters.
//
// Deprecated: use [log.RFC3339NanoFixed].
const RFC3339NanoFixed = log.RFC3339NanoFixed
// Level is a logging level.
//
// Deprecated: use [log.Level].
type Level = log.Level
// Supported log levels.
const (
// TraceLevel level.
//
// Deprecated: use [log.TraceLevel].
TraceLevel Level = log.TraceLevel
// DebugLevel level.
//
// Deprecated: use [log.DebugLevel].
DebugLevel Level = log.DebugLevel
// InfoLevel level.
//
// Deprecated: use [log.InfoLevel].
InfoLevel Level = log.InfoLevel
// WarnLevel level.
//
// Deprecated: use [log.WarnLevel].
WarnLevel Level = log.WarnLevel
// ErrorLevel level
//
// Deprecated: use [log.ErrorLevel].
ErrorLevel Level = log.ErrorLevel
// FatalLevel level.
//
// Deprecated: use [log.FatalLevel].
FatalLevel Level = log.FatalLevel
// PanicLevel level.
//
// Deprecated: use [log.PanicLevel].
PanicLevel Level = log.PanicLevel
)
// SetLevel sets log level globally. It returns an error if the given
// level is not supported.
//
// Deprecated: use [log.SetLevel].
func SetLevel(level string) error {
return log.SetLevel(level)
}
// GetLevel returns the current log level.
//
// Deprecated: use [log.GetLevel].
func GetLevel() log.Level {
return log.GetLevel()
}
// OutputFormat specifies a log output format.
//
// Deprecated: use [log.OutputFormat].
type OutputFormat = log.OutputFormat
// Supported log output formats.
const (
// TextFormat represents the text logging format.
//
// Deprecated: use [log.TextFormat].
TextFormat log.OutputFormat = "text"
// JSONFormat represents the JSON logging format.
//
// Deprecated: use [log.JSONFormat].
JSONFormat log.OutputFormat = "json"
)
// SetFormat sets the log output format.
//
// Deprecated: use [log.SetFormat].
func SetFormat(format OutputFormat) error {
return log.SetFormat(format)
}
// WithLogger returns a new context with the provided logger. Use in
// combination with logger.WithField(s) for great effect.
//
// Deprecated: use [log.WithLogger].
func WithLogger(ctx context.Context, logger *log.Entry) context.Context {
return log.WithLogger(ctx, logger)
}
// GetLogger retrieves the current logger from the context. If no logger is
// available, the default logger is returned.
//
// Deprecated: use [log.GetLogger].
func GetLogger(ctx context.Context) *log.Entry {
return log.GetLogger(ctx)
}

View File

@ -20,7 +20,7 @@ import (
"runtime" "runtime"
"sync" "sync"
"github.com/containerd/containerd/log" "github.com/containerd/log"
) )
// Present the ARM instruction set architecture, eg: v7, v8 // Present the ARM instruction set architecture, eg: v7, v8

View File

@ -24,7 +24,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/containerd/containerd/errdefs" "github.com/containerd/errdefs"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@ -22,7 +22,7 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"github.com/containerd/containerd/errdefs" "github.com/containerd/errdefs"
) )
func getCPUVariant() (string, error) { func getCPUVariant() (string, error) {

View File

@ -116,7 +116,7 @@ import (
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/containerd/containerd/errdefs" "github.com/containerd/errdefs"
) )
var ( var (

View File

@ -15,7 +15,7 @@
package libcni package libcni
// Note this is the actual implementation of the CNI specification, which // Note this is the actual implementation of the CNI specification, which
// is reflected in the https://github.com/containernetworking/cni/blob/master/SPEC.md file // is reflected in the SPEC.md file.
// it is typically bundled into runtime providers (i.e. containerd or cri-o would use this // it is typically bundled into runtime providers (i.e. containerd or cri-o would use this
// before calling runc or hcsshim). It is also bundled into CNI providers as well, for example, // before calling runc or hcsshim). It is also bundled into CNI providers as well, for example,
// to add an IP to a container, to parse the configuration of the CNI and so on. // to add an IP to a container, to parse the configuration of the CNI and so on.
@ -23,10 +23,11 @@ package libcni
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"github.com/containernetworking/cni/pkg/invoke" "github.com/containernetworking/cni/pkg/invoke"
@ -38,6 +39,8 @@ import (
var ( var (
CacheDir = "/var/lib/cni" CacheDir = "/var/lib/cni"
// slightly awkward wording to preserve anyone matching on error strings
ErrorCheckNotSupp = fmt.Errorf("does not support the CHECK command")
) )
const ( const (
@ -73,10 +76,25 @@ type NetworkConfigList struct {
Name string Name string
CNIVersion string CNIVersion string
DisableCheck bool DisableCheck bool
DisableGC bool
Plugins []*NetworkConfig Plugins []*NetworkConfig
Bytes []byte Bytes []byte
} }
type NetworkAttachment struct {
ContainerID string
Network string
IfName string
Config []byte
NetNS string
CniArgs [][2]string
CapabilityArgs map[string]interface{}
}
type GCArgs struct {
ValidAttachments []types.GCAttachment
}
type CNI interface { type CNI interface {
AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
@ -92,6 +110,13 @@ type CNI interface {
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error) ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
GCNetworkList(ctx context.Context, net *NetworkConfigList, args *GCArgs) error
GetStatusNetworkList(ctx context.Context, net *NetworkConfigList) error
GetCachedAttachments(containerID string) ([]*NetworkAttachment, error)
GetVersionInfo(ctx context.Context, pluginType string) (version.PluginInfo, error)
} }
type CNIConfig struct { type CNIConfig struct {
@ -139,8 +164,11 @@ func buildOneConfig(name, cniVersion string, orig *NetworkConfig, prevResult typ
if err != nil { if err != nil {
return nil, err return nil, err
} }
if rt != nil {
return injectRuntimeConfig(orig, rt)
}
return injectRuntimeConfig(orig, rt) return orig, nil
} }
// This function takes a libcni RuntimeConf structure and injects values into // This function takes a libcni RuntimeConf structure and injects values into
@ -195,6 +223,7 @@ type cachedInfo struct {
Config []byte `json:"config"` Config []byte `json:"config"`
IfName string `json:"ifName"` IfName string `json:"ifName"`
NetworkName string `json:"networkName"` NetworkName string `json:"networkName"`
NetNS string `json:"netns,omitempty"`
CniArgs [][2]string `json:"cniArgs,omitempty"` CniArgs [][2]string `json:"cniArgs,omitempty"`
CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"` CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"`
RawResult map[string]interface{} `json:"result,omitempty"` RawResult map[string]interface{} `json:"result,omitempty"`
@ -229,6 +258,7 @@ func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string,
Config: config, Config: config,
IfName: rt.IfName, IfName: rt.IfName,
NetworkName: netName, NetworkName: netName,
NetNS: rt.NetNS,
CniArgs: rt.Args, CniArgs: rt.Args,
CapabilityArgs: rt.CapabilityArgs, CapabilityArgs: rt.CapabilityArgs,
} }
@ -254,11 +284,11 @@ func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string,
if err != nil { if err != nil {
return err return err
} }
if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil { if err := os.MkdirAll(filepath.Dir(fname), 0o700); err != nil {
return err return err
} }
return ioutil.WriteFile(fname, newBytes, 0600) return os.WriteFile(fname, newBytes, 0o600)
} }
func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error { func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error {
@ -277,7 +307,7 @@ func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *R
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
bytes, err = ioutil.ReadFile(fname) bytes, err = os.ReadFile(fname)
if err != nil { if err != nil {
// Ignore read errors; the cached result may not exist on-disk // Ignore read errors; the cached result may not exist on-disk
return nil, nil, nil return nil, nil, nil
@ -305,7 +335,7 @@ func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *Runtim
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err := ioutil.ReadFile(fname) data, err := os.ReadFile(fname)
if err != nil { if err != nil {
// Ignore read errors; the cached result may not exist on-disk // Ignore read errors; the cached result may not exist on-disk
return nil, nil return nil, nil
@ -333,7 +363,7 @@ func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fdata, err := ioutil.ReadFile(fname) fdata, err := os.ReadFile(fname)
if err != nil { if err != nil {
// Ignore read errors; the cached result may not exist on-disk // Ignore read errors; the cached result may not exist on-disk
return nil, nil return nil, nil
@ -390,6 +420,68 @@ func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf)
return c.getCachedConfig(net.Network.Name, rt) return c.getCachedConfig(net.Network.Name, rt)
} }
// GetCachedAttachments returns a list of network attachments from the cache.
// The returned list will be filtered by the containerID if the value is not empty.
func (c *CNIConfig) GetCachedAttachments(containerID string) ([]*NetworkAttachment, error) {
dirPath := filepath.Join(c.getCacheDir(&RuntimeConf{}), "results")
entries, err := os.ReadDir(dirPath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
fileNames := make([]string, 0, len(entries))
for _, e := range entries {
fileNames = append(fileNames, e.Name())
}
sort.Strings(fileNames)
attachments := []*NetworkAttachment{}
for _, fname := range fileNames {
if len(containerID) > 0 {
part := fmt.Sprintf("-%s-", containerID)
pos := strings.Index(fname, part)
if pos <= 0 || pos+len(part) >= len(fname) {
continue
}
}
cacheFile := filepath.Join(dirPath, fname)
bytes, err := os.ReadFile(cacheFile)
if err != nil {
continue
}
cachedInfo := cachedInfo{}
if err := json.Unmarshal(bytes, &cachedInfo); err != nil {
continue
}
if cachedInfo.Kind != CNICacheV1 {
continue
}
if len(containerID) > 0 && cachedInfo.ContainerID != containerID {
continue
}
if cachedInfo.IfName == "" || cachedInfo.NetworkName == "" {
continue
}
attachments = append(attachments, &NetworkAttachment{
ContainerID: cachedInfo.ContainerID,
Network: cachedInfo.NetworkName,
IfName: cachedInfo.IfName,
Config: cachedInfo.Config,
NetNS: cachedInfo.NetNS,
CniArgs: cachedInfo.CniArgs,
CapabilityArgs: cachedInfo.CapabilityArgs,
})
}
return attachments, nil
}
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) { func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
c.ensureExec() c.ensureExec()
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
@ -453,7 +545,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis
if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
return err return err
} else if !gtet { } else if !gtet {
return fmt.Errorf("configuration version %q does not support the CHECK command", list.CNIVersion) return fmt.Errorf("configuration version %q %w", list.CNIVersion, ErrorCheckNotSupp)
} }
if list.DisableCheck { if list.DisableCheck {
@ -497,9 +589,9 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
return err return err
} else if gtet { } else if gtet {
cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt) if cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt); err != nil {
if err != nil { _ = c.cacheDel(list.Name, rt)
return fmt.Errorf("failed to get network %q cached result: %w", list.Name, err) cachedResult = nil
} }
} }
@ -509,6 +601,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
return fmt.Errorf("plugin %s failed (delete): %w", pluginDescription(net.Network), err) return fmt.Errorf("plugin %s failed (delete): %w", pluginDescription(net.Network), err)
} }
} }
_ = c.cacheDel(list.Name, rt) _ = c.cacheDel(list.Name, rt)
return nil return nil
@ -547,7 +640,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru
if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil { if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
return err return err
} else if !gtet { } else if !gtet {
return fmt.Errorf("configuration version %q does not support the CHECK command", net.Network.CNIVersion) return fmt.Errorf("configuration version %q %w", net.Network.CNIVersion, ErrorCheckNotSupp)
} }
cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
@ -666,6 +759,127 @@ func (c *CNIConfig) GetVersionInfo(ctx context.Context, pluginType string) (vers
return invoke.GetVersionInfo(ctx, pluginPath, c.exec) return invoke.GetVersionInfo(ctx, pluginPath, c.exec)
} }
// GCNetworkList will do two things
// - dump the list of cached attachments, and issue deletes as necessary
// - issue a GC to the underlying plugins (if the version is high enough)
func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList, args *GCArgs) error {
// If DisableGC is set, then don't bother GCing at all.
if list.DisableGC {
return nil
}
// First, get the list of cached attachments
cachedAttachments, err := c.GetCachedAttachments("")
if err != nil {
return nil
}
var validAttachments map[types.GCAttachment]interface{}
if args != nil {
validAttachments = make(map[types.GCAttachment]interface{}, len(args.ValidAttachments))
for _, a := range args.ValidAttachments {
validAttachments[a] = nil
}
}
var errs []error
for _, cachedAttachment := range cachedAttachments {
if cachedAttachment.Network != list.Name {
continue
}
// we found this attachment
gca := types.GCAttachment{
ContainerID: cachedAttachment.ContainerID,
IfName: cachedAttachment.IfName,
}
if _, ok := validAttachments[gca]; ok {
continue
}
// otherwise, this attachment wasn't valid and we should issue a CNI DEL
rt := RuntimeConf{
ContainerID: cachedAttachment.ContainerID,
NetNS: cachedAttachment.NetNS,
IfName: cachedAttachment.IfName,
Args: cachedAttachment.CniArgs,
CapabilityArgs: cachedAttachment.CapabilityArgs,
}
if err := c.DelNetworkList(ctx, list, &rt); err != nil {
errs = append(errs, fmt.Errorf("failed to delete stale attachment %s %s: %w", rt.ContainerID, rt.IfName, err))
}
}
// now, if the version supports it, issue a GC
if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); gt {
inject := map[string]interface{}{
"name": list.Name,
"cniVersion": list.CNIVersion,
}
if args != nil {
inject["cni.dev/valid-attachments"] = args.ValidAttachments
}
for _, plugin := range list.Plugins {
// build config here
pluginConfig, err := InjectConf(plugin, inject)
if err != nil {
errs = append(errs, fmt.Errorf("failed to generate configuration to GC plugin %s: %w", plugin.Network.Type, err))
}
if err := c.gcNetwork(ctx, pluginConfig); err != nil {
errs = append(errs, fmt.Errorf("failed to GC plugin %s: %w", plugin.Network.Type, err))
}
}
}
return errors.Join(errs...)
}
func (c *CNIConfig) gcNetwork(ctx context.Context, net *NetworkConfig) error {
c.ensureExec()
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
if err != nil {
return err
}
args := c.args("GC", &RuntimeConf{})
return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec)
}
func (c *CNIConfig) GetStatusNetworkList(ctx context.Context, list *NetworkConfigList) error {
// If the version doesn't support status, abort.
if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); !gt {
return nil
}
inject := map[string]interface{}{
"name": list.Name,
"cniVersion": list.CNIVersion,
}
for _, plugin := range list.Plugins {
// build config here
pluginConfig, err := InjectConf(plugin, inject)
if err != nil {
return fmt.Errorf("failed to generate configuration to get plugin STATUS %s: %w", plugin.Network.Type, err)
}
if err := c.getStatusNetwork(ctx, pluginConfig); err != nil {
return err // Don't collect errors here, so we return a clean error code.
}
}
return nil
}
func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *NetworkConfig) error {
c.ensureExec()
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
if err != nil {
return err
}
args := c.args("STATUS", &RuntimeConf{})
return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec)
}
// ===== // =====
func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args { func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args {
return &invoke.Args{ return &invoke.Args{

View File

@ -16,13 +16,16 @@ package libcni
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"slices"
"sort" "sort"
"strings"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/version"
) )
type NotFoundError struct { type NotFoundError struct {
@ -54,7 +57,7 @@ func ConfFromBytes(bytes []byte) (*NetworkConfig, error) {
} }
func ConfFromFile(filename string) (*NetworkConfig, error) { func ConfFromFile(filename string) (*NetworkConfig, error) {
bytes, err := ioutil.ReadFile(filename) bytes, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading %s: %w", filename, err) return nil, fmt.Errorf("error reading %s: %w", filename, err)
} }
@ -85,17 +88,89 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
} }
} }
disableCheck := false rawVersions, ok := rawList["cniVersions"]
if rawDisableCheck, ok := rawList["disableCheck"]; ok { if ok {
disableCheck, ok = rawDisableCheck.(bool) // Parse the current package CNI version
rvs, ok := rawVersions.([]interface{})
if !ok { if !ok {
return nil, fmt.Errorf("error parsing configuration list: invalid disableCheck type %T", rawDisableCheck) return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions: %T", rvs)
} }
vs := make([]string, 0, len(rvs))
for i, rv := range rvs {
v, ok := rv.(string)
if !ok {
return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions index %d: %T", i, rv)
}
gt, err := version.GreaterThan(v, version.Current())
if err != nil {
return nil, fmt.Errorf("error parsing configuration list: invalid cniVersions entry %s at index %d: %w", v, i, err)
} else if !gt {
// Skip versions "greater" than this implementation of the spec
vs = append(vs, v)
}
}
// if cniVersion was already set, append it to the list for sorting.
if cniVersion != "" {
gt, err := version.GreaterThan(cniVersion, version.Current())
if err != nil {
return nil, fmt.Errorf("error parsing configuration list: invalid cniVersion %s: %w", cniVersion, err)
} else if !gt {
// ignore any versions higher than the current implemented spec version
vs = append(vs, cniVersion)
}
}
slices.SortFunc[[]string](vs, func(v1, v2 string) int {
if v1 == v2 {
return 0
}
if gt, _ := version.GreaterThan(v1, v2); gt {
return 1
}
return -1
})
if len(vs) > 0 {
cniVersion = vs[len(vs)-1]
}
}
readBool := func(key string) (bool, error) {
rawVal, ok := rawList[key]
if !ok {
return false, nil
}
if b, ok := rawVal.(bool); ok {
return b, nil
}
s, ok := rawVal.(string)
if !ok {
return false, fmt.Errorf("error parsing configuration list: invalid type %T for %s", rawVal, key)
}
s = strings.ToLower(s)
switch s {
case "false":
return false, nil
case "true":
return true, nil
}
return false, fmt.Errorf("error parsing configuration list: invalid value %q for %s", s, key)
}
disableCheck, err := readBool("disableCheck")
if err != nil {
return nil, err
}
disableGC, err := readBool("disableGC")
if err != nil {
return nil, err
} }
list := &NetworkConfigList{ list := &NetworkConfigList{
Name: name, Name: name,
DisableCheck: disableCheck, DisableCheck: disableCheck,
DisableGC: disableGC,
CNIVersion: cniVersion, CNIVersion: cniVersion,
Bytes: bytes, Bytes: bytes,
} }
@ -129,7 +204,7 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
} }
func ConfListFromFile(filename string) (*NetworkConfigList, error) { func ConfListFromFile(filename string) (*NetworkConfigList, error) {
bytes, err := ioutil.ReadFile(filename) bytes, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, fmt.Errorf("error reading %s: %w", filename, err) return nil, fmt.Errorf("error reading %s: %w", filename, err)
} }
@ -138,7 +213,7 @@ func ConfListFromFile(filename string) (*NetworkConfigList, error) {
func ConfFiles(dir string, extensions []string) ([]string, error) { func ConfFiles(dir string, extensions []string) ([]string, error) {
// In part, adapted from rkt/networking/podenv.go#listFiles // In part, adapted from rkt/networking/podenv.go#listFiles
files, err := ioutil.ReadDir(dir) files, err := os.ReadDir(dir)
switch { switch {
case err == nil: // break case err == nil: // break
case os.IsNotExist(err): case os.IsNotExist(err):
@ -206,7 +281,8 @@ func LoadConfList(dir, name string) (*NetworkConfigList, error) {
singleConf, err := LoadConf(dir, name) singleConf, err := LoadConf(dir, name)
if err != nil { if err != nil {
// A little extra logic so the error makes sense // A little extra logic so the error makes sense
if _, ok := err.(NoConfigsFoundError); len(files) != 0 && ok { var ncfErr NoConfigsFoundError
if len(files) != 0 && errors.As(err, &ncfErr) {
// Config lists found but no config files found // Config lists found but no config files found
return nil, NotFoundError{dir, name} return nil, NotFoundError{dir, name}
} }

View File

@ -51,25 +51,34 @@ func DelegateAdd(ctx context.Context, delegatePlugin string, netconf []byte, exe
// DelegateCheck calls the given delegate plugin with the CNI CHECK action and // DelegateCheck calls the given delegate plugin with the CNI CHECK action and
// JSON configuration // JSON configuration
func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
return delegateNoResult(ctx, delegatePlugin, netconf, exec, "CHECK")
}
func delegateNoResult(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec, verb string) error {
pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) pluginPath, realExec, err := delegateCommon(delegatePlugin, exec)
if err != nil { if err != nil {
return err return err
} }
// DelegateCheck will override the original CNI_COMMAND env from process with CHECK return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs(verb), realExec)
return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("CHECK"), realExec)
} }
// DelegateDel calls the given delegate plugin with the CNI DEL action and // DelegateDel calls the given delegate plugin with the CNI DEL action and
// JSON configuration // JSON configuration
func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) return delegateNoResult(ctx, delegatePlugin, netconf, exec, "DEL")
if err != nil { }
return err
}
// DelegateDel will override the original CNI_COMMAND env from process with DEL // DelegateStatus calls the given delegate plugin with the CNI STATUS action and
return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("DEL"), realExec) // JSON configuration
func DelegateStatus(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
return delegateNoResult(ctx, delegatePlugin, netconf, exec, "STATUS")
}
// DelegateGC calls the given delegate plugin with the CNI GC action and
// JSON configuration
func DelegateGC(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error {
return delegateNoResult(ctx, delegatePlugin, netconf, exec, "GC")
} }
// return CNIArgs used by delegation // return CNIArgs used by delegation

View File

@ -81,17 +81,17 @@ func fixupResultVersion(netconf, result []byte) (string, []byte, error) {
// object to ExecPluginWithResult() to verify the incoming stdin and environment // object to ExecPluginWithResult() to verify the incoming stdin and environment
// and provide a tailored response: // and provide a tailored response:
// //
//import ( // import (
// "encoding/json" // "encoding/json"
// "path" // "path"
// "strings" // "strings"
//) // )
// //
//type fakeExec struct { // type fakeExec struct {
// version.PluginDecoder // version.PluginDecoder
//} // }
// //
//func (f *fakeExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) { // func (f *fakeExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
// net := &types.NetConf{} // net := &types.NetConf{}
// err := json.Unmarshal(stdinData, net) // err := json.Unmarshal(stdinData, net)
// if err != nil { // if err != nil {
@ -109,14 +109,14 @@ func fixupResultVersion(netconf, result []byte) (string, []byte, error) {
// } // }
// } // }
// return []byte("{\"CNIVersion\":\"0.4.0\"}"), nil // return []byte("{\"CNIVersion\":\"0.4.0\"}"), nil
//} // }
// //
//func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) { // func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) {
// if len(paths) > 0 { // if len(paths) > 0 {
// return path.Join(paths[0], plugin), nil // return path.Join(paths[0], plugin), nil
// } // }
// return "", fmt.Errorf("failed to find plugin %s in paths %v", plugin, paths) // return "", fmt.Errorf("failed to find plugin %s in paths %v", plugin, paths)
//} // }
func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) { func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) {
if exec == nil { if exec == nil {

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris
package invoke package invoke

View File

@ -26,9 +26,10 @@ import (
convert "github.com/containernetworking/cni/pkg/types/internal" convert "github.com/containernetworking/cni/pkg/types/internal"
) )
const ImplementedSpecVersion string = "1.0.0" // The types did not change between v1.0 and v1.1
const ImplementedSpecVersion string = "1.1.0"
var supportedVersions = []string{ImplementedSpecVersion} var supportedVersions = []string{"1.0.0", "1.1.0"}
// Register converters for all versions less than the implemented spec version // Register converters for all versions less than the implemented spec version
func init() { func init() {
@ -38,10 +39,14 @@ func init() {
convert.RegisterConverter("0.3.0", supportedVersions, convertFrom04x) convert.RegisterConverter("0.3.0", supportedVersions, convertFrom04x)
convert.RegisterConverter("0.3.1", supportedVersions, convertFrom04x) convert.RegisterConverter("0.3.1", supportedVersions, convertFrom04x)
convert.RegisterConverter("0.4.0", supportedVersions, convertFrom04x) convert.RegisterConverter("0.4.0", supportedVersions, convertFrom04x)
convert.RegisterConverter("1.0.0", []string{"1.1.0"}, convertFrom100)
// Down-converters // Down-converters
convert.RegisterConverter("1.0.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x) convert.RegisterConverter("1.0.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x)
convert.RegisterConverter("1.0.0", []string{"0.1.0", "0.2.0"}, convertTo02x) convert.RegisterConverter("1.0.0", []string{"0.1.0", "0.2.0"}, convertTo02x)
convert.RegisterConverter("1.1.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x)
convert.RegisterConverter("1.1.0", []string{"0.1.0", "0.2.0"}, convertTo02x)
convert.RegisterConverter("1.1.0", []string{"1.0.0"}, convertFrom100)
// Creator // Creator
convert.RegisterCreator(supportedVersions, NewResult) convert.RegisterCreator(supportedVersions, NewResult)
@ -90,12 +95,49 @@ type Result struct {
DNS types.DNS `json:"dns,omitempty"` DNS types.DNS `json:"dns,omitempty"`
} }
// Note: DNS should be omit if DNS is empty but default Marshal function
// will output empty structure hence need to write a Marshal function
func (r *Result) MarshalJSON() ([]byte, error) {
// use type alias to escape recursion for json.Marshal() to MarshalJSON()
type fixObjType = Result
bytes, err := json.Marshal(fixObjType(*r)) //nolint:all
if err != nil {
return nil, err
}
fixupObj := make(map[string]interface{})
if err := json.Unmarshal(bytes, &fixupObj); err != nil {
return nil, err
}
if r.DNS.IsEmpty() {
delete(fixupObj, "dns")
}
return json.Marshal(fixupObj)
}
// convertFrom100 does nothing except set the version; the types are the same
func convertFrom100(from types.Result, toVersion string) (types.Result, error) {
fromResult := from.(*Result)
result := &Result{
CNIVersion: toVersion,
Interfaces: fromResult.Interfaces,
IPs: fromResult.IPs,
Routes: fromResult.Routes,
DNS: fromResult.DNS,
}
return result, nil
}
func convertFrom02x(from types.Result, toVersion string) (types.Result, error) { func convertFrom02x(from types.Result, toVersion string) (types.Result, error) {
result040, err := convert.Convert(from, "0.4.0") result040, err := convert.Convert(from, "0.4.0")
if err != nil { if err != nil {
return nil, err return nil, err
} }
result100, err := convertFrom04x(result040, ImplementedSpecVersion) result100, err := convertFrom04x(result040, toVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -226,9 +268,12 @@ func (r *Result) PrintTo(writer io.Writer) error {
// Interface contains values about the created interfaces // Interface contains values about the created interfaces
type Interface struct { type Interface struct {
Name string `json:"name"` Name string `json:"name"`
Mac string `json:"mac,omitempty"` Mac string `json:"mac,omitempty"`
Sandbox string `json:"sandbox,omitempty"` Mtu int `json:"mtu,omitempty"`
Sandbox string `json:"sandbox,omitempty"`
SocketPath string `json:"socketPath,omitempty"`
PciID string `json:"pciID,omitempty"`
} }
func (i *Interface) String() string { func (i *Interface) String() string {

View File

@ -26,8 +26,8 @@ import (
type UnmarshallableBool bool type UnmarshallableBool bool
// UnmarshalText implements the encoding.TextUnmarshaler interface. // UnmarshalText implements the encoding.TextUnmarshaler interface.
// Returns boolean true if the string is "1" or "[Tt]rue" // Returns boolean true if the string is "1" or "true" or "True"
// Returns boolean false if the string is "0" or "[Ff]alse" // Returns boolean false if the string is "0" or "false" or "False”
func (b *UnmarshallableBool) UnmarshalText(data []byte) error { func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
s := strings.ToLower(string(data)) s := strings.ToLower(string(data))
switch s { switch s {

View File

@ -19,6 +19,9 @@ import (
"fmt" "fmt"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
_ "github.com/containernetworking/cni/pkg/types/020"
_ "github.com/containernetworking/cni/pkg/types/040"
_ "github.com/containernetworking/cni/pkg/types/100"
convert "github.com/containernetworking/cni/pkg/types/internal" convert "github.com/containernetworking/cni/pkg/types/internal"
) )

View File

@ -56,30 +56,73 @@ func (n *IPNet) UnmarshalJSON(data []byte) error {
return nil return nil
} }
// NetConf describes a network. // NetConfType describes a network.
type NetConf struct { type NetConfType struct {
CNIVersion string `json:"cniVersion,omitempty"` CNIVersion string `json:"cniVersion,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Capabilities map[string]bool `json:"capabilities,omitempty"` Capabilities map[string]bool `json:"capabilities,omitempty"`
IPAM IPAM `json:"ipam,omitempty"` IPAM IPAM `json:"ipam,omitempty"`
DNS DNS `json:"dns"` DNS DNS `json:"dns,omitempty"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult Result `json:"-"` PrevResult Result `json:"-"`
// ValidAttachments is only supplied when executing a GC operation
ValidAttachments []GCAttachment `json:"cni.dev/valid-attachments,omitempty"`
}
// NetConf is defined as different type as custom MarshalJSON() and issue #1096
type NetConf NetConfType
// GCAttachment is the parameters to a GC call -- namely,
// the container ID and ifname pair that represents a
// still-valid attachment.
type GCAttachment struct {
ContainerID string `json:"containerID"`
IfName string `json:"ifname"`
}
// Note: DNS should be omit if DNS is empty but default Marshal function
// will output empty structure hence need to write a Marshal function
func (n *NetConfType) MarshalJSON() ([]byte, error) {
// use type alias to escape recursion for json.Marshal() to MarshalJSON()
type fixObjType = NetConf
bytes, err := json.Marshal(fixObjType(*n))
if err != nil {
return nil, err
}
fixupObj := make(map[string]interface{})
if err := json.Unmarshal(bytes, &fixupObj); err != nil {
return nil, err
}
if n.DNS.IsEmpty() {
delete(fixupObj, "dns")
}
return json.Marshal(fixupObj)
} }
type IPAM struct { type IPAM struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
} }
// IsEmpty returns true if IPAM structure has no value, otherwise return false
func (i *IPAM) IsEmpty() bool {
return i.Type == ""
}
// NetConfList describes an ordered list of networks. // NetConfList describes an ordered list of networks.
type NetConfList struct { type NetConfList struct {
CNIVersion string `json:"cniVersion,omitempty"` CNIVersion string `json:"cniVersion,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
DisableCheck bool `json:"disableCheck,omitempty"` DisableCheck bool `json:"disableCheck,omitempty"`
DisableGC bool `json:"disableGC,omitempty"`
Plugins []*NetConf `json:"plugins,omitempty"` Plugins []*NetConf `json:"plugins,omitempty"`
} }
@ -116,31 +159,48 @@ type DNS struct {
Options []string `json:"options,omitempty"` Options []string `json:"options,omitempty"`
} }
// IsEmpty returns true if DNS structure has no value, otherwise return false
func (d *DNS) IsEmpty() bool {
if len(d.Nameservers) == 0 && d.Domain == "" && len(d.Search) == 0 && len(d.Options) == 0 {
return true
}
return false
}
func (d *DNS) Copy() *DNS { func (d *DNS) Copy() *DNS {
if d == nil { if d == nil {
return nil return nil
} }
to := &DNS{Domain: d.Domain} to := &DNS{Domain: d.Domain}
for _, ns := range d.Nameservers { to.Nameservers = append(to.Nameservers, d.Nameservers...)
to.Nameservers = append(to.Nameservers, ns) to.Search = append(to.Search, d.Search...)
} to.Options = append(to.Options, d.Options...)
for _, s := range d.Search {
to.Search = append(to.Search, s)
}
for _, o := range d.Options {
to.Options = append(to.Options, o)
}
return to return to
} }
type Route struct { type Route struct {
Dst net.IPNet Dst net.IPNet
GW net.IP GW net.IP
MTU int
AdvMSS int
Priority int
Table *int
Scope *int
} }
func (r *Route) String() string { func (r *Route) String() string {
return fmt.Sprintf("%+v", *r) table := "<nil>"
if r.Table != nil {
table = fmt.Sprintf("%d", *r.Table)
}
scope := "<nil>"
if r.Scope != nil {
scope = fmt.Sprintf("%d", *r.Scope)
}
return fmt.Sprintf("{Dst:%+v GW:%v MTU:%d AdvMSS:%d Priority:%d Table:%s Scope:%s}", r.Dst, r.GW, r.MTU, r.AdvMSS, r.Priority, table, scope)
} }
func (r *Route) Copy() *Route { func (r *Route) Copy() *Route {
@ -148,14 +208,30 @@ func (r *Route) Copy() *Route {
return nil return nil
} }
return &Route{ route := &Route{
Dst: r.Dst, Dst: r.Dst,
GW: r.GW, GW: r.GW,
MTU: r.MTU,
AdvMSS: r.AdvMSS,
Priority: r.Priority,
Scope: r.Scope,
} }
if r.Table != nil {
table := *r.Table
route.Table = &table
}
if r.Scope != nil {
scope := *r.Scope
route.Scope = &scope
}
return route
} }
// Well known error codes // Well known error codes
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes // see https://github.com/containernetworking/cni/blob/main/SPEC.md#well-known-error-codes
const ( const (
ErrUnknown uint = iota // 0 ErrUnknown uint = iota // 0
ErrIncompatibleCNIVersion // 1 ErrIncompatibleCNIVersion // 1
@ -165,6 +241,7 @@ const (
ErrIOFailure // 5 ErrIOFailure // 5
ErrDecodingFailure // 6 ErrDecodingFailure // 6
ErrInvalidNetworkConfig // 7 ErrInvalidNetworkConfig // 7
ErrInvalidNetNS // 8
ErrTryAgainLater uint = 11 ErrTryAgainLater uint = 11
ErrInternal uint = 999 ErrInternal uint = 999
) )
@ -200,8 +277,13 @@ func (e *Error) Print() error {
// JSON (un)marshallable types // JSON (un)marshallable types
type route struct { type route struct {
Dst IPNet `json:"dst"` Dst IPNet `json:"dst"`
GW net.IP `json:"gw,omitempty"` GW net.IP `json:"gw,omitempty"`
MTU int `json:"mtu,omitempty"`
AdvMSS int `json:"advmss,omitempty"`
Priority int `json:"priority,omitempty"`
Table *int `json:"table,omitempty"`
Scope *int `json:"scope,omitempty"`
} }
func (r *Route) UnmarshalJSON(data []byte) error { func (r *Route) UnmarshalJSON(data []byte) error {
@ -212,13 +294,24 @@ func (r *Route) UnmarshalJSON(data []byte) error {
r.Dst = net.IPNet(rt.Dst) r.Dst = net.IPNet(rt.Dst)
r.GW = rt.GW r.GW = rt.GW
r.MTU = rt.MTU
r.AdvMSS = rt.AdvMSS
r.Priority = rt.Priority
r.Table = rt.Table
r.Scope = rt.Scope
return nil return nil
} }
func (r Route) MarshalJSON() ([]byte, error) { func (r Route) MarshalJSON() ([]byte, error) {
rt := route{ rt := route{
Dst: IPNet(r.Dst), Dst: IPNet(r.Dst),
GW: r.GW, GW: r.GW,
MTU: r.MTU,
AdvMSS: r.AdvMSS,
Priority: r.Priority,
Table: r.Table,
Scope: r.Scope,
} }
return json.Marshal(rt) return json.Marshal(rt)

View File

@ -36,7 +36,6 @@ var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`)
// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters // ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters
func ValidateContainerID(containerID string) *types.Error { func ValidateContainerID(containerID string) *types.Error {
if containerID == "" { if containerID == "" {
return types.NewError(types.ErrUnknownContainer, "missing containerID", "") return types.NewError(types.ErrUnknownContainer, "missing containerID", "")
} }
@ -48,7 +47,6 @@ func ValidateContainerID(containerID string) *types.Error {
// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters // ValidateNetworkName will validate that the supplied networkName does not contain invalid characters
func ValidateNetworkName(networkName string) *types.Error { func ValidateNetworkName(networkName string) *types.Error {
if networkName == "" { if networkName == "" {
return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "") return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "")
} }
@ -58,11 +56,11 @@ func ValidateNetworkName(networkName string) *types.Error {
return nil return nil
} }
// ValidateInterfaceName will validate the interface name based on the three rules below // ValidateInterfaceName will validate the interface name based on the four rules below
// 1. The name must not be empty // 1. The name must not be empty
// 2. The name must be less than 16 characters // 2. The name must be less than 16 characters
// 3. The name must not be "." or ".." // 3. The name must not be "." or ".."
// 3. The name must not contain / or : or any whitespace characters // 4. The name must not contain / or : or any whitespace characters
// ref to https://github.com/torvalds/linux/blob/master/net/core/dev.c#L1024 // ref to https://github.com/torvalds/linux/blob/master/net/core/dev.c#L1024
func ValidateInterfaceName(ifName string) *types.Error { func ValidateInterfaceName(ifName string) *types.Error {
if len(ifName) == 0 { if len(ifName) == 0 {

View File

@ -142,3 +142,27 @@ func GreaterThanOrEqualTo(version, otherVersion string) (bool, error) {
} }
return false, nil return false, nil
} }
// GreaterThan returns true if the first version is greater than the second
func GreaterThan(version, otherVersion string) (bool, error) {
firstMajor, firstMinor, firstMicro, err := ParseVersion(version)
if err != nil {
return false, err
}
secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion)
if err != nil {
return false, err
}
if firstMajor > secondMajor {
return true, nil
} else if firstMajor == secondMajor {
if firstMinor > secondMinor {
return true, nil
} else if firstMinor == secondMinor && firstMicro > secondMicro {
return true, nil
}
}
return false, nil
}

View File

@ -19,13 +19,12 @@ import (
"fmt" "fmt"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
types100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/cni/pkg/types/create" "github.com/containernetworking/cni/pkg/types/create"
) )
// Current reports the version of the CNI spec implemented by this library // Current reports the version of the CNI spec implemented by this library
func Current() string { func Current() string {
return types100.ImplementedSpecVersion return "1.1.0"
} }
// Legacy PluginInfo describes a plugin that is backwards compatible with the // Legacy PluginInfo describes a plugin that is backwards compatible with the
@ -35,8 +34,10 @@ func Current() string {
// //
// Any future CNI spec versions which meet this definition should be added to // Any future CNI spec versions which meet this definition should be added to
// this list. // this list.
var Legacy = PluginSupports("0.1.0", "0.2.0") var (
var All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0") Legacy = PluginSupports("0.1.0", "0.2.0")
All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0", "1.1.0")
)
// VersionsFrom returns a list of versions starting from min, inclusive // VersionsFrom returns a list of versions starting from min, inclusive
func VersionsStartingFrom(min string) PluginInfo { func VersionsStartingFrom(min string) PluginInfo {

View File

@ -32,7 +32,7 @@ env:
DEBIAN_NAME: "debian-13" DEBIAN_NAME: "debian-13"
# Image identifiers # Image identifiers
IMAGE_SUFFIX: "c20240411t124913z-f39f38d13" IMAGE_SUFFIX: "c20240620t153000z-f40f39d13"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}" DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"
@ -137,15 +137,9 @@ cross_build_task:
alias: cross_build alias: cross_build
only_if: >- only_if: >-
$CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*' $CIRRUS_CHANGE_TITLE !=~ '.*CI:DOCS.*'
env:
osx_instance: HOME: /root
image: ghcr.io/cirruslabs/macos-ventura-base:latest
script: script:
- brew update
- brew install go
- brew install go-md2man
- brew install gpgme
- go version - go version
- make cross CGO_ENABLED=0 - make cross CGO_ENABLED=0
@ -181,7 +175,7 @@ unit_task:
conformance_task: conformance_task:
name: 'Build Conformance w/ $STORAGE_DRIVER' name: 'Debian Conformance w/ $STORAGE_DRIVER'
alias: conformance alias: conformance
only_if: *not_build_docs only_if: *not_build_docs
depends_on: *smoke_vendor_cross depends_on: *smoke_vendor_cross
@ -194,6 +188,7 @@ conformance_task:
matrix: matrix:
- env: - env:
STORAGE_DRIVER: 'vfs' STORAGE_DRIVER: 'vfs'
TMPDIR: '/var/tmp'
- env: - env:
STORAGE_DRIVER: 'overlay' STORAGE_DRIVER: 'overlay'

View File

@ -2,45 +2,88 @@
# See the documentation for more information: # See the documentation for more information:
# https://packit.dev/docs/configuration/ # https://packit.dev/docs/configuration/
specfile_path: rpm/buildah.spec downstream_package_name: buildah
upstream_tag_template: v{version} upstream_tag_template: v{version}
packages:
buildah-fedora:
pkg_tool: fedpkg
specfile_path: rpm/buildah.spec
buildah-centos:
pkg_tool: centpkg
specfile_path: rpm/buildah.spec
buildah-rhel:
specfile_path: rpm/buildah.spec
srpm_build_deps: srpm_build_deps:
- make - make
jobs: jobs:
- job: copr_build - job: copr_build
trigger: pull_request trigger: pull_request
notifications: packages: [buildah-fedora]
notifications: &copr_build_failure_notification
failure_comment: failure_comment:
message: "Ephemeral COPR build failed. @containers/packit-build please check." message: "Ephemeral COPR build failed. @containers/packit-build please check."
enable_net: true
targets: targets:
- fedora-all-x86_64 fedora-all-x86_64: {}
- fedora-all-aarch64 fedora-all-aarch64: {}
- fedora-eln-x86_64 fedora-eln-x86_64:
- fedora-eln-aarch64 additional_repos:
- "https://kojipkgs.fedoraproject.org/repos/eln-build/latest/x86_64/"
fedora-eln-aarch64:
additional_repos:
- "https://kojipkgs.fedoraproject.org/repos/eln-build/latest/aarch64/"
enable_net: true
- job: copr_build
trigger: pull_request
packages: [buildah-centos]
notifications: *copr_build_failure_notification
targets:
- centos-stream-9-x86_64
- centos-stream-9-aarch64
- centos-stream-10-x86_64
- centos-stream-10-aarch64
enable_net: true
- job: copr_build
trigger: pull_request
packages: [buildah-rhel]
notifications: *copr_build_failure_notification
targets:
- epel-9-x86_64 - epel-9-x86_64
- epel-9-aarch64 - epel-9-aarch64
additional_repos: enable_net: true
- "copr://rhcontainerbot/podman-next"
# Run on commit to main branch # Run on commit to main branch
- job: copr_build - job: copr_build
trigger: commit trigger: commit
packages: [buildah-fedora]
notifications: notifications:
failure_comment: failure_comment:
message: "podman-next COPR build failed. @containers/packit-build please check." message: "podman-next COPR build failed. @containers/packit-build please check."
branch: main
owner: rhcontainerbot owner: rhcontainerbot
project: podman-next project: podman-next
enable_net: true enable_net: true
# Sync to Fedora
- job: propose_downstream - job: propose_downstream
trigger: release trigger: release
packages: [buildah-fedora]
update_release: false update_release: false
dist_git_branches: dist_git_branches:
- fedora-all - fedora-all
# Sync to CentOS Stream
- job: propose_downstream
trigger: release
packages: [buildah-centos]
update_release: false
dist_git_branches:
- c10s
- job: koji_build - job: koji_build
trigger: commit trigger: commit
dist_git_branches: dist_git_branches:

View File

@ -691,8 +691,8 @@ func (b *Builder) userForCopy(mountPoint string, userspec string) (uint32, uint3
return owner.UID, owner.GID, nil return owner.UID, owner.GID, nil
} }
// EnsureContainerPathAs creates the specified directory owned by USER // EnsureContainerPathAs creates the specified directory if it doesn't exist,
// with the file mode set to MODE. // setting a newly-created directory's owner to USER and its permissions to MODE.
func (b *Builder) EnsureContainerPathAs(path, user string, mode *os.FileMode) error { func (b *Builder) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
mountPoint, err := b.Mount(b.MountLabel) mountPoint, err := b.Mount(b.MountLabel)
if err != nil { if err != nil {
@ -722,5 +722,4 @@ func (b *Builder) EnsureContainerPathAs(path, user string, mode *os.FileMode) er
GIDMap: destGIDMap, GIDMap: destGIDMap,
} }
return copier.Mkdir(mountPoint, filepath.Join(mountPoint, path), opts) return copier.Mkdir(mountPoint, filepath.Join(mountPoint, path), opts)
} }

View File

@ -518,7 +518,12 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
if effectiveImportantFlags != expectedImportantFlags { if effectiveImportantFlags != expectedImportantFlags {
// Do a remount to try to get the desired flags to stick. // Do a remount to try to get the desired flags to stick.
effectiveUnimportantFlags := uintptr(fs.Flags) & ^possibleImportantFlags effectiveUnimportantFlags := uintptr(fs.Flags) & ^possibleImportantFlags
if err = unix.Mount(target, target, m.Type, unix.MS_REMOUNT|bindFlags|requestFlags|mountFlagsForFSFlags(effectiveUnimportantFlags), ""); err != nil { remountFlags := unix.MS_REMOUNT | bindFlags | requestFlags | mountFlagsForFSFlags(effectiveUnimportantFlags)
// If we are requesting a read-only mount, add any possibleImportantFlags present in fs.Flags to remountFlags.
if requestFlags&unix.ST_RDONLY == unix.ST_RDONLY {
remountFlags |= uintptr(fs.Flags) & possibleImportantFlags
}
if err = unix.Mount(target, target, m.Type, remountFlags, ""); err != nil {
return undoBinds, fmt.Errorf("remounting %q in mount namespace with flags %#x instead of %#x: %w", target, requestFlags, effectiveImportantFlags, err) return undoBinds, fmt.Errorf("remounting %q in mount namespace with flags %#x instead of %#x: %w", target, requestFlags, effectiveImportantFlags, err)
} }
// Check if the desired flags stuck. // Check if the desired flags stuck.

View File

@ -25,6 +25,7 @@ import (
"github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/stringid"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
) )
const ( const (
@ -127,6 +128,10 @@ type CommitOptions struct {
// SBOMScanOptions encapsulates options which control whether or not we // SBOMScanOptions encapsulates options which control whether or not we
// run scanners on the rootfs that we're about to commit, and how. // run scanners on the rootfs that we're about to commit, and how.
SBOMScanOptions []SBOMScanOptions SBOMScanOptions []SBOMScanOptions
// CompatSetParent causes the "parent" field to be set when committing
// the image in Docker format. Newer BuildKit-based builds don't set
// this field.
CompatSetParent types.OptionalBool
} }
var ( var (
@ -325,7 +330,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
logrus.Debugf("committing image with reference %q is allowed by policy", transports.ImageName(dest)) logrus.Debugf("committing image with reference %q is allowed by policy", transports.ImageName(dest))
// If we need to scan the rootfs, do it now. // If we need to scan the rootfs, do it now.
options.ExtraImageContent = copyStringStringMap(options.ExtraImageContent) options.ExtraImageContent = maps.Clone(options.ExtraImageContent)
var extraImageContent, extraLocalContent map[string]string var extraImageContent, extraLocalContent map[string]string
if len(options.SBOMScanOptions) != 0 { if len(options.SBOMScanOptions) != 0 {
var scansDirectory string var scansDirectory string
@ -339,9 +344,14 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
} }
}() }()
} }
for k, v := range extraImageContent { if len(extraImageContent) > 0 {
if _, set := options.ExtraImageContent[k]; !set { if options.ExtraImageContent == nil {
options.ExtraImageContent[k] = v options.ExtraImageContent = make(map[string]string, len(extraImageContent))
}
for k, v := range extraImageContent {
if _, set := options.ExtraImageContent[k]; !set {
options.ExtraImageContent[k] = v
}
} }
} }
} }

View File

@ -19,6 +19,7 @@ import (
"github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/stringid"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1" ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
@ -91,8 +92,13 @@ func (b *Builder) initConfig(ctx context.Context, img types.Image, sys *types.Sy
if err := json.Unmarshal(b.Manifest, &v1Manifest); err != nil { if err := json.Unmarshal(b.Manifest, &v1Manifest); err != nil {
return fmt.Errorf("parsing OCI manifest %q: %w", string(b.Manifest), err) return fmt.Errorf("parsing OCI manifest %q: %w", string(b.Manifest), err)
} }
for k, v := range v1Manifest.Annotations { if len(v1Manifest.Annotations) > 0 {
b.ImageAnnotations[k] = v if b.ImageAnnotations == nil {
b.ImageAnnotations = make(map[string]string, len(v1Manifest.Annotations))
}
for k, v := range v1Manifest.Annotations {
b.ImageAnnotations[k] = v
}
} }
} }
} }
@ -158,7 +164,7 @@ func (b *Builder) setupLogger() {
// Annotations returns a set of key-value pairs from the image's manifest. // Annotations returns a set of key-value pairs from the image's manifest.
func (b *Builder) Annotations() map[string]string { func (b *Builder) Annotations() map[string]string {
return copyStringStringMap(b.ImageAnnotations) return maps.Clone(b.ImageAnnotations)
} }
// SetAnnotation adds or overwrites a key's value from the image's manifest. // SetAnnotation adds or overwrites a key's value from the image's manifest.
@ -180,7 +186,7 @@ func (b *Builder) UnsetAnnotation(key string) {
// ClearAnnotations removes all keys and their values from the image's // ClearAnnotations removes all keys and their values from the image's
// manifest. // manifest.
func (b *Builder) ClearAnnotations() { func (b *Builder) ClearAnnotations() {
b.ImageAnnotations = map[string]string{} b.ImageAnnotations = nil
} }
// CreatedBy returns a description of how this image was built. // CreatedBy returns a description of how this image was built.
@ -223,7 +229,7 @@ func (b *Builder) SetOSVersion(version string) {
// OSFeatures returns a list of OS features which the container, or a container // OSFeatures returns a list of OS features which the container, or a container
// built using an image built from this container, depends on the OS supplying. // built using an image built from this container, depends on the OS supplying.
func (b *Builder) OSFeatures() []string { func (b *Builder) OSFeatures() []string {
return copyStringSlice(b.OCIv1.OSFeatures) return slices.Clone(b.OCIv1.OSFeatures)
} }
// SetOSFeature adds a feature of the OS which the container, or a container // SetOSFeature adds a feature of the OS which the container, or a container
@ -327,7 +333,7 @@ func (b *Builder) SetUser(spec string) {
// OnBuild returns the OnBuild value from the container. // OnBuild returns the OnBuild value from the container.
func (b *Builder) OnBuild() []string { func (b *Builder) OnBuild() []string {
return copyStringSlice(b.Docker.Config.OnBuild) return slices.Clone(b.Docker.Config.OnBuild)
} }
// ClearOnBuild removes all values from the OnBuild structure // ClearOnBuild removes all values from the OnBuild structure
@ -363,7 +369,7 @@ func (b *Builder) SetWorkDir(there string) {
// Shell returns the default shell for running commands in the // Shell returns the default shell for running commands in the
// container, or in a container built using an image built from this container. // container, or in a container built using an image built from this container.
func (b *Builder) Shell() []string { func (b *Builder) Shell() []string {
return copyStringSlice(b.Docker.Config.Shell) return slices.Clone(b.Docker.Config.Shell)
} }
// SetShell sets the default shell for running // SetShell sets the default shell for running
@ -376,13 +382,13 @@ func (b *Builder) SetShell(shell []string) {
b.Logger.Warnf("SHELL is not supported for OCI image format, %s will be ignored. Must use `docker` format", shell) b.Logger.Warnf("SHELL is not supported for OCI image format, %s will be ignored. Must use `docker` format", shell)
} }
b.Docker.Config.Shell = copyStringSlice(shell) b.Docker.Config.Shell = slices.Clone(shell)
} }
// Env returns a list of key-value pairs to be set when running commands in the // Env returns a list of key-value pairs to be set when running commands in the
// container, or in a container built using an image built from this container. // container, or in a container built using an image built from this container.
func (b *Builder) Env() []string { func (b *Builder) Env() []string {
return copyStringSlice(b.OCIv1.Config.Env) return slices.Clone(b.OCIv1.Config.Env)
} }
// SetEnv adds or overwrites a value to the set of environment strings which // SetEnv adds or overwrites a value to the set of environment strings which
@ -432,22 +438,22 @@ func (b *Builder) ClearEnv() {
// set, to use when running a container built from an image built from this // set, to use when running a container built from an image built from this
// container. // container.
func (b *Builder) Cmd() []string { func (b *Builder) Cmd() []string {
return copyStringSlice(b.OCIv1.Config.Cmd) return slices.Clone(b.OCIv1.Config.Cmd)
} }
// SetCmd sets the default command, or command parameters if an Entrypoint is // SetCmd sets the default command, or command parameters if an Entrypoint is
// set, to use when running a container built from an image built from this // set, to use when running a container built from an image built from this
// container. // container.
func (b *Builder) SetCmd(cmd []string) { func (b *Builder) SetCmd(cmd []string) {
b.OCIv1.Config.Cmd = copyStringSlice(cmd) b.OCIv1.Config.Cmd = slices.Clone(cmd)
b.Docker.Config.Cmd = copyStringSlice(cmd) b.Docker.Config.Cmd = slices.Clone(cmd)
} }
// Entrypoint returns the command to be run for containers built from images // Entrypoint returns the command to be run for containers built from images
// built from this container. // built from this container.
func (b *Builder) Entrypoint() []string { func (b *Builder) Entrypoint() []string {
if len(b.OCIv1.Config.Entrypoint) > 0 { if len(b.OCIv1.Config.Entrypoint) > 0 {
return copyStringSlice(b.OCIv1.Config.Entrypoint) return slices.Clone(b.OCIv1.Config.Entrypoint)
} }
return nil return nil
} }
@ -455,14 +461,14 @@ func (b *Builder) Entrypoint() []string {
// SetEntrypoint sets the command to be run for in containers built from images // SetEntrypoint sets the command to be run for in containers built from images
// built from this container. // built from this container.
func (b *Builder) SetEntrypoint(ep []string) { func (b *Builder) SetEntrypoint(ep []string) {
b.OCIv1.Config.Entrypoint = copyStringSlice(ep) b.OCIv1.Config.Entrypoint = slices.Clone(ep)
b.Docker.Config.Entrypoint = copyStringSlice(ep) b.Docker.Config.Entrypoint = slices.Clone(ep)
} }
// Labels returns a set of key-value pairs from the image's runtime // Labels returns a set of key-value pairs from the image's runtime
// configuration. // configuration.
func (b *Builder) Labels() map[string]string { func (b *Builder) Labels() map[string]string {
return copyStringStringMap(b.OCIv1.Config.Labels) return maps.Clone(b.OCIv1.Config.Labels)
} }
// SetLabel adds or overwrites a key's value from the image's runtime // SetLabel adds or overwrites a key's value from the image's runtime
@ -669,11 +675,12 @@ func (b *Builder) Healthcheck() *docker.HealthConfig {
return nil return nil
} }
return &docker.HealthConfig{ return &docker.HealthConfig{
Test: copyStringSlice(b.Docker.Config.Healthcheck.Test), Test: slices.Clone(b.Docker.Config.Healthcheck.Test),
Interval: b.Docker.Config.Healthcheck.Interval, Interval: b.Docker.Config.Healthcheck.Interval,
Timeout: b.Docker.Config.Healthcheck.Timeout, Timeout: b.Docker.Config.Healthcheck.Timeout,
StartPeriod: b.Docker.Config.Healthcheck.StartPeriod, StartPeriod: b.Docker.Config.Healthcheck.StartPeriod,
Retries: b.Docker.Config.Healthcheck.Retries, StartInterval: b.Docker.Config.Healthcheck.StartInterval,
Retries: b.Docker.Config.Healthcheck.Retries,
} }
} }
@ -690,11 +697,12 @@ func (b *Builder) SetHealthcheck(config *docker.HealthConfig) {
b.Logger.Warnf("HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format") b.Logger.Warnf("HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format")
} }
b.Docker.Config.Healthcheck = &docker.HealthConfig{ b.Docker.Config.Healthcheck = &docker.HealthConfig{
Test: copyStringSlice(config.Test), Test: slices.Clone(config.Test),
Interval: config.Interval, Interval: config.Interval,
Timeout: config.Timeout, Timeout: config.Timeout,
StartPeriod: config.StartPeriod, StartPeriod: config.StartPeriod,
Retries: config.Retries, StartInterval: config.StartInterval,
Retries: config.Retries,
} }
} }
} }

View File

@ -1,5 +1,5 @@
//go:build (linux && !mips && !mipsle && !mips64 && !mips64le) || freebsd //go:build (linux && !mips && !mipsle && !mips64 && !mips64le) || freebsd || netbsd
// +build linux,!mips,!mipsle,!mips64,!mips64le freebsd // +build linux,!mips,!mipsle,!mips64,!mips64le freebsd netbsd
package copier package copier

View File

@ -1,5 +1,5 @@
//go:build linux || darwin || freebsd //go:build !windows
// +build linux darwin freebsd // +build !windows
package copier package copier

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"time" "time"
"github.com/containers/common/libimage"
nettypes "github.com/containers/common/libnetwork/types" nettypes "github.com/containers/common/libnetwork/types"
"github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
@ -272,6 +273,10 @@ type BuildOptions struct {
// the build was unsuccessful. // the build was unsuccessful.
ForceRmIntermediateCtrs bool ForceRmIntermediateCtrs bool
// BlobDirectory is a directory which we'll use for caching layer blobs. // BlobDirectory is a directory which we'll use for caching layer blobs.
//
// This option will be overridden for cache pulls if
// CachePullDestinationLookupReferenceFunc is set, and overridden for cache pushes if
// CachePushSourceLookupReferenceFunc is set.
BlobDirectory string BlobDirectory string
// Target the targeted FROM in the Dockerfile to build. // Target the targeted FROM in the Dockerfile to build.
Target string Target string
@ -342,4 +347,27 @@ type BuildOptions struct {
// CDIConfigDir is the location of CDI configuration files, if the files in // CDIConfigDir is the location of CDI configuration files, if the files in
// the default configuration locations shouldn't be used. // the default configuration locations shouldn't be used.
CDIConfigDir string CDIConfigDir string
// CachePullSourceLookupReferenceFunc is an optional LookupReferenceFunc
// used to look up source references for cache pulls.
CachePullSourceLookupReferenceFunc libimage.LookupReferenceFunc
// CachePullDestinationLookupReferenceFunc is an optional generator
// function which provides a LookupReferenceFunc used to look up
// destination references for cache pulls.
//
// BlobDirectory will be ignored for cache pulls if this option is set.
CachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) libimage.LookupReferenceFunc
// CachePushSourceLookupReferenceFunc is an optional generator function
// which provides a LookupReferenceFunc used to look up source
// references for cache pushes.
//
// BlobDirectory will be ignored for cache pushes if this option is set.
CachePushSourceLookupReferenceFunc func(dest types.ImageReference) libimage.LookupReferenceFunc
// CachePushDestinationLookupReferenceFunc is an optional
// LookupReferenceFunc used to look up destination references for cache
// pushes
CachePushDestinationLookupReferenceFunc libimage.LookupReferenceFunc
// CompatSetParent causes the "parent" field to be set in the image's
// configuration when committing in Docker format. Newer
// BuildKit-based docker build doesn't set this field.
CompatSetParent types.OptionalBool
} }

View File

@ -1,5 +1,5 @@
//go:build darwin || windows //go:build darwin || windows || netbsd
// +build darwin windows // +build darwin windows netbsd
package define package define

View File

@ -5,6 +5,9 @@ import (
) )
// PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever. // PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever.
// N.B.: the enumeration values for this type differ from those used by
// github.com/containers/common/pkg/config.PullPolicy (their zero values
// indicate different policies), so they are not interchangeable.
type PullPolicy int type PullPolicy int
const ( const (

View File

@ -29,7 +29,7 @@ const (
// identify working containers. // identify working containers.
Package = "buildah" Package = "buildah"
// Version for the Package. Also used by .packit.sh for Packit builds. // Version for the Package. Also used by .packit.sh for Packit builds.
Version = "1.36.0" Version = "1.37.0-dev"
// DefaultRuntime if containers.conf fails. // DefaultRuntime if containers.conf fails.
DefaultRuntime = "runc" DefaultRuntime = "runc"

View File

@ -32,6 +32,7 @@ import (
specs "github.com/opencontainers/image-spec/specs-go" specs "github.com/opencontainers/image-spec/specs-go"
v1 "github.com/opencontainers/image-spec/specs-go/v1" v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
) )
const ( const (
@ -83,6 +84,7 @@ type containerImageRef struct {
overrideChanges []string overrideChanges []string
overrideConfig *manifest.Schema2Config overrideConfig *manifest.Schema2Config
extraImageContent map[string]string extraImageContent map[string]string
compatSetParent types.OptionalBool
} }
type blobLayerInfo struct { type blobLayerInfo struct {
@ -321,7 +323,11 @@ func (i *containerImageRef) createConfigsAndManifests() (v1.Image, v1.Manifest,
if err := json.Unmarshal(i.dconfig, &dimage); err != nil { if err := json.Unmarshal(i.dconfig, &dimage); err != nil {
return v1.Image{}, v1.Manifest{}, docker.V2Image{}, docker.V2S2Manifest{}, err return v1.Image{}, v1.Manifest{}, docker.V2Image{}, docker.V2S2Manifest{}, err
} }
dimage.Parent = docker.ID(i.parent) // Set the parent, but only if we want to be compatible with "classic" docker build.
if i.compatSetParent == types.OptionalBoolTrue {
dimage.Parent = docker.ID(i.parent)
}
// Set the container ID and containerConfig in the docker format.
dimage.Container = i.containerID dimage.Container = i.containerID
if dimage.Config != nil { if dimage.Config != nil {
dimage.ContainerConfig = *dimage.Config dimage.ContainerConfig = *dimage.Config
@ -721,18 +727,18 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System
Created: &created, Created: &created,
CreatedBy: i.createdBy, CreatedBy: i.createdBy,
Author: oimage.Author, Author: oimage.Author,
Comment: comment,
EmptyLayer: i.emptyLayer, EmptyLayer: i.emptyLayer,
} }
oimage.History = append(oimage.History, onews) oimage.History = append(oimage.History, onews)
oimage.History[baseImageHistoryLen].Comment = comment
dnews := docker.V2S2History{ dnews := docker.V2S2History{
Created: created, Created: created,
CreatedBy: i.createdBy, CreatedBy: i.createdBy,
Author: dimage.Author, Author: dimage.Author,
Comment: comment,
EmptyLayer: i.emptyLayer, EmptyLayer: i.emptyLayer,
} }
dimage.History = append(dimage.History, dnews) dimage.History = append(dimage.History, dnews)
dimage.History[baseImageHistoryLen].Comment = comment
appendHistory(i.postEmptyLayers) appendHistory(i.postEmptyLayers)
// Add a history entry for the extra image content if we added a layer for it. // Add a history entry for the extra image content if we added a layer for it.
@ -1102,7 +1108,8 @@ func (b *Builder) makeContainerImageRef(options CommitOptions) (*containerImageR
postEmptyLayers: b.AppendedEmptyLayers, postEmptyLayers: b.AppendedEmptyLayers,
overrideChanges: options.OverrideChanges, overrideChanges: options.OverrideChanges,
overrideConfig: options.OverrideConfig, overrideConfig: options.OverrideConfig,
extraImageContent: copyStringStringMap(options.ExtraImageContent), extraImageContent: maps.Clone(options.ExtraImageContent),
compatSetParent: options.CompatSetParent,
} }
return ref, nil return ref, nil
} }

View File

@ -70,6 +70,9 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
if options.CommonBuildOpts == nil { if options.CommonBuildOpts == nil {
options.CommonBuildOpts = &define.CommonBuildOptions{} options.CommonBuildOpts = &define.CommonBuildOptions{}
} }
if options.Args == nil {
options.Args = make(map[string]string)
}
if err := parse.Volumes(options.CommonBuildOpts.Volumes); err != nil { if err := parse.Volumes(options.CommonBuildOpts.Volumes); err != nil {
return "", nil, fmt.Errorf("validating volumes: %w", err) return "", nil, fmt.Errorf("validating volumes: %w", err)
} }

View File

@ -35,6 +35,7 @@ import (
"github.com/openshift/imagebuilder" "github.com/openshift/imagebuilder"
"github.com/openshift/imagebuilder/dockerfile/parser" "github.com/openshift/imagebuilder/dockerfile/parser"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"golang.org/x/sync/semaphore" "golang.org/x/sync/semaphore"
) )
@ -94,67 +95,72 @@ type Executor struct {
cniPluginPath string cniPluginPath string
cniConfigDir string cniConfigDir string
// NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks.
networkInterface nettypes.ContainerNetwork networkInterface nettypes.ContainerNetwork
idmappingOptions *define.IDMappingOptions idmappingOptions *define.IDMappingOptions
commonBuildOptions *define.CommonBuildOptions commonBuildOptions *define.CommonBuildOptions
defaultMountsFilePath string defaultMountsFilePath string
iidfile string iidfile string
squash bool squash bool
labels []string labels []string
layerLabels []string layerLabels []string
annotations []string annotations []string
layers bool layers bool
noHostname bool noHostname bool
noHosts bool noHosts bool
useCache bool useCache bool
removeIntermediateCtrs bool removeIntermediateCtrs bool
forceRmIntermediateCtrs bool forceRmIntermediateCtrs bool
imageMap map[string]string // Used to map images that we create to handle the AS construct. imageMap map[string]string // Used to map images that we create to handle the AS construct.
containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers. containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers.
baseMap map[string]struct{} // Holds the names of every base image, as given. baseMap map[string]struct{} // Holds the names of every base image, as given.
rootfsMap map[string]struct{} // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. rootfsMap map[string]struct{} // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction.
blobDirectory string blobDirectory string
excludes []string excludes []string
groupAdd []string groupAdd []string
ignoreFile string ignoreFile string
args map[string]string args map[string]string
globalArgs map[string]string globalArgs map[string]string
unusedArgs map[string]struct{} unusedArgs map[string]struct{}
capabilities []string capabilities []string
devices define.ContainerDevices devices define.ContainerDevices
deviceSpecs []string deviceSpecs []string
signBy string signBy string
architecture string architecture string
timestamp *time.Time timestamp *time.Time
os string os string
maxPullPushRetries int maxPullPushRetries int
retryPullPushDelay time.Duration retryPullPushDelay time.Duration
ociDecryptConfig *encconfig.DecryptConfig cachePullSourceLookupReferenceFunc libimage.LookupReferenceFunc
lastError error cachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) libimage.LookupReferenceFunc
terminatedStage map[string]error cachePushSourceLookupReferenceFunc func(dest types.ImageReference) libimage.LookupReferenceFunc
stagesLock sync.Mutex cachePushDestinationLookupReferenceFunc libimage.LookupReferenceFunc
stagesSemaphore *semaphore.Weighted ociDecryptConfig *encconfig.DecryptConfig
logRusage bool lastError error
rusageLogFile io.Writer terminatedStage map[string]error
imageInfoLock sync.Mutex stagesLock sync.Mutex
imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs stagesSemaphore *semaphore.Weighted
fromOverride string logRusage bool
additionalBuildContexts map[string]*define.AdditionalBuildContext rusageLogFile io.Writer
manifest string imageInfoLock sync.Mutex
secrets map[string]define.Secret imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs
sshsources map[string]*sshagent.Source fromOverride string
logPrefix string additionalBuildContexts map[string]*define.AdditionalBuildContext
unsetEnvs []string manifest string
unsetLabels []string secrets map[string]define.Secret
processLabel string // Shares processLabel of first stage container with containers of other stages in same build sshsources map[string]*sshagent.Source
mountLabel string // Shares mountLabel of first stage container with containers of other stages in same build logPrefix string
buildOutput string // Specifies instructions for any custom build output unsetEnvs []string
osVersion string unsetLabels []string
osFeatures []string processLabel string // Shares processLabel of first stage container with containers of other stages in same build
envs []string mountLabel string // Shares mountLabel of first stage container with containers of other stages in same build
confidentialWorkload define.ConfidentialWorkloadOptions buildOutput string // Specifies instructions for any custom build output
sbomScanOptions []define.SBOMScanOptions osVersion string
cdiConfigDir string osFeatures []string
envs []string
confidentialWorkload define.ConfidentialWorkloadOptions
sbomScanOptions []define.SBOMScanOptions
cdiConfigDir string
compatSetParent types.OptionalBool
} }
type imageTypeAndHistoryAndDiffIDs struct { type imageTypeAndHistoryAndDiffIDs struct {
@ -221,92 +227,97 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
} }
exec := Executor{ exec := Executor{
args: options.Args, args: options.Args,
cacheFrom: options.CacheFrom, cacheFrom: options.CacheFrom,
cacheTo: options.CacheTo, cacheTo: options.CacheTo,
cacheTTL: options.CacheTTL, cacheTTL: options.CacheTTL,
containerSuffix: options.ContainerSuffix, containerSuffix: options.ContainerSuffix,
logger: logger, logger: logger,
stages: make(map[string]*StageExecutor), stages: make(map[string]*StageExecutor),
store: store, store: store,
contextDir: options.ContextDirectory, contextDir: options.ContextDirectory,
excludes: excludes, excludes: excludes,
groupAdd: options.GroupAdd, groupAdd: options.GroupAdd,
ignoreFile: options.IgnoreFile, ignoreFile: options.IgnoreFile,
pullPolicy: options.PullPolicy, pullPolicy: options.PullPolicy,
registry: options.Registry, registry: options.Registry,
ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions,
quiet: options.Quiet, quiet: options.Quiet,
runtime: options.Runtime, runtime: options.Runtime,
runtimeArgs: options.RuntimeArgs, runtimeArgs: options.RuntimeArgs,
transientMounts: transientMounts, transientMounts: transientMounts,
compression: options.Compression, compression: options.Compression,
output: options.Output, output: options.Output,
outputFormat: options.OutputFormat, outputFormat: options.OutputFormat,
additionalTags: options.AdditionalTags, additionalTags: options.AdditionalTags,
signaturePolicyPath: options.SignaturePolicyPath, signaturePolicyPath: options.SignaturePolicyPath,
skipUnusedStages: options.SkipUnusedStages, skipUnusedStages: options.SkipUnusedStages,
systemContext: options.SystemContext, systemContext: options.SystemContext,
log: options.Log, log: options.Log,
in: options.In, in: options.In,
out: options.Out, out: options.Out,
err: options.Err, err: options.Err,
reportWriter: writer, reportWriter: writer,
isolation: options.Isolation, isolation: options.Isolation,
namespaceOptions: options.NamespaceOptions, namespaceOptions: options.NamespaceOptions,
configureNetwork: options.ConfigureNetwork, configureNetwork: options.ConfigureNetwork,
cniPluginPath: options.CNIPluginPath, cniPluginPath: options.CNIPluginPath,
cniConfigDir: options.CNIConfigDir, cniConfigDir: options.CNIConfigDir,
networkInterface: options.NetworkInterface, networkInterface: options.NetworkInterface,
idmappingOptions: options.IDMappingOptions, idmappingOptions: options.IDMappingOptions,
commonBuildOptions: options.CommonBuildOpts, commonBuildOptions: options.CommonBuildOpts,
defaultMountsFilePath: options.DefaultMountsFilePath, defaultMountsFilePath: options.DefaultMountsFilePath,
iidfile: options.IIDFile, iidfile: options.IIDFile,
squash: options.Squash, squash: options.Squash,
labels: append([]string{}, options.Labels...), labels: slices.Clone(options.Labels),
layerLabels: append([]string{}, options.LayerLabels...), layerLabels: slices.Clone(options.LayerLabels),
annotations: append([]string{}, options.Annotations...), annotations: slices.Clone(options.Annotations),
layers: options.Layers, layers: options.Layers,
noHostname: options.CommonBuildOpts.NoHostname, noHostname: options.CommonBuildOpts.NoHostname,
noHosts: options.CommonBuildOpts.NoHosts, noHosts: options.CommonBuildOpts.NoHosts,
useCache: !options.NoCache, useCache: !options.NoCache,
removeIntermediateCtrs: options.RemoveIntermediateCtrs, removeIntermediateCtrs: options.RemoveIntermediateCtrs,
forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs,
imageMap: make(map[string]string), imageMap: make(map[string]string),
containerMap: make(map[string]*buildah.Builder), containerMap: make(map[string]*buildah.Builder),
baseMap: make(map[string]struct{}), baseMap: make(map[string]struct{}),
rootfsMap: make(map[string]struct{}), rootfsMap: make(map[string]struct{}),
blobDirectory: options.BlobDirectory, blobDirectory: options.BlobDirectory,
unusedArgs: make(map[string]struct{}), unusedArgs: make(map[string]struct{}),
capabilities: capabilities, capabilities: capabilities,
deviceSpecs: options.Devices, deviceSpecs: options.Devices,
signBy: options.SignBy, signBy: options.SignBy,
architecture: options.Architecture, architecture: options.Architecture,
timestamp: options.Timestamp, timestamp: options.Timestamp,
os: options.OS, os: options.OS,
maxPullPushRetries: options.MaxPullPushRetries, maxPullPushRetries: options.MaxPullPushRetries,
retryPullPushDelay: options.PullPushRetryDelay, retryPullPushDelay: options.PullPushRetryDelay,
ociDecryptConfig: options.OciDecryptConfig, cachePullSourceLookupReferenceFunc: options.CachePullSourceLookupReferenceFunc,
terminatedStage: make(map[string]error), cachePullDestinationLookupReferenceFunc: options.CachePullDestinationLookupReferenceFunc,
stagesSemaphore: options.JobSemaphore, cachePushSourceLookupReferenceFunc: options.CachePushSourceLookupReferenceFunc,
logRusage: options.LogRusage, cachePushDestinationLookupReferenceFunc: options.CachePushDestinationLookupReferenceFunc,
rusageLogFile: rusageLogFile, ociDecryptConfig: options.OciDecryptConfig,
imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs), terminatedStage: make(map[string]error),
fromOverride: options.From, stagesSemaphore: options.JobSemaphore,
additionalBuildContexts: options.AdditionalBuildContexts, logRusage: options.LogRusage,
manifest: options.Manifest, rusageLogFile: rusageLogFile,
secrets: secrets, imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs),
sshsources: sshsources, fromOverride: options.From,
logPrefix: logPrefix, additionalBuildContexts: options.AdditionalBuildContexts,
unsetEnvs: append([]string{}, options.UnsetEnvs...), manifest: options.Manifest,
unsetLabels: append([]string{}, options.UnsetLabels...), secrets: secrets,
buildOutput: options.BuildOutput, sshsources: sshsources,
osVersion: options.OSVersion, logPrefix: logPrefix,
osFeatures: append([]string{}, options.OSFeatures...), unsetEnvs: slices.Clone(options.UnsetEnvs),
envs: append([]string{}, options.Envs...), unsetLabels: slices.Clone(options.UnsetLabels),
confidentialWorkload: options.ConfidentialWorkload, buildOutput: options.BuildOutput,
sbomScanOptions: options.SBOMScanOptions, osVersion: options.OSVersion,
cdiConfigDir: options.CDIConfigDir, osFeatures: slices.Clone(options.OSFeatures),
envs: slices.Clone(options.Envs),
confidentialWorkload: options.ConfidentialWorkload,
sbomScanOptions: options.SBOMScanOptions,
cdiConfigDir: options.CDIConfigDir,
compatSetParent: options.CompatSetParent,
} }
if exec.err == nil { if exec.err == nil {
exec.err = os.Stderr exec.err = os.Stderr

View File

@ -349,6 +349,26 @@ func (s *StageExecutor) volumeCacheRestore() error {
// Copy copies data into the working tree. The "Download" field is how // Copy copies data into the working tree. The "Download" field is how
// imagebuilder tells us the instruction was "ADD" and not "COPY". // imagebuilder tells us the instruction was "ADD" and not "COPY".
func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) error { func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) error {
for _, cp := range copies {
if cp.KeepGitDir {
if cp.Download {
return errors.New("ADD --keep-git-dir is not supported")
}
return errors.New("COPY --keep-git-dir is not supported")
}
if cp.Link {
return errors.New("COPY --link is not supported")
}
if cp.Parents {
return errors.New("COPY --parents is not supported")
}
if len(cp.Excludes) > 0 {
if cp.Download {
return errors.New("ADD --excludes is not supported")
}
return errors.New("COPY --excludes is not supported")
}
}
s.builder.ContentDigester.Restart() s.builder.ContentDigester.Restart()
return s.performCopy(excludes, copies...) return s.performCopy(excludes, copies...)
} }
@ -860,12 +880,15 @@ func (s *StageExecutor) prepare(ctx context.Context, from string, initializeIBCo
from = base from = base
} }
displayFrom := from displayFrom := from
if ib.Platform != "" {
displayFrom = "--platform=" + ib.Platform + " " + displayFrom
}
// stage.Name will be a numeric string for all stages without an "AS" clause // stage.Name will be a numeric string for all stages without an "AS" clause
asImageName := stage.Name asImageName := stage.Name
if asImageName != "" { if asImageName != "" {
if _, err := strconv.Atoi(asImageName); err != nil { if _, err := strconv.Atoi(asImageName); err != nil {
displayFrom = from + " AS " + asImageName displayFrom += " AS " + asImageName
} }
} }
@ -1992,6 +2015,12 @@ func (s *StageExecutor) pushCache(ctx context.Context, src, cacheKey string) err
MaxRetries: s.executor.maxPullPushRetries, MaxRetries: s.executor.maxPullPushRetries,
RetryDelay: s.executor.retryPullPushDelay, RetryDelay: s.executor.retryPullPushDelay,
} }
if s.executor.cachePushSourceLookupReferenceFunc != nil {
options.SourceLookupReferenceFunc = s.executor.cachePushSourceLookupReferenceFunc(dest)
}
if s.executor.cachePushDestinationLookupReferenceFunc != nil {
options.DestinationLookupReferenceFunc = s.executor.cachePushDestinationLookupReferenceFunc
}
ref, digest, err := buildah.Push(ctx, src, dest, options) ref, digest, err := buildah.Push(ctx, src, dest, options)
if err != nil { if err != nil {
return fmt.Errorf("failed pushing cache to %q: %w", dest, err) return fmt.Errorf("failed pushing cache to %q: %w", dest, err)
@ -2013,7 +2042,8 @@ func (s *StageExecutor) pullCache(ctx context.Context, cacheKey string) (referen
return nil, "", err return nil, "", err
} }
for _, src := range srcList { for _, src := range srcList {
logrus.Debugf("trying to pull cache from remote repo: %+v", src.DockerReference()) srcDockerRef := src.DockerReference()
logrus.Debugf("trying to pull cache from remote repo: %+v", srcDockerRef)
options := buildah.PullOptions{ options := buildah.PullOptions{
SignaturePolicyPath: s.executor.signaturePolicyPath, SignaturePolicyPath: s.executor.signaturePolicyPath,
Store: s.executor.store, Store: s.executor.store,
@ -2025,7 +2055,14 @@ func (s *StageExecutor) pullCache(ctx context.Context, cacheKey string) (referen
ReportWriter: nil, ReportWriter: nil,
PullPolicy: define.PullIfNewer, PullPolicy: define.PullIfNewer,
} }
id, err := buildah.Pull(ctx, src.DockerReference().String(), options) if s.executor.cachePullSourceLookupReferenceFunc != nil {
options.SourceLookupReferenceFunc = s.executor.cachePullSourceLookupReferenceFunc
}
if s.executor.cachePullDestinationLookupReferenceFunc != nil {
options.DestinationLookupReferenceFunc = s.executor.cachePullDestinationLookupReferenceFunc(src)
}
id, err := buildah.Pull(ctx, srcDockerRef.String(), options)
if err != nil { if err != nil {
logrus.Debugf("failed pulling cache from source %s: %v", src, err) logrus.Debugf("failed pulling cache from source %s: %v", src, err)
continue // failed pulling this one try next continue // failed pulling this one try next
@ -2179,11 +2216,12 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
s.builder.SetStopSignal(config.StopSignal) s.builder.SetStopSignal(config.StopSignal)
if config.Healthcheck != nil { if config.Healthcheck != nil {
s.builder.SetHealthcheck(&buildahdocker.HealthConfig{ s.builder.SetHealthcheck(&buildahdocker.HealthConfig{
Test: append([]string{}, config.Healthcheck.Test...), Test: append([]string{}, config.Healthcheck.Test...),
Interval: config.Healthcheck.Interval, Interval: config.Healthcheck.Interval,
Timeout: config.Healthcheck.Timeout, Timeout: config.Healthcheck.Timeout,
StartPeriod: config.Healthcheck.StartPeriod, StartPeriod: config.Healthcheck.StartPeriod,
Retries: config.Healthcheck.Retries, StartInterval: config.Healthcheck.StartInterval,
Retries: config.Healthcheck.Retries,
}) })
} else { } else {
s.builder.SetHealthcheck(nil) s.builder.SetHealthcheck(nil)
@ -2237,6 +2275,7 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
RetryDelay: s.executor.retryPullPushDelay, RetryDelay: s.executor.retryPullPushDelay,
HistoryTimestamp: s.executor.timestamp, HistoryTimestamp: s.executor.timestamp,
Manifest: s.executor.manifest, Manifest: s.executor.manifest,
CompatSetParent: s.executor.compatSetParent,
} }
if finalInstruction { if finalInstruction {
options.ConfidentialWorkloadOptions = s.executor.confidentialWorkload options.ConfidentialWorkloadOptions = s.executor.confidentialWorkload
@ -2291,9 +2330,11 @@ func (s *StageExecutor) generateBuildOutput(buildOutputOpts define.BuildOutputOp
} }
func (s *StageExecutor) EnsureContainerPath(path string) error { func (s *StageExecutor) EnsureContainerPath(path string) error {
logrus.Debugf("EnsureContainerPath %q in %q", path, s.builder.ContainerID)
return s.builder.EnsureContainerPathAs(path, "", nil) return s.builder.EnsureContainerPathAs(path, "", nil)
} }
func (s *StageExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error { func (s *StageExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
logrus.Debugf("EnsureContainerPath %q (owner %q, mode %o) in %q", path, user, mode, s.builder.ContainerID)
return s.builder.EnsureContainerPathAs(path, user, mode) return s.builder.EnsureContainerPathAs(path, user, mode)
} }

View File

@ -97,7 +97,6 @@ func importBuilderDataFromImage(ctx context.Context, store storage.Store, system
FromImageDigest: imageDigest, FromImageDigest: imageDigest,
Container: containerName, Container: containerName,
ContainerID: containerID, ContainerID: containerID,
ImageAnnotations: map[string]string{},
ImageCreatedBy: "", ImageCreatedBy: "",
NamespaceOptions: defaultNamespaceOptions, NamespaceOptions: defaultNamespaceOptions,
IDMappingOptions: define.IDMappingOptions{ IDMappingOptions: define.IDMappingOptions{

View File

@ -1,6 +1,8 @@
package config package config
import ( import (
"slices"
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
dockerclient "github.com/fsouza/go-dockerclient" dockerclient "github.com/fsouza/go-dockerclient"
) )
@ -41,17 +43,17 @@ func Schema2ConfigFromGoDockerclientConfig(config *dockerclient.Config) *manifes
Tty: config.Tty, Tty: config.Tty,
OpenStdin: config.OpenStdin, OpenStdin: config.OpenStdin,
StdinOnce: config.StdinOnce, StdinOnce: config.StdinOnce,
Env: append([]string{}, config.Env...), Env: slices.Clone(config.Env),
Cmd: append([]string{}, config.Cmd...), Cmd: slices.Clone(config.Cmd),
Healthcheck: overrideHealthCheck, Healthcheck: overrideHealthCheck,
ArgsEscaped: config.ArgsEscaped, ArgsEscaped: config.ArgsEscaped,
Image: config.Image, Image: config.Image,
Volumes: volumes, Volumes: volumes,
WorkingDir: config.WorkingDir, WorkingDir: config.WorkingDir,
Entrypoint: append([]string{}, config.Entrypoint...), Entrypoint: slices.Clone(config.Entrypoint),
NetworkDisabled: config.NetworkDisabled, NetworkDisabled: config.NetworkDisabled,
MacAddress: config.MacAddress, MacAddress: config.MacAddress,
OnBuild: append([]string{}, config.OnBuild...), OnBuild: slices.Clone(config.OnBuild),
Labels: labels, Labels: labels,
StopSignal: config.StopSignal, StopSignal: config.StopSignal,
Shell: config.Shell, Shell: config.Shell,

View File

@ -21,6 +21,8 @@ import (
v1 "github.com/opencontainers/image-spec/specs-go/v1" v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/openshift/imagebuilder" "github.com/openshift/imagebuilder"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
) )
const ( const (
@ -313,10 +315,10 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
UIDMap: uidmap, UIDMap: uidmap,
GIDMap: gidmap, GIDMap: gidmap,
}, },
Capabilities: copyStringSlice(options.Capabilities), Capabilities: slices.Clone(options.Capabilities),
CommonBuildOpts: options.CommonBuildOpts, CommonBuildOpts: options.CommonBuildOpts,
TopLayer: topLayer, TopLayer: topLayer,
Args: copyStringStringMap(options.Args), Args: maps.Clone(options.Args),
Format: options.Format, Format: options.Format,
TempVolumes: map[string]bool{}, TempVolumes: map[string]bool{},
Devices: options.Devices, Devices: options.Devices,

View File

@ -263,8 +263,12 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
fs.String("os", runtime.GOOS, "set the OS to the provided value instead of the current operating system of the host") fs.String("os", runtime.GOOS, "set the OS to the provided value instead of the current operating system of the host")
fs.StringArrayVar(&flags.OSFeatures, "os-feature", []string{}, "set required OS `feature` for the target image in addition to values from the base image") fs.StringArrayVar(&flags.OSFeatures, "os-feature", []string{}, "set required OS `feature` for the target image in addition to values from the base image")
fs.StringVar(&flags.OSVersion, "os-version", "", "set required OS `version` for the target image instead of the value from the base image") fs.StringVar(&flags.OSVersion, "os-version", "", "set required OS `version` for the target image instead of the value from the base image")
fs.StringVar(&flags.Pull, "pull", "true", "pull base and SBOM scanner images from the registry if newer or not present in store, if false, only pull base and SBOM scanner images if not present, if always, pull base and SBOM scanner images even if the named images are present in store, if never, only use images present in store if available") fs.StringVar(&flags.Pull, "pull", "missing", `pull base and SBOM scanner images from the registry. Values:
fs.Lookup("pull").NoOptDefVal = "true" //allow `--pull ` to be set to `true` as expected. always: pull base and SBOM scanner images even if the named images are present in store.
missing: pull base and SBOM scanner images if the named images are not present in store.
never: only use images present in store if available.
newer: only pull base and SBOM scanner images when newer images exist on the registry than those in the store.`)
fs.Lookup("pull").NoOptDefVal = "missing" //treat a --pull with no argument like --pull=missing
fs.BoolVar(&flags.PullAlways, "pull-always", false, "pull the image even if the named image is present in store") fs.BoolVar(&flags.PullAlways, "pull-always", false, "pull the image even if the named image is present in store")
if err := fs.MarkHidden("pull-always"); err != nil { if err := fs.MarkHidden("pull-always"); err != nil {
panic(fmt.Sprintf("error marking the pull-always flag as hidden: %v", err)) panic(fmt.Sprintf("error marking the pull-always flag as hidden: %v", err))

View File

@ -449,6 +449,42 @@ func SystemContextFromFlagSet(flags *pflag.FlagSet, findFlagFunc func(name strin
return ctx, nil return ctx, nil
} }
// pullPolicyWithFlags parses a string value of a pull policy, evaluating it in
// combination with "always" and "never" boolean flags.
// Allow for:
// * --pull
// * --pull=""
// * --pull=true
// * --pull=false
// * --pull=never
// * --pull=always
// * --pull=ifmissing
// * --pull=missing
// * --pull=notpresent
// * --pull=newer
// * --pull=ifnewer
// and --pull-always and --pull-never as boolean flags.
func pullPolicyWithFlags(policySpec string, always, never bool) (define.PullPolicy, error) {
if always {
return define.PullAlways, nil
}
if never {
return define.PullNever, nil
}
policy := strings.ToLower(policySpec)
switch policy {
case "true", "missing", "ifmissing", "notpresent":
return define.PullIfMissing, nil
case "always":
return define.PullAlways, nil
case "false", "never":
return define.PullNever, nil
case "ifnewer", "newer":
return define.PullIfNewer, nil
}
return 0, fmt.Errorf("unrecognized pull policy %q", policySpec)
}
// PullPolicyFromOptions returns a PullPolicy that reflects the combination of // PullPolicyFromOptions returns a PullPolicy that reflects the combination of
// the specified "pull" and undocumented "pull-always" and "pull-never" flags. // the specified "pull" and undocumented "pull-always" and "pull-never" flags.
func PullPolicyFromOptions(c *cobra.Command) (define.PullPolicy, error) { func PullPolicyFromOptions(c *cobra.Command) (define.PullPolicy, error) {
@ -474,30 +510,23 @@ func PullPolicyFromFlagSet(flags *pflag.FlagSet, findFlagFunc func(name string)
return 0, errors.New("can only set one of 'pull' or 'pull-always' or 'pull-never'") return 0, errors.New("can only set one of 'pull' or 'pull-always' or 'pull-never'")
} }
// Allow for --pull, --pull=true, --pull=false, --pull=never, --pull=always // The --pull-never and --pull-always options will not be documented.
// --pull-always and --pull-never. The --pull-never and --pull-always options
// will not be documented.
pullPolicy := define.PullIfMissing
pullFlagValue := findFlagFunc("pull").Value.String()
if strings.EqualFold(pullFlagValue, "true") || strings.EqualFold(pullFlagValue, "ifnewer") {
pullPolicy = define.PullIfNewer
}
pullAlwaysFlagValue, err := flags.GetBool("pull-always") pullAlwaysFlagValue, err := flags.GetBool("pull-always")
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("checking the --pull-always flag value: %w", err)
}
if pullAlwaysFlagValue || strings.EqualFold(pullFlagValue, "always") {
pullPolicy = define.PullAlways
} }
pullNeverFlagValue, err := flags.GetBool("pull-never") pullNeverFlagValue, err := flags.GetBool("pull-never")
if err != nil {
return 0, fmt.Errorf("checking the --pull-never flag value: %w", err)
}
// The --pull[=...] flag is the one we really care about.
pullFlagValue := findFlagFunc("pull").Value.String()
pullPolicy, err := pullPolicyWithFlags(pullFlagValue, pullAlwaysFlagValue, pullNeverFlagValue)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if pullNeverFlagValue ||
strings.EqualFold(pullFlagValue, "never") ||
strings.EqualFold(pullFlagValue, "false") {
pullPolicy = define.PullNever
}
logrus.Debugf("Pull Policy for pull [%v]", pullPolicy) logrus.Debugf("Pull Policy for pull [%v]", pullPolicy)
return pullPolicy, nil return pullPolicy, nil

View File

@ -0,0 +1,25 @@
package util
import (
"time"
"unsafe"
"golang.org/x/sys/unix"
)
func clockGettime(clockid int32, time *unix.Timespec) (err error) {
_, _, e1 := unix.Syscall(unix.SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0)
if e1 != 0 {
return e1
}
return nil
}
func ReadUptime() (time.Duration, error) {
tv, err := unix.SysctlTimeval("kern.boottime")
if err != nil {
return 0, err
}
sec, nsec := tv.Unix()
return time.Now().Sub(time.Unix(sec, nsec)), nil
}

View File

@ -1,5 +1,5 @@
//go:build linux || freebsd || darwin //go:build !windows
// +build linux freebsd darwin // +build !windows
package util package util

View File

@ -33,6 +33,8 @@ type PullOptions struct {
// BlobDirectory is the name of a directory in which we'll attempt to // BlobDirectory is the name of a directory in which we'll attempt to
// store copies of layer blobs that we pull down, if any. It should // store copies of layer blobs that we pull down, if any. It should
// already exist. // already exist.
//
// Not applicable if DestinationLookupReferenceFunc is set.
BlobDirectory string BlobDirectory string
// AllTags is a boolean value that determines if all tagged images // AllTags is a boolean value that determines if all tagged images
// will be downloaded from the repository. The default is false. // will be downloaded from the repository. The default is false.
@ -50,6 +52,12 @@ type PullOptions struct {
OciDecryptConfig *encconfig.DecryptConfig OciDecryptConfig *encconfig.DecryptConfig
// PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever. // PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever.
PullPolicy define.PullPolicy PullPolicy define.PullPolicy
// SourceLookupReference provides a function to look up source
// references.
SourceLookupReferenceFunc libimage.LookupReferenceFunc
// DestinationLookupReference provides a function to look up destination
// references. Overrides BlobDirectory, if set.
DestinationLookupReferenceFunc libimage.LookupReferenceFunc
} }
// Pull copies the contents of the image from somewhere else to local storage. Returns the // Pull copies the contents of the image from somewhere else to local storage. Returns the
@ -62,7 +70,12 @@ func Pull(ctx context.Context, imageName string, options PullOptions) (imageID s
libimageOptions.OciDecryptConfig = options.OciDecryptConfig libimageOptions.OciDecryptConfig = options.OciDecryptConfig
libimageOptions.AllTags = options.AllTags libimageOptions.AllTags = options.AllTags
libimageOptions.RetryDelay = &options.RetryDelay libimageOptions.RetryDelay = &options.RetryDelay
libimageOptions.DestinationLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal) libimageOptions.SourceLookupReferenceFunc = options.SourceLookupReferenceFunc
if options.DestinationLookupReferenceFunc != nil {
libimageOptions.DestinationLookupReferenceFunc = options.DestinationLookupReferenceFunc
} else {
libimageOptions.DestinationLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal)
}
if options.MaxRetries > 0 { if options.MaxRetries > 0 {
retries := uint(options.MaxRetries) retries := uint(options.MaxRetries)

View File

@ -66,6 +66,8 @@ type PushOptions struct {
// prebuilt copies of layer blobs that we might otherwise need to // prebuilt copies of layer blobs that we might otherwise need to
// regenerate from on-disk layers, substituting them in the list of // regenerate from on-disk layers, substituting them in the list of
// blobs to copy whenever possible. // blobs to copy whenever possible.
//
// Not applicable if SourceLookupReferenceFunc is set.
BlobDirectory string BlobDirectory string
// Quiet is a boolean value that determines if minimal output to // Quiet is a boolean value that determines if minimal output to
// the user will be displayed, this is best used for logging. // the user will be displayed, this is best used for logging.
@ -90,6 +92,12 @@ type PushOptions struct {
// integers in the slice represent 0-indexed layer indices, with support for negative // integers in the slice represent 0-indexed layer indices, with support for negative
// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer. // indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
OciEncryptLayers *[]int OciEncryptLayers *[]int
// SourceLookupReference provides a function to look up source
// references. Overrides BlobDirectory, if set.
SourceLookupReferenceFunc libimage.LookupReferenceFunc
// DestinationLookupReference provides a function to look up destination
// references.
DestinationLookupReferenceFunc libimage.LookupReferenceFunc
// CompressionFormat is the format to use for the compression of the blobs // CompressionFormat is the format to use for the compression of the blobs
CompressionFormat *compression.Algorithm CompressionFormat *compression.Algorithm
@ -125,7 +133,12 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options
if options.Compression == archive.Gzip { if options.Compression == archive.Gzip {
compress = types.Compress compress = types.Compress
} }
libimageOptions.SourceLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, compress) if options.SourceLookupReferenceFunc != nil {
libimageOptions.SourceLookupReferenceFunc = options.SourceLookupReferenceFunc
} else {
libimageOptions.SourceLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, compress)
}
libimageOptions.DestinationLookupReferenceFunc = options.DestinationLookupReferenceFunc
runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext}) runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext})
if err != nil { if err != nil {

View File

@ -53,6 +53,7 @@ import (
"github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label" "github.com/opencontainers/selinux/go-selinux/label"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"golang.org/x/term" "golang.org/x/term"
) )
@ -83,12 +84,17 @@ func (b *Builder) createResolvConf(rdir string, chownOpts *idtools.IDPair) (stri
// addResolvConf copies files from host and sets them up to bind mount into container // addResolvConf copies files from host and sets them up to bind mount into container
func (b *Builder) addResolvConfEntries(file string, networkNameServer []string, func (b *Builder) addResolvConfEntries(file string, networkNameServer []string,
namespaces []specs.LinuxNamespace, keepHostServers, ipv6 bool) error { spec *specs.Spec, keepHostServers, ipv6 bool) error {
defaultConfig, err := config.Default() defaultConfig, err := config.Default()
if err != nil { if err != nil {
return fmt.Errorf("failed to get config: %w", err) return fmt.Errorf("failed to get config: %w", err)
} }
var namespaces []specs.LinuxNamespace
if spec.Linux != nil {
namespaces = spec.Linux.Namespaces
}
dnsServers, dnsSearch, dnsOptions := b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions dnsServers, dnsSearch, dnsOptions := b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions
nameservers := make([]string, 0, len(defaultConfig.Containers.DNSServers.Get())+len(dnsServers)) nameservers := make([]string, 0, len(defaultConfig.Containers.DNSServers.Get())+len(dnsServers))
nameservers = append(nameservers, defaultConfig.Containers.DNSServers.Get()...) nameservers = append(nameservers, defaultConfig.Containers.DNSServers.Get()...)
@ -540,7 +546,7 @@ func runUsingRuntime(options RunOptions, configureNetwork bool, moreCreateArgs [
} }
} }
runtimeArgs := options.Args[:] runtimeArgs := slices.Clone(options.Args)
if options.CgroupManager == config.SystemdCgroupsManager { if options.CgroupManager == config.SystemdCgroupsManager {
runtimeArgs = append(runtimeArgs, "--systemd-cgroup") runtimeArgs = append(runtimeArgs, "--systemd-cgroup")
} }
@ -1253,7 +1259,7 @@ func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options Run
} }
if resolvFile != "" { if resolvFile != "" {
err = b.addResolvConfEntries(resolvFile, netResult.dnsServers, spec.Linux.Namespaces, netResult.keepHostResolvers, netResult.ipv6) err = b.addResolvConfEntries(resolvFile, netResult.dnsServers, spec, netResult.keepHostResolvers, netResult.ipv6)
if err != nil { if err != nil {
return err return err
} }

View File

@ -423,7 +423,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
// Only add entries here if we do not have to do setup network, // Only add entries here if we do not have to do setup network,
// if we do we have to do it much later after the network setup. // if we do we have to do it much later after the network setup.
if !configureNetwork { if !configureNetwork {
err = b.addResolvConfEntries(resolvFile, nil, spec.Linux.Namespaces, false, true) err = b.addResolvConfEntries(resolvFile, nil, spec, false, true)
if err != nil { if err != nil {
return err return err
} }

View File

@ -28,20 +28,6 @@ func InitReexec() bool {
return reexec.Init() return reexec.Init()
} }
func copyStringStringMap(m map[string]string) map[string]string {
n := map[string]string{}
for k, v := range m {
n[k] = v
}
return n
}
func copyStringSlice(s []string) []string {
t := make([]string, len(s))
copy(t, s)
return t
}
func copyHistory(history []v1.History) []v1.History { func copyHistory(history []v1.History) []v1.History {
if len(history) == 0 { if len(history) == 0 {
return nil return nil

View File

@ -1,5 +1,5 @@
//go:build linux || darwin || freebsd //go:build linux || darwin || freebsd || netbsd
// +build linux darwin freebsd // +build linux darwin freebsd netbsd
package util package util

View File

@ -12,7 +12,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/containers/common/libimage/manifests"
"github.com/containers/common/libimage/platform" "github.com/containers/common/libimage/platform"
"github.com/containers/common/pkg/config" "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/retry" "github.com/containers/common/pkg/retry"
@ -32,12 +31,6 @@ const (
defaultRetryDelay = time.Second defaultRetryDelay = time.Second
) )
// LookupReferenceFunc return an image reference based on the specified one.
// The returned reference can return custom ImageSource or ImageDestination
// objects which intercept or filter blobs, manifests, and signatures as
// they are read and written.
type LookupReferenceFunc = manifests.LookupReferenceFunc
// CopyOptions allow for customizing image-copy operations. // CopyOptions allow for customizing image-copy operations.
type CopyOptions struct { type CopyOptions struct {
// If set, will be used for copying the image. Fields below may // If set, will be used for copying the image. Fields below may

View File

@ -6,6 +6,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"maps"
"slices" "slices"
"time" "time"
@ -20,7 +21,6 @@ import (
structcopier "github.com/jinzhu/copier" structcopier "github.com/jinzhu/copier"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/exp/maps"
) )
// NOTE: the abstractions and APIs here are a first step to further merge // NOTE: the abstractions and APIs here are a first step to further merge
@ -238,9 +238,7 @@ func (m *ManifestList) Inspect() (*define.ManifestListData, error) {
for i, manifest := range ociFormat.Manifests { for i, manifest := range ociFormat.Manifests {
inspectList.Manifests[i].Annotations = manifest.Annotations inspectList.Manifests[i].Annotations = manifest.Annotations
inspectList.Manifests[i].ArtifactType = manifest.ArtifactType inspectList.Manifests[i].ArtifactType = manifest.ArtifactType
if manifest.URLs != nil { inspectList.Manifests[i].URLs = slices.Clone(manifest.URLs)
inspectList.Manifests[i].URLs = slices.Clone(manifest.URLs)
}
inspectList.Manifests[i].Data = manifest.Data inspectList.Manifests[i].Data = manifest.Data
inspectList.Manifests[i].Files, err = m.list.Files(manifest.Digest) inspectList.Manifests[i].Files, err = m.list.Files(manifest.Digest)
if err != nil { if err != nil {
@ -252,10 +250,7 @@ func (m *ManifestList) Inspect() (*define.ManifestListData, error) {
if platform == nil { if platform == nil {
platform = &imgspecv1.Platform{} platform = &imgspecv1.Platform{}
} }
var osFeatures []string osFeatures := slices.Clone(platform.OSFeatures)
if platform.OSFeatures != nil {
osFeatures = slices.Clone(platform.OSFeatures)
}
inspectList.Subject = &define.ManifestListDescriptor{ inspectList.Subject = &define.ManifestListDescriptor{
Platform: manifest.Schema2PlatformSpec{ Platform: manifest.Schema2PlatformSpec{
OS: platform.OS, OS: platform.OS,
@ -483,23 +478,23 @@ func (m *ManifestList) AddArtifact(ctx context.Context, options *ManifestListAdd
// Options for annotating a manifest list. // Options for annotating a manifest list.
type ManifestListAnnotateOptions struct { type ManifestListAnnotateOptions struct {
// Add the specified annotations to the added image. // Add the specified annotations to the added image. Empty values are ignored.
Annotations map[string]string Annotations map[string]string
// Add the specified architecture to the added image. // Add the specified architecture to the added image. Empty values are ignored.
Architecture string Architecture string
// Add the specified features to the added image. // Add the specified features to the added image. Empty values are ignored.
Features []string Features []string
// Add the specified OS to the added image. // Add the specified OS to the added image. Empty values are ignored.
OS string OS string
// Add the specified OS features to the added image. // Add the specified OS features to the added image. Empty values are ignored.
OSFeatures []string OSFeatures []string
// Add the specified OS version to the added image. // Add the specified OS version to the added image. Empty values are ignored.
OSVersion string OSVersion string
// Add the specified variant to the added image. // Add the specified variant to the added image. Empty values are ignored unless Architecture is set to a non-empty value.
Variant string Variant string
// Add the specified annotations to the index itself. // Add the specified annotations to the index itself. Empty values are ignored.
IndexAnnotations map[string]string IndexAnnotations map[string]string
// Set the subject to which the index refers. // Set the subject to which the index refers. Empty values are ignored.
Subject string Subject string
} }
@ -536,7 +531,7 @@ func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAn
return err return err
} }
} }
if len(options.Variant) > 0 { if len(options.Architecture) != 0 || len(options.Variant) > 0 {
if err := m.list.SetVariant(d, options.Variant); err != nil { if err := m.list.SetVariant(d, options.Variant); err != nil {
return err return err
} }

View File

@ -7,6 +7,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"maps"
"mime" "mime"
"net/http" "net/http"
"os" "os"
@ -40,7 +41,6 @@ import (
imgspec "github.com/opencontainers/image-spec/specs-go" imgspec "github.com/opencontainers/image-spec/specs-go"
v1 "github.com/opencontainers/image-spec/specs-go/v1" v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
) )
const ( const (
@ -236,11 +236,7 @@ func (l *list) SaveToImage(store storage.Store, imageID string, names []string,
// Files returns the list of files associated with a particular artifact // Files returns the list of files associated with a particular artifact
// instance in the image index, primarily for display purposes. // instance in the image index, primarily for display purposes.
func (l *list) Files(instanceDigest digest.Digest) ([]string, error) { func (l *list) Files(instanceDigest digest.Digest) ([]string, error) {
filesList, ok := l.artifacts.Files[instanceDigest] return slices.Clone(l.artifacts.Files[instanceDigest]), nil
if ok {
return slices.Clone(filesList), nil
}
return nil, nil
} }
// instanceByFile returns the instanceDigest of the first manifest in the index // instanceByFile returns the instanceDigest of the first manifest in the index
@ -640,9 +636,7 @@ func (l *list) Add(ctx context.Context, sys *types.SystemContext, ref types.Imag
if instanceInfo.OS == "" { if instanceInfo.OS == "" {
instanceInfo.OS = config.OS instanceInfo.OS = config.OS
instanceInfo.OSVersion = config.OSVersion instanceInfo.OSVersion = config.OSVersion
if config.OSFeatures != nil { instanceInfo.OSFeatures = slices.Clone(config.OSFeatures)
instanceInfo.OSFeatures = slices.Clone(config.OSFeatures)
}
} }
if instanceInfo.Architecture == "" { if instanceInfo.Architecture == "" {
instanceInfo.Architecture = config.Architecture instanceInfo.Architecture = config.Architecture
@ -906,9 +900,7 @@ func (l *list) AddArtifact(ctx context.Context, sys *types.SystemContext, option
Subject: subject, Subject: subject,
} }
// Add in annotations, more or less exactly as specified. // Add in annotations, more or less exactly as specified.
if options.Annotations != nil { artifactManifest.Annotations = maps.Clone(options.Annotations)
artifactManifest.Annotations = maps.Clone(options.Annotations)
}
// Encode and save the data we care about. // Encode and save the data we care about.
artifactManifestBytes, err := json.Marshal(artifactManifest) artifactManifestBytes, err := json.Marshal(artifactManifest)

View File

@ -0,0 +1,9 @@
package libimage
import "github.com/containers/common/libimage/manifests"
// LookupReferenceFunc return an image reference based on the specified one.
// The returned reference can return custom ImageSource or ImageDestination
// objects which intercept or filter blobs, manifests, and signatures as
// they are read and written.
type LookupReferenceFunc = manifests.LookupReferenceFunc

View File

@ -462,6 +462,10 @@ func (n *Netns) setupMounts() error {
// 5. Mount the new prepared run dir to /run, it has to be recursive to keep the other bind mounts. // 5. Mount the new prepared run dir to /run, it has to be recursive to keep the other bind mounts.
runDir := n.getPath("run") runDir := n.getPath("run")
err = os.MkdirAll(runDir, 0o700)
if err != nil {
return wrapError("create run directory", err)
}
// relabel the new run directory to the iptables /run label // relabel the new run directory to the iptables /run label
// this is important, otherwise the iptables command will fail // this is important, otherwise the iptables command will fail
err = label.Relabel(runDir, "system_u:object_r:iptables_var_run_t:s0", false) err = label.Relabel(runDir, "system_u:object_r:iptables_var_run_t:s0", false)

View File

@ -326,6 +326,11 @@ func createIpvlanOrMacvlan(network *types.Network) error {
return fmt.Errorf("unknown ipvlan mode %q", value) return fmt.Errorf("unknown ipvlan mode %q", value)
} }
} }
case types.MetricOption:
_, err := strconv.ParseUint(value, 10, 32)
if err != nil {
return err
}
case types.MTUOption: case types.MTUOption:
_, err := internalutil.ParseMTU(value) _, err := internalutil.ParseMTU(value)
if err != nil { if err != nil {

View File

@ -130,6 +130,7 @@ func createPastaArgs(opts *SetupOptions) ([]string, []string, error) {
noTCPNamespacePorts := true noTCPNamespacePorts := true
noUDPNamespacePorts := true noUDPNamespacePorts := true
noMapGW := true noMapGW := true
quiet := true
cmdArgs := []string{"--config-net"} cmdArgs := []string{"--config-net"}
// first append options set in the config // first append options set in the config
@ -158,6 +159,8 @@ func createPastaArgs(opts *SetupOptions) ([]string, []string, error) {
noTCPNamespacePorts = false noTCPNamespacePorts = false
case "-U", "--udp-ns": case "-U", "--udp-ns":
noUDPNamespacePorts = false noUDPNamespacePorts = false
case "-d", "--debug", "--trace":
quiet = false
case dnsForwardOpt: case dnsForwardOpt:
// if there is no arg after it pasta will likely error out anyway due invalid cli args // if there is no arg after it pasta will likely error out anyway due invalid cli args
if len(cmdArgs) > i+1 { if len(cmdArgs) > i+1 {
@ -216,9 +219,12 @@ func createPastaArgs(opts *SetupOptions) ([]string, []string, error) {
if noMapGW { if noMapGW {
cmdArgs = append(cmdArgs, "--no-map-gw") cmdArgs = append(cmdArgs, "--no-map-gw")
} }
if quiet {
// pass --quiet to silence the info output from pasta if verbose/trace pasta is not required
cmdArgs = append(cmdArgs, "--quiet")
}
// always pass --quiet to silence the info output from pasta cmdArgs = append(cmdArgs, "--netns", opts.Netns)
cmdArgs = append(cmdArgs, "--quiet", "--netns", opts.Netns)
return cmdArgs, dnsForwardIPs, nil return cmdArgs, dnsForwardIPs, nil
} }

View File

@ -51,9 +51,16 @@ func DefaultProfile() *Seccomp {
{ {
Names: []string{ Names: []string{
"bdflush", "bdflush",
"cachestat",
"futex_requeue",
"futex_wait",
"futex_waitv",
"futex_wake",
"io_pgetevents", "io_pgetevents",
"io_pgetevents_time64",
"kexec_file_load", "kexec_file_load",
"kexec_load", "kexec_load",
"map_shadow_stack",
"migrate_pages", "migrate_pages",
"move_pages", "move_pages",
"nfsservctl", "nfsservctl",
@ -68,9 +75,9 @@ func DefaultProfile() *Seccomp {
"pciconfig_write", "pciconfig_write",
"sgetmask", "sgetmask",
"ssetmask", "ssetmask",
"swapcontext",
"swapoff", "swapoff",
"swapon", "swapon",
"syscall",
"sysfs", "sysfs",
"uselib", "uselib",
"userfaultfd", "userfaultfd",
@ -310,7 +317,6 @@ func DefaultProfile() *Seccomp {
"pwritev2", "pwritev2",
"read", "read",
"readahead", "readahead",
"readdir",
"readlink", "readlink",
"readlinkat", "readlinkat",
"readv", "readv",
@ -398,15 +404,12 @@ func DefaultProfile() *Seccomp {
"shmdt", "shmdt",
"shmget", "shmget",
"shutdown", "shutdown",
"sigaction",
"sigaltstack", "sigaltstack",
"signal", "signal",
"signalfd", "signalfd",
"signalfd4", "signalfd4",
"sigpending",
"sigprocmask", "sigprocmask",
"sigreturn", "sigreturn",
"sigsuspend",
"socketcall", "socketcall",
"socketpair", "socketpair",
"splice", "splice",
@ -420,7 +423,6 @@ func DefaultProfile() *Seccomp {
"sync", "sync",
"sync_file_range", "sync_file_range",
"syncfs", "syncfs",
"syscall",
"sysinfo", "sysinfo",
"syslog", "syslog",
"tee", "tee",
@ -433,7 +435,6 @@ func DefaultProfile() *Seccomp {
"timer_gettime64", "timer_gettime64",
"timer_settime", "timer_settime",
"timer_settime64", "timer_settime64",
"timerfd",
"timerfd_create", "timerfd_create",
"timerfd_gettime", "timerfd_gettime",
"timerfd_gettime64", "timerfd_gettime64",
@ -523,6 +524,7 @@ func DefaultProfile() *Seccomp {
{ {
Names: []string{ Names: []string{
"sync_file_range2", "sync_file_range2",
"swapcontext",
}, },
Action: ActAllow, Action: ActAllow,
Args: []*Arg{}, Args: []*Arg{},
@ -577,6 +579,16 @@ func DefaultProfile() *Seccomp {
Arches: []string{"s390", "s390x"}, Arches: []string{"s390", "s390x"},
}, },
}, },
{
Names: []string{
"riscv_flush_icache",
},
Action: ActAllow,
Args: []*Arg{},
Includes: Filter{
Arches: []string{"riscv64"},
},
},
{ {
Names: []string{ Names: []string{
"open_by_handle_at", "open_by_handle_at",
@ -604,8 +616,8 @@ func DefaultProfile() *Seccomp {
"bpf", "bpf",
"fanotify_init", "fanotify_init",
"lookup_dcookie", "lookup_dcookie",
"perf_event_open",
"quotactl", "quotactl",
"quotactl_fd",
"setdomainname", "setdomainname",
"sethostname", "sethostname",
"setns", "setns",
@ -618,11 +630,11 @@ func DefaultProfile() *Seccomp {
}, },
{ {
Names: []string{ Names: []string{
"bpf",
"fanotify_init", "fanotify_init",
"lookup_dcookie", "lookup_dcookie",
"perf_event_open", "perf_event_open",
"quotactl", "quotactl",
"quotactl_fd",
"setdomainname", "setdomainname",
"sethostname", "sethostname",
"setns", "setns",
@ -885,6 +897,50 @@ func DefaultProfile() *Seccomp {
Caps: []string{"CAP_AUDIT_WRITE"}, Caps: []string{"CAP_AUDIT_WRITE"},
}, },
}, },
{
Names: []string{
"bpf",
},
Action: ActErrno,
Errno: "EPERM",
ErrnoRet: &eperm,
Args: []*Arg{},
Excludes: Filter{
Caps: []string{"CAP_SYS_ADMIN", "CAP_BPF"},
},
},
{
Names: []string{
"bpf",
},
Action: ActAllow,
Args: []*Arg{},
Includes: Filter{
Caps: []string{"CAP_BPF"},
},
},
{
Names: []string{
"perf_event_open",
},
Action: ActErrno,
Errno: "EPERM",
ErrnoRet: &eperm,
Args: []*Arg{},
Excludes: Filter{
Caps: []string{"CAP_SYS_ADMIN", "CAP_BPF"},
},
},
{
Names: []string{
"perf_event_open",
},
Action: ActAllow,
Args: []*Arg{},
Includes: Filter{
Caps: []string{"CAP_PERFMON"},
},
},
} }
return &Seccomp{ return &Seccomp{

View File

@ -55,9 +55,16 @@
{ {
"names": [ "names": [
"bdflush", "bdflush",
"cachestat",
"futex_requeue",
"futex_wait",
"futex_waitv",
"futex_wake",
"io_pgetevents", "io_pgetevents",
"io_pgetevents_time64",
"kexec_file_load", "kexec_file_load",
"kexec_load", "kexec_load",
"map_shadow_stack",
"migrate_pages", "migrate_pages",
"move_pages", "move_pages",
"nfsservctl", "nfsservctl",
@ -72,9 +79,9 @@
"pciconfig_write", "pciconfig_write",
"sgetmask", "sgetmask",
"ssetmask", "ssetmask",
"swapcontext",
"swapoff", "swapoff",
"swapon", "swapon",
"syscall",
"sysfs", "sysfs",
"uselib", "uselib",
"userfaultfd", "userfaultfd",
@ -317,7 +324,6 @@
"pwritev2", "pwritev2",
"read", "read",
"readahead", "readahead",
"readdir",
"readlink", "readlink",
"readlinkat", "readlinkat",
"readv", "readv",
@ -405,15 +411,12 @@
"shmdt", "shmdt",
"shmget", "shmget",
"shutdown", "shutdown",
"sigaction",
"sigaltstack", "sigaltstack",
"signal", "signal",
"signalfd", "signalfd",
"signalfd4", "signalfd4",
"sigpending",
"sigprocmask", "sigprocmask",
"sigreturn", "sigreturn",
"sigsuspend",
"socketcall", "socketcall",
"socketpair", "socketpair",
"splice", "splice",
@ -427,7 +430,6 @@
"sync", "sync",
"sync_file_range", "sync_file_range",
"syncfs", "syncfs",
"syscall",
"sysinfo", "sysinfo",
"syslog", "syslog",
"tee", "tee",
@ -440,7 +442,6 @@
"timer_gettime64", "timer_gettime64",
"timer_settime", "timer_settime",
"timer_settime64", "timer_settime64",
"timerfd",
"timerfd_create", "timerfd_create",
"timerfd_gettime", "timerfd_gettime",
"timerfd_gettime64", "timerfd_gettime64",
@ -562,7 +563,8 @@
}, },
{ {
"names": [ "names": [
"sync_file_range2" "sync_file_range2",
"swapcontext"
], ],
"action": "SCMP_ACT_ALLOW", "action": "SCMP_ACT_ALLOW",
"args": [], "args": [],
@ -642,6 +644,20 @@
}, },
"excludes": {} "excludes": {}
}, },
{
"names": [
"riscv_flush_icache"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"arches": [
"riscv64"
]
},
"excludes": {}
},
{ {
"names": [ "names": [
"open_by_handle_at" "open_by_handle_at"
@ -677,8 +693,8 @@
"bpf", "bpf",
"fanotify_init", "fanotify_init",
"lookup_dcookie", "lookup_dcookie",
"perf_event_open",
"quotactl", "quotactl",
"quotactl_fd",
"setdomainname", "setdomainname",
"sethostname", "sethostname",
"setns" "setns"
@ -695,11 +711,11 @@
}, },
{ {
"names": [ "names": [
"bpf",
"fanotify_init", "fanotify_init",
"lookup_dcookie", "lookup_dcookie",
"perf_event_open", "perf_event_open",
"quotactl", "quotactl",
"quotactl_fd",
"setdomainname", "setdomainname",
"sethostname", "sethostname",
"setns" "setns"
@ -1047,6 +1063,68 @@
] ]
}, },
"excludes": {} "excludes": {}
},
{
"names": [
"bpf"
],
"action": "SCMP_ACT_ERRNO",
"args": [],
"comment": "",
"includes": {},
"excludes": {
"caps": [
"CAP_SYS_ADMIN",
"CAP_BPF"
]
},
"errnoRet": 1,
"errno": "EPERM"
},
{
"names": [
"bpf"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_BPF"
]
},
"excludes": {}
},
{
"names": [
"perf_event_open"
],
"action": "SCMP_ACT_ERRNO",
"args": [],
"comment": "",
"includes": {},
"excludes": {
"caps": [
"CAP_SYS_ADMIN",
"CAP_BPF"
]
},
"errnoRet": 1,
"errno": "EPERM"
},
{
"names": [
"perf_event_open"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "",
"includes": {
"caps": [
"CAP_PERFMON"
]
},
"excludes": {}
} }
] ]
} }

View File

@ -409,7 +409,6 @@ func (ic *imageCopier) compareImageDestinationManifestEqual(ctx context.Context,
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "". // copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "".
func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algorithm, error) { func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algorithm, error) {
srcInfos := ic.src.LayerInfos() srcInfos := ic.src.LayerInfos()
numLayers := len(srcInfos)
updatedSrcInfos, err := ic.src.LayerInfosForCopy(ctx) updatedSrcInfos, err := ic.src.LayerInfosForCopy(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -440,7 +439,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
// copyGroup is used to determine if all layers are copied // copyGroup is used to determine if all layers are copied
copyGroup := sync.WaitGroup{} copyGroup := sync.WaitGroup{}
data := make([]copyLayerData, numLayers) data := make([]copyLayerData, len(srcInfos))
copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) { copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) {
defer ic.c.concurrentBlobCopiesSemaphore.Release(1) defer ic.c.concurrentBlobCopiesSemaphore.Release(1)
defer copyGroup.Done() defer copyGroup.Done()
@ -463,9 +462,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
// Decide which layers to encrypt // Decide which layers to encrypt
layersToEncrypt := set.New[int]() layersToEncrypt := set.New[int]()
var encryptAll bool
if ic.c.options.OciEncryptLayers != nil { if ic.c.options.OciEncryptLayers != nil {
encryptAll = len(*ic.c.options.OciEncryptLayers) == 0
totalLayers := len(srcInfos) totalLayers := len(srcInfos)
for _, l := range *ic.c.options.OciEncryptLayers { for _, l := range *ic.c.options.OciEncryptLayers {
switch { switch {
@ -478,7 +475,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
} }
} }
if encryptAll { if len(*ic.c.options.OciEncryptLayers) == 0 { // “encrypt all layers”
for i := 0; i < len(srcInfos); i++ { for i := 0; i < len(srcInfos); i++ {
layersToEncrypt.Add(i) layersToEncrypt.Add(i)
} }
@ -493,8 +490,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
defer copyGroup.Wait() defer copyGroup.Wait()
for i, srcLayer := range srcInfos { for i, srcLayer := range srcInfos {
err = ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1) if err := ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1); err != nil {
if err != nil {
// This can only fail with ctx.Err(), so no need to blame acquiring the semaphore. // This can only fail with ctx.Err(), so no need to blame acquiring the semaphore.
return fmt.Errorf("copying layer: %w", err) return fmt.Errorf("copying layer: %w", err)
} }
@ -509,8 +505,8 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor
} }
compressionAlgos := set.New[string]() compressionAlgos := set.New[string]()
destInfos := make([]types.BlobInfo, numLayers) destInfos := make([]types.BlobInfo, len(srcInfos))
diffIDs := make([]digest.Digest, numLayers) diffIDs := make([]digest.Digest, len(srcInfos))
for i, cld := range data { for i, cld := range data {
if cld.err != nil { if cld.err != nil {
return nil, cld.err return nil, cld.err

View File

@ -86,11 +86,9 @@ type extensionSignatureList struct {
Signatures []extensionSignature `json:"signatures"` Signatures []extensionSignature `json:"signatures"`
} }
// bearerToken records a cached token we can use to authenticate.
type bearerToken struct { type bearerToken struct {
Token string `json:"token"` token string
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
IssuedAt time.Time `json:"issued_at"`
expirationTime time.Time expirationTime time.Time
} }
@ -147,25 +145,6 @@ const (
noAuth noAuth
) )
func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) {
token := new(bearerToken)
if err := json.Unmarshal(blob, &token); err != nil {
return nil, err
}
if token.Token == "" {
token.Token = token.AccessToken
}
if token.ExpiresIn < minimumTokenLifetimeSeconds {
token.ExpiresIn = minimumTokenLifetimeSeconds
logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
}
if token.IssuedAt.IsZero() {
token.IssuedAt = time.Now().UTC()
}
token.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
return token, nil
}
// dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort. // dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort.
func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) { func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) {
if sys != nil && sys.DockerCertPath != "" { if sys != nil && sys.DockerCertPath != "" {
@ -774,7 +753,7 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope
token = *t token = *t
c.tokenCache.Store(cacheKey, token) c.tokenCache.Store(cacheKey, token)
} }
registryToken = token.Token registryToken = token.token
} }
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken)) req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken))
return nil return nil
@ -827,12 +806,7 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall
return nil, err return nil, err
} }
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) return newBearerTokenFromHTTPResponseBody(res)
if err != nil {
return nil, err
}
return newBearerTokenFromJSONBlob(tokenBlob)
} }
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
@ -878,12 +852,50 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
if err := httpResponseToError(res, "Requesting bearer token"); err != nil { if err := httpResponseToError(res, "Requesting bearer token"); err != nil {
return nil, err return nil, err
} }
tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
return newBearerTokenFromHTTPResponseBody(res)
}
// newBearerTokenFromHTTPResponseBody parses a http.Response to obtain a bearerToken.
// The caller is still responsible for ensuring res.Body is closed.
func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error) {
blob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newBearerTokenFromJSONBlob(tokenBlob) var token struct {
Token string `json:"token"`
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
IssuedAt time.Time `json:"issued_at"`
expirationTime time.Time
}
if err := json.Unmarshal(blob, &token); err != nil {
const bodySampleLength = 50
bodySample := blob
if len(bodySample) > bodySampleLength {
bodySample = bodySample[:bodySampleLength]
}
return nil, fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
}
bt := &bearerToken{
token: token.Token,
}
if bt.token == "" {
bt.token = token.AccessToken
}
if token.ExpiresIn < minimumTokenLifetimeSeconds {
token.ExpiresIn = minimumTokenLifetimeSeconds
logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn)
}
if token.IssuedAt.IsZero() {
token.IssuedAt = time.Now().UTC()
}
bt.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
return bt, nil
} }
// detectPropertiesHelper performs the work of detectProperties which executes // detectPropertiesHelper performs the work of detectProperties which executes

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/image/v5/manifest" "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/sirupsen/logrus"
) )
// Image is a Docker-specific implementation of types.ImageCloser with a few extra methods // Image is a Docker-specific implementation of types.ImageCloser with a few extra methods
@ -90,6 +91,14 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
} }
for _, tag := range tagsHolder.Tags { for _, tag := range tagsHolder.Tags {
if _, err := reference.WithTag(dr.ref, tag); err != nil { // Ensure the tag does not contain unexpected values if _, err := reference.WithTag(dr.ref, tag); err != nil { // Ensure the tag does not contain unexpected values
// Per https://github.com/containers/skopeo/issues/2346 , unknown versions of JFrog Artifactory,
// contrary to the tag format specified in
// https://github.com/opencontainers/distribution-spec/blob/8a871c8234977df058f1a14e299fe0a673853da2/spec.md?plain=1#L160 ,
// include digests in the list.
if _, err := digest.Parse(tag); err == nil {
logrus.Debugf("Ignoring invalid tag %q matching a digest format", tag)
continue
}
return nil, fmt.Errorf("registry returned invalid tag %q: %w", tag, err) return nil, fmt.Errorf("registry returned invalid tag %q: %w", tag, err)
} }
tags = append(tags, tag) tags = append(tags, tag)

View File

@ -1,7 +1,9 @@
package docker package docker
import ( import (
"bytes"
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -11,6 +13,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"os/exec"
"strings" "strings"
"sync" "sync"
@ -162,6 +165,34 @@ func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, logica
client.Close() client.Close()
return nil, err return nil, err
} }
if h, err := sysregistriesv2.AdditionalLayerStoreAuthHelper(endpointSys); err == nil && h != "" {
acf := map[string]struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
IdentityToken string `json:"identityToken,omitempty"`
}{
physicalRef.ref.String(): {
Username: client.auth.Username,
Password: client.auth.Password,
IdentityToken: client.auth.IdentityToken,
},
}
acfD, err := json.Marshal(acf)
if err != nil {
logrus.Warnf("failed to marshal auth config: %v", err)
} else {
cmd := exec.Command(h)
cmd.Stdin = bytes.NewReader(acfD)
if err := cmd.Run(); err != nil {
var stderr string
if ee, ok := err.(*exec.ExitError); ok {
stderr = string(ee.Stderr)
}
logrus.Warnf("Failed to call additional-layer-store-auth-helper (stderr:%s): %v", stderr, err)
}
}
}
return s, nil return s, nil
} }

View File

@ -1,6 +1,7 @@
package manifest package manifest
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"maps" "maps"
@ -296,29 +297,51 @@ func OCI1IndexPublicFromComponents(components []imgspecv1.Descriptor, annotation
}, },
} }
for i, component := range components { for i, component := range components {
var platform *imgspecv1.Platform index.Manifests[i] = oci1DescriptorClone(component)
if component.Platform != nil {
platformCopy := ociPlatformClone(*component.Platform)
platform = &platformCopy
}
m := imgspecv1.Descriptor{
MediaType: component.MediaType,
ArtifactType: component.ArtifactType,
Size: component.Size,
Digest: component.Digest,
URLs: slices.Clone(component.URLs),
Annotations: maps.Clone(component.Annotations),
Platform: platform,
}
index.Manifests[i] = m
} }
return &index return &index
} }
func oci1DescriptorClone(d imgspecv1.Descriptor) imgspecv1.Descriptor {
var platform *imgspecv1.Platform
if d.Platform != nil {
platformCopy := ociPlatformClone(*d.Platform)
platform = &platformCopy
}
return imgspecv1.Descriptor{
MediaType: d.MediaType,
Digest: d.Digest,
Size: d.Size,
URLs: slices.Clone(d.URLs),
Annotations: maps.Clone(d.Annotations),
Data: bytes.Clone(d.Data),
Platform: platform,
ArtifactType: d.ArtifactType,
}
}
// OCI1IndexPublicClone creates a deep copy of the passed-in index. // OCI1IndexPublicClone creates a deep copy of the passed-in index.
// This is publicly visible as c/image/manifest.OCI1IndexClone. // This is publicly visible as c/image/manifest.OCI1IndexClone.
func OCI1IndexPublicClone(index *OCI1IndexPublic) *OCI1IndexPublic { func OCI1IndexPublicClone(index *OCI1IndexPublic) *OCI1IndexPublic {
return OCI1IndexPublicFromComponents(index.Manifests, index.Annotations) var subject *imgspecv1.Descriptor
if index.Subject != nil {
s := oci1DescriptorClone(*index.Subject)
subject = &s
}
manifests := make([]imgspecv1.Descriptor, len(index.Manifests))
for i, m := range index.Manifests {
manifests[i] = oci1DescriptorClone(m)
}
return &OCI1IndexPublic{
Index: imgspecv1.Index{
Versioned: index.Versioned,
MediaType: index.MediaType,
ArtifactType: index.ArtifactType,
Manifests: manifests,
Subject: subject,
Annotations: maps.Clone(index.Annotations),
},
}
} }
// ToOCI1Index returns the index encoded as an OCI1 index. // ToOCI1Index returns the index encoded as an OCI1 index.

View File

@ -248,6 +248,11 @@ type V2RegistriesConf struct {
// potentially use all unqualified-search registries // potentially use all unqualified-search registries
ShortNameMode string `toml:"short-name-mode"` ShortNameMode string `toml:"short-name-mode"`
// AdditionalLayerStoreAuthHelper is a helper binary that receives
// registry credentials pass them to Additional Layer Store for
// registry authentication. These credentials are only collected when pulling (not pushing).
AdditionalLayerStoreAuthHelper string `toml:"additional-layer-store-auth-helper"`
shortNameAliasConf shortNameAliasConf
// If you add any field, make sure to update Nonempty() below. // If you add any field, make sure to update Nonempty() below.
@ -825,6 +830,16 @@ func CredentialHelpers(sys *types.SystemContext) ([]string, error) {
return config.partialV2.CredentialHelpers, nil return config.partialV2.CredentialHelpers, nil
} }
// AdditionalLayerStoreAuthHelper returns the helper for passing registry
// credentials to Additional Layer Store.
func AdditionalLayerStoreAuthHelper(sys *types.SystemContext) (string, error) {
config, err := getConfig(sys)
if err != nil {
return "", err
}
return config.partialV2.AdditionalLayerStoreAuthHelper, nil
}
// refMatchingSubdomainPrefix returns the length of ref // refMatchingSubdomainPrefix returns the length of ref
// iff ref, which is a registry, repository namespace, repository or image reference (as formatted by // iff ref, which is a registry, repository namespace, repository or image reference (as formatted by
// reference.Domain(), reference.Named.Name() or reference.Reference.String() // reference.Domain(), reference.Named.Name() or reference.Reference.String()
@ -1051,6 +1066,11 @@ func (c *parsedConfig) updateWithConfigurationFrom(updates *parsedConfig) {
c.shortNameMode = updates.shortNameMode c.shortNameMode = updates.shortNameMode
} }
// == Merge AdditionalLayerStoreAuthHelper:
if updates.partialV2.AdditionalLayerStoreAuthHelper != "" {
c.partialV2.AdditionalLayerStoreAuthHelper = updates.partialV2.AdditionalLayerStoreAuthHelper
}
// == Merge aliasCache: // == Merge aliasCache:
// We dont maintain (in fact we actively clear) c.partialV2.shortNameAliasConf. // We dont maintain (in fact we actively clear) c.partialV2.shortNameAliasConf.
c.aliasCache.updateWithConfigurationFrom(updates.aliasCache) c.aliasCache.updateWithConfigurationFrom(updates.aliasCache)

View File

@ -15,6 +15,7 @@ import (
"github.com/containers/image/v5/signature/internal" "github.com/containers/image/v5/signature/internal"
"github.com/containers/storage/pkg/homedir" "github.com/containers/storage/pkg/homedir"
// This is a fallback code; the primary recommendation is to use the gpgme mechanism // This is a fallback code; the primary recommendation is to use the gpgme mechanism
// implementation, which is out-of-process and more appropriate for handling long-term private key material // implementation, which is out-of-process and more appropriate for handling long-term private key material
// than any Go implementation. // than any Go implementation.
@ -150,7 +151,7 @@ func (m *openpgpSigningMechanism) Verify(unverifiedSignature []byte) (contents [
return nil, "", fmt.Errorf("signature error: %v", md.SignatureError) return nil, "", fmt.Errorf("signature error: %v", md.SignatureError)
} }
if md.SignedBy == nil { if md.SignedBy == nil {
return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Invalid GPG signature: %#v", md.Signature)) return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Key not found for key ID %x in signature", md.SignedByKeyId))
} }
if md.Signature != nil { if md.Signature != nil {
if md.Signature.SigLifetimeSecs != nil { if md.Signature.SigLifetimeSecs != nil {

View File

@ -325,7 +325,13 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces
if out.UncompressedDigest != "" { if out.UncompressedDigest != "" {
// The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is // The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is
// responsible for ensuring blobDigest has been validated. // responsible for ensuring blobDigest has been validated.
if out.CompressedDigest != blobDigest {
return private.UploadedBlob{}, fmt.Errorf("internal error: ApplyDiffWithDiffer returned CompressedDigest %q not matching expected %q",
out.CompressedDigest, blobDigest)
}
s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest
// We trust ApplyDiffWithDiffer to validate or create both values correctly.
options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest)
} else { } else {
// Dont identify layers by TOC if UncompressedDigest is available. // Dont identify layers by TOC if UncompressedDigest is available.
// - Using UncompressedDigest allows image reuse with non-partially-pulled layers // - Using UncompressedDigest allows image reuse with non-partially-pulled layers

View File

@ -46,7 +46,14 @@ func tryProcFilter(args []string, input io.Reader, cleanup func()) (io.ReadClose
go func() { go func() {
err := cmd.Run() err := cmd.Run()
if err != nil && stderrBuf.Len() > 0 { if err != nil && stderrBuf.Len() > 0 {
err = fmt.Errorf("%s: %w", strings.TrimRight(stderrBuf.String(), "\n"), err) b := make([]byte, 1)
// if there is an error reading from input, prefer to return that error
_, errRead := input.Read(b)
if errRead != nil && errRead != io.EOF {
err = errRead
} else {
err = fmt.Errorf("%s: %w", strings.TrimRight(stderrBuf.String(), "\n"), err)
}
} }
w.CloseWithError(err) // CloseWithErr(nil) == Close() w.CloseWithError(err) // CloseWithErr(nil) == Close()
cleanup() cleanup()

View File

@ -17,6 +17,7 @@ package name
import ( import (
// nolint: depguard // nolint: depguard
_ "crypto/sha256" // Recommended by go-digest. _ "crypto/sha256" // Recommended by go-digest.
"encoding/json"
"strings" "strings"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
@ -59,6 +60,25 @@ func (d Digest) String() string {
return d.original return d.original
} }
// MarshalJSON formats the digest into a string for JSON serialization.
func (d Digest) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
// UnmarshalJSON parses a JSON string into a Digest.
func (d *Digest) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
n, err := NewDigest(s)
if err != nil {
return err
}
*d = n
return nil
}
// NewDigest returns a new Digest representing the given name. // NewDigest returns a new Digest representing the given name.
func NewDigest(name string, opts ...Option) (Digest, error) { func NewDigest(name string, opts ...Option) (Digest, error) {
// Split on "@" // Split on "@"

81
vendor/github.com/sylabs/sif/v2/pkg/sif/add.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package sif
import (
"fmt"
"time"
)
// addOpts accumulates object add options.
type addOpts struct {
t time.Time
}
// AddOpt are used to specify object add options.
type AddOpt func(*addOpts) error
// OptAddDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptAddDeterministic() AddOpt {
return func(ao *addOpts) error {
ao.t = time.Time{}
return nil
}
}
// OptAddWithTime specifies t as the image modification time.
func OptAddWithTime(t time.Time) AddOpt {
return func(ao *addOpts) error {
ao.t = t
return nil
}
}
// AddObject adds a new data object and its descriptor into the specified SIF file.
//
// By default, the image modification time is set to the current time for non-deterministic images,
// and unset otherwise. To override this, consider using OptAddDeterministic or OptAddWithTime.
func (f *FileImage) AddObject(di DescriptorInput, opts ...AddOpt) error {
ao := addOpts{}
if !f.isDeterministic() {
ao.t = time.Now()
}
for _, opt := range opts {
if err := opt(&ao); err != nil {
return fmt.Errorf("%w", err)
}
}
// Find an unused descriptor.
i := 0
for _, rd := range f.rds {
if !rd.Used {
break
}
i++
}
if err := f.writeDataObject(i, di, ao.t); err != nil {
return fmt.Errorf("%w", err)
}
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.ModifiedAt = ao.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved. // Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved. // Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved. // Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the // This software is licensed under a 3-clause BSD license. Please consult the
@ -8,7 +8,6 @@
package sif package sif
import ( import (
"encoding"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
@ -56,6 +55,20 @@ func writeDataObjectAt(ws io.WriteSeeker, offsetUnaligned int64, di DescriptorIn
return nil return nil
} }
// calculatedDataSize calculates the size of the data section based on the in-use descriptors.
func (f *FileImage) calculatedDataSize() int64 {
dataEnd := f.DataOffset()
f.WithDescriptors(func(d Descriptor) bool {
if objectEnd := d.Offset() + d.Size(); dataEnd < objectEnd {
dataEnd = objectEnd
}
return false
})
return dataEnd - f.DataOffset()
}
var ( var (
errInsufficientCapacity = errors.New("insufficient descriptor capacity to add data object(s) to image") errInsufficientCapacity = errors.New("insufficient descriptor capacity to add data object(s) to image")
errPrimaryPartition = errors.New("image already contains a primary partition") errPrimaryPartition = errors.New("image already contains a primary partition")
@ -81,6 +94,8 @@ func (f *FileImage) writeDataObject(i int, di DescriptorInput, t time.Time) erro
d := &f.rds[i] d := &f.rds[i]
d.ID = uint32(i) + 1 d.ID = uint32(i) + 1
f.h.DataSize = f.calculatedDataSize()
if err := writeDataObjectAt(f.rw, f.h.DataOffset+f.h.DataSize, di, t, d); err != nil { if err := writeDataObjectAt(f.rw, f.h.DataOffset+f.h.DataSize, di, t, d); err != nil {
return err return err
} }
@ -321,378 +336,3 @@ func CreateContainerAtPath(path string, opts ...CreateOpt) (*FileImage, error) {
f.closeOnUnload = true f.closeOnUnload = true
return f, nil return f, nil
} }
// addOpts accumulates object add options.
type addOpts struct {
t time.Time
}
// AddOpt are used to specify object add options.
type AddOpt func(*addOpts) error
// OptAddDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptAddDeterministic() AddOpt {
return func(ao *addOpts) error {
ao.t = time.Time{}
return nil
}
}
// OptAddWithTime specifies t as the image modification time.
func OptAddWithTime(t time.Time) AddOpt {
return func(ao *addOpts) error {
ao.t = t
return nil
}
}
// AddObject adds a new data object and its descriptor into the specified SIF file.
//
// By default, the image modification time is set to the current time for non-deterministic images,
// and unset otherwise. To override this, consider using OptAddDeterministic or OptAddWithTime.
func (f *FileImage) AddObject(di DescriptorInput, opts ...AddOpt) error {
ao := addOpts{}
if !f.isDeterministic() {
ao.t = time.Now()
}
for _, opt := range opts {
if err := opt(&ao); err != nil {
return fmt.Errorf("%w", err)
}
}
// Find an unused descriptor.
i := 0
for _, rd := range f.rds {
if !rd.Used {
break
}
i++
}
if err := f.writeDataObject(i, di, ao.t); err != nil {
return fmt.Errorf("%w", err)
}
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.ModifiedAt = ao.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}
// isLast return true if the data object associated with d is the last in f.
func (f *FileImage) isLast(d *rawDescriptor) bool {
isLast := true
end := d.Offset + d.Size
f.WithDescriptors(func(d Descriptor) bool {
isLast = d.Offset()+d.Size() <= end
return !isLast
})
return isLast
}
// zeroReader is an io.Reader that returns a stream of zero-bytes.
type zeroReader struct{}
func (zeroReader) Read(b []byte) (int, error) {
for i := range b {
b[i] = 0
}
return len(b), nil
}
// zero overwrites the data object described by d with a stream of zero bytes.
func (f *FileImage) zero(d *rawDescriptor) error {
if _, err := f.rw.Seek(d.Offset, io.SeekStart); err != nil {
return err
}
_, err := io.CopyN(f.rw, zeroReader{}, d.Size)
return err
}
// truncateAt truncates f at the start of the padded data object described by d.
func (f *FileImage) truncateAt(d *rawDescriptor) error {
start := d.Offset + d.Size - d.SizeWithPadding
return f.rw.Truncate(start)
}
// deleteOpts accumulates object deletion options.
type deleteOpts struct {
zero bool
compact bool
t time.Time
}
// DeleteOpt are used to specify object deletion options.
type DeleteOpt func(*deleteOpts) error
// OptDeleteZero specifies whether the deleted object should be zeroed.
func OptDeleteZero(b bool) DeleteOpt {
return func(do *deleteOpts) error {
do.zero = b
return nil
}
}
// OptDeleteCompact specifies whether the image should be compacted following object deletion.
func OptDeleteCompact(b bool) DeleteOpt {
return func(do *deleteOpts) error {
do.compact = b
return nil
}
}
// OptDeleteDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptDeleteDeterministic() DeleteOpt {
return func(do *deleteOpts) error {
do.t = time.Time{}
return nil
}
}
// OptDeleteWithTime specifies t as the image modification time.
func OptDeleteWithTime(t time.Time) DeleteOpt {
return func(do *deleteOpts) error {
do.t = t
return nil
}
}
var errCompactNotImplemented = errors.New("compact not implemented for non-last object")
// DeleteObject deletes the data object with id, according to opts.
//
// To zero the data region of the deleted object, use OptDeleteZero. To compact the file following
// object deletion, use OptDeleteCompact.
//
// By default, the image modification time is set to the current time for non-deterministic images,
// and unset otherwise. To override this, consider using OptDeleteDeterministic or
// OptDeleteWithTime.
func (f *FileImage) DeleteObject(id uint32, opts ...DeleteOpt) error {
do := deleteOpts{}
if !f.isDeterministic() {
do.t = time.Now()
}
for _, opt := range opts {
if err := opt(&do); err != nil {
return fmt.Errorf("%w", err)
}
}
d, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if do.compact && !f.isLast(d) {
return fmt.Errorf("%w", errCompactNotImplemented)
}
if do.zero {
if err := f.zero(d); err != nil {
return fmt.Errorf("%w", err)
}
}
if do.compact {
if err := f.truncateAt(d); err != nil {
return fmt.Errorf("%w", err)
}
f.h.DataSize -= d.SizeWithPadding
}
f.h.DescriptorsFree++
f.h.ModifiedAt = do.t.Unix()
// If we remove the primary partition, set the global header Arch field to HdrArchUnknown
// to indicate that the SIF file doesn't include a primary partition and no dependency
// on any architecture exists.
if d.isPartitionOfType(PartPrimSys) {
f.h.Arch = hdrArchUnknown
}
// Reset rawDescripter with empty struct
*d = rawDescriptor{}
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}
// setOpts accumulates object set options.
type setOpts struct {
t time.Time
}
// SetOpt are used to specify object set options.
type SetOpt func(*setOpts) error
// OptSetDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptSetDeterministic() SetOpt {
return func(so *setOpts) error {
so.t = time.Time{}
return nil
}
}
// OptSetWithTime specifies t as the image/object modification time.
func OptSetWithTime(t time.Time) SetOpt {
return func(so *setOpts) error {
so.t = t
return nil
}
}
var (
errNotPartition = errors.New("data object not a partition")
errNotSystem = errors.New("data object not a system partition")
)
// SetPrimPart sets the specified system partition to be the primary one.
//
// By default, the image/object modification times are set to the current time for
// non-deterministic images, and unset otherwise. To override this, consider using
// OptSetDeterministic or OptSetWithTime.
func (f *FileImage) SetPrimPart(id uint32, opts ...SetOpt) error {
so := setOpts{}
if !f.isDeterministic() {
so.t = time.Now()
}
for _, opt := range opts {
if err := opt(&so); err != nil {
return fmt.Errorf("%w", err)
}
}
descr, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if descr.DataType != DataPartition {
return fmt.Errorf("%w", errNotPartition)
}
var p partition
if err := descr.getExtra(binaryUnmarshaler{&p}); err != nil {
return fmt.Errorf("%w", err)
}
// if already primary system partition, nothing to do
if p.Parttype == PartPrimSys {
return nil
}
if p.Parttype != PartSystem {
return fmt.Errorf("%w", errNotSystem)
}
// If there is currently a primary system partition, update it.
if d, err := f.getDescriptor(WithPartitionType(PartPrimSys)); err == nil {
var p partition
if err := d.getExtra(binaryUnmarshaler{&p}); err != nil {
return fmt.Errorf("%w", err)
}
p.Parttype = PartSystem
if err := d.setExtra(p); err != nil {
return fmt.Errorf("%w", err)
}
d.ModifiedAt = so.t.Unix()
} else if !errors.Is(err, ErrObjectNotFound) {
return fmt.Errorf("%w", err)
}
// Update the descriptor of the new primary system partition.
p.Parttype = PartPrimSys
if err := descr.setExtra(p); err != nil {
return fmt.Errorf("%w", err)
}
descr.ModifiedAt = so.t.Unix()
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.Arch = p.Arch
f.h.ModifiedAt = so.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}
// SetMetadata sets the metadata of the data object with id to md, according to opts.
//
// By default, the image/object modification times are set to the current time for
// non-deterministic images, and unset otherwise. To override this, consider using
// OptSetDeterministic or OptSetWithTime.
func (f *FileImage) SetMetadata(id uint32, md encoding.BinaryMarshaler, opts ...SetOpt) error {
so := setOpts{}
if !f.isDeterministic() {
so.t = time.Now()
}
for _, opt := range opts {
if err := opt(&so); err != nil {
return fmt.Errorf("%w", err)
}
}
rd, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if err := rd.setExtra(md); err != nil {
return fmt.Errorf("%w", err)
}
rd.ModifiedAt = so.t.Unix()
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.ModifiedAt = so.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}

163
vendor/github.com/sylabs/sif/v2/pkg/sif/delete.go generated vendored Normal file
View File

@ -0,0 +1,163 @@
// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package sif
import (
"fmt"
"io"
"time"
)
// zeroReader is an io.Reader that returns a stream of zero-bytes.
type zeroReader struct{}
func (zeroReader) Read(b []byte) (int, error) {
clear(b)
return len(b), nil
}
// zero overwrites the data object described by d with a stream of zero bytes.
func (f *FileImage) zero(d *rawDescriptor) error {
if _, err := f.rw.Seek(d.Offset, io.SeekStart); err != nil {
return err
}
_, err := io.CopyN(f.rw, zeroReader{}, d.Size)
return err
}
// deleteOpts accumulates object deletion options.
type deleteOpts struct {
zero bool
compact bool
t time.Time
}
// DeleteOpt are used to specify object deletion options.
type DeleteOpt func(*deleteOpts) error
// OptDeleteZero specifies whether the deleted object should be zeroed.
func OptDeleteZero(b bool) DeleteOpt {
return func(do *deleteOpts) error {
do.zero = b
return nil
}
}
// OptDeleteCompact specifies whether the image should be compacted following object deletion.
func OptDeleteCompact(b bool) DeleteOpt {
return func(do *deleteOpts) error {
do.compact = b
return nil
}
}
// OptDeleteDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptDeleteDeterministic() DeleteOpt {
return func(do *deleteOpts) error {
do.t = time.Time{}
return nil
}
}
// OptDeleteWithTime specifies t as the image modification time.
func OptDeleteWithTime(t time.Time) DeleteOpt {
return func(do *deleteOpts) error {
do.t = t
return nil
}
}
// DeleteObject deletes the data object with id, according to opts. If no matching descriptor is
// found, an error wrapping ErrObjectNotFound is returned.
//
// To zero the data region of the deleted object, use OptDeleteZero. To remove unused space at the
// end of the FileImage following object deletion, use OptDeleteCompact.
//
// By default, the image modification time is set to the current time for non-deterministic images,
// and unset otherwise. To override this, consider using OptDeleteDeterministic or
// OptDeleteWithTime.
func (f *FileImage) DeleteObject(id uint32, opts ...DeleteOpt) error {
return f.DeleteObjects(WithID(id), opts...)
}
// DeleteObjects deletes the data objects selected by fn, according to opts. If no descriptors are
// selected by fns, an error wrapping ErrObjectNotFound is returned.
//
// To zero the data region of the deleted object, use OptDeleteZero. To remove unused space at the
// end of the FileImage following object deletion, use OptDeleteCompact.
//
// By default, the image modification time is set to the current time for non-deterministic images,
// and unset otherwise. To override this, consider using OptDeleteDeterministic or
// OptDeleteWithTime.
func (f *FileImage) DeleteObjects(fn DescriptorSelectorFunc, opts ...DeleteOpt) error {
do := deleteOpts{}
if !f.isDeterministic() {
do.t = time.Now()
}
for _, opt := range opts {
if err := opt(&do); err != nil {
return fmt.Errorf("%w", err)
}
}
var selected bool
if err := f.withDescriptors(fn, func(d *rawDescriptor) error {
selected = true
if do.zero {
if err := f.zero(d); err != nil {
return fmt.Errorf("%w", err)
}
}
f.h.DescriptorsFree++
// If we remove the primary partition, set the global header Arch field to HdrArchUnknown
// to indicate that the SIF file doesn't include a primary partition and no dependency
// on any architecture exists.
if d.isPartitionOfType(PartPrimSys) {
f.h.Arch = hdrArchUnknown
}
// Reset rawDescripter with empty struct
*d = rawDescriptor{}
return nil
}); err != nil {
return fmt.Errorf("%w", err)
}
if !selected {
return fmt.Errorf("%w", ErrObjectNotFound)
}
f.h.ModifiedAt = do.t.Unix()
if do.compact {
f.h.DataSize = f.calculatedDataSize()
if err := f.rw.Truncate(f.h.DataOffset + f.h.DataSize); err != nil {
return fmt.Errorf("%w", err)
}
}
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved. // Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved. // Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved. // Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the // This software is licensed under a 3-clause BSD license. Please consult the
@ -92,7 +92,9 @@ func newOCIBlobDigest() *ociBlob {
// MarshalBinary encodes ob into binary format. // MarshalBinary encodes ob into binary format.
func (ob *ociBlob) MarshalBinary() ([]byte, error) { func (ob *ociBlob) MarshalBinary() ([]byte, error) {
ob.digest.Hex = hex.EncodeToString(ob.hasher.Sum(nil)) if ob.digest.Hex == "" {
ob.digest.Hex = hex.EncodeToString(ob.hasher.Sum(nil))
}
return ob.digest.MarshalText() return ob.digest.MarshalText()
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021-2023, Sylabs Inc. All rights reserved. // Copyright (c) 2021-2024, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the // This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE file distributed with the sources of this project regarding your // LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software. // rights to use or distribute this software.
@ -184,10 +184,16 @@ func multiSelectorFunc(fns ...DescriptorSelectorFunc) DescriptorSelectorFunc {
} }
} }
var errNilSelectFunc = errors.New("descriptor selector func must not be nil")
// withDescriptors calls onMatchFn with each in-use descriptor in f for which selectFn returns // withDescriptors calls onMatchFn with each in-use descriptor in f for which selectFn returns
// true. If selectFn or onMatchFn return a non-nil error, the iteration halts, and the error is // true. If selectFn or onMatchFn return a non-nil error, the iteration halts, and the error is
// returned to the caller. // returned to the caller.
func (f *FileImage) withDescriptors(selectFn DescriptorSelectorFunc, onMatchFn func(*rawDescriptor) error) error { func (f *FileImage) withDescriptors(selectFn DescriptorSelectorFunc, onMatchFn func(*rawDescriptor) error) error {
if selectFn == nil {
return errNilSelectFunc
}
for i, d := range f.rds { for i, d := range f.rds {
if !d.Used { if !d.Used {
continue continue

220
vendor/github.com/sylabs/sif/v2/pkg/sif/set.go generated vendored Normal file
View File

@ -0,0 +1,220 @@
// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved.
// Copyright (c) 2017, SingularityWare, LLC. All rights reserved.
// Copyright (c) 2017, Yannick Cote <yhcote@gmail.com> All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE file distributed with the sources of this project regarding your
// rights to use or distribute this software.
package sif
import (
"encoding"
"errors"
"fmt"
"time"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
// setOpts accumulates object set options.
type setOpts struct {
t time.Time
}
// SetOpt are used to specify object set options.
type SetOpt func(*setOpts) error
// OptSetDeterministic sets header/descriptor fields to values that support deterministic
// modification of images.
func OptSetDeterministic() SetOpt {
return func(so *setOpts) error {
so.t = time.Time{}
return nil
}
}
// OptSetWithTime specifies t as the image/object modification time.
func OptSetWithTime(t time.Time) SetOpt {
return func(so *setOpts) error {
so.t = t
return nil
}
}
var (
errNotPartition = errors.New("data object not a partition")
errNotSystem = errors.New("data object not a system partition")
)
// SetPrimPart sets the specified system partition to be the primary one.
//
// By default, the image/object modification times are set to the current time for
// non-deterministic images, and unset otherwise. To override this, consider using
// OptSetDeterministic or OptSetWithTime.
func (f *FileImage) SetPrimPart(id uint32, opts ...SetOpt) error {
so := setOpts{}
if !f.isDeterministic() {
so.t = time.Now()
}
for _, opt := range opts {
if err := opt(&so); err != nil {
return fmt.Errorf("%w", err)
}
}
descr, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if descr.DataType != DataPartition {
return fmt.Errorf("%w", errNotPartition)
}
var p partition
if err := descr.getExtra(binaryUnmarshaler{&p}); err != nil {
return fmt.Errorf("%w", err)
}
// if already primary system partition, nothing to do
if p.Parttype == PartPrimSys {
return nil
}
if p.Parttype != PartSystem {
return fmt.Errorf("%w", errNotSystem)
}
// If there is currently a primary system partition, update it.
if d, err := f.getDescriptor(WithPartitionType(PartPrimSys)); err == nil {
var p partition
if err := d.getExtra(binaryUnmarshaler{&p}); err != nil {
return fmt.Errorf("%w", err)
}
p.Parttype = PartSystem
if err := d.setExtra(p); err != nil {
return fmt.Errorf("%w", err)
}
d.ModifiedAt = so.t.Unix()
} else if !errors.Is(err, ErrObjectNotFound) {
return fmt.Errorf("%w", err)
}
// Update the descriptor of the new primary system partition.
p.Parttype = PartPrimSys
if err := descr.setExtra(p); err != nil {
return fmt.Errorf("%w", err)
}
descr.ModifiedAt = so.t.Unix()
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.Arch = p.Arch
f.h.ModifiedAt = so.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}
// SetMetadata sets the metadata of the data object with id to md, according to opts.
//
// By default, the image/object modification times are set to the current time for
// non-deterministic images, and unset otherwise. To override this, consider using
// OptSetDeterministic or OptSetWithTime.
func (f *FileImage) SetMetadata(id uint32, md encoding.BinaryMarshaler, opts ...SetOpt) error {
so := setOpts{}
if !f.isDeterministic() {
so.t = time.Now()
}
for _, opt := range opts {
if err := opt(&so); err != nil {
return fmt.Errorf("%w", err)
}
}
rd, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if err := rd.setExtra(md); err != nil {
return fmt.Errorf("%w", err)
}
rd.ModifiedAt = so.t.Unix()
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.ModifiedAt = so.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}
// SetOCIBlobDigest updates the digest of the OCI blob object with id to h, according to opts.
//
// By default, the image/object modification times are set to the current time for
// non-deterministic images, and unset otherwise. To override this, consider using
// OptSetDeterministic or OptSetWithTime.
func (f *FileImage) SetOCIBlobDigest(id uint32, h v1.Hash, opts ...SetOpt) error {
rd, err := f.getDescriptor(WithID(id))
if err != nil {
return fmt.Errorf("%w", err)
}
if got := rd.DataType; got != DataOCIRootIndex && got != DataOCIBlob {
return &unexpectedDataTypeError{got, []DataType{DataOCIRootIndex, DataOCIBlob}}
}
so := setOpts{}
if !f.isDeterministic() {
so.t = time.Now()
}
for _, opt := range opts {
if err := opt(&so); err != nil {
return fmt.Errorf("%w", err)
}
}
md := &ociBlob{
digest: h,
}
if err := rd.setExtra(md); err != nil {
return fmt.Errorf("%w", err)
}
rd.ModifiedAt = so.t.Unix()
if err := f.writeDescriptors(); err != nil {
return fmt.Errorf("%w", err)
}
f.h.ModifiedAt = so.t.Unix()
if err := f.writeHeader(); err != nil {
return fmt.Errorf("%w", err)
}
return nil
}

View File

@ -22,10 +22,12 @@ func Sort[S ~[]E, E constraints.Ordered](x S) {
// SortFunc sorts the slice x in ascending order as determined by the cmp // SortFunc sorts the slice x in ascending order as determined by the cmp
// function. This sort is not guaranteed to be stable. // function. This sort is not guaranteed to be stable.
// cmp(a, b) should return a negative number when a < b, a positive number when // cmp(a, b) should return a negative number when a < b, a positive number when
// a > b and zero when a == b. // a > b and zero when a == b or when a is not comparable to b in the sense
// of the formal definition of Strict Weak Ordering.
// //
// SortFunc requires that cmp is a strict weak ordering. // SortFunc requires that cmp is a strict weak ordering.
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
// To indicate 'uncomparable', return 0 from the function.
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
n := len(x) n := len(x)
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp) pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)

40
vendor/modules.txt vendored
View File

@ -107,10 +107,8 @@ github.com/chzyer/readline
# github.com/containerd/cgroups/v3 v3.0.3 # github.com/containerd/cgroups/v3 v3.0.3
## explicit; go 1.18 ## explicit; go 1.18
github.com/containerd/cgroups/v3/cgroup1/stats github.com/containerd/cgroups/v3/cgroup1/stats
# github.com/containerd/containerd v1.7.17 # github.com/containerd/containerd v1.7.18
## explicit; go 1.21 ## explicit; go 1.21
github.com/containerd/containerd/errdefs
github.com/containerd/containerd/log
github.com/containerd/containerd/pkg/userns github.com/containerd/containerd/pkg/userns
github.com/containerd/containerd/platforms github.com/containerd/containerd/platforms
# github.com/containerd/errdefs v0.1.0 # github.com/containerd/errdefs v0.1.0
@ -126,8 +124,8 @@ github.com/containerd/stargz-snapshotter/estargz/errorutil
# github.com/containerd/typeurl/v2 v2.1.1 # github.com/containerd/typeurl/v2 v2.1.1
## explicit; go 1.13 ## explicit; go 1.13
github.com/containerd/typeurl/v2 github.com/containerd/typeurl/v2
# github.com/containernetworking/cni v1.1.2 # github.com/containernetworking/cni v1.2.2
## explicit; go 1.14 ## explicit; go 1.21
github.com/containernetworking/cni/libcni github.com/containernetworking/cni/libcni
github.com/containernetworking/cni/pkg/invoke github.com/containernetworking/cni/pkg/invoke
github.com/containernetworking/cni/pkg/types github.com/containernetworking/cni/pkg/types
@ -141,8 +139,8 @@ github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.5.1 # github.com/containernetworking/plugins v1.5.1
## explicit; go 1.20 ## explicit; go 1.20
github.com/containernetworking/plugins/pkg/ns github.com/containernetworking/plugins/pkg/ns
# github.com/containers/buildah v1.36.0 # github.com/containers/buildah v1.36.1-0.20240715114330-4a82e0a3f382
## explicit; go 1.21 ## explicit; go 1.21.0
github.com/containers/buildah github.com/containers/buildah
github.com/containers/buildah/bind github.com/containers/buildah/bind
github.com/containers/buildah/chroot github.com/containers/buildah/chroot
@ -171,8 +169,8 @@ github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util github.com/containers/buildah/pkg/util
github.com/containers/buildah/pkg/volumes github.com/containers/buildah/pkg/volumes
github.com/containers/buildah/util github.com/containers/buildah/util
# github.com/containers/common v0.59.1-0.20240603155017-49ad520556e7 # github.com/containers/common v0.59.1-0.20240715151621-fdf625dfee0e
## explicit; go 1.21 ## explicit; go 1.21.0
github.com/containers/common/internal github.com/containers/common/internal
github.com/containers/common/internal/attributedstring github.com/containers/common/internal/attributedstring
github.com/containers/common/libimage github.com/containers/common/libimage
@ -244,8 +242,8 @@ github.com/containers/conmon/runner/config
# github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70 # github.com/containers/gvisor-tap-vsock v0.7.4-0.20240515153903-01a1a0cd3f70
## explicit; go 1.20 ## explicit; go 1.20
github.com/containers/gvisor-tap-vsock/pkg/types github.com/containers/gvisor-tap-vsock/pkg/types
# github.com/containers/image/v5 v5.31.1-0.20240603155732-aa935041e316 # github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516
## explicit; go 1.21 ## explicit; go 1.21.0
github.com/containers/image/v5/copy github.com/containers/image/v5/copy
github.com/containers/image/v5/directory github.com/containers/image/v5/directory
github.com/containers/image/v5/directory/explicitfilepath github.com/containers/image/v5/directory/explicitfilepath
@ -325,7 +323,7 @@ github.com/containers/libhvee/pkg/wmiext
# github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 # github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01
## explicit ## explicit
github.com/containers/libtrust github.com/containers/libtrust
# github.com/containers/luksy v0.0.0-20240506205542-84b50f50f3ee # github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c
## explicit; go 1.20 ## explicit; go 1.20
github.com/containers/luksy github.com/containers/luksy
# github.com/containers/ocicrypt v1.2.0 # github.com/containers/ocicrypt v1.2.0
@ -355,7 +353,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process github.com/containers/psgo/internal/process
# github.com/containers/storage v1.54.1-0.20240712121534-ab74785ce9e8 # github.com/containers/storage v1.54.1-0.20240712125645-98ad80d6d165
## explicit; go 1.21 ## explicit; go 1.21
github.com/containers/storage github.com/containers/storage
github.com/containers/storage/drivers github.com/containers/storage/drivers
@ -656,7 +654,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.19.1 # github.com/google/go-containerregistry v0.20.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
@ -884,7 +882,7 @@ github.com/opencontainers/go-digest
## explicit; go 1.18 ## explicit; go 1.18
github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1 github.com/opencontainers/image-spec/specs-go/v1
# github.com/opencontainers/runc v1.1.12 => github.com/opencontainers/runc v1.1.1-0.20240131200429-02120488a4c0 # github.com/opencontainers/runc v1.1.13 => github.com/opencontainers/runc v1.1.1-0.20240131200429-02120488a4c0
## explicit; go 1.20 ## explicit; go 1.20
github.com/opencontainers/runc/libcontainer/apparmor github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups github.com/opencontainers/runc/libcontainer/cgroups
@ -1027,8 +1025,8 @@ github.com/stefanberger/go-pkcs11uri
## explicit; go 1.17 ## explicit; go 1.17
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
github.com/stretchr/testify/require github.com/stretchr/testify/require
# github.com/sylabs/sif/v2 v2.16.0 # github.com/sylabs/sif/v2 v2.18.0
## explicit; go 1.21 ## explicit; go 1.21.0
github.com/sylabs/sif/v2/pkg/sif github.com/sylabs/sif/v2/pkg/sif
# github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 # github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
## explicit ## explicit
@ -1178,12 +1176,12 @@ golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/knownhosts
golang.org/x/crypto/twofish golang.org/x/crypto/twofish
golang.org/x/crypto/xts golang.org/x/crypto/xts
# golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc # golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
## 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.17.0 # golang.org/x/mod v0.18.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/mod/semver golang.org/x/mod/semver
golang.org/x/mod/sumdb/note golang.org/x/mod/sumdb/note
@ -1203,7 +1201,7 @@ golang.org/x/net/internal/socks
golang.org/x/net/internal/timeseries golang.org/x/net/internal/timeseries
golang.org/x/net/proxy golang.org/x/net/proxy
golang.org/x/net/trace golang.org/x/net/trace
# golang.org/x/oauth2 v0.20.0 # golang.org/x/oauth2 v0.21.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/oauth2 golang.org/x/oauth2
golang.org/x/oauth2/internal golang.org/x/oauth2/internal
@ -1247,7 +1245,7 @@ golang.org/x/text/unicode/norm
# golang.org/x/time v0.5.0 # golang.org/x/time v0.5.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/time/rate golang.org/x/time/rate
# golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d # golang.org/x/tools v0.22.0
## explicit; go 1.19 ## explicit; go 1.19
golang.org/x/tools/cover golang.org/x/tools/cover
golang.org/x/tools/go/ast/inspector golang.org/x/tools/go/ast/inspector