diff --git a/go.mod b/go.mod index aa65a178c..7ba5bb583 100644 --- a/go.mod +++ b/go.mod @@ -12,15 +12,15 @@ require ( github.com/containerd/containerd v1.7.18 github.com/containernetworking/cni v1.2.2 github.com/containernetworking/plugins v1.5.1 - github.com/containers/image/v5 v5.31.1 + github.com/containers/image/v5 v5.31.1-0.20240625185001-825c645ee42e github.com/containers/ocicrypt v1.1.10 - github.com/containers/storage v1.54.0 + github.com/containers/storage v1.54.1-0.20240626141655-3b6406632da1 github.com/coreos/go-systemd/v22 v22.5.0 github.com/cyphar/filepath-securejoin v0.2.5 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/disiqueira/gotree/v3 v3.0.2 github.com/docker/distribution v2.8.3+incompatible - github.com/docker/docker v26.1.4+incompatible + github.com/docker/docker v27.0.1+incompatible github.com/docker/go-units v0.5.0 github.com/fsnotify/fsnotify v1.7.0 github.com/godbus/dbus/v5 v5.1.0 @@ -58,7 +58,7 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Microsoft/hcsshim v0.12.3 // indirect + github.com/Microsoft/hcsshim v0.12.4 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect @@ -71,10 +71,11 @@ require ( github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker-credential-helpers v0.8.1 // indirect + github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect @@ -92,7 +93,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // 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.19.2 // indirect github.com/google/go-intervals v0.0.2 // indirect github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/google/uuid v1.6.0 // indirect @@ -100,10 +101,10 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/kr/fs v0.1.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect + github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect @@ -124,9 +125,9 @@ require ( github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/sigstore/fulcio v1.4.5 // indirect github.com/sigstore/rekor v1.3.6 // indirect - github.com/sigstore/sigstore v1.8.3 // indirect + github.com/sigstore/sigstore v1.8.4 // 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.17.0 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/ulikunitz/xz v0.5.12 // indirect @@ -146,7 +147,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 81a610c4d..40802d2ca 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.12.3 h1:LS9NXqXhMoqNCplK1ApmVSfB4UnVLRDWRapB6EIlxE0= -github.com/Microsoft/hcsshim v0.12.3/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ= +github.com/Microsoft/hcsshim v0.12.4 h1:Ev7YUMHAHoWNm+aDSPzc5W9s6E2jyL1szpVDJeZ/Rr4= +github.com/Microsoft/hcsshim v0.12.4/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= @@ -59,14 +59,14 @@ github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw 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/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM= -github.com/containers/image/v5 v5.31.1 h1:3x9soI6Biml/GiDLpkSmKrkRSwVGctxu/vONpoUdklA= -github.com/containers/image/v5 v5.31.1/go.mod h1:5QfOqSackPkSbF7Qxc1DnVNnPJKQ+KWLkfEfDpK590Q= +github.com/containers/image/v5 v5.31.1-0.20240625185001-825c645ee42e h1:LpiU4M3/AbWvsVeir/cvAZM5407qGU1nOS/QqPAUGWA= +github.com/containers/image/v5 v5.31.1-0.20240625185001-825c645ee42e/go.mod h1:ypu8lOh6/6lI1wDXkRN0WepD1Dc/GU4QpiBJMnK6WFY= 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/ocicrypt v1.1.10 h1:r7UR6o8+lyhkEywetubUUgcKFjOWOaWz8cEBrCPX0ic= github.com/containers/ocicrypt v1.1.10/go.mod h1:YfzSSr06PTHQwSTUKqDSjish9BeW1E4HUmreluQcMd8= -github.com/containers/storage v1.54.0 h1:xwYAlf6n9OnIlURQLLg3FYHbO74fQ/2W2N6EtQEUM4I= -github.com/containers/storage v1.54.0/go.mod h1:PlMOoinRrBSnhYODLxt4EXl0nmJt+X0kjG0Xdt9fMTw= +github.com/containers/storage v1.54.1-0.20240626141655-3b6406632da1 h1:OPlAEpvduSljsEBLicQRC9YoSdzrJfzfi0ZWdN0IZvI= +github.com/containers/storage v1.54.1-0.20240626141655-3b6406632da1/go.mod h1:y1CGloHDYq9uK3Og/zLkrJ8vpSuFwNaIWOyB8IX076w= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -82,14 +82,14 @@ 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/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/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc= -github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v27.0.1+incompatible h1:d/OrlblkOTkhJ1IaAGD1bLgUBtFQC/oP0VjkFMIN+B0= +github.com/docker/cli v27.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU= -github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= -github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/docker v27.0.1+incompatible h1:AbszR+lCnR3f297p/g0arbQoyhAkImxQOR/XO9YZeIg= +github.com/docker/docker v27.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= +github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -108,6 +108,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= +github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -167,8 +169,8 @@ github.com/google/go-cmp v0.5.3/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 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.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/google/go-containerregistry v0.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w= +github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -199,8 +201,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -209,8 +211,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU= +github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 h1:aiPrFdHDCCvigNBCkOWj2lv9Bx5xDp210OANZEoiP0I= +github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0/go.mod h1:srVwm2N3DC/tWqQ+igZXDrmKlNRN8X/dmJ1wEZrv760= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= @@ -296,8 +298,8 @@ github.com/sigstore/fulcio v1.4.5 h1:WWNnrOknD0DbruuZWCbN+86WRROpEl3Xts+WT2Ek1yc github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8= github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= -github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4= -github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs= +github.com/sigstore/sigstore v1.8.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w= +github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -316,8 +318,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/sylabs/sif/v2 v2.16.0 h1:2eqaBaQQsn5DZTzm3QZm0HupZQEjNXfxRnCmtyCihEU= -github.com/sylabs/sif/v2 v2.16.0/go.mod h1:d5TxgD/mhMUU3kWLmZmWJQ99Wg0asaTP0bq3ezR1xpg= +github.com/sylabs/sif/v2 v2.17.0 h1:edml4cdWbodiQCL33hUQTa7IxYuFqUy96p1PRSgzdUg= +github.com/sylabs/sif/v2 v2.17.0/go.mod h1:7rW8RU2rxScWLPqkKVK+HKaOBMnqe8mXjHKWPbvI8w0= 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/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= @@ -498,8 +500,6 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh 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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= -gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go index 082c018a4..e97e4f631 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go @@ -57,9 +57,10 @@ type PaPolicy struct { type OutboundNatPolicy struct { Policy - VIP string `json:"VIP,omitempty"` - Exceptions []string `json:"ExceptionList,omitempty"` - Destinations []string `json:",omitempty"` + VIP string `json:"VIP,omitempty"` + Exceptions []string `json:"ExceptionList,omitempty"` + Destinations []string `json:",omitempty"` + MaxPortPoolUsage uint16 `json:",omitempty"` } type ProxyPolicy struct { diff --git a/vendor/github.com/containers/image/v5/docker/docker_client.go b/vendor/github.com/containers/image/v5/docker/docker_client.go index 94cbcb1d9..6b65c52ed 100644 --- a/vendor/github.com/containers/image/v5/docker/docker_client.go +++ b/vendor/github.com/containers/image/v5/docker/docker_client.go @@ -147,10 +147,22 @@ const ( noAuth ) -func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) { +// 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 { + return nil, err + } + token := new(bearerToken) if err := json.Unmarshal(blob, &token); err != nil { - return nil, err + 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) } if token.Token == "" { token.Token = token.AccessToken @@ -827,12 +839,7 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall return nil, err } - tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) - if err != nil { - return nil, err - } - - return newBearerTokenFromJSONBlob(tokenBlob) + return newBearerTokenFromHTTPResponseBody(res) } func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, @@ -878,12 +885,8 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, if err := httpResponseToError(res, "Requesting bearer token"); err != nil { return nil, err } - tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) - if err != nil { - return nil, err - } - return newBearerTokenFromJSONBlob(tokenBlob) + return newBearerTokenFromHTTPResponseBody(res) } // detectPropertiesHelper performs the work of detectProperties which executes diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_src.go b/vendor/github.com/containers/image/v5/docker/docker_image_src.go index a2b6dbed7..c8f6ba305 100644 --- a/vendor/github.com/containers/image/v5/docker/docker_image_src.go +++ b/vendor/github.com/containers/image/v5/docker/docker_image_src.go @@ -1,7 +1,9 @@ package docker import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -11,6 +13,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "strings" "sync" @@ -162,6 +165,34 @@ func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, logica client.Close() 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 } diff --git a/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go b/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go index 037572b0e..b413ec513 100644 --- a/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go +++ b/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go @@ -74,3 +74,15 @@ func DefaultCache(sys *types.SystemContext) types.BlobInfoCache { logrus.Debugf("Using SQLite blob info cache at %s", path) return cache } + +// CleanupDefaultCache removes the blob info cache directory. +// It deletes the cache directory but it does not affect any file or memory buffer currently +// in use. +func CleanupDefaultCache(sys *types.SystemContext) error { + dir, err := blobInfoCacheDir(sys, rootless.GetRootlessEUID()) + if err != nil { + // Mirror the DefaultCache behavior that does not fail in this case + return nil + } + return os.RemoveAll(dir) +} diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go index 45427a350..1b161474d 100644 --- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go +++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go @@ -248,6 +248,11 @@ type V2RegistriesConf struct { // potentially use all unqualified-search registries 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 // 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 } +// 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 // iff ref, which is a registry, repository namespace, repository or image reference (as formatted by // reference.Domain(), reference.Named.Name() or reference.Reference.String() @@ -1051,6 +1066,11 @@ func (c *parsedConfig) updateWithConfigurationFrom(updates *parsedConfig) { c.shortNameMode = updates.shortNameMode } + // == Merge AdditionalLayerStoreAuthHelper: + if updates.partialV2.AdditionalLayerStoreAuthHelper != "" { + c.partialV2.AdditionalLayerStoreAuthHelper = updates.partialV2.AdditionalLayerStoreAuthHelper + } + // == Merge aliasCache: // We don’t maintain (in fact we actively clear) c.partialV2.shortNameAliasConf. c.aliasCache.updateWithConfigurationFrom(updates.aliasCache) diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go index 9e0338158..7eee41227 100644 --- a/vendor/github.com/containers/image/v5/version/version.go +++ b/vendor/github.com/containers/image/v5/version/version.go @@ -6,12 +6,12 @@ const ( // VersionMajor is for an API incompatible changes VersionMajor = 5 // VersionMinor is for functionality in a backwards-compatible manner - VersionMinor = 31 + VersionMinor = 32 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 1 + VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "" + VersionDev = "-dev" ) // Version is the specification version that the package types support. diff --git a/vendor/github.com/containers/storage/.cirrus.yml b/vendor/github.com/containers/storage/.cirrus.yml index c2474c7f2..50b987616 100644 --- a/vendor/github.com/containers/storage/.cirrus.yml +++ b/vendor/github.com/containers/storage/.cirrus.yml @@ -23,7 +23,7 @@ env: # GCE project where images live IMAGE_PROJECT: "libpod-218412" # VM Image built in containers/automation_images - IMAGE_SUFFIX: "c20240513t140131z-f40f39d13" + IMAGE_SUFFIX: "c20240529t141726z-f40f39d13" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}" diff --git a/vendor/github.com/containers/storage/Makefile b/vendor/github.com/containers/storage/Makefile index 7ee2642fc..96ea9f9a5 100644 --- a/vendor/github.com/containers/storage/Makefile +++ b/vendor/github.com/containers/storage/Makefile @@ -53,6 +53,8 @@ local-cross cross: ## cross build the binaries for arm, darwin, and freebsd os=`echo $${target} | cut -f1 -d/` ; \ arch=`echo $${target} | cut -f2 -d/` ; \ suffix=$${os}.$${arch} ; \ + echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) ./... ; \ + env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) ./... || exit 1 ; \ echo env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags \"$(NATIVETAGS) $(TAGS)\" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage ; \ env CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} $(GO) build -compiler gc -tags "$(NATIVETAGS) $(TAGS)" $(FLAGS) -o containers-storage.$${suffix} ./cmd/containers-storage || exit 1 ; \ done diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION index b7921ae87..5c74e39ac 100644 --- a/vendor/github.com/containers/storage/VERSION +++ b/vendor/github.com/containers/storage/VERSION @@ -1 +1 @@ -1.54.0 +1.55.0-dev diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go index e00314d3f..8d001a89e 100644 --- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go +++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go @@ -75,8 +75,6 @@ func init() { type Driver struct { sync.Mutex root string - uidMaps []idtools.IDMap - gidMaps []idtools.IDMap ctr *graphdriver.RefCounter pathCacheLock sync.Mutex pathCache map[string]string @@ -129,22 +127,16 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) a := &Driver{ root: home, - uidMaps: options.UIDMaps, - gidMaps: options.GIDMaps, pathCache: make(map[string]string), ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)), locker: locker.New(), mountOptions: mountOptions, } - rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps) - if err != nil { - return nil, err - } // Create the root aufs driver dir and return // if it already exists // If not populate the dir structure - if err := idtools.MkdirAllAs(home, 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(home, 0o700); err != nil { if os.IsExist(err) { return a, nil } @@ -157,7 +149,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) // Populate the dir structure for _, p := range paths { - if err := idtools.MkdirAllAs(path.Join(home, p), 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(path.Join(home, p), 0o700); err != nil { return nil, err } } @@ -334,7 +326,7 @@ func (a *Driver) createDirsFor(id, parent string) error { // The path of directories are /mnt/ // and /diff/ for _, p := range paths { - rootPair := idtools.NewIDMappingsFromMaps(a.uidMaps, a.gidMaps).RootPair() + rootPair := idtools.IDPair{UID: 0, GID: 0} rootPerms := defaultPerms if parent != "" { st, err := system.Stat(path.Join(a.rootPath(), p, parent)) diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go index 11ae56364..7a0f9cbc7 100644 --- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go +++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go @@ -66,11 +66,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) return nil, fmt.Errorf("%q is not on a btrfs filesystem: %w", home, graphdriver.ErrPrerequisites) } - rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps) - if err != nil { - return nil, err - } - if err := idtools.MkdirAllAs(filepath.Join(home, "subvolumes"), 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(filepath.Join(home, "subvolumes"), 0o700); err != nil { return nil, err } @@ -85,8 +81,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) driver := &Driver{ home: home, - uidMaps: options.UIDMaps, - gidMaps: options.GIDMaps, options: opt, } @@ -129,8 +123,6 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) { type Driver struct { // root of the file system home string - uidMaps []idtools.IDMap - gidMaps []idtools.IDMap options btrfsOptions quotaEnabled bool once sync.Once @@ -481,11 +473,7 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { quotas := d.quotasDir() subvolumes := d.subvolumesDir() - rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) - if err != nil { - return err - } - if err := idtools.MkdirAllAs(subvolumes, 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(subvolumes, 0o700); err != nil { return err } if parent == "" { @@ -523,7 +511,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil { return err } - if err := idtools.MkdirAllAs(quotas, 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(quotas, 0o700); err != nil { return err } if err := os.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0o644); err != nil { @@ -531,14 +519,6 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { } } - // if we have a remapped root (user namespaces enabled), change the created snapshot - // dir ownership to match - if rootUID != 0 || rootGID != 0 { - if err := os.Chown(path.Join(subvolumes, id), rootUID, rootGID); err != nil { - return err - } - } - mountLabel := "" if opts != nil { mountLabel = opts.MountLabel diff --git a/vendor/github.com/containers/storage/drivers/chown.go b/vendor/github.com/containers/storage/drivers/chown.go index ca43c3f05..d728e919b 100644 --- a/vendor/github.com/containers/storage/drivers/chown.go +++ b/vendor/github.com/containers/storage/drivers/chown.go @@ -4,11 +4,12 @@ import ( "bytes" "errors" "fmt" + "io/fs" "os" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/reexec" - "github.com/opencontainers/selinux/pkg/pwalk" + "github.com/opencontainers/selinux/pkg/pwalkdir" ) const ( @@ -54,13 +55,14 @@ func chownByMapsMain() { chowner := newLChowner() - chown := func(path string, info os.FileInfo, _ error) error { - if path == "." { + var chown fs.WalkDirFunc = func(path string, d fs.DirEntry, _ error) error { + info, err := d.Info() + if path == "." || err != nil { return nil } return chowner.LChown(path, info, toHost, toContainer) } - if err := pwalk.Walk(".", chown); err != nil { + if err := pwalkdir.Walk(".", chown); err != nil { fmt.Fprintf(os.Stderr, "error during chown: %v", err) os.Exit(1) } diff --git a/vendor/github.com/containers/storage/drivers/chroot_unix.go b/vendor/github.com/containers/storage/drivers/chroot_unix.go index 9a1c6751f..a65f0d58d 100644 --- a/vendor/github.com/containers/storage/drivers/chroot_unix.go +++ b/vendor/github.com/containers/storage/drivers/chroot_unix.go @@ -1,5 +1,5 @@ -//go:build linux || darwin || freebsd || solaris -// +build linux darwin freebsd solaris +//go:build !windows +// +build !windows package graphdriver diff --git a/vendor/github.com/containers/storage/drivers/copy/copy_linux.go b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go index 9c3d7c668..878940945 100644 --- a/vendor/github.com/containers/storage/drivers/copy/copy_linux.go +++ b/vendor/github.com/containers/storage/drivers/copy/copy_linux.go @@ -50,13 +50,13 @@ func CopyRegularToFile(srcPath string, dstFile *os.File, fileinfo os.FileInfo, c defer srcFile.Close() if *copyWithFileClone { - _, _, err = unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd()) - if err == nil { + _, _, errno := unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd()) + if errno == 0 { return nil } *copyWithFileClone = false - if err == unix.EXDEV { + if errno == unix.EXDEV { *copyWithFileRange = false } } diff --git a/vendor/github.com/containers/storage/drivers/driver.go b/vendor/github.com/containers/storage/drivers/driver.go index b42ba0757..c1495162e 100644 --- a/vendor/github.com/containers/storage/drivers/driver.go +++ b/vendor/github.com/containers/storage/drivers/driver.go @@ -215,20 +215,25 @@ const ( DifferOutputFormatFlat ) +// DifferFsVerity is a part of the experimental Differ interface and should not be used from outside of c/storage. +// It configures the fsverity requirement. type DifferFsVerity int const ( // DifferFsVerityDisabled means no fs-verity is used DifferFsVerityDisabled = iota - // DifferFsVerityEnabled means fs-verity is used when supported - DifferFsVerityEnabled + // DifferFsVerityIfAvailable means fs-verity is used when supported by + // the underlying kernel and filesystem. + DifferFsVerityIfAvailable - // DifferFsVerityRequired means fs-verity is required + // DifferFsVerityRequired means fs-verity is required. Note this is not + // currently set or exposed by the overlay driver. DifferFsVerityRequired ) -// DifferOptions overrides how the differ work +// DifferOptions is a part of the experimental Differ interface and should not be used from outside of c/storage. +// It overrides how the differ works. type DifferOptions struct { // Format defines the destination directory layout format Format DifferOutputFormat @@ -377,8 +382,6 @@ type Options struct { ImageStore string DriverPriority []string DriverOptions []string - UIDMaps []idtools.IDMap - GIDMaps []idtools.IDMap ExperimentalEnabled bool } diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go index 8b6f64b1e..058522898 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "io/fs" "os" "os/exec" "path" @@ -119,8 +120,6 @@ type Driver struct { home string runhome string imageStore string - uidMaps []idtools.IDMap - gidMaps []idtools.IDMap ctr *graphdriver.RefCounter quotaCtl *quota.Control options overlayOptions @@ -332,13 +331,9 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) backingFs = fsName runhome := filepath.Join(options.RunRoot, filepath.Base(home)) - rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps) - if err != nil { - return nil, err - } // Create the driver home dir - if err := idtools.MkdirAllAs(path.Join(home, linkDir), 0o755, 0, 0); err != nil { + if err := os.MkdirAll(path.Join(home, linkDir), 0o755); err != nil { return nil, err } @@ -348,7 +343,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) } } - if err := idtools.MkdirAllAs(runhome, 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(runhome, 0o700); err != nil { return nil, err } @@ -373,9 +368,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) return nil, err } } else { - if opts.forceMask != nil { - return nil, errors.New("'force_mask' is supported only with 'mount_program'") - } // check if they are running over btrfs, aufs, overlay, or ecryptfs switch fsMagic { case graphdriver.FsMagicAufs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs: @@ -457,8 +449,6 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) home: home, imageStore: options.ImageStore, runhome: runhome, - uidMaps: options.UIDMaps, - gidMaps: options.GIDMaps, ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(fileSystemType)), supportsDType: supportsDType, usingMetacopy: usingMetacopy, @@ -983,6 +973,10 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts } } + if d.options.forceMask != nil && d.options.mountProgram == "" { + return fmt.Errorf("overlay: force_mask option for writeable layers is only supported with a mount_program") + } + if _, ok := opts.StorageOpt["size"]; !ok { if opts.StorageOpt == nil { opts.StorageOpt = map[string]string{} @@ -1021,8 +1015,8 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl disableQuota := readOnly - uidMaps := d.uidMaps - gidMaps := d.gidMaps + var uidMaps []idtools.IDMap + var gidMaps []idtools.IDMap if opts != nil && opts.IDMappings != nil { uidMaps = opts.IDMappings.UIDs() @@ -1047,14 +1041,23 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl if err := idtools.MkdirAllAndChownNew(path.Dir(dir), 0o755, idPair); err != nil { return err } + + st := idtools.Stat{IDs: idPair, Mode: defaultPerms} + if parent != "" { parentBase := d.dir(parent) - st, err := system.Stat(filepath.Join(parentBase, "diff")) - if err != nil { - return err + parentDiff := filepath.Join(parentBase, "diff") + if xSt, err := idtools.GetContainersOverrideXattr(parentDiff); err == nil { + st = xSt + } else { + systemSt, err := system.Stat(parentDiff) + if err != nil { + return err + } + st.IDs.UID = int(systemSt.UID()) + st.IDs.GID = int(systemSt.GID()) + st.Mode = os.FileMode(systemSt.Mode()) } - rootUID = int(st.UID()) - rootGID = int(st.GID()) } if err := fileutils.Lexists(dir); err == nil { @@ -1100,22 +1103,21 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl } } - perms := defaultPerms + forcedSt := st if d.options.forceMask != nil { - perms = *d.options.forceMask + forcedSt.IDs = idPair + forcedSt.Mode = *d.options.forceMask } - if parent != "" { - parentBase := d.dir(parent) - st, err := system.Stat(filepath.Join(parentBase, "diff")) - if err != nil { - return err - } - perms = os.FileMode(st.Mode()) + diff := path.Join(dir, "diff") + if err := idtools.MkdirAs(diff, forcedSt.Mode, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil { + return err } - if err := idtools.MkdirAs(path.Join(dir, "diff"), perms, rootUID, rootGID); err != nil { - return err + if d.options.forceMask != nil { + if err := idtools.SetContainersOverrideXattr(diff, st); err != nil { + return err + } } lid := generateID(idLength) @@ -1130,16 +1132,16 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl return err } - if err := idtools.MkdirAs(path.Join(dir, "work"), 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAs(path.Join(dir, "work"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil { return err } - if err := idtools.MkdirAs(path.Join(dir, "merged"), 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAs(path.Join(dir, "merged"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID); err != nil { return err } // if no parent directory, create a dummy lower directory and skip writing a "lowers" file if parent == "" { - return idtools.MkdirAs(path.Join(dir, "empty"), 0o700, rootUID, rootGID) + return idtools.MkdirAs(path.Join(dir, "empty"), 0o700, forcedSt.IDs.UID, forcedSt.IDs.GID) } lower, err := d.getLower(parent) @@ -1283,12 +1285,6 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) { } func (d *Driver) optsAppendMappings(opts string, uidMaps, gidMaps []idtools.IDMap) string { - if uidMaps == nil { - uidMaps = d.uidMaps - } - if gidMaps == nil { - gidMaps = d.gidMaps - } if uidMaps != nil { var uids, gids bytes.Buffer if len(uidMaps) == 1 && uidMaps[0].Size == 1 { @@ -1539,11 +1535,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO for err == nil { absLowers = append(absLowers, filepath.Join(dir, nameWithSuffix("diff", diffN))) diffN++ - st, err = os.Stat(filepath.Join(dir, nameWithSuffix("diff", diffN))) - if err == nil && !permsKnown { - perms = os.FileMode(st.Mode()) - permsKnown = true - } + err = fileutils.Exists(filepath.Join(dir, nameWithSuffix("diff", diffN))) } idmappedMountProcessPid := -1 @@ -2024,11 +2016,27 @@ func (d *Driver) getWhiteoutFormat() archive.WhiteoutFormat { } type overlayFileGetter struct { - diffDirs []string + diffDirs []string + composefsMounts map[string]*os.File // map from diff dir to the directory with the composefs blob mounted } func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) { + buf := make([]byte, unix.PathMax) for _, d := range g.diffDirs { + if f, found := g.composefsMounts[d]; found { + // there is no *at equivalent for getxattr, but it can be emulated by opening the file under /proc/self/fd/$FD/$PATH + len, err := unix.Getxattr(fmt.Sprintf("/proc/self/fd/%d/%s", int(f.Fd()), path), "trusted.overlay.redirect", buf) + if err != nil { + if errors.Is(err, unix.ENODATA) { + continue + } + return nil, &fs.PathError{Op: "getxattr", Path: path, Err: err} + } + + // the xattr value is the path to the file in the composefs layer diff directory + return os.Open(filepath.Join(d, string(buf[:len]))) + } + f, err := os.Open(filepath.Join(d, path)) if err == nil { return f, nil @@ -2041,7 +2049,16 @@ func (g *overlayFileGetter) Get(path string) (io.ReadCloser, error) { } func (g *overlayFileGetter) Close() error { - return nil + var errs *multierror.Error + for _, f := range g.composefsMounts { + if err := f.Close(); err != nil { + errs = multierror.Append(errs, err) + } + if err := unix.Rmdir(f.Name()); err != nil { + errs = multierror.Append(errs, err) + } + } + return errs.ErrorOrNil() } func (d *Driver) getStagingDir(id string) string { @@ -2052,10 +2069,7 @@ func (d *Driver) getStagingDir(id string) string { // DiffGetter returns a FileGetCloser that can read files from the directory that // contains files for the layer differences, either for this layer, or one of our // lowers if we're just a template directory. Used for direct access for tar-split. -func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) { - if d.usingComposefs { - return nil, nil - } +func (d *Driver) DiffGetter(id string) (_ graphdriver.FileGetCloser, Err error) { p, err := d.getDiffPath(id) if err != nil { return nil, err @@ -2064,7 +2078,41 @@ func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) { if err != nil { return nil, err } - return &overlayFileGetter{diffDirs: append([]string{p}, paths...)}, nil + + // map from diff dir to the directory with the composefs blob mounted + composefsMounts := make(map[string]*os.File) + defer func() { + if Err != nil { + for _, f := range composefsMounts { + f.Close() + unix.Rmdir(f.Name()) + } + } + }() + diffDirs := append([]string{p}, paths...) + for _, diffDir := range diffDirs { + // diffDir has the form $GRAPH_ROOT/overlay/$ID/diff, so grab the $ID from the parent directory + id := path.Base(path.Dir(diffDir)) + composefsBlob := d.getComposefsData(id) + if fileutils.Exists(composefsBlob) != nil { + // not a composefs layer, ignore it + continue + } + dir, err := os.MkdirTemp(d.runhome, "composefs-mnt") + if err != nil { + return nil, err + } + if err := mountComposefsBlob(composefsBlob, dir); err != nil { + return nil, err + } + fd, err := os.Open(dir) + if err != nil { + return nil, err + } + composefsMounts[diffDir] = fd + _ = unix.Unmount(dir, unix.MNT_DETACH) + } + return &overlayFileGetter{diffDirs: diffDirs, composefsMounts: composefsMounts}, nil } // CleanupStagingDirectory cleanups the staging directory. @@ -2100,9 +2148,16 @@ func supportsDataOnlyLayersCached(home, runhome string) (bool, error) { // ApplyDiffWithDiffer applies the changes in the new layer using the specified function func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.ApplyDiffWithDifferOpts, differ graphdriver.Differ) (output graphdriver.DriverWithDifferOutput, errRet error) { var idMappings *idtools.IDMappings + var forceMask *os.FileMode + if options != nil { idMappings = options.Mappings + forceMask = options.ForceMask } + if d.options.forceMask != nil { + forceMask = d.options.forceMask + } + if idMappings == nil { idMappings = &idtools.IDMappings{} } @@ -2120,8 +2175,8 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App return graphdriver.DriverWithDifferOutput{}, err } perms := defaultPerms - if d.options.forceMask != nil { - perms = *d.options.forceMask + if forceMask != nil { + perms = *forceMask } applyDir = filepath.Join(layerDir, "dir") if err := os.Mkdir(applyDir, perms); err != nil { @@ -2155,7 +2210,7 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App } if d.usingComposefs { differOptions.Format = graphdriver.DifferOutputFormatFlat - differOptions.UseFsVerity = graphdriver.DifferFsVerityEnabled + differOptions.UseFsVerity = graphdriver.DifferFsVerityIfAvailable } out, err := differ.ApplyDiff(applyDir, &archive.TarOptions{ UIDMaps: idMappings.UIDs(), @@ -2163,6 +2218,7 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App IgnoreChownErrors: d.options.ignoreChownErrors, WhiteoutFormat: d.getWhiteoutFormat(), InUserNS: unshare.IsRootless(), + ForceMask: forceMask, }, &differOptions) out.Target = applyDir @@ -2476,6 +2532,19 @@ func nameWithSuffix(name string, number int) string { return fmt.Sprintf("%s%d", name, number) } +func validateOneAdditionalLayerPath(target string) error { + for _, p := range []string{ + filepath.Join(target, "diff"), + filepath.Join(target, "info"), + filepath.Join(target, "blob"), + } { + if err := fileutils.Exists(p); err != nil { + return err + } + } + return nil +} + func (d *Driver) getAdditionalLayerPath(tocDigest digest.Digest, ref string) (string, error) { refElem := base64.StdEncoding.EncodeToString([]byte(ref)) for _, ls := range d.options.layerStores { @@ -2484,18 +2553,11 @@ func (d *Driver) getAdditionalLayerPath(tocDigest digest.Digest, ref string) (st ref = refElem } target := path.Join(ls.path, ref, tocDigest.String()) - // Check if all necessary files exist - for _, p := range []string{ - filepath.Join(target, "diff"), - filepath.Join(target, "info"), - filepath.Join(target, "blob"), - } { - if err := fileutils.Exists(p); err != nil { - wrapped := fmt.Errorf("failed to stat additional layer %q: %w", p, err) - return "", fmt.Errorf("%v: %w", wrapped, graphdriver.ErrLayerUnknown) - } + err := validateOneAdditionalLayerPath(target) + if err == nil { + return target, nil } - return target, nil + logrus.Debugf("additional Layer Store %v failed to stat additional layer: %v", ls, err) } return "", fmt.Errorf("additional layer (%q, %q) not found: %w", tocDigest, ref, graphdriver.ErrLayerUnknown) diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay_cgo.go b/vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota.go similarity index 86% rename from vendor/github.com/containers/storage/drivers/overlay/overlay_cgo.go rename to vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota.go index 88bfbf9c7..bc80301d4 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay_cgo.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota.go @@ -1,5 +1,5 @@ -//go:build linux && cgo -// +build linux,cgo +//go:build linux && cgo && !exclude_disk_quota +// +build linux,cgo,!exclude_disk_quota package overlay diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota_unsupported.go b/vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota_unsupported.go new file mode 100644 index 000000000..1340c45b3 --- /dev/null +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay_disk_quota_unsupported.go @@ -0,0 +1,18 @@ +//go:build linux && (!cgo || exclude_disk_quota) +// +build linux +// +build !cgo exclude_disk_quota + +package overlay + +import ( + "path" + + "github.com/containers/storage/pkg/directory" +) + +// ReadWriteDiskUsage returns the disk usage of the writable directory for the ID. +// For Overlay, it attempts to check the XFS quota for size, and falls back to +// finding the size of the "diff" directory. +func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) { + return directory.Usage(path.Join(d.dir(id), "diff")) +} diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go b/vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go index d4f540c9c..0577711b3 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay_nocgo.go @@ -5,18 +5,8 @@ package overlay import ( "fmt" - "path" - - "github.com/containers/storage/pkg/directory" ) -// ReadWriteDiskUsage returns the disk usage of the writable directory for the ID. -// For Overlay, it attempts to check the XFS quota for size, and falls back to -// finding the size of the "diff" directory. -func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) { - return directory.Usage(path.Join(d.dir(id), "diff")) -} - func getComposeFsHelper() (string, error) { return "", fmt.Errorf("composefs not supported on this build") } diff --git a/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go b/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go index b0623bdac..92e4001d7 100644 --- a/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go +++ b/vendor/github.com/containers/storage/drivers/quota/projectquota_supported.go @@ -19,16 +19,6 @@ package quota #include #include -#ifndef FS_XFLAG_PROJINHERIT -struct fsxattr { - __u32 fsx_xflags; - __u32 fsx_extsize; - __u32 fsx_nextents; - __u32 fsx_projid; - unsigned char fsx_pad[12]; -}; -#define FS_XFLAG_PROJINHERIT 0x00000200 -#endif #ifndef FS_IOC_FSGETXATTR #define FS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) #endif @@ -357,7 +347,6 @@ func setProjectID(targetPath string, projectID uint32) error { return fmt.Errorf("failed to get projid for %s: %w", targetPath, errno) } fsx.fsx_projid = C.__u32(projectID) - fsx.fsx_xflags |= C.FS_XFLAG_PROJINHERIT _, _, errno = unix.Syscall(unix.SYS_IOCTL, getDirFd(dir), C.FS_IOC_FSSETXATTR, uintptr(unsafe.Pointer(&fsx))) if errno != 0 { diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go index db9032117..1b9de2dc2 100644 --- a/vendor/github.com/containers/storage/drivers/vfs/driver.go +++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go @@ -33,12 +33,10 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) d := &Driver{ name: "vfs", home: home, - idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps), imageStore: options.ImageStore, } - rootIDs := d.idMappings.RootPair() - if err := idtools.MkdirAllAndChown(filepath.Join(home, "dir"), 0o700, rootIDs); err != nil { + if err := os.MkdirAll(filepath.Join(home, "dir"), 0o700); err != nil { return nil, err } for _, option := range options.DriverOptions { @@ -79,7 +77,6 @@ type Driver struct { name string home string additionalHomes []string - idMappings *idtools.IDMappings ignoreChownErrors bool naiveDiff graphdriver.DiffDriver updater graphdriver.LayerIDMapUpdater @@ -152,14 +149,21 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool return fmt.Errorf("--storage-opt is not supported for vfs") } - idMappings := d.idMappings + var uidMaps []idtools.IDMap + var gidMaps []idtools.IDMap + if opts != nil && opts.IDMappings != nil { - idMappings = opts.IDMappings + uidMaps = opts.IDMappings.UIDs() + gidMaps = opts.IDMappings.GIDs() + } + + rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) + if err != nil { + return err } dir := d.dir2(id, ro) - rootIDs := idMappings.RootPair() - if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0o700, rootIDs); err != nil { + if err := os.MkdirAll(filepath.Dir(dir), 0o700); err != nil { return err } @@ -174,16 +178,17 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool rootPerms = os.FileMode(0o700) } + idPair := idtools.IDPair{UID: rootUID, GID: rootGID} if parent != "" { st, err := system.Stat(d.dir(parent)) if err != nil { return err } rootPerms = os.FileMode(st.Mode()) - rootIDs.UID = int(st.UID()) - rootIDs.GID = int(st.GID()) + idPair.UID = int(st.UID()) + idPair.GID = int(st.GID()) } - if err := idtools.MkdirAndChown(dir, rootPerms, rootIDs); err != nil { + if err := idtools.MkdirAllAndChownNew(dir, rootPerms, idPair); err != nil { return err } labelOpts := []string{"level:s0"} diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs.go b/vendor/github.com/containers/storage/drivers/zfs/zfs.go index e02289784..5a7b2da7b 100644 --- a/vendor/github.com/containers/storage/drivers/zfs/zfs.go +++ b/vendor/github.com/containers/storage/drivers/zfs/zfs.go @@ -106,11 +106,7 @@ func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) { return nil, fmt.Errorf("zfs get all -t filesystem -rHp '%s' should contain '%s'", options.fsName, options.fsName) } - rootUID, rootGID, err := idtools.GetRootUIDGID(opt.UIDMaps, opt.GIDMaps) - if err != nil { - return nil, fmt.Errorf("failed to get root uid/gid: %w", err) - } - if err := idtools.MkdirAllAs(base, 0o700, rootUID, rootGID); err != nil { + if err := os.MkdirAll(base, 0o700); err != nil { return nil, fmt.Errorf("failed to create '%s': %w", base, err) } @@ -118,8 +114,6 @@ func Init(base string, opt graphdriver.Options) (graphdriver.Driver, error) { dataset: rootDataset, options: options, filesystemsCache: filesystemsCache, - uidMaps: opt.UIDMaps, - gidMaps: opt.GIDMaps, ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()), } return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil @@ -177,8 +171,6 @@ type Driver struct { options zfsOptions sync.Mutex // protects filesystem cache against concurrent access filesystemsCache map[string]bool - uidMaps []idtools.IDMap - gidMaps []idtools.IDMap ctr *graphdriver.RefCounter } @@ -448,12 +440,8 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr opts := label.FormatMountLabel(mountOptions, options.MountLabel) logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, opts) - rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) - if err != nil { - return "", err - } // Create the target directories if they don't exist - if err := idtools.MkdirAllAs(mountpoint, 0o755, rootUID, rootGID); err != nil { + if err := os.MkdirAll(mountpoint, 0o755); err != nil { return "", err } diff --git a/vendor/github.com/containers/storage/lockfile_compat.go b/vendor/github.com/containers/storage/lockfile_compat.go index 640203881..ec98b40ce 100644 --- a/vendor/github.com/containers/storage/lockfile_compat.go +++ b/vendor/github.com/containers/storage/lockfile_compat.go @@ -5,7 +5,7 @@ import ( ) // Deprecated: Use lockfile.*LockFile. -type Locker = lockfile.Locker //lint:ignore SA1019 // lockfile.Locker is deprecated +type Locker = lockfile.Locker //nolint:staticcheck // SA1019 lockfile.Locker is deprecated // Deprecated: Use lockfile.GetLockFile. func GetLockfile(path string) (lockfile.Locker, error) { diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go index 77c9c818c..733b16833 100644 --- a/vendor/github.com/containers/storage/pkg/archive/archive.go +++ b/vendor/github.com/containers/storage/pkg/archive/archive.go @@ -169,10 +169,17 @@ func DetectCompression(source []byte) Compression { } // DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive. -func DecompressStream(archive io.Reader) (io.ReadCloser, error) { +func DecompressStream(archive io.Reader) (_ io.ReadCloser, Err error) { p := pools.BufioReader32KPool buf := p.Get(archive) bs, err := buf.Peek(10) + + defer func() { + if Err != nil { + p.Put(buf) + } + }() + if err != nil && err != io.EOF { // Note: we'll ignore any io.EOF error because there are some odd // cases where the layer.tar file will be empty (zero bytes) and @@ -189,6 +196,12 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) { readBufWrapper := p.NewReadCloserWrapper(buf, buf) return readBufWrapper, nil case Gzip: + cleanup := func() { + p.Put(buf) + } + if rc, canUse := tryProcFilter([]string{"pigz", "-d"}, buf, cleanup); canUse { + return rc, nil + } gzReader, err := gzip.NewReader(buf) if err != nil { return nil, err @@ -207,6 +220,12 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) { readBufWrapper := p.NewReadCloserWrapper(buf, xzReader) return readBufWrapper, nil case Zstd: + cleanup := func() { + p.Put(buf) + } + if rc, canUse := tryProcFilter([]string{"zstd", "-d"}, buf, cleanup); canUse { + return rc, nil + } return zstdReader(buf) default: return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension()) @@ -214,9 +233,16 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) { } // CompressStream compresses the dest with specified compression algorithm. -func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { +func CompressStream(dest io.Writer, compression Compression) (_ io.WriteCloser, Err error) { p := pools.BufioWriter32KPool buf := p.Get(dest) + + defer func() { + if Err != nil { + p.Put(buf) + } + }() + switch compression { case Uncompressed: writeBufWrapper := p.NewWriteCloserWrapper(buf, buf) @@ -642,7 +668,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L } } - case tar.TypeReg, tar.TypeRegA: + case tar.TypeReg: // Source is regular file. We use system.OpenFileSequential to use sequential // file access to avoid depleting the standby list on Windows. // On Linux, this equates to a regular os.OpenFile @@ -701,8 +727,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L } if forceMask != nil && (hdr.Typeflag != tar.TypeSymlink || runtime.GOOS == "darwin") { - value := fmt.Sprintf("%d:%d:0%o", hdr.Uid, hdr.Gid, hdrInfo.Mode()&0o7777) - if err := system.Lsetxattr(path, idtools.ContainersOverrideXattr, []byte(value), 0); err != nil { + value := idtools.Stat{ + IDs: idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}, + Mode: hdrInfo.Mode() & 0o7777, + } + if err := idtools.SetContainersOverrideXattr(path, value); err != nil { return err } } @@ -1113,9 +1142,14 @@ loop: } } - if options.ForceMask != nil && rootHdr != nil { - value := fmt.Sprintf("%d:%d:0%o", rootHdr.Uid, rootHdr.Gid, rootHdr.Mode) - if err := system.Lsetxattr(dest, idtools.ContainersOverrideXattr, []byte(value), 0); err != nil { + if options.ForceMask != nil { + value := idtools.Stat{Mode: 0o755} + if rootHdr != nil { + value.IDs.UID = rootHdr.Uid + value.IDs.GID = rootHdr.Gid + value.Mode = os.FileMode(rootHdr.Mode) + } + if err := idtools.SetContainersOverrideXattr(dest, value); err != nil { return err } } diff --git a/vendor/github.com/containers/storage/pkg/archive/archive_bsd.go b/vendor/github.com/containers/storage/pkg/archive/archive_bsd.go index 4d362f075..a754d0d4a 100644 --- a/vendor/github.com/containers/storage/pkg/archive/archive_bsd.go +++ b/vendor/github.com/containers/storage/pkg/archive/archive_bsd.go @@ -1,5 +1,5 @@ -//go:build freebsd || darwin -// +build freebsd darwin +//go:build netbsd || freebsd || darwin +// +build netbsd freebsd darwin package archive diff --git a/vendor/github.com/containers/storage/pkg/archive/changes_unix.go b/vendor/github.com/containers/storage/pkg/archive/changes_unix.go index 6b2e59380..25429406f 100644 --- a/vendor/github.com/containers/storage/pkg/archive/changes_unix.go +++ b/vendor/github.com/containers/storage/pkg/archive/changes_unix.go @@ -31,9 +31,9 @@ func statDifferent(oldStat *system.StatT, oldInfo *FileInfo, newStat *system.Sta ownerChanged || oldStat.Rdev() != newStat.Rdev() || oldStat.Flags() != newStat.Flags() || + !sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || // Don't look at size for dirs, its not a good measure of change - (oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR && - (!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) { + ((oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR) && (oldStat.Size() != newStat.Size())) { return true } return false diff --git a/vendor/github.com/containers/storage/pkg/archive/filter.go b/vendor/github.com/containers/storage/pkg/archive/filter.go new file mode 100644 index 000000000..e63d72e6a --- /dev/null +++ b/vendor/github.com/containers/storage/pkg/archive/filter.go @@ -0,0 +1,55 @@ +package archive + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strings" + "sync" +) + +var filterPath sync.Map + +func getFilterPath(name string) string { + path, ok := filterPath.Load(name) + if ok { + return path.(string) + } + + path, err := exec.LookPath(name) + if err != nil { + path = "" + } + + filterPath.Store(name, path) + return path.(string) +} + +// tryProcFilter tries to run the command specified in args, passing input to its stdin and returning its stdout. +// cleanup() is a caller provided function that will be called when the command finishes running, regardless of +// whether it succeeds or fails. +// If the command is not found, it returns (nil, false) and the cleanup function is not called. +func tryProcFilter(args []string, input io.Reader, cleanup func()) (io.ReadCloser, bool) { + path := getFilterPath(args[0]) + if path == "" { + return nil, false + } + + var stderrBuf bytes.Buffer + + r, w := io.Pipe() + cmd := exec.Command(path, args[1:]...) + cmd.Stdin = input + cmd.Stdout = w + cmd.Stderr = &stderrBuf + go func() { + err := cmd.Run() + if err != nil && stderrBuf.Len() > 0 { + err = fmt.Errorf("%s: %w", strings.TrimRight(stderrBuf.String(), "\n"), err) + } + w.CloseWithError(err) // CloseWithErr(nil) == Close() + cleanup() + }() + return r, true +} diff --git a/vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go b/vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go index 09ef6d5de..5b8acdaba 100644 --- a/vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go +++ b/vendor/github.com/containers/storage/pkg/chrootarchive/chroot_linux.go @@ -19,10 +19,13 @@ import ( // Old root is removed after the call to pivot_root so it is no longer available under the new root. // This is similar to how libcontainer sets up a container's rootfs func chroot(path string) (err error) { - caps, err := capability.NewPid(0) + caps, err := capability.NewPid2(0) if err != nil { return err } + if err := caps.Load(); err != nil { + return err + } // initialize nss libraries in Glibc so that the dynamic libraries are loaded in the host // environment not in the chroot from untrusted files. diff --git a/vendor/github.com/containers/storage/pkg/chunked/bloom_filter.go b/vendor/github.com/containers/storage/pkg/chunked/bloom_filter_linux.go similarity index 87% rename from vendor/github.com/containers/storage/pkg/chunked/bloom_filter.go rename to vendor/github.com/containers/storage/pkg/chunked/bloom_filter_linux.go index 45d76ec30..09e75680a 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/bloom_filter.go +++ b/vendor/github.com/containers/storage/pkg/chunked/bloom_filter_linux.go @@ -2,10 +2,15 @@ package chunked import ( "encoding/binary" + "fmt" "hash/crc32" "io" + + "github.com/docker/go-units" ) +const bloomFilterMaxLength = 100 * units.MB // max size for bloom filter + type bloomFilter struct { bitArray []uint64 k uint32 @@ -79,6 +84,10 @@ func readBloomFilter(reader io.Reader) (*bloomFilter, error) { if err := binary.Read(reader, binary.LittleEndian, &k); err != nil { return nil, err } + // sanity check + if bloomFilterLen > bloomFilterMaxLength { + return nil, fmt.Errorf("bloom filter length %d exceeds max length %d", bloomFilterLen, bloomFilterMaxLength) + } bloomFilterArray := make([]uint64, bloomFilterLen) if err := binary.Read(reader, binary.LittleEndian, &bloomFilterArray); err != nil { return nil, err diff --git a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go index 34d1b92f4..6d6a575ba 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go @@ -18,6 +18,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/chunked/internal" "github.com/containers/storage/pkg/ioutils" + "github.com/docker/go-units" jsoniter "github.com/json-iterator/go" digest "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" @@ -34,6 +35,8 @@ const ( // https://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html bloomFilterScale = 10 // how much bigger is the bloom filter than the number of entries bloomFilterHashes = 3 // number of hash functions for the bloom filter + + maxTagsLen = 100 * units.MB // max size for tags len ) type cacheFile struct { @@ -635,6 +638,14 @@ func readCacheFileFromMemory(bigDataBuffer []byte) (*cacheFile, error) { if err := binary.Read(bigData, binary.LittleEndian, &fnamesLen); err != nil { return nil, err } + + if tagsLen > maxTagsLen { + return nil, fmt.Errorf("tags len %d exceeds the maximum allowed size %d", tagsLen, maxTagsLen) + } + if digestLen > tagLen { + return nil, fmt.Errorf("digest len %d exceeds the tag len %d", digestLen, tagLen) + } + tags := make([]byte, tagsLen) if _, err := bigData.Read(tags); err != nil { return nil, err @@ -643,6 +654,10 @@ func readCacheFileFromMemory(bigDataBuffer []byte) (*cacheFile, error) { // retrieve the unread part of the buffer. remaining := bigDataBuffer[len(bigDataBuffer)-bigData.Len():] + if vdataLen >= uint64(len(remaining)) { + return nil, fmt.Errorf("vdata len %d exceeds the remaining buffer size %d", vdataLen, len(remaining)) + } + vdata := remaining[:vdataLen] fnames := remaining[vdataLen:] @@ -901,7 +916,7 @@ func unmarshalToc(manifest []byte) (*internal.TOC, error) { s := iter.ReadString() d, err := digest.Parse(s) if err != nil { - return nil, fmt.Errorf("Invalid tarSplitDigest %q: %w", s, err) + return nil, fmt.Errorf("invalid tarSplitDigest %q: %w", s, err) } toc.TarSplitDigest = d diff --git a/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go b/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go index 7b3879a99..05b4ba11d 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/compression_linux.go @@ -209,16 +209,27 @@ func readZstdChunkedManifest(blobStream ImageSourceSeekable, tocDigest digest.Di } decodedTarSplit := []byte{} - if tarSplitChunk.Offset > 0 { + if toc.TarSplitDigest != "" { + if tarSplitChunk.Offset <= 0 { + return nil, nil, nil, 0, fmt.Errorf("TOC requires a tar-split, but the %s annotation does not describe a position", internal.TarSplitInfoKey) + } tarSplit, err := readBlob(tarSplitChunk.Length) if err != nil { return nil, nil, nil, 0, err } - decodedTarSplit, err = decodeAndValidateBlob(tarSplit, tarSplitLengthUncompressed, toc.TarSplitDigest.String()) if err != nil { return nil, nil, nil, 0, fmt.Errorf("validating and decompressing tar-split: %w", err) } + } else if tarSplitChunk.Offset > 0 { + // We must ignore the tar-split when the digest is not present in the TOC, because we can’t authenticate it. + // + // But if we asked for the chunk, now we must consume the data to not block the producer. + // Ideally the GetBlobAt API should be changed so that this is not necessary. + _, err := readBlob(tarSplitChunk.Length) + if err != nil { + return nil, nil, nil, 0, err + } } return decodedBlob, toc, decodedTarSplit, int64(manifestChunk.Offset), err } diff --git a/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go b/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go index 701b6aa53..0cf8352d9 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go +++ b/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go @@ -1,3 +1,5 @@ +//go:build unix + package dump import ( @@ -5,9 +7,9 @@ import ( "fmt" "io" "path/filepath" + "reflect" "strings" "time" - "unicode" "github.com/containers/storage/pkg/chunked/internal" "golang.org/x/sys/unix" @@ -25,15 +27,21 @@ func escaped(val string, escape int) string { escapeEqual := escape&ESCAPE_EQUAL != 0 escapeLoneDash := escape&ESCAPE_LONE_DASH != 0 - length := len(val) - if escapeLoneDash && val == "-" { return fmt.Sprintf("\\x%.2x", val[0]) } + // This is intended to match the C isprint API with LC_CTYPE=C + isprint := func(c byte) bool { + return c >= 32 && c < 127 + } + // This is intended to match the C isgraph API with LC_CTYPE=C + isgraph := func(c byte) bool { + return c > 32 && c < 127 + } + var result string - for i := 0; i < length; i++ { - c := val[i] + for _, c := range []byte(val) { hexEscape := false var special string @@ -50,9 +58,9 @@ func escaped(val string, escape int) string { hexEscape = escapeEqual default: if noescapeSpace { - hexEscape = !unicode.IsPrint(rune(c)) + hexEscape = !isprint(c) } else { - hexEscape = !unicode.IsPrint(rune(c)) || unicode.IsSpace(rune(c)) + hexEscape = !isgraph(c) } } @@ -104,9 +112,30 @@ func sanitizeName(name string) string { return path } -func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]string, entry *internal.FileMetadata) error { +func dumpNode(out io.Writer, added map[string]*internal.FileMetadata, links map[string]int, verityDigests map[string]string, entry *internal.FileMetadata) error { path := sanitizeName(entry.Name) + parent := filepath.Dir(path) + if _, found := added[parent]; !found && path != "/" { + parentEntry := &internal.FileMetadata{ + Name: parent, + Type: internal.TypeDir, + Mode: 0o755, + } + if err := dumpNode(out, added, links, verityDigests, parentEntry); err != nil { + return err + } + + } + if e, found := added[path]; found { + // if the entry was already added, make sure it has the same data + if !reflect.DeepEqual(*e, *entry) { + return fmt.Errorf("entry %q already added with different data", path) + } + return nil + } + added[path] = entry + if _, err := fmt.Fprint(out, escaped(path, ESCAPE_STANDARD)); err != nil { return err } @@ -151,7 +180,7 @@ func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]stri } } - if _, err := fmt.Fprintf(out, escapedOptional(payload, ESCAPE_LONE_DASH)); err != nil { + if _, err := fmt.Fprint(out, escapedOptional(payload, ESCAPE_LONE_DASH)); err != nil { return err } @@ -165,7 +194,7 @@ func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]stri return err } digest := verityDigests[payload] - if _, err := fmt.Fprintf(out, escapedOptional(digest, ESCAPE_LONE_DASH)); err != nil { + if _, err := fmt.Fprint(out, escapedOptional(digest, ESCAPE_LONE_DASH)); err != nil { return err } @@ -201,6 +230,7 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader, }() links := make(map[string]int) + added := make(map[string]*internal.FileMetadata) for _, e := range toc.Entries { if e.Linkname == "" { continue @@ -211,14 +241,14 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader, links[e.Linkname] = links[e.Linkname] + 1 } - if len(toc.Entries) == 0 || (sanitizeName(toc.Entries[0].Name) != "/") { + if len(toc.Entries) == 0 { root := &internal.FileMetadata{ Name: "/", Type: internal.TypeDir, Mode: 0o755, } - if err := dumpNode(w, links, verityDigests, root); err != nil { + if err := dumpNode(w, added, links, verityDigests, root); err != nil { pipeW.CloseWithError(err) closed = true return @@ -229,7 +259,7 @@ func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader, if e.Type == internal.TypeChunk { continue } - if err := dumpNode(w, links, verityDigests, &e); err != nil { + if err := dumpNode(w, added, links, verityDigests, &e); err != nil { pipeW.CloseWithError(err) closed = true return diff --git a/vendor/github.com/containers/storage/pkg/chunked/filesystem_linux.go b/vendor/github.com/containers/storage/pkg/chunked/filesystem_linux.go new file mode 100644 index 000000000..b7aa88cb5 --- /dev/null +++ b/vendor/github.com/containers/storage/pkg/chunked/filesystem_linux.go @@ -0,0 +1,603 @@ +package chunked + +import ( + "encoding/base64" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + "sync/atomic" + "syscall" + "time" + + driversCopy "github.com/containers/storage/drivers/copy" + "github.com/containers/storage/pkg/archive" + "github.com/containers/storage/pkg/chunked/internal" + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/vbatts/tar-split/archive/tar" + "golang.org/x/sys/unix" +) + +// procPathForFile returns an absolute path in /proc which +// refers to the file; see procPathForFd. +func procPathForFile(f *os.File) string { + return procPathForFd(int(f.Fd())) +} + +// procPathForFd returns an absolute path in /proc which +// refers to the file; this allows passing a file descriptor +// in places that don't accept a file descriptor. +func procPathForFd(fd int) string { + return fmt.Sprintf("/proc/self/fd/%d", fd) +} + +// fileMetadata is a wrapper around internal.FileMetadata with additional private fields that +// are not part of the TOC document. +// Type: TypeChunk entries are stored in Chunks, the primary [fileMetadata] entries never use TypeChunk. +type fileMetadata struct { + internal.FileMetadata + + // chunks stores the TypeChunk entries relevant to this entry when FileMetadata.Type == TypeReg. + chunks []*internal.FileMetadata + + // skipSetAttrs is set when the file attributes must not be + // modified, e.g. it is a hard link from a different source, + // or a composefs file. + skipSetAttrs bool +} + +func doHardLink(dirfd, srcFd int, destFile string) error { + destDir, destBase := filepath.Split(destFile) + destDirFd := dirfd + if destDir != "" && destDir != "." { + f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0) + if err != nil { + return err + } + defer f.Close() + destDirFd = int(f.Fd()) + } + + doLink := func() error { + // Using unix.AT_EMPTY_PATH requires CAP_DAC_READ_SEARCH while this variant that uses + // /proc/self/fd doesn't and can be used with rootless. + srcPath := procPathForFd(srcFd) + err := unix.Linkat(unix.AT_FDCWD, srcPath, destDirFd, destBase, unix.AT_SYMLINK_FOLLOW) + if err != nil { + return &fs.PathError{Op: "linkat", Path: destFile, Err: err} + } + return nil + } + + err := doLink() + + // if the destination exists, unlink it first and try again + if err != nil && os.IsExist(err) { + unix.Unlinkat(destDirFd, destBase, 0) + return doLink() + } + return err +} + +func copyFileContent(srcFd int, fileMetadata *fileMetadata, dirfd int, mode os.FileMode, useHardLinks bool) (*os.File, int64, error) { + destFile := fileMetadata.Name + src := procPathForFd(srcFd) + st, err := os.Stat(src) + if err != nil { + return nil, -1, fmt.Errorf("copy file content for %q: %w", destFile, err) + } + + copyWithFileRange, copyWithFileClone := true, true + + if useHardLinks { + err := doHardLink(dirfd, srcFd, destFile) + if err == nil { + // if the file was deduplicated with a hard link, skip overriding file metadata. + fileMetadata.skipSetAttrs = true + return nil, st.Size(), nil + } + } + + // If the destination file already exists, we shouldn't blow it away + dstFile, err := openFileUnderRoot(dirfd, destFile, newFileFlags, mode) + if err != nil { + return nil, -1, fmt.Errorf("open file %q under rootfs for copy: %w", destFile, err) + } + + err = driversCopy.CopyRegularToFile(src, dstFile, st, ©WithFileRange, ©WithFileClone) + if err != nil { + dstFile.Close() + return nil, -1, fmt.Errorf("copy to file %q under rootfs: %w", destFile, err) + } + return dstFile, st.Size(), nil +} + +func timeToTimespec(time *time.Time) (ts unix.Timespec) { + if time == nil || time.IsZero() { + // Return UTIME_OMIT special value + ts.Sec = 0 + ts.Nsec = ((1 << 30) - 2) + return + } + return unix.NsecToTimespec(time.UnixNano()) +} + +// chown changes the owner and group of the file at the specified path under the directory +// pointed by dirfd. +// If nofollow is true, the function will not follow symlinks. +// If path is empty, the function will change the owner and group of the file descriptor. +// absolutePath is the absolute path of the file, used only for error messages. +func chown(dirfd int, path string, uid, gid int, nofollow bool, absolutePath string) error { + var err error + flags := 0 + if nofollow { + flags |= unix.AT_SYMLINK_NOFOLLOW + } else if path == "" { + flags |= unix.AT_EMPTY_PATH + } + err = unix.Fchownat(dirfd, path, uid, gid, flags) + if err == nil { + return nil + } + if errors.Is(err, syscall.EINVAL) { + return fmt.Errorf(`potentially insufficient UIDs or GIDs available in the user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": %w`, uid, gid, path, err) + } + return &fs.PathError{Op: "fchownat", Path: absolutePath, Err: err} +} + +// setFileAttrs sets the file attributes for file given metadata +func setFileAttrs(dirfd int, file *os.File, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions, usePath bool) error { + if metadata.skipSetAttrs { + return nil + } + if file == nil { + return errors.New("invalid file") + } + fd := int(file.Fd()) + + t, err := typeToTarType(metadata.Type) + if err != nil { + return err + } + + // If it is a symlink, force to use the path + if t == tar.TypeSymlink { + usePath = true + } + + baseName := "" + if usePath { + dirName := filepath.Dir(metadata.Name) + if dirName != "" { + parentFd, err := openFileUnderRoot(dirfd, dirName, unix.O_PATH|unix.O_DIRECTORY, 0) + if err != nil { + return err + } + defer parentFd.Close() + + dirfd = int(parentFd.Fd()) + } + baseName = filepath.Base(metadata.Name) + } + + doChown := func() error { + var err error + if usePath { + err = chown(dirfd, baseName, metadata.UID, metadata.GID, true, metadata.Name) + } else { + err = chown(fd, "", metadata.UID, metadata.GID, false, metadata.Name) + } + if options.IgnoreChownErrors { + return nil + } + return err + } + + doSetXattr := func(k string, v []byte) error { + err := unix.Fsetxattr(fd, k, v, 0) + if err != nil { + return &fs.PathError{Op: "fsetxattr", Path: metadata.Name, Err: err} + } + return nil + } + + doUtimes := func() error { + ts := []unix.Timespec{timeToTimespec(metadata.AccessTime), timeToTimespec(metadata.ModTime)} + var err error + if usePath { + err = unix.UtimesNanoAt(dirfd, baseName, ts, unix.AT_SYMLINK_NOFOLLOW) + } else { + err = unix.UtimesNanoAt(unix.AT_FDCWD, procPathForFd(fd), ts, 0) + } + if err != nil { + return &fs.PathError{Op: "utimensat", Path: metadata.Name, Err: err} + } + return nil + } + + doChmod := func() error { + var err error + op := "" + if usePath { + err = unix.Fchmodat(dirfd, baseName, uint32(mode), unix.AT_SYMLINK_NOFOLLOW) + op = "fchmodat" + } else { + err = unix.Fchmod(fd, uint32(mode)) + op = "fchmod" + } + if err != nil { + return &fs.PathError{Op: op, Path: metadata.Name, Err: err} + } + return nil + } + + if err := doChown(); err != nil { + return err + } + + canIgnore := func(err error) bool { + return err == nil || errors.Is(err, unix.ENOSYS) || errors.Is(err, unix.ENOTSUP) + } + + for k, v := range metadata.Xattrs { + if _, found := xattrsToIgnore[k]; found { + continue + } + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return fmt.Errorf("decode xattr %q: %w", v, err) + } + if err := doSetXattr(k, data); !canIgnore(err) { + return fmt.Errorf("set xattr %s=%q for %q: %w", k, data, metadata.Name, err) + } + } + + if err := doUtimes(); !canIgnore(err) { + return err + } + + if err := doChmod(); !canIgnore(err) { + return err + } + return nil +} + +func openFileUnderRootFallback(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { + root := procPathForFd(dirfd) + + targetRoot, err := os.Readlink(root) + if err != nil { + return -1, err + } + + hasNoFollow := (flags & unix.O_NOFOLLOW) != 0 + + var fd int + // If O_NOFOLLOW is specified in the flags, then resolve only the parent directory and use the + // last component as the path to openat(). + if hasNoFollow { + dirName, baseName := filepath.Split(name) + if dirName != "" && dirName != "." { + newRoot, err := securejoin.SecureJoin(root, dirName) + if err != nil { + return -1, err + } + root = newRoot + } + + parentDirfd, err := unix.Open(root, unix.O_PATH|unix.O_CLOEXEC, 0) + if err != nil { + return -1, &fs.PathError{Op: "open", Path: root, Err: err} + } + defer unix.Close(parentDirfd) + + fd, err = unix.Openat(parentDirfd, baseName, int(flags), uint32(mode)) + if err != nil { + return -1, &fs.PathError{Op: "openat", Path: name, Err: err} + } + } else { + newPath, err := securejoin.SecureJoin(root, name) + if err != nil { + return -1, err + } + fd, err = unix.Openat(dirfd, newPath, int(flags), uint32(mode)) + if err != nil { + return -1, &fs.PathError{Op: "openat", Path: newPath, Err: err} + } + } + + target, err := os.Readlink(procPathForFd(fd)) + if err != nil { + unix.Close(fd) + return -1, err + } + + // Add an additional check to make sure the opened fd is inside the rootfs + if !strings.HasPrefix(target, targetRoot) { + unix.Close(fd) + return -1, fmt.Errorf("while resolving %q. It resolves outside the root directory", name) + } + + return fd, err +} + +func openFileUnderRootOpenat2(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { + how := unix.OpenHow{ + Flags: flags, + Mode: uint64(mode & 0o7777), + Resolve: unix.RESOLVE_IN_ROOT, + } + fd, err := unix.Openat2(dirfd, name, &how) + if err != nil { + return -1, &fs.PathError{Op: "openat2", Path: name, Err: err} + } + return fd, nil +} + +// skipOpenat2 is set when openat2 is not supported by the underlying kernel and avoid +// using it again. +var skipOpenat2 int32 + +// openFileUnderRootRaw tries to open a file using openat2 and if it is not supported fallbacks to a +// userspace lookup. +func openFileUnderRootRaw(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { + var fd int + var err error + if name == "" { + fd, err := unix.Dup(dirfd) + if err != nil { + return -1, fmt.Errorf("failed to duplicate file descriptor %d: %w", dirfd, err) + } + return fd, nil + } + if atomic.LoadInt32(&skipOpenat2) > 0 { + fd, err = openFileUnderRootFallback(dirfd, name, flags, mode) + } else { + fd, err = openFileUnderRootOpenat2(dirfd, name, flags, mode) + // If the function failed with ENOSYS, switch off the support for openat2 + // and fallback to using safejoin. + if err != nil && errors.Is(err, unix.ENOSYS) { + atomic.StoreInt32(&skipOpenat2, 1) + fd, err = openFileUnderRootFallback(dirfd, name, flags, mode) + } + } + return fd, err +} + +// openFileUnderRoot safely opens a file under the specified root directory using openat2 +// dirfd is an open file descriptor to the target checkout directory. +// name is the path to open relative to dirfd. +// flags are the flags to pass to the open syscall. +// mode specifies the mode to use for newly created files. +func openFileUnderRoot(dirfd int, name string, flags uint64, mode os.FileMode) (*os.File, error) { + fd, err := openFileUnderRootRaw(dirfd, name, flags, mode) + if err == nil { + return os.NewFile(uintptr(fd), name), nil + } + + hasCreate := (flags & unix.O_CREAT) != 0 + if errors.Is(err, unix.ENOENT) && hasCreate { + parent := filepath.Dir(name) + if parent != "" { + newDirfd, err2 := openOrCreateDirUnderRoot(dirfd, parent, 0) + if err2 == nil { + defer newDirfd.Close() + fd, err := openFileUnderRootRaw(int(newDirfd.Fd()), filepath.Base(name), flags, mode) + if err == nil { + return os.NewFile(uintptr(fd), name), nil + } + } + } + } + return nil, fmt.Errorf("open %q under the rootfs: %w", name, err) +} + +// openOrCreateDirUnderRoot safely opens a directory or create it if it is missing. +// dirfd is an open file descriptor to the target checkout directory. +// name is the path to open relative to dirfd. +// mode specifies the mode to use for newly created files. +func openOrCreateDirUnderRoot(dirfd int, name string, mode os.FileMode) (*os.File, error) { + fd, err := openFileUnderRootRaw(dirfd, name, unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err == nil { + return os.NewFile(uintptr(fd), name), nil + } + + if errors.Is(err, unix.ENOENT) { + parent := filepath.Dir(name) + if parent != "" { + pDir, err2 := openOrCreateDirUnderRoot(dirfd, parent, mode) + if err2 != nil { + return nil, err + } + defer pDir.Close() + + baseName := filepath.Base(name) + + if err2 := unix.Mkdirat(int(pDir.Fd()), baseName, uint32(mode)); err2 != nil { + return nil, &fs.PathError{Op: "mkdirat", Path: name, Err: err2} + } + + fd, err = openFileUnderRootRaw(int(pDir.Fd()), baseName, unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err == nil { + return os.NewFile(uintptr(fd), name), nil + } + } + } + return nil, err +} + +// appendHole creates a hole with the specified size at the open fd. +// fd is the open file descriptor. +// name is the path to use for error messages. +// size is the size of the hole to create. +func appendHole(fd int, name string, size int64) error { + off, err := unix.Seek(fd, size, unix.SEEK_CUR) + if err != nil { + return &fs.PathError{Op: "seek", Path: name, Err: err} + } + // Make sure the file size is changed. It might be the last hole and no other data written afterwards. + if err := unix.Ftruncate(fd, off); err != nil { + return &fs.PathError{Op: "ftruncate", Path: name, Err: err} + } + return nil +} + +func safeMkdir(dirfd int, mode os.FileMode, name string, metadata *fileMetadata, options *archive.TarOptions) error { + parent, base := filepath.Split(name) + parentFd := dirfd + if parent != "" && parent != "." { + parentFile, err := openOrCreateDirUnderRoot(dirfd, parent, 0) + if err != nil { + return err + } + defer parentFile.Close() + parentFd = int(parentFile.Fd()) + } + + if err := unix.Mkdirat(parentFd, base, uint32(mode)); err != nil { + if !os.IsExist(err) { + return &fs.PathError{Op: "mkdirat", Path: name, Err: err} + } + } + + file, err := openFileUnderRoot(parentFd, base, unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err != nil { + return err + } + defer file.Close() + + return setFileAttrs(dirfd, file, mode, metadata, options, false) +} + +func safeLink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error { + sourceFile, err := openFileUnderRoot(dirfd, metadata.Linkname, unix.O_PATH|unix.O_RDONLY|unix.O_NOFOLLOW, 0) + if err != nil { + return err + } + defer sourceFile.Close() + + err = doHardLink(dirfd, int(sourceFile.Fd()), metadata.Name) + if err != nil { + return err + } + + newFile, err := openFileUnderRoot(dirfd, metadata.Name, unix.O_WRONLY|unix.O_NOFOLLOW, 0) + if err != nil { + // If the target is a symlink, open the file with O_PATH. + if errors.Is(err, unix.ELOOP) { + newFile, err := openFileUnderRoot(dirfd, metadata.Name, unix.O_PATH|unix.O_NOFOLLOW, 0) + if err != nil { + return err + } + defer newFile.Close() + + return setFileAttrs(dirfd, newFile, mode, metadata, options, true) + } + return err + } + defer newFile.Close() + + return setFileAttrs(dirfd, newFile, mode, metadata, options, false) +} + +func safeSymlink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error { + destDir, destBase := filepath.Split(metadata.Name) + destDirFd := dirfd + if destDir != "" && destDir != "." { + f, err := openOrCreateDirUnderRoot(dirfd, destDir, 0) + if err != nil { + return err + } + defer f.Close() + destDirFd = int(f.Fd()) + } + + if err := unix.Symlinkat(metadata.Linkname, destDirFd, destBase); err != nil { + return &fs.PathError{Op: "symlinkat", Path: metadata.Name, Err: err} + } + return nil +} + +type whiteoutHandler struct { + Dirfd int + Root string +} + +func (d whiteoutHandler) Setxattr(path, name string, value []byte) error { + file, err := openOrCreateDirUnderRoot(d.Dirfd, path, 0) + if err != nil { + return err + } + defer file.Close() + + if err := unix.Fsetxattr(int(file.Fd()), name, value, 0); err != nil { + return &fs.PathError{Op: "fsetxattr", Path: path, Err: err} + } + return nil +} + +func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error { + dir, base := filepath.Split(path) + dirfd := d.Dirfd + if dir != "" && dir != "." { + dir, err := openOrCreateDirUnderRoot(d.Dirfd, dir, 0) + if err != nil { + return err + } + defer dir.Close() + + dirfd = int(dir.Fd()) + } + + if err := unix.Mknodat(dirfd, base, mode, dev); err != nil { + return &fs.PathError{Op: "mknodat", Path: path, Err: err} + } + + return nil +} + +func (d whiteoutHandler) Chown(path string, uid, gid int) error { + file, err := openFileUnderRoot(d.Dirfd, path, unix.O_PATH, 0) + if err != nil { + return err + } + defer file.Close() + + return chown(int(file.Fd()), "", uid, gid, false, path) +} + +type readerAtCloser interface { + io.ReaderAt + io.Closer +} + +// seekableFile is a struct that wraps an *os.File to provide an ImageSourceSeekable. +type seekableFile struct { + reader readerAtCloser +} + +func (f *seekableFile) Close() error { + return f.reader.Close() +} + +func (f *seekableFile) GetBlobAt(chunks []ImageSourceChunk) (chan io.ReadCloser, chan error, error) { + streams := make(chan io.ReadCloser) + errs := make(chan error) + + go func() { + for _, chunk := range chunks { + streams <- io.NopCloser(io.NewSectionReader(f.reader, int64(chunk.Offset), int64(chunk.Length))) + } + close(streams) + close(errs) + }() + + return streams, errs, nil +} + +func newSeekableFile(reader readerAtCloser) *seekableFile { + return &seekableFile{reader: reader} +} diff --git a/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go b/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go index 5decbfb63..5dd8a4b90 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go +++ b/vendor/github.com/containers/storage/pkg/chunked/internal/compression.go @@ -17,13 +17,30 @@ import ( "github.com/opencontainers/go-digest" ) +// TOC is short for Table of Contents and is used by the zstd:chunked +// file format to effectively add an overall index into the contents +// of a tarball; it also includes file metadata. type TOC struct { - Version int `json:"version"` - Entries []FileMetadata `json:"entries"` - TarSplitDigest digest.Digest `json:"tarSplitDigest,omitempty"` + // Version is currently expected to be 1 + Version int `json:"version"` + // Entries is the list of file metadata in this TOC. + // The ordering in this array currently defaults to being the same + // as that of the tar stream; however, this should not be relied on. + Entries []FileMetadata `json:"entries"` + // TarSplitDigest is the checksum of the "tar-split" data which + // is included as a distinct skippable zstd frame before the TOC. + TarSplitDigest digest.Digest `json:"tarSplitDigest,omitempty"` } +// FileMetadata is an entry in the TOC that includes both generic file metadata +// that duplicates what can found in the tar header (and should match), but +// also special/custom content (see below). +// +// Note that the metadata here, when fetched by a zstd:chunked aware client, +// is used instead of that in the tar stream. The contents of the tar stream +// are not used in this scenario. type FileMetadata struct { + // The metadata below largely duplicates that in the tar headers. Type string `json:"type"` Name string `json:"name"` Linkname string `json:"linkName,omitempty"` @@ -37,9 +54,11 @@ type FileMetadata struct { Devmajor int64 `json:"devMajor,omitempty"` Devminor int64 `json:"devMinor,omitempty"` Xattrs map[string]string `json:"xattrs,omitempty"` - Digest string `json:"digest,omitempty"` - Offset int64 `json:"offset,omitempty"` - EndOffset int64 `json:"endOffset,omitempty"` + // Digest is a hexadecimal sha256 checksum of the file contents; it + // is empty for empty files + Digest string `json:"digest,omitempty"` + Offset int64 `json:"offset,omitempty"` + EndOffset int64 `json:"endOffset,omitempty"` ChunkSize int64 `json:"chunkSize,omitempty"` ChunkOffset int64 `json:"chunkOffset,omitempty"` @@ -53,19 +72,23 @@ const ( ) const ( + // The following types correspond to regular types of entries that can + // appear in a tar archive. TypeReg = "reg" - TypeChunk = "chunk" TypeLink = "hardlink" TypeChar = "char" TypeBlock = "block" TypeDir = "dir" TypeFifo = "fifo" TypeSymlink = "symlink" + // TypeChunk is special; in zstd:chunked not only are files individually + // compressed and indexable, there is a "rolling checksum" used to compute + // "chunks" of individual file contents, that are also added to the TOC + TypeChunk = "chunk" ) var TarTypes = map[byte]string{ tar.TypeReg: TypeReg, - tar.TypeRegA: TypeReg, tar.TypeLink: TypeLink, tar.TypeChar: TypeChar, tar.TypeBlock: TypeBlock, @@ -83,11 +106,23 @@ func GetType(t byte) (string, error) { } const ( + // ManifestChecksumKey is a hexadecimal sha256 digest of the compressed manifest digest. ManifestChecksumKey = "io.github.containers.zstd-chunked.manifest-checksum" - ManifestInfoKey = "io.github.containers.zstd-chunked.manifest-position" - TarSplitInfoKey = "io.github.containers.zstd-chunked.tarsplit-position" - - TarSplitChecksumKey = "io.github.containers.zstd-chunked.tarsplit-checksum" // Deprecated: Use the TOC.TarSplitDigest field instead, this annotation is no longer read nor written. + // ManifestInfoKey is an annotation that signals the start of the TOC (manifest) + // contents which are embedded as a skippable zstd frame. It has a format of + // four decimal integers separated by `:` as follows: + // ::: + // The is ManifestTypeCRFS which should have the value `1`. + ManifestInfoKey = "io.github.containers.zstd-chunked.manifest-position" + // TarSplitInfoKey is an annotation that signals the start of the "tar-split" metadata + // contents which are embedded as a skippable zstd frame. It has a format of + // three decimal integers separated by `:` as follows: + // :: + TarSplitInfoKey = "io.github.containers.zstd-chunked.tarsplit-position" + + // TarSplitChecksumKey is no longer used and is replaced by the TOC.TarSplitDigest field instead. + // The value is retained here as a constant as a historical reference for older zstd:chunked images. + // TarSplitChecksumKey = "io.github.containers.zstd-chunked.tarsplit-checksum" // ManifestTypeCRFS is a manifest file compatible with the CRFS TOC file. ManifestTypeCRFS = 1 diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go index e001022cb..f7a514e3b 100644 --- a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go +++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go @@ -8,20 +8,18 @@ import ( "fmt" "hash" "io" + "io/fs" "os" "path/filepath" "reflect" "sort" "strings" "sync" - "sync/atomic" "syscall" - "time" "github.com/containerd/stargz-snapshotter/estargz" storage "github.com/containers/storage" graphdriver "github.com/containers/storage/drivers" - driversCopy "github.com/containers/storage/drivers/copy" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chunked/compressor" "github.com/containers/storage/pkg/chunked/internal" @@ -29,8 +27,6 @@ import ( "github.com/containers/storage/pkg/fsverity" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/system" - "github.com/containers/storage/types" - securejoin "github.com/cyphar/filepath-securejoin" jsoniter "github.com/json-iterator/go" "github.com/klauspost/compress/zstd" "github.com/klauspost/pgzip" @@ -42,9 +38,8 @@ import ( const ( maxNumberMissingChunks = 1024 - autoMergePartsThreshold = 128 // if the gap between two ranges is below this threshold, automatically merge them. + autoMergePartsThreshold = 1024 // if the gap between two ranges is below this threshold, automatically merge them. newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY) - containersOverrideXattr = "user.containers.override_stat" bigDataKey = "zstd-chunked-manifest" chunkedData = "zstd-chunked-data" chunkedLayerDataKey = "zstd-chunked-layer-data" @@ -59,21 +54,6 @@ const ( copyGoRoutines = 32 ) -// fileMetadata is a wrapper around internal.FileMetadata with additional private fields that -// are not part of the TOC document. -// Type: TypeChunk entries are stored in Chunks, the primary [fileMetadata] entries never use TypeChunk. -type fileMetadata struct { - internal.FileMetadata - - // chunks stores the TypeChunk entries relevant to this entry when FileMetadata.Type == TypeReg. - chunks []*internal.FileMetadata - - // skipSetAttrs is set when the file attributes must not be - // modified, e.g. it is a hard link from a different source, - // or a composefs file. - skipSetAttrs bool -} - type compressedFileType int type chunkedDiffer struct { @@ -111,7 +91,7 @@ type chunkedDiffer struct { blobSize int64 - storeOpts *types.StoreOptions + pullOptions map[string]string useFsVerity graphdriver.DifferFsVerity fsVerityDigests map[string]string @@ -127,98 +107,7 @@ type chunkedLayerData struct { Format graphdriver.DifferOutputFormat `json:"format"` } -func timeToTimespec(time *time.Time) (ts unix.Timespec) { - if time == nil || time.IsZero() { - // Return UTIME_OMIT special value - ts.Sec = 0 - ts.Nsec = ((1 << 30) - 2) - return - } - return unix.NsecToTimespec(time.UnixNano()) -} - -func doHardLink(srcFd int, destDirFd int, destBase string) error { - doLink := func() error { - // Using unix.AT_EMPTY_PATH requires CAP_DAC_READ_SEARCH while this variant that uses - // /proc/self/fd doesn't and can be used with rootless. - srcPath := fmt.Sprintf("/proc/self/fd/%d", srcFd) - return unix.Linkat(unix.AT_FDCWD, srcPath, destDirFd, destBase, unix.AT_SYMLINK_FOLLOW) - } - - err := doLink() - - // if the destination exists, unlink it first and try again - if err != nil && os.IsExist(err) { - unix.Unlinkat(destDirFd, destBase, 0) - return doLink() - } - return err -} - -func copyFileContent(srcFd int, fileMetadata *fileMetadata, dirfd int, mode os.FileMode, useHardLinks bool) (*os.File, int64, error) { - destFile := fileMetadata.Name - src := fmt.Sprintf("/proc/self/fd/%d", srcFd) - st, err := os.Stat(src) - if err != nil { - return nil, -1, fmt.Errorf("copy file content for %q: %w", destFile, err) - } - - copyWithFileRange, copyWithFileClone := true, true - - if useHardLinks { - destDirPath := filepath.Dir(destFile) - destBase := filepath.Base(destFile) - destDir, err := openFileUnderRoot(destDirPath, dirfd, 0, mode) - if err == nil { - defer destDir.Close() - - err := doHardLink(srcFd, int(destDir.Fd()), destBase) - if err == nil { - // if the file was deduplicated with a hard link, skip overriding file metadata. - fileMetadata.skipSetAttrs = true - return nil, st.Size(), nil - } - } - } - - // If the destination file already exists, we shouldn't blow it away - dstFile, err := openFileUnderRoot(destFile, dirfd, newFileFlags, mode) - if err != nil { - return nil, -1, fmt.Errorf("open file %q under rootfs for copy: %w", destFile, err) - } - - err = driversCopy.CopyRegularToFile(src, dstFile, st, ©WithFileRange, ©WithFileClone) - if err != nil { - dstFile.Close() - return nil, -1, fmt.Errorf("copy to file %q under rootfs: %w", destFile, err) - } - return dstFile, st.Size(), nil -} - -type seekableFile struct { - file *os.File -} - -func (f *seekableFile) Close() error { - return f.file.Close() -} - -func (f *seekableFile) GetBlobAt(chunks []ImageSourceChunk) (chan io.ReadCloser, chan error, error) { - streams := make(chan io.ReadCloser) - errs := make(chan error) - - go func() { - for _, chunk := range chunks { - streams <- io.NopCloser(io.NewSectionReader(f.file, int64(chunk.Offset), int64(chunk.Length))) - } - close(streams) - close(errs) - }() - - return streams, errs, nil -} - -func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *seekableFile, digest.Digest, map[string]string, error) { +func (c *chunkedDiffer) convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *seekableFile, digest.Digest, map[string]string, error) { diff, err := archive.DecompressStream(payload) if err != nil { return 0, nil, "", nil, err @@ -226,7 +115,7 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se fd, err := unix.Open(destDirectory, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600) if err != nil { - return 0, nil, "", nil, err + return 0, nil, "", nil, &fs.PathError{Op: "open", Path: destDirectory, Err: err} } f := os.NewFile(uintptr(fd), destDirectory) @@ -240,7 +129,7 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se } convertedOutputDigester := digest.Canonical.Digester() - copied, err := io.Copy(io.MultiWriter(chunked, convertedOutputDigester.Hash()), diff) + copied, err := io.CopyBuffer(io.MultiWriter(chunked, convertedOutputDigester.Hash()), diff, c.copyBuffer) if err != nil { f.Close() return 0, nil, "", nil, err @@ -249,21 +138,15 @@ func convertTarToZstdChunked(destDirectory string, payload *os.File) (int64, *se f.Close() return 0, nil, "", nil, err } - is := seekableFile{ - file: f, - } - return copied, &is, convertedOutputDigester.Digest(), newAnnotations, nil + return copied, newSeekableFile(f), convertedOutputDigester.Digest(), newAnnotations, nil } // GetDiffer returns a differ than can be used with ApplyDiffWithDiffer. func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable) (graphdriver.Differ, error) { - storeOpts, err := types.DefaultStoreOptions() - if err != nil { - return nil, err - } + pullOptions := store.PullOptions() - if !parseBooleanPullOption(&storeOpts, "enable_partial_images", true) { + if !parseBooleanPullOption(pullOptions, "enable_partial_images", true) { return nil, errors.New("enable_partial_images not configured") } @@ -279,21 +162,21 @@ func GetDiffer(ctx context.Context, store storage.Store, blobDigest digest.Diges if err != nil { return nil, fmt.Errorf("parsing zstd:chunked TOC digest %q: %w", zstdChunkedTOCDigestString, err) } - return makeZstdChunkedDiffer(ctx, store, blobSize, zstdChunkedTOCDigest, annotations, iss, &storeOpts) + return makeZstdChunkedDiffer(ctx, store, blobSize, zstdChunkedTOCDigest, annotations, iss, pullOptions) } if hasEstargzTOC { estargzTOCDigest, err := digest.Parse(estargzTOCDigestString) if err != nil { return nil, fmt.Errorf("parsing estargz TOC digest %q: %w", estargzTOCDigestString, err) } - return makeEstargzChunkedDiffer(ctx, store, blobSize, estargzTOCDigest, iss, &storeOpts) + return makeEstargzChunkedDiffer(ctx, store, blobSize, estargzTOCDigest, iss, pullOptions) } - return makeConvertFromRawDiffer(ctx, store, blobDigest, blobSize, annotations, iss, &storeOpts) + return makeConvertFromRawDiffer(ctx, store, blobDigest, blobSize, annotations, iss, pullOptions) } -func makeConvertFromRawDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) { - if !parseBooleanPullOption(storeOpts, "convert_images", false) { +func makeConvertFromRawDiffer(ctx context.Context, store storage.Store, blobDigest digest.Digest, blobSize int64, annotations map[string]string, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) { + if !parseBooleanPullOption(pullOptions, "convert_images", false) { return nil, errors.New("convert_images not configured") } @@ -309,12 +192,12 @@ func makeConvertFromRawDiffer(ctx context.Context, store storage.Store, blobDige convertToZstdChunked: true, copyBuffer: makeCopyBuffer(), layersCache: layersCache, - storeOpts: storeOpts, + pullOptions: pullOptions, stream: iss, }, nil } -func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, annotations map[string]string, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) { +func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, annotations map[string]string, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) { manifest, toc, tarSplit, tocOffset, err := readZstdChunkedManifest(iss, tocDigest, annotations) if err != nil { return nil, fmt.Errorf("read zstd:chunked manifest: %w", err) @@ -333,14 +216,14 @@ func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize in layersCache: layersCache, manifest: manifest, toc: toc, - storeOpts: storeOpts, + pullOptions: pullOptions, stream: iss, tarSplit: tarSplit, tocOffset: tocOffset, }, nil } -func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, iss ImageSourceSeekable, storeOpts *types.StoreOptions) (*chunkedDiffer, error) { +func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize int64, tocDigest digest.Digest, iss ImageSourceSeekable, pullOptions map[string]string) (*chunkedDiffer, error) { manifest, tocOffset, err := readEstargzChunkedManifest(iss, blobSize, tocDigest) if err != nil { return nil, fmt.Errorf("read zstd:chunked manifest: %w", err) @@ -358,7 +241,7 @@ func makeEstargzChunkedDiffer(ctx context.Context, store storage.Store, blobSize fileType: fileTypeEstargz, layersCache: layersCache, manifest: manifest, - storeOpts: storeOpts, + pullOptions: pullOptions, stream: iss, tocOffset: tocOffset, }, nil @@ -375,15 +258,15 @@ func makeCopyBuffer() []byte { // dirfd is an open file descriptor to the destination root directory. // useHardLinks defines whether the deduplication can be performed using hard links. func copyFileFromOtherLayer(file *fileMetadata, source string, name string, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) { - srcDirfd, err := unix.Open(source, unix.O_RDONLY, 0) + srcDirfd, err := unix.Open(source, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { - return false, nil, 0, fmt.Errorf("open source file: %w", err) + return false, nil, 0, &fs.PathError{Op: "open", Path: source, Err: err} } defer unix.Close(srcDirfd) - srcFile, err := openFileUnderRoot(name, srcDirfd, unix.O_RDONLY, 0) + srcFile, err := openFileUnderRoot(srcDirfd, name, unix.O_RDONLY|syscall.O_CLOEXEC, 0) if err != nil { - return false, nil, 0, fmt.Errorf("open source file under target rootfs (%s): %w", name, err) + return false, nil, 0, err } defer srcFile.Close() @@ -420,7 +303,7 @@ func canDedupFileWithHardLink(file *fileMetadata, fd int, s os.FileInfo) bool { return false } - path := fmt.Sprintf("/proc/self/fd/%d", fd) + path := procPathForFd(fd) listXattrs, err := system.Llistxattr(path) if err != nil { @@ -476,7 +359,7 @@ func findFileInOSTreeRepos(file *fileMetadata, ostreeRepos []string, dirfd int, if st.Size() != file.Size { continue } - fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0) + fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK|unix.O_CLOEXEC, 0) if err != nil { logrus.Debugf("could not open sourceFile %s: %v", sourceFile, err) return false, nil, 0, nil @@ -585,15 +468,15 @@ type missingPart struct { } func (o *originFile) OpenFile() (io.ReadCloser, error) { - srcDirfd, err := unix.Open(o.Root, unix.O_RDONLY, 0) + srcDirfd, err := unix.Open(o.Root, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { - return nil, fmt.Errorf("open source file: %w", err) + return nil, &fs.PathError{Op: "open", Path: o.Root, Err: err} } defer unix.Close(srcDirfd) - srcFile, err := openFileUnderRoot(o.Path, srcDirfd, unix.O_RDONLY, 0) + srcFile, err := openFileUnderRoot(srcDirfd, o.Path, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { - return nil, fmt.Errorf("open source file under target rootfs: %w", err) + return nil, err } if _, err := srcFile.Seek(o.Offset, 0); err != nil { @@ -603,253 +486,6 @@ func (o *originFile) OpenFile() (io.ReadCloser, error) { return srcFile, nil } -// setFileAttrs sets the file attributes for file given metadata -func setFileAttrs(dirfd int, file *os.File, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions, usePath bool) error { - if metadata.skipSetAttrs { - return nil - } - if file == nil || file.Fd() < 0 { - return errors.New("invalid file") - } - fd := int(file.Fd()) - - t, err := typeToTarType(metadata.Type) - if err != nil { - return err - } - - // If it is a symlink, force to use the path - if t == tar.TypeSymlink { - usePath = true - } - - baseName := "" - if usePath { - dirName := filepath.Dir(metadata.Name) - if dirName != "" { - parentFd, err := openFileUnderRoot(dirName, dirfd, unix.O_PATH|unix.O_DIRECTORY, 0) - if err != nil { - return err - } - defer parentFd.Close() - - dirfd = int(parentFd.Fd()) - } - baseName = filepath.Base(metadata.Name) - } - - doChown := func() error { - if usePath { - return unix.Fchownat(dirfd, baseName, metadata.UID, metadata.GID, unix.AT_SYMLINK_NOFOLLOW) - } - return unix.Fchown(fd, metadata.UID, metadata.GID) - } - - doSetXattr := func(k string, v []byte) error { - return unix.Fsetxattr(fd, k, v, 0) - } - - doUtimes := func() error { - ts := []unix.Timespec{timeToTimespec(metadata.AccessTime), timeToTimespec(metadata.ModTime)} - if usePath { - return unix.UtimesNanoAt(dirfd, baseName, ts, unix.AT_SYMLINK_NOFOLLOW) - } - return unix.UtimesNanoAt(unix.AT_FDCWD, fmt.Sprintf("/proc/self/fd/%d", fd), ts, 0) - } - - doChmod := func() error { - if usePath { - return unix.Fchmodat(dirfd, baseName, uint32(mode), unix.AT_SYMLINK_NOFOLLOW) - } - return unix.Fchmod(fd, uint32(mode)) - } - - if err := doChown(); err != nil { - if !options.IgnoreChownErrors { - return fmt.Errorf("chown %q to %d:%d: %w", metadata.Name, metadata.UID, metadata.GID, err) - } - } - - canIgnore := func(err error) bool { - return err == nil || errors.Is(err, unix.ENOSYS) || errors.Is(err, unix.ENOTSUP) - } - - for k, v := range metadata.Xattrs { - if _, found := xattrsToIgnore[k]; found { - continue - } - data, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return fmt.Errorf("decode xattr %q: %w", v, err) - } - if err := doSetXattr(k, data); !canIgnore(err) { - return fmt.Errorf("set xattr %s=%q for %q: %w", k, data, metadata.Name, err) - } - } - - if err := doUtimes(); !canIgnore(err) { - return fmt.Errorf("set utimes for %q: %w", metadata.Name, err) - } - - if err := doChmod(); !canIgnore(err) { - return fmt.Errorf("chmod %q: %w", metadata.Name, err) - } - return nil -} - -func openFileUnderRootFallback(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { - root := fmt.Sprintf("/proc/self/fd/%d", dirfd) - - targetRoot, err := os.Readlink(root) - if err != nil { - return -1, err - } - - hasNoFollow := (flags & unix.O_NOFOLLOW) != 0 - - var fd int - // If O_NOFOLLOW is specified in the flags, then resolve only the parent directory and use the - // last component as the path to openat(). - if hasNoFollow { - dirName := filepath.Dir(name) - if dirName != "" { - newRoot, err := securejoin.SecureJoin(root, filepath.Dir(name)) - if err != nil { - return -1, err - } - root = newRoot - } - - parentDirfd, err := unix.Open(root, unix.O_PATH, 0) - if err != nil { - return -1, err - } - defer unix.Close(parentDirfd) - - fd, err = unix.Openat(parentDirfd, filepath.Base(name), int(flags), uint32(mode)) - if err != nil { - return -1, err - } - } else { - newPath, err := securejoin.SecureJoin(root, name) - if err != nil { - return -1, err - } - fd, err = unix.Openat(dirfd, newPath, int(flags), uint32(mode)) - if err != nil { - return -1, err - } - } - - target, err := os.Readlink(fmt.Sprintf("/proc/self/fd/%d", fd)) - if err != nil { - unix.Close(fd) - return -1, err - } - - // Add an additional check to make sure the opened fd is inside the rootfs - if !strings.HasPrefix(target, targetRoot) { - unix.Close(fd) - return -1, fmt.Errorf("while resolving %q. It resolves outside the root directory", name) - } - - return fd, err -} - -func openFileUnderRootOpenat2(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { - how := unix.OpenHow{ - Flags: flags, - Mode: uint64(mode & 0o7777), - Resolve: unix.RESOLVE_IN_ROOT, - } - return unix.Openat2(dirfd, name, &how) -} - -// skipOpenat2 is set when openat2 is not supported by the underlying kernel and avoid -// using it again. -var skipOpenat2 int32 - -// openFileUnderRootRaw tries to open a file using openat2 and if it is not supported fallbacks to a -// userspace lookup. -func openFileUnderRootRaw(dirfd int, name string, flags uint64, mode os.FileMode) (int, error) { - var fd int - var err error - if atomic.LoadInt32(&skipOpenat2) > 0 { - fd, err = openFileUnderRootFallback(dirfd, name, flags, mode) - } else { - fd, err = openFileUnderRootOpenat2(dirfd, name, flags, mode) - // If the function failed with ENOSYS, switch off the support for openat2 - // and fallback to using safejoin. - if err != nil && errors.Is(err, unix.ENOSYS) { - atomic.StoreInt32(&skipOpenat2, 1) - fd, err = openFileUnderRootFallback(dirfd, name, flags, mode) - } - } - return fd, err -} - -// openFileUnderRoot safely opens a file under the specified root directory using openat2 -// name is the path to open relative to dirfd. -// dirfd is an open file descriptor to the target checkout directory. -// flags are the flags to pass to the open syscall. -// mode specifies the mode to use for newly created files. -func openFileUnderRoot(name string, dirfd int, flags uint64, mode os.FileMode) (*os.File, error) { - fd, err := openFileUnderRootRaw(dirfd, name, flags, mode) - if err == nil { - return os.NewFile(uintptr(fd), name), nil - } - - hasCreate := (flags & unix.O_CREAT) != 0 - if errors.Is(err, unix.ENOENT) && hasCreate { - parent := filepath.Dir(name) - if parent != "" { - newDirfd, err2 := openOrCreateDirUnderRoot(parent, dirfd, 0) - if err2 == nil { - defer newDirfd.Close() - fd, err := openFileUnderRootRaw(int(newDirfd.Fd()), filepath.Base(name), flags, mode) - if err == nil { - return os.NewFile(uintptr(fd), name), nil - } - } - } - } - return nil, fmt.Errorf("open %q under the rootfs: %w", name, err) -} - -// openOrCreateDirUnderRoot safely opens a directory or create it if it is missing. -// name is the path to open relative to dirfd. -// dirfd is an open file descriptor to the target checkout directory. -// mode specifies the mode to use for newly created files. -func openOrCreateDirUnderRoot(name string, dirfd int, mode os.FileMode) (*os.File, error) { - fd, err := openFileUnderRootRaw(dirfd, name, unix.O_DIRECTORY|unix.O_RDONLY, mode) - if err == nil { - return os.NewFile(uintptr(fd), name), nil - } - - if errors.Is(err, unix.ENOENT) { - parent := filepath.Dir(name) - if parent != "" { - pDir, err2 := openOrCreateDirUnderRoot(parent, dirfd, mode) - if err2 != nil { - return nil, err - } - defer pDir.Close() - - baseName := filepath.Base(name) - - if err2 := unix.Mkdirat(int(pDir.Fd()), baseName, 0o755); err2 != nil { - return nil, err - } - - fd, err = openFileUnderRootRaw(int(pDir.Fd()), baseName, unix.O_DIRECTORY|unix.O_RDONLY, mode) - if err == nil { - return os.NewFile(uintptr(fd), name), nil - } - } - } - return nil, err -} - func (c *chunkedDiffer) prepareCompressedStreamToFile(partCompression compressedFileType, from io.Reader, mf *missingFileChunk) (compressedFileType, error) { switch { case partCompression == fileTypeHole: @@ -918,19 +554,6 @@ func hashHole(h hash.Hash, size int64, copyBuffer []byte) error { return nil } -// appendHole creates a hole with the specified size at the open fd. -func appendHole(fd int, size int64) error { - off, err := unix.Seek(fd, size, unix.SEEK_CUR) - if err != nil { - return err - } - // Make sure the file size is changed. It might be the last hole and no other data written afterwards. - if err := unix.Ftruncate(fd, off); err != nil { - return err - } - return nil -} - func (c *chunkedDiffer) appendCompressedStreamToFile(compression compressedFileType, destFile *destinationFile, size int64) error { switch compression { case fileTypeZstdChunked: @@ -948,7 +571,7 @@ func (c *chunkedDiffer) appendCompressedStreamToFile(compression compressedFileT return err } case fileTypeHole: - if err := appendHole(int(destFile.file.Fd()), size); err != nil { + if err := appendHole(int(destFile.file.Fd()), destFile.metadata.Name, size); err != nil { return err } if destFile.hash != nil { @@ -977,7 +600,7 @@ type destinationFile struct { } func openDestinationFile(dirfd int, metadata *fileMetadata, options *archive.TarOptions, skipValidation bool, recordFsVerity recordFsVerityFunc) (*destinationFile, error) { - file, err := openFileUnderRoot(metadata.Name, dirfd, newFileFlags, 0) + file, err := openFileUnderRoot(dirfd, metadata.Name, newFileFlags, 0) if err != nil { return nil, err } @@ -1339,161 +962,6 @@ func (c *chunkedDiffer) retrieveMissingFiles(stream ImageSourceSeekable, dest st return nil } -func safeMkdir(dirfd int, mode os.FileMode, name string, metadata *fileMetadata, options *archive.TarOptions) error { - parent := filepath.Dir(name) - base := filepath.Base(name) - - parentFd := dirfd - if parent != "." { - parentFile, err := openOrCreateDirUnderRoot(parent, dirfd, 0) - if err != nil { - return err - } - defer parentFile.Close() - parentFd = int(parentFile.Fd()) - } - - if err := unix.Mkdirat(parentFd, base, uint32(mode)); err != nil { - if !os.IsExist(err) { - return fmt.Errorf("mkdir %q: %w", name, err) - } - } - - file, err := openFileUnderRoot(base, parentFd, unix.O_DIRECTORY|unix.O_RDONLY, 0) - if err != nil { - return err - } - defer file.Close() - - return setFileAttrs(dirfd, file, mode, metadata, options, false) -} - -func safeLink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error { - sourceFile, err := openFileUnderRoot(metadata.Linkname, dirfd, unix.O_PATH|unix.O_RDONLY|unix.O_NOFOLLOW, 0) - if err != nil { - return err - } - defer sourceFile.Close() - - destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name) - destDirFd := dirfd - if destDir != "." { - f, err := openOrCreateDirUnderRoot(destDir, dirfd, 0) - if err != nil { - return err - } - defer f.Close() - destDirFd = int(f.Fd()) - } - - err = doHardLink(int(sourceFile.Fd()), destDirFd, destBase) - if err != nil { - return fmt.Errorf("create hardlink %q pointing to %q: %w", metadata.Name, metadata.Linkname, err) - } - - newFile, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_WRONLY|unix.O_NOFOLLOW, 0) - if err != nil { - // If the target is a symlink, open the file with O_PATH. - if errors.Is(err, unix.ELOOP) { - newFile, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_PATH|unix.O_NOFOLLOW, 0) - if err != nil { - return err - } - defer newFile.Close() - - return setFileAttrs(dirfd, newFile, mode, metadata, options, true) - } - return err - } - defer newFile.Close() - - return setFileAttrs(dirfd, newFile, mode, metadata, options, false) -} - -func safeSymlink(dirfd int, mode os.FileMode, metadata *fileMetadata, options *archive.TarOptions) error { - destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name) - destDirFd := dirfd - if destDir != "." { - f, err := openOrCreateDirUnderRoot(destDir, dirfd, 0) - if err != nil { - return err - } - defer f.Close() - destDirFd = int(f.Fd()) - } - - if err := unix.Symlinkat(metadata.Linkname, destDirFd, destBase); err != nil { - return fmt.Errorf("create symlink %q pointing to %q: %w", metadata.Name, metadata.Linkname, err) - } - return nil -} - -type whiteoutHandler struct { - Dirfd int - Root string -} - -func (d whiteoutHandler) Setxattr(path, name string, value []byte) error { - file, err := openOrCreateDirUnderRoot(path, d.Dirfd, 0) - if err != nil { - return err - } - defer file.Close() - - if err := unix.Fsetxattr(int(file.Fd()), name, value, 0); err != nil { - return fmt.Errorf("set xattr %s=%q for %q: %w", name, value, path, err) - } - return nil -} - -func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error { - dir := filepath.Dir(path) - base := filepath.Base(path) - - dirfd := d.Dirfd - if dir != "" { - dir, err := openOrCreateDirUnderRoot(dir, d.Dirfd, 0) - if err != nil { - return err - } - defer dir.Close() - - dirfd = int(dir.Fd()) - } - - if err := unix.Mknodat(dirfd, base, mode, dev); err != nil { - return fmt.Errorf("mknod %q: %w", path, err) - } - - return nil -} - -func checkChownErr(err error, name string, uid, gid int) error { - if errors.Is(err, syscall.EINVAL) { - return fmt.Errorf(`potentially insufficient UIDs or GIDs available in user namespace (requested %d:%d for %s): Check /etc/subuid and /etc/subgid if configured locally and run "podman system migrate": %w`, uid, gid, name, err) - } - return err -} - -func (d whiteoutHandler) Chown(path string, uid, gid int) error { - file, err := openFileUnderRoot(path, d.Dirfd, unix.O_PATH, 0) - if err != nil { - return err - } - defer file.Close() - - if err := unix.Fchownat(int(file.Fd()), "", uid, gid, unix.AT_EMPTY_PATH); err != nil { - var stat unix.Stat_t - if unix.Fstat(int(file.Fd()), &stat) == nil { - if stat.Uid == uint32(uid) && stat.Gid == uint32(gid) { - return nil - } - } - return checkChownErr(err, path, uid, gid) - } - return nil -} - type hardLinkToCreate struct { dest string dirfd int @@ -1501,8 +969,8 @@ type hardLinkToCreate struct { metadata *fileMetadata } -func parseBooleanPullOption(storeOpts *storage.StoreOptions, name string, def bool) bool { - if value, ok := storeOpts.PullOptions[name]; ok { +func parseBooleanPullOption(pullOptions map[string]string, name string, def bool) bool { + if value, ok := pullOptions[name]; ok { return strings.ToLower(value) == "true" } return def @@ -1515,10 +983,10 @@ type findAndCopyFileOptions struct { } func reopenFileReadOnly(f *os.File) (*os.File, error) { - path := fmt.Sprintf("/proc/self/fd/%d", f.Fd()) + path := procPathForFile(f) fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { - return nil, err + return nil, &fs.PathError{Op: "open", Path: path, Err: err} } return os.NewFile(uintptr(fd), f.Name()), nil } @@ -1636,7 +1104,7 @@ func (c *chunkedDiffer) copyAllBlobToFile(destination *os.File) (digest.Digest, r := io.TeeReader(payload, originalRawDigester.Hash()) // copy the entire tarball and compute its digest - _, err = io.Copy(destination, r) + _, err = io.CopyBuffer(destination, r, c.copyBuffer) return originalRawDigester.Digest(), err } @@ -1660,7 +1128,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff if c.convertToZstdChunked { fd, err := unix.Open(dest, unix.O_TMPFILE|unix.O_RDWR|unix.O_CLOEXEC, 0o600) if err != nil { - return graphdriver.DriverWithDifferOutput{}, err + return graphdriver.DriverWithDifferOutput{}, &fs.PathError{Op: "open", Path: dest, Err: err} } blobFile := os.NewFile(uintptr(fd), "blob-file") defer func() { @@ -1683,7 +1151,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff return graphdriver.DriverWithDifferOutput{}, err } - tarSize, fileSource, diffID, annotations, err := convertTarToZstdChunked(dest, blobFile) + tarSize, fileSource, diffID, annotations, err := c.convertTarToZstdChunked(dest, blobFile) if err != nil { return graphdriver.DriverWithDifferOutput{}, err } @@ -1760,10 +1228,10 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff // When the hard links deduplication is used, file attributes are ignored because setting them // modifies the source file as well. - useHardLinks := parseBooleanPullOption(c.storeOpts, "use_hard_links", false) + useHardLinks := parseBooleanPullOption(c.pullOptions, "use_hard_links", false) // List of OSTree repositories to use for deduplication - ostreeRepos := strings.Split(c.storeOpts.PullOptions["ostree_repos"], ":") + ostreeRepos := strings.Split(c.pullOptions["ostree_repos"], ":") whiteoutConverter := archive.GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData) @@ -1790,16 +1258,19 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff if options.ForceMask != nil { uid, gid, mode, err := archive.GetFileOwner(dest) if err == nil { - value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode) - if err := unix.Setxattr(dest, containersOverrideXattr, []byte(value), 0); err != nil { + value := idtools.Stat{ + IDs: idtools.IDPair{UID: int(uid), GID: int(gid)}, + Mode: os.FileMode(mode), + } + if err := idtools.SetContainersOverrideXattr(dest, value); err != nil { return output, err } } } - dirfd, err := unix.Open(dest, unix.O_RDONLY|unix.O_PATH, 0) + dirfd, err := unix.Open(dest, unix.O_RDONLY|unix.O_PATH|unix.O_CLOEXEC, 0) if err != nil { - return output, fmt.Errorf("cannot open %q: %w", dest, err) + return output, &fs.PathError{Op: "open", Path: dest, Err: err} } defer unix.Close(dirfd) @@ -1868,11 +1339,14 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff } filesToWaitFor := 0 - for i, r := range mergedEntries { + for i := range mergedEntries { + r := &mergedEntries[i] if options.ForceMask != nil { - value := fmt.Sprintf("%d:%d:0%o", r.UID, r.GID, r.Mode&0o7777) - r.Xattrs[containersOverrideXattr] = base64.StdEncoding.EncodeToString([]byte(value)) - r.Mode = int64(*options.ForceMask) + value := idtools.FormatContainersOverrideXattr(r.UID, r.GID, int(r.Mode)) + if r.Xattrs == nil { + r.Xattrs = make(map[string]string) + } + r.Xattrs[idtools.ContainersOverrideXattr] = base64.StdEncoding.EncodeToString([]byte(value)) } mode := os.FileMode(r.Mode) @@ -1916,12 +1390,12 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff if r.Size == 0 { // Used to have a scope for cleanup. createEmptyFile := func() error { - file, err := openFileUnderRoot(r.Name, dirfd, newFileFlags, 0) + file, err := openFileUnderRoot(dirfd, r.Name, newFileFlags, 0) if err != nil { return err } defer file.Close() - if err := setFileAttrs(dirfd, file, mode, &r, options, false); err != nil { + if err := setFileAttrs(dirfd, file, mode, r, options, false); err != nil { return err } return nil @@ -1936,7 +1410,7 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff if r.Name == "" || r.Name == "." { output.RootDirMode = &mode } - if err := safeMkdir(dirfd, mode, r.Name, &r, options); err != nil { + if err := safeMkdir(dirfd, mode, r.Name, r, options); err != nil { return output, err } continue @@ -1950,12 +1424,12 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff dest: dest, dirfd: dirfd, mode: mode, - metadata: &r, + metadata: r, }) continue case tar.TypeSymlink: - if err := safeSymlink(dirfd, mode, &r, options); err != nil { + if err := safeSymlink(dirfd, mode, r, options); err != nil { return output, err } continue @@ -2167,13 +1641,13 @@ func (c *chunkedDiffer) mergeTocEntries(fileType compressedFileType, entries []i // validateChunkChecksum checks if the file at $root/$path[offset:chunk.ChunkSize] has the // same digest as chunk.ChunkDigest func validateChunkChecksum(chunk *internal.FileMetadata, root, path string, offset int64, copyBuffer []byte) bool { - parentDirfd, err := unix.Open(root, unix.O_PATH, 0) + parentDirfd, err := unix.Open(root, unix.O_PATH|unix.O_CLOEXEC, 0) if err != nil { return false } defer unix.Close(parentDirfd) - fd, err := openFileUnderRoot(path, parentDirfd, unix.O_RDONLY, 0) + fd, err := openFileUnderRoot(parentDirfd, path, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { return false } diff --git a/vendor/github.com/containers/storage/pkg/config/config.go b/vendor/github.com/containers/storage/pkg/config/config.go index 7f49d029d..560df3cf5 100644 --- a/vendor/github.com/containers/storage/pkg/config/config.go +++ b/vendor/github.com/containers/storage/pkg/config/config.go @@ -75,10 +75,6 @@ type OptionsConfig struct { // Size Size string `toml:"size,omitempty"` - // RemapUIDs is a list of default UID mappings to use for layers. - RemapUIDs string `toml:"remap-uids,omitempty"` - // RemapGIDs is a list of default GID mappings to use for layers. - RemapGIDs string `toml:"remap-gids,omitempty"` // IgnoreChownErrors is a flag for whether chown errors should be // ignored when building an image. IgnoreChownErrors string `toml:"ignore_chown_errors,omitempty"` @@ -90,13 +86,6 @@ type OptionsConfig struct { // files and directories. ForceMask os.FileMode `toml:"force_mask,omitempty"` - // RemapUser is the name of one or more entries in /etc/subuid which - // should be used to set up default UID mappings. - RemapUser string `toml:"remap-user,omitempty"` - // RemapGroup is the name of one or more entries in /etc/subgid which - // should be used to set up default GID mappings. - RemapGroup string `toml:"remap-group,omitempty"` - // RootAutoUsernsUser is the name of one or more entries in /etc/subuid and // /etc/subgid which should be used to set up automatically a userns. RootAutoUsernsUser string `toml:"root-auto-userns-user,omitempty"` diff --git a/vendor/github.com/containers/storage/pkg/directory/directory_unix.go b/vendor/github.com/containers/storage/pkg/directory/directory_unix.go index 36e1bdd5f..dd6c02a77 100644 --- a/vendor/github.com/containers/storage/pkg/directory/directory_unix.go +++ b/vendor/github.com/containers/storage/pkg/directory/directory_unix.go @@ -1,5 +1,5 @@ -//go:build linux || darwin || freebsd || solaris -// +build linux darwin freebsd solaris +//go:build !windows +// +build !windows package directory diff --git a/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go b/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go deleted file mode 100644 index 9057fe1b2..000000000 --- a/vendor/github.com/containers/storage/pkg/homedir/homedir_others.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build !linux && !darwin && !freebsd && !windows -// +build !linux,!darwin,!freebsd,!windows - -package homedir - -// Copyright 2013-2018 Docker, Inc. -// NOTE: this package has originally been copied from github.com/docker/docker. - -import ( - "errors" - "os" - "path/filepath" -) - -// GetRuntimeDir is unsupported on non-linux system. -func GetRuntimeDir() (string, error) { - return "", errors.New("homedir.GetRuntimeDir() is not supported on this system") -} - -// StickRuntimeDirContents is unsupported on non-linux system. -func StickRuntimeDirContents(files []string) ([]string, error) { - return nil, errors.New("homedir.StickRuntimeDirContents() is not supported on this system") -} - -// GetConfigHome returns XDG_CONFIG_HOME. -// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set. -// -// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html -func GetConfigHome() (string, error) { - if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" { - return xdgConfigHome, nil - } - home := Get() - if home == "" { - return "", errors.New("could not get either XDG_CONFIG_HOME or HOME") - } - return filepath.Join(home, ".config"), nil -} diff --git a/vendor/github.com/containers/storage/pkg/idtools/idtools.go b/vendor/github.com/containers/storage/pkg/idtools/idtools.go index ef5a95254..dc963481a 100644 --- a/vendor/github.com/containers/storage/pkg/idtools/idtools.go +++ b/vendor/github.com/containers/storage/pkg/idtools/idtools.go @@ -367,21 +367,77 @@ func checkChownErr(err error, name string, uid, gid int) error { return err } +// Stat contains file states that can be overriden with ContainersOverrideXattr. +type Stat struct { + IDs IDPair + Mode os.FileMode +} + +// FormatContainersOverrideXattr will format the given uid, gid, and mode into a string +// that can be used as the value for the ContainersOverrideXattr xattr. +func FormatContainersOverrideXattr(uid, gid, mode int) string { + return fmt.Sprintf("%d:%d:0%o", uid, gid, mode&0o7777) +} + +// GetContainersOverrideXattr will get and decode ContainersOverrideXattr. +func GetContainersOverrideXattr(path string) (Stat, error) { + var stat Stat + xstat, err := system.Lgetxattr(path, ContainersOverrideXattr) + if err != nil { + return stat, err + } + + attrs := strings.Split(string(xstat), ":") + if len(attrs) != 3 { + return stat, fmt.Errorf("The number of clons in %s does not equal to 3", + ContainersOverrideXattr) + } + + value, err := strconv.ParseUint(attrs[0], 10, 32) + if err != nil { + return stat, fmt.Errorf("Failed to parse UID: %w", err) + } + + stat.IDs.UID = int(value) + + value, err = strconv.ParseUint(attrs[0], 10, 32) + if err != nil { + return stat, fmt.Errorf("Failed to parse GID: %w", err) + } + + stat.IDs.GID = int(value) + + value, err = strconv.ParseUint(attrs[2], 8, 32) + if err != nil { + return stat, fmt.Errorf("Failed to parse mode: %w", err) + } + + stat.Mode = os.FileMode(value) + + return stat, nil +} + +// SetContainersOverrideXattr will encode and set ContainersOverrideXattr. +func SetContainersOverrideXattr(path string, stat Stat) error { + value := FormatContainersOverrideXattr(stat.IDs.UID, stat.IDs.GID, int(stat.Mode)) + return system.Lsetxattr(path, ContainersOverrideXattr, []byte(value), 0) +} + func SafeChown(name string, uid, gid int) error { if runtime.GOOS == "darwin" { - var mode uint64 = 0o0700 + var mode os.FileMode = 0o0700 xstat, err := system.Lgetxattr(name, ContainersOverrideXattr) if err == nil { attrs := strings.Split(string(xstat), ":") if len(attrs) == 3 { val, err := strconv.ParseUint(attrs[2], 8, 32) if err == nil { - mode = val + mode = os.FileMode(val) } } } - value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode) - if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil { + value := Stat{IDPair{uid, gid}, mode} + if err = SetContainersOverrideXattr(name, value); err != nil { return err } uid = os.Getuid() @@ -397,19 +453,19 @@ func SafeChown(name string, uid, gid int) error { func SafeLchown(name string, uid, gid int) error { if runtime.GOOS == "darwin" { - var mode uint64 = 0o0700 + var mode os.FileMode = 0o0700 xstat, err := system.Lgetxattr(name, ContainersOverrideXattr) if err == nil { attrs := strings.Split(string(xstat), ":") if len(attrs) == 3 { val, err := strconv.ParseUint(attrs[2], 8, 32) if err == nil { - mode = val + mode = os.FileMode(val) } } } - value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode) - if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil { + value := Stat{IDPair{uid, gid}, mode} + if err = SetContainersOverrideXattr(name, value); err != nil { return err } uid = os.Getuid() diff --git a/vendor/github.com/containers/storage/pkg/lockfile/lockfile.go b/vendor/github.com/containers/storage/pkg/lockfile/lockfile.go index 510147578..faf995a2d 100644 --- a/vendor/github.com/containers/storage/pkg/lockfile/lockfile.go +++ b/vendor/github.com/containers/storage/pkg/lockfile/lockfile.go @@ -426,10 +426,13 @@ func (l *LockFile) lock(lType lockType) { // command. func (l *LockFile) tryLock(lType lockType) error { var success bool + var rwMutexUnlocker func() if lType == readLock { success = l.rwMutex.TryRLock() + rwMutexUnlocker = l.rwMutex.RUnlock } else { success = l.rwMutex.TryLock() + rwMutexUnlocker = l.rwMutex.Unlock } if !success { return fmt.Errorf("resource temporarily unavailable") @@ -440,7 +443,7 @@ func (l *LockFile) tryLock(lType lockType) error { // If we're the first reference on the lock, we need to open the file again. fd, err := openLock(l.file, l.ro) if err != nil { - l.rwMutex.Unlock() + rwMutexUnlocker() return err } l.fd = fd @@ -450,7 +453,7 @@ func (l *LockFile) tryLock(lType lockType) error { // reader lock or a writer lock. if err = lockHandle(l.fd, lType, true); err != nil { closeHandle(fd) - l.rwMutex.Unlock() + rwMutexUnlocker() return err } } diff --git a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go index 0eff003bc..6c8399f9e 100644 --- a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go +++ b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go @@ -1,5 +1,5 @@ -//go:build linux || solaris || darwin || freebsd -// +build linux solaris darwin freebsd +//go:build !windows +// +build !windows package lockfile diff --git a/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go b/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go index cbc0299fb..2d9e75ea1 100644 --- a/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go +++ b/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go @@ -1,5 +1,18 @@ package mount -import "github.com/moby/sys/mountinfo" +import ( + "fmt" + "os" -var PidMountInfo = mountinfo.PidMountInfo + "github.com/moby/sys/mountinfo" +) + +func PidMountInfo(pid int) ([]*Info, error) { + f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) + if err != nil { + return nil, err + } + defer f.Close() + + return mountinfo.GetMountsFromReader(f, nil) +} diff --git a/vendor/github.com/containers/storage/pkg/system/syscall_unix.go b/vendor/github.com/containers/storage/pkg/system/syscall_unix.go index c4816c133..217e2fe83 100644 --- a/vendor/github.com/containers/storage/pkg/system/syscall_unix.go +++ b/vendor/github.com/containers/storage/pkg/system/syscall_unix.go @@ -1,5 +1,5 @@ -//go:build linux || freebsd || darwin -// +build linux freebsd darwin +//go:build !windows +// +build !windows package system diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go index a8dc1ba03..58adbfb8a 100644 --- a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go +++ b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go @@ -526,8 +526,11 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { } else { // If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able // to use unshare(), so don't bother creating a new user namespace at this point. - capabilities, err := capability.NewPid(0) + capabilities, err := capability.NewPid2(0) + bailOnError(err, "Initializing a new Capabilities object of pid 0") + err = capabilities.Load() bailOnError(err, "Reading the current capabilities sets") + if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) { return } diff --git a/vendor/github.com/containers/storage/storage.conf b/vendor/github.com/containers/storage/storage.conf index 0f8d1f024..94a9b36d4 100644 --- a/vendor/github.com/containers/storage/storage.conf +++ b/vendor/github.com/containers/storage/storage.conf @@ -19,6 +19,10 @@ driver = "overlay" # Temporary storage location runroot = "/run/containers/storage" +# Priority list for the storage drivers that will be tested one +# after the other to pick the storage driver if it is not defined. +# driver_priority = ["overlay", "btrfs"] + # Primary Read/Write location of container storage # When changing the graphroot location on an SELINUX system, you must # ensure the labeling matches the default locations labels with the @@ -77,28 +81,6 @@ additionalimagestores = [ # operation so it is not enabled by default. pull_options = {enable_partial_images = "true", use_hard_links = "false", ostree_repos=""} -# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of -# a container, to the UIDs/GIDs as they should appear outside of the container, -# and the length of the range of UIDs/GIDs. Additional mapped sets can be -# listed and will be heeded by libraries, but there are limits to the number of -# mappings which the kernel will allow when you later attempt to run a -# container. -# -# remap-uids = "0:1668442479:65536" -# remap-gids = "0:1668442479:65536" - -# Remap-User/Group is a user name which can be used to look up one or more UID/GID -# ranges in the /etc/subuid or /etc/subgid file. Mappings are set up starting -# with an in-container ID of 0 and then a host-level ID taken from the lowest -# range that matches the specified name, and using the length of that range. -# Additional ranges are then assigned, using the ranges which specify the -# lowest host-level IDs first, to the lowest not-yet-mapped in-container ID, -# until all of the entries have been used for maps. This setting overrides the -# Remap-UIDs/GIDs setting. -# -# remap-user = "containers" -# remap-group = "containers" - # Root-auto-userns-user is a user name which can be used to look up one or more UID/GID # ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned # to containers configured to create automatically a user namespace. Containers diff --git a/vendor/github.com/containers/storage/storage.conf-freebsd b/vendor/github.com/containers/storage/storage.conf-freebsd index 43278a1fc..5f421e0c1 100644 --- a/vendor/github.com/containers/storage/storage.conf-freebsd +++ b/vendor/github.com/containers/storage/storage.conf-freebsd @@ -39,27 +39,6 @@ graphroot = "/var/db/containers/storage" additionalimagestores = [ ] -# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of -# a container, to the UIDs/GIDs as they should appear outside of the container, -# and the length of the range of UIDs/GIDs. Additional mapped sets can be -# listed and will be heeded by libraries, but there are limits to the number of -# mappings which the kernel will allow when you later attempt to run a -# container. -# -# remap-uids = 0:1668442479:65536 -# remap-gids = 0:1668442479:65536 - -# Remap-User/Group is a user name which can be used to look up one or more UID/GID -# ranges in the /etc/subuid or /etc/subgid file. Mappings are set up starting -# with an in-container ID of 0 and then a host-level ID taken from the lowest -# range that matches the specified name, and using the length of that range. -# Additional ranges are then assigned, using the ranges which specify the -# lowest host-level IDs first, to the lowest not-yet-mapped in-container ID, -# until all of the entries have been used for maps. -# -# remap-user = "containers" -# remap-group = "containers" - # Root-auto-userns-user is a user name which can be used to look up one or more UID/GID # ranges in the /etc/subuid and /etc/subgid file. These ranges will be partitioned # to containers configured to create automatically a user namespace. Containers diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go index 957675ba4..29af59320 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -1088,8 +1088,6 @@ func (s *store) createGraphDriverLocked() (drivers.Driver, error) { RunRoot: s.runRoot, DriverPriority: s.graphDriverPriority, DriverOptions: s.graphOptions, - UIDMaps: s.uidMap, - GIDMaps: s.gidMap, } return drivers.New(s.graphDriverName, config) } @@ -1437,7 +1435,9 @@ func (s *store) canUseShifting(uidmap, gidmap []idtools.IDMap) bool { return true } -// putLayer requires the rlstore, rlstores, as well as s.containerStore (even if not an argument to this function) to be locked for write. +// On entry: +// - rlstore must be locked for writing +// - rlstores MUST NOT be locked func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader, slo *stagedLayerOptions) (*Layer, int64, error) { var parentLayer *Layer var options LayerOptions @@ -1474,6 +1474,11 @@ func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, pare return nil, -1, ErrLayerUnknown } parentLayer = ilayer + + if err := s.containerStore.startWriting(); err != nil { + return nil, -1, err + } + defer s.containerStore.stopWriting() containers, err := s.containerStore.Containers() if err != nil { return nil, -1, err @@ -1490,6 +1495,13 @@ func (s *store) putLayer(rlstore rwLayerStore, rlstores []roLayerStore, id, pare gidMap = ilayer.GIDMap } } else { + // FIXME? It’s unclear why we are holding containerStore locked here at all + // (and because we are not modifying it, why it is a write lock, not a read lock). + if err := s.containerStore.startWriting(); err != nil { + return nil, -1, err + } + defer s.containerStore.stopWriting() + if !options.HostUIDMapping && len(options.UIDMap) == 0 { uidMap = s.uidMap } @@ -1525,10 +1537,6 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w return nil, -1, err } defer rlstore.stopWriting() - if err := s.containerStore.startWriting(); err != nil { - return nil, -1, err - } - defer s.containerStore.stopWriting() return s.putLayer(rlstore, rlstores, id, parent, names, mountLabel, writeable, lOptions, diff, nil) } @@ -3009,16 +3017,14 @@ func (s *store) ApplyStagedLayer(args ApplyStagedLayerOptions) (*Layer, error) { return layer, err } if err == nil { + // This code path exists only for cmd/containers/storage.applyDiffUsingStagingDirectory; we have tests that + // assume layer creation and applying a staged layer are separate steps. Production pull code always uses the + // other path, where layer creation is atomic. return layer, rlstore.applyDiffFromStagingDirectory(args.ID, args.DiffOutput, args.DiffOptions) } // if the layer doesn't exist yet, try to create it. - if err := s.containerStore.startWriting(); err != nil { - return nil, err - } - defer s.containerStore.stopWriting() - slo := stagedLayerOptions{ DiffOutput: args.DiffOutput, DiffOptions: args.DiffOptions, diff --git a/vendor/github.com/containers/storage/types/options.go b/vendor/github.com/containers/storage/types/options.go index 03e5f7ab6..7cf5bcf93 100644 --- a/vendor/github.com/containers/storage/types/options.go +++ b/vendor/github.com/containers/storage/types/options.go @@ -481,33 +481,6 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) erro if config.Storage.Options.MountOpt != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt)) } - - uidmap, err := idtools.ParseIDMap([]string{config.Storage.Options.RemapUIDs}, "remap-uids") - if err != nil { - return err - } - gidmap, err := idtools.ParseIDMap([]string{config.Storage.Options.RemapGIDs}, "remap-gids") - if err != nil { - return err - } - - if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup == "" { - config.Storage.Options.RemapGroup = config.Storage.Options.RemapUser - } - if config.Storage.Options.RemapGroup != "" && config.Storage.Options.RemapUser == "" { - config.Storage.Options.RemapUser = config.Storage.Options.RemapGroup - } - if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup != "" { - mappings, err := idtools.NewIDMappings(config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup) - if err != nil { - logrus.Warningf("Error initializing ID mappings for %s:%s %v\n", config.Storage.Options.RemapUser, config.Storage.Options.RemapGroup, err) - return err - } - uidmap = mappings.UIDs() - gidmap = mappings.GIDs() - } - storeOptions.UIDMap = uidmap - storeOptions.GIDMap = gidmap storeOptions.RootAutoNsUser = config.Storage.Options.RootAutoUsernsUser if config.Storage.Options.AutoUsernsMinSize > 0 { storeOptions.AutoNsMinSize = config.Storage.Options.AutoUsernsMinSize diff --git a/vendor/github.com/containers/storage/types/options_freebsd.go b/vendor/github.com/containers/storage/types/options_bsd.go similarity index 95% rename from vendor/github.com/containers/storage/types/options_freebsd.go rename to vendor/github.com/containers/storage/types/options_bsd.go index be2bc2f27..300eb19b5 100644 --- a/vendor/github.com/containers/storage/types/options_freebsd.go +++ b/vendor/github.com/containers/storage/types/options_bsd.go @@ -1,3 +1,5 @@ +//go:build freebsd || netbsd + package types const ( diff --git a/vendor/github.com/containers/storage/types/storage_test.conf b/vendor/github.com/containers/storage/types/storage_test.conf index c42d33fb9..761b3a795 100644 --- a/vendor/github.com/containers/storage/types/storage_test.conf +++ b/vendor/github.com/containers/storage/types/storage_test.conf @@ -25,16 +25,6 @@ rootless_storage_path = "$HOME/$UID/containers/storage" additionalimagestores = [ ] -# Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of -# a container, to the UIDs/GIDs as they should appear outside of the container, -# and the length of the range of UIDs/GIDs. Additional mapped sets can be -# listed and will be heeded by libraries, but there are limits to the number of -# mappings which the kernel will allow when you later attempt to run a -# container. -# -remap-uids = "0:1000000000:30000" -remap-gids = "0:1500000000:60000" - [storage.options.overlay] # mountopt specifies comma separated list of extra mount options diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/docker/docker/AUTHORS index 36315d429..5f93eeb4e 100644 --- a/vendor/github.com/docker/docker/AUTHORS +++ b/vendor/github.com/docker/docker/AUTHORS @@ -10,6 +10,7 @@ Aaron Huslage Aaron L. Xu Aaron Lehmann Aaron Welch +Aaron Yoshitake Abel Muiño Abhijeet Kasurde Abhinandan Prativadi @@ -62,6 +63,7 @@ alambike Alan Hoyle Alan Scherger Alan Thompson +Alano Terblanche Albert Callarisa Albert Zhang Albin Kerouanton @@ -141,6 +143,7 @@ Andreas Tiefenthaler Andrei Gherzan Andrei Ushakov Andrei Vagin +Andrew Baxter <423qpsxzhh8k3h@s.rendaw.me> Andrew C. Bodine Andrew Clay Shafer Andrew Duckworth @@ -193,6 +196,7 @@ Anton Löfgren Anton Nikitin Anton Polonskiy Anton Tiurin +Antonio Aguilar Antonio Murdaca Antonis Kalipetis Antony Messerli @@ -221,7 +225,6 @@ Avi Das Avi Kivity Avi Miller Avi Vaid -ayoshitake Azat Khuyiyakhmetov Bao Yonglei Bardia Keyoumarsi @@ -316,6 +319,7 @@ Burke Libbey Byung Kang Caleb Spare Calen Pennington +Calvin Liu Cameron Boehmer Cameron Sparr Cameron Spear @@ -362,6 +366,7 @@ Chen Qiu Cheng-mean Liu Chengfei Shang Chengguang Xu +Chentianze Chenyang Yan chenyuzhu Chetan Birajdar @@ -409,6 +414,7 @@ Christopher Crone Christopher Currie Christopher Jones Christopher Latham +Christopher Petito Christopher Rigor Christy Norman Chun Chen @@ -777,6 +783,7 @@ Gabriel L. Somlo Gabriel Linder Gabriel Monroy Gabriel Nicolas Avellaneda +Gabriel Tomitsuka Gaetan de Villele Galen Sampson Gang Qiao @@ -792,6 +799,7 @@ Geoff Levand Geoffrey Bachelet Geon Kim George Kontridze +George Ma George MacRorie George Xie Georgi Hristozov @@ -913,6 +921,7 @@ Illo Abdulrahim Ilya Dmitrichenko Ilya Gusev Ilya Khlopotov +imalasong <2879499479@qq.com> imre Fitos inglesp Ingo Gottwald @@ -930,6 +939,7 @@ J Bruni J. Nunn Jack Danger Canty Jack Laxson +Jack Walker <90711509+j2walker@users.noreply.github.com> Jacob Atzen Jacob Edelman Jacob Tomlinson @@ -989,6 +999,7 @@ Jason Shepherd Jason Smith Jason Sommer Jason Stangroome +Jasper Siepkes Javier Bassi jaxgeller Jay @@ -1100,6 +1111,7 @@ Jon Johnson Jon Surrell Jon Wedaman Jonas Dohse +Jonas Geiler Jonas Heinrich Jonas Pfenniger Jonathan A. Schweder @@ -1267,6 +1279,7 @@ Lakshan Perera Lalatendu Mohanty Lance Chen Lance Kinley +Lars Andringa Lars Butler Lars Kellogg-Stedman Lars R. Damerow @@ -1673,6 +1686,7 @@ Patrick Böänziger Patrick Devine Patrick Haas Patrick Hemmer +Patrick St. laurent Patrick Stapleton Patrik Cyvoct pattichen @@ -1878,6 +1892,7 @@ Royce Remer Rozhnov Alexandr Rudolph Gottesheim Rui Cao +Rui JingAn Rui Lopes Ruilin Li Runshen Zhu @@ -2184,6 +2199,7 @@ Tomek Mańko Tommaso Visconti Tomoya Tabuchi Tomáš Hrčka +Tomáš Virtus tonic Tonny Xu Tony Abboud @@ -2228,6 +2244,7 @@ Victor I. Wood Victor Lyuboslavsky Victor Marmol Victor Palma +Victor Toni Victor Vieux Victoria Bialas Vijaya Kumar K @@ -2279,6 +2296,7 @@ Wassim Dhif Wataru Ishida Wayne Chang Wayne Song +weebney Weerasak Chongnguluam Wei Fu Wei Wu diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go index b11c2fe02..f831735f8 100644 --- a/vendor/github.com/docker/docker/api/common.go +++ b/vendor/github.com/docker/docker/api/common.go @@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api" // Common constants for daemon and client. const ( // DefaultVersion of the current REST API. - DefaultVersion = "1.45" + DefaultVersion = "1.46" // MinSupportedAPIVersion is the minimum API version that can be supported // by the API server, specified as "major.minor". Note that the daemon diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml index 43a780e99..cc754bf1f 100644 --- a/vendor/github.com/docker/docker/api/swagger.yaml +++ b/vendor/github.com/docker/docker/api/swagger.yaml @@ -19,10 +19,10 @@ produces: consumes: - "application/json" - "text/plain" -basePath: "/v1.45" +basePath: "/v1.46" info: title: "Docker Engine API" - version: "1.45" + version: "1.46" x-logo: url: "https://docs.docker.com/assets/images/logo-docker-main.png" description: | @@ -55,8 +55,8 @@ info: the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. - If you omit the version-prefix, the current version of the API (v1.45) is used. - For example, calling `/info` is the same as calling `/v1.45/info`. Using the + If you omit the version-prefix, the current version of the API (v1.46) is used. + For example, calling `/info` is the same as calling `/v1.46/info`. Using the API without a version-prefix is deprecated and will be removed in a future release. Engine releases in the near future should support this version of the API, @@ -442,6 +442,21 @@ definitions: Mode: description: "The permission mode for the tmpfs mount in an integer." type: "integer" + Options: + description: | + The options to be passed to the tmpfs mount. An array of arrays. + Flag options should be provided as 1-length arrays. Other types + should be provided as as 2-length arrays, where the first item is + the key and the second the value. + type: "array" + items: + type: "array" + minItems: 1 + maxItems: 2 + items: + type: "string" + example: + [["noexec"]] RestartPolicy: description: | @@ -1198,13 +1213,6 @@ definitions: ContainerConfig: description: | Configuration for a container that is portable between hosts. - - When used as `ContainerConfig` field in an image, `ContainerConfig` is an - optional field containing the configuration of the container that was last - committed when creating the image. - - Previous versions of Docker builder used this field to store build cache, - and it is not in active use anymore. type: "object" properties: Hostname: @@ -1363,6 +1371,289 @@ definitions: type: "string" example: ["/bin/sh", "-c"] + ImageConfig: + description: | + Configuration of the image. These fields are used as defaults + when starting a container from the image. + type: "object" + properties: + Hostname: + description: | + The hostname to use for the container, as a valid RFC 1123 hostname. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always empty. It must not be used, and will be removed in API v1.47. + type: "string" + example: "" + Domainname: + description: | + The domain name to use for the container. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always empty. It must not be used, and will be removed in API v1.47. + type: "string" + example: "" + User: + description: "The user that commands are run as inside the container." + type: "string" + example: "web:web" + AttachStdin: + description: | + Whether to attach to `stdin`. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + AttachStdout: + description: | + Whether to attach to `stdout`. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + AttachStderr: + description: | + Whether to attach to `stderr`. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + ExposedPorts: + description: | + An object mapping ports to an empty object in the form: + + `{"/": {}}` + type: "object" + x-nullable: true + additionalProperties: + type: "object" + enum: + - {} + default: {} + example: { + "80/tcp": {}, + "443/tcp": {} + } + Tty: + description: | + Attach standard streams to a TTY, including `stdin` if it is not closed. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + OpenStdin: + description: | + Open `stdin` + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + StdinOnce: + description: | + Close `stdin` after one attached client disconnects. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always false. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + Env: + description: | + A list of environment variables to set inside the container in the + form `["VAR=value", ...]`. A variable without `=` is removed from the + environment, rather than to have an empty value. + type: "array" + items: + type: "string" + example: + - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + Cmd: + description: | + Command to run specified as a string or an array of strings. + type: "array" + items: + type: "string" + example: ["/bin/sh"] + Healthcheck: + $ref: "#/definitions/HealthConfig" + ArgsEscaped: + description: "Command is already escaped (Windows only)" + type: "boolean" + default: false + example: false + x-nullable: true + Image: + description: | + The name (or reference) of the image to use when creating the container, + or which was used when the container was created. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always empty. It must not be used, and will be removed in API v1.47. + type: "string" + default: "" + example: "" + Volumes: + description: | + An object mapping mount point paths inside the container to empty + objects. + type: "object" + additionalProperties: + type: "object" + enum: + - {} + default: {} + example: + "/app/data": {} + "/app/config": {} + WorkingDir: + description: "The working directory for commands to run in." + type: "string" + example: "/public/" + Entrypoint: + description: | + The entry point for the container as a string or an array of strings. + + If the array consists of exactly one empty string (`[""]`) then the + entry point is reset to system default (i.e., the entry point used by + docker when there is no `ENTRYPOINT` instruction in the `Dockerfile`). + type: "array" + items: + type: "string" + example: [] + NetworkDisabled: + description: | + Disable networking for the container. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always omitted. It must not be used, and will be removed in API v1.47. + type: "boolean" + default: false + example: false + x-nullable: true + MacAddress: + description: | + MAC address of the container. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always omitted. It must not be used, and will be removed in API v1.47. + type: "string" + default: "" + example: "" + x-nullable: true + OnBuild: + description: | + `ONBUILD` metadata that were defined in the image's `Dockerfile`. + type: "array" + x-nullable: true + items: + type: "string" + example: [] + Labels: + description: "User-defined key/value metadata." + type: "object" + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" + StopSignal: + description: | + Signal to stop a container as a string or unsigned integer. + type: "string" + example: "SIGTERM" + x-nullable: true + StopTimeout: + description: | + Timeout to stop a container in seconds. + +


+ + > **Deprecated**: this field is not part of the image specification and is + > always omitted. It must not be used, and will be removed in API v1.47. + type: "integer" + default: 10 + x-nullable: true + Shell: + description: | + Shell for when `RUN`, `CMD`, and `ENTRYPOINT` uses a shell. + type: "array" + x-nullable: true + items: + type: "string" + example: ["/bin/sh", "-c"] + # FIXME(thaJeztah): temporarily using a full example to remove some "omitempty" fields. Remove once the fields are removed. + example: + "Hostname": "" + "Domainname": "" + "User": "web:web" + "AttachStdin": false + "AttachStdout": false + "AttachStderr": false + "ExposedPorts": { + "80/tcp": {}, + "443/tcp": {} + } + "Tty": false + "OpenStdin": false + "StdinOnce": false + "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"] + "Cmd": ["/bin/sh"] + "Healthcheck": { + "Test": ["string"], + "Interval": 0, + "Timeout": 0, + "Retries": 0, + "StartPeriod": 0, + "StartInterval": 0 + } + "ArgsEscaped": true + "Image": "" + "Volumes": { + "/app/data": {}, + "/app/config": {} + } + "WorkingDir": "/public/" + "Entrypoint": [] + "OnBuild": [] + "Labels": { + "com.example.some-label": "some-value", + "com.example.some-other-label": "some-other-value" + } + "StopSignal": "SIGTERM" + "Shell": ["/bin/sh", "-c"] + NetworkingConfig: description: | NetworkingConfig represents the container's networking configuration for @@ -1758,21 +2049,6 @@ definitions: format: "dateTime" x-nullable: true example: "2022-02-04T21:20:12.497794809Z" - Container: - description: | - The ID of the container that was used to create the image. - - Depending on how the image was created, this field may be empty. - - **Deprecated**: this field is kept for backward compatibility, but - will be removed in API v1.45. - type: "string" - example: "65974bc86f1770ae4bff79f651ebdbce166ae9aada632ee3fa9af3a264911735" - ContainerConfig: - description: | - **Deprecated**: this field is kept for backward compatibility, but - will be removed in API v1.45. - $ref: "#/definitions/ContainerConfig" DockerVersion: description: | The version of Docker that was used to build the image. @@ -1780,7 +2056,7 @@ definitions: Depending on how the image was created, this field may be empty. type: "string" x-nullable: false - example: "20.10.7" + example: "27.0.1" Author: description: | Name of the author that was specified when committing the image, or as @@ -1789,7 +2065,7 @@ definitions: x-nullable: false example: "" Config: - $ref: "#/definitions/ContainerConfig" + $ref: "#/definitions/ImageConfig" Architecture: description: | Hardware CPU architecture that the image runs on. @@ -1866,6 +2142,7 @@ definitions: format: "dateTime" example: "2022-02-28T14:40:02.623929178Z" x-nullable: true + ImageSummary: type: "object" x-go-name: "Summary" @@ -2380,6 +2657,24 @@ definitions: type: "string" example: "10.133.77.91" + NetworkCreateResponse: + description: "OK response to NetworkCreate operation" + type: "object" + title: "NetworkCreateResponse" + x-go-name: "CreateResponse" + required: [Id, Warning] + properties: + Id: + description: "The ID of the created network." + type: "string" + x-nullable: false + example: "b5c4fc71e8022147cd25de22b22173de4e3b170134117172eb595cb91b4e7e5d" + Warning: + description: "Warnings encountered when creating the container" + type: "string" + x-nullable: false + example: "" + BuildInfo: type: "object" properties: @@ -2579,6 +2874,17 @@ definitions: example: - "server_x" - "server_y" + DriverOpts: + description: | + DriverOpts is a mapping of driver options and values. These options + are passed directly to the driver and are driver specific. + type: "object" + x-nullable: true + additionalProperties: + type: "string" + example: + com.example.some-label: "some-value" + com.example.some-other-label: "some-other-value" # Operational data NetworkID: @@ -2622,17 +2928,6 @@ definitions: type: "integer" format: "int64" example: 64 - DriverOpts: - description: | - DriverOpts is a mapping of driver options and values. These options - are passed directly to the driver and are driver specific. - type: "object" - x-nullable: true - additionalProperties: - type: "string" - example: - com.example.some-label: "some-value" - com.example.some-other-label: "some-other-value" DNSNames: description: | List of all DNS names an endpoint has on a specific network. This @@ -3804,6 +4099,13 @@ definitions: but this is just provided for lookup/display purposes. The secret in the reference will be identified by its ID. type: "string" + OomScoreAdj: + type: "integer" + format: "int64" + description: | + An integer value containing the score given to the container in + order to tune OOM killer preferences. + example: 0 Configs: description: | Configs contains references to zero or more configs that will be @@ -4000,7 +4302,7 @@ definitions: `node.platform.os` | Node operating system | `node.platform.os==windows` `node.platform.arch` | Node architecture | `node.platform.arch==x86_64` `node.labels` | User-defined node labels | `node.labels.security==high` - `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-14.04` + `engine.labels` | Docker Engine's labels | `engine.labels.operatingsystem==ubuntu-24.04` `engine.labels` apply to Docker Engine labels like operating system, drivers, etc. Swarm administrators add `node.labels` for operational @@ -4723,6 +5025,12 @@ definitions: properties: NetworkMode: type: "string" + Annotations: + description: "Arbitrary key-value metadata attached to container" + type: "object" + x-nullable: true + additionalProperties: + type: "string" NetworkSettings: description: "A summary of the container's network settings" type: "object" @@ -4991,7 +5299,7 @@ definitions: Version of the component type: "string" x-nullable: false - example: "19.03.12" + example: "27.0.1" Details: description: | Key/value pairs of strings with additional information about the @@ -5005,17 +5313,17 @@ definitions: Version: description: "The version of the daemon" type: "string" - example: "19.03.12" + example: "27.0.1" ApiVersion: description: | The default (and highest) API version that is supported by the daemon type: "string" - example: "1.40" + example: "1.46" MinAPIVersion: description: | The minimum API version that is supported by the daemon type: "string" - example: "1.12" + example: "1.24" GitCommit: description: | The Git commit of the source code that was used to build the daemon @@ -5026,7 +5334,7 @@ definitions: The version Go used to compile the daemon, and the version of the Go runtime in use. type: "string" - example: "go1.13.14" + example: "go1.21.11" Os: description: | The operating system that the daemon is running on ("linux" or "windows") @@ -5043,7 +5351,7 @@ definitions: This field is omitted when empty. type: "string" - example: "4.19.76-linuxkit" + example: "6.8.0-31-generic" Experimental: description: | Indicates if the daemon is started with experimental features enabled. @@ -5249,13 +5557,13 @@ definitions: information is queried from the HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ registry value, for example _"10.0 14393 (14393.1198.amd64fre.rs1_release_sec.170427-1353)"_. type: "string" - example: "4.9.38-moby" + example: "6.8.0-31-generic" OperatingSystem: description: | - Name of the host's operating system, for example: "Ubuntu 16.04.2 LTS" + Name of the host's operating system, for example: "Ubuntu 24.04 LTS" or "Windows Server 2016 Datacenter" type: "string" - example: "Alpine Linux v3.5" + example: "Ubuntu 24.04 LTS" OSVersion: description: | Version of the host's operating system @@ -5266,7 +5574,7 @@ definitions: > very existence, and the formatting of values, should not be considered > stable, and may change without notice. type: "string" - example: "16.04" + example: "24.04" OSType: description: | Generic type of the operating system of the host, as returned by the @@ -5368,7 +5676,7 @@ definitions: description: | Version string of the daemon. type: "string" - example: "24.0.2" + example: "27.0.1" Runtimes: description: | List of [OCI compliant](https://github.com/opencontainers/runtime-spec) @@ -5520,6 +5828,58 @@ definitions: example: - "/etc/cdi" - "/var/run/cdi" + Containerd: + $ref: "#/definitions/ContainerdInfo" + x-nullable: true + + ContainerdInfo: + description: | + Information for connecting to the containerd instance that is used by the daemon. + This is included for debugging purposes only. + type: "object" + properties: + Address: + description: "The address of the containerd socket." + type: "string" + example: "/run/containerd/containerd.sock" + Namespaces: + description: | + The namespaces that the daemon uses for running containers and + plugins in containerd. These namespaces can be configured in the + daemon configuration, and are considered to be used exclusively + by the daemon, Tampering with the containerd instance may cause + unexpected behavior. + + As these namespaces are considered to be exclusively accessed + by the daemon, it is not recommended to change these values, + or to change them to a value that is used by other systems, + such as cri-containerd. + type: "object" + properties: + Containers: + description: | + The default containerd namespace used for containers managed + by the daemon. + + The default namespace for containers is "moby", but will be + suffixed with the `.` of the remapped `root` if + user-namespaces are enabled and the containerd image-store + is used. + type: "string" + default: "moby" + example: "moby" + Plugins: + description: | + The default containerd namespace used for plugins managed by + the daemon. + + The default namespace for plugins is "plugins.moby", but will be + suffixed with the `.` of the remapped `root` if + user-namespaces are enabled and the containerd image-store + is used. + type: "string" + default: "plugins.moby" + example: "plugins.moby" # PluginsInfo is a temp struct holding Plugins name # registered with docker daemon. It is used by Info struct @@ -6372,6 +6732,8 @@ paths: SizeRootFs: 0 HostConfig: NetworkMode: "default" + Annotations: + io.kubernetes.docker.type: "container" NetworkSettings: Networks: bridge: @@ -6407,6 +6769,9 @@ paths: SizeRootFs: 0 HostConfig: NetworkMode: "default" + Annotations: + io.kubernetes.docker.type: "container" + io.kubernetes.sandbox.id: "3befe639bed0fd6afdd65fd1fa84506756f59360ec4adc270b0fdac9be22b4d3" NetworkSettings: Networks: bridge: @@ -6435,6 +6800,9 @@ paths: SizeRootFs: 0 HostConfig: NetworkMode: "default" + Annotations: + io.kubernetes.image.id: "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82" + io.kubernetes.image.name: "ubuntu:latest" NetworkSettings: Networks: bridge: @@ -6463,6 +6831,8 @@ paths: SizeRootFs: 0 HostConfig: NetworkMode: "default" + Annotations: + io.kubernetes.config.source: "api" NetworkSettings: Networks: bridge: @@ -8740,6 +9110,11 @@ paths: details. type: "string" required: true + - name: "platform" + in: "query" + description: "Select a platform-specific manifest to be pushed. OCI platform (JSON encoded)" + type: "string" + x-nullable: true tags: ["Image"] /images/{name}/tag: post: @@ -9188,7 +9563,7 @@ paths: Containers report these events: `attach`, `commit`, `copy`, `create`, `destroy`, `detach`, `die`, `exec_create`, `exec_detach`, `exec_start`, `exec_die`, `export`, `health_status`, `kill`, `oom`, `pause`, `rename`, `resize`, `restart`, `start`, `stop`, `top`, `unpause`, `update`, and `prune` - Images report these events: `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` + Images report these events: `create, `delete`, `import`, `load`, `pull`, `push`, `save`, `tag`, `untag`, and `prune` Volumes report these events: `create`, `mount`, `unmount`, `destroy`, and `prune` @@ -10144,19 +10519,9 @@ paths: - "application/json" responses: 201: - description: "No error" + description: "Network created successfully" schema: - type: "object" - title: "NetworkCreateResponse" - properties: - Id: - description: "The ID of the created network." - type: "string" - Warning: - type: "string" - example: - Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30" - Warning: "" + $ref: "#/definitions/NetworkCreateResponse" 400: description: "bad parameter" schema: @@ -10189,11 +10554,6 @@ paths: description: "The network's name." type: "string" example: "my_network" - CheckDuplicate: - description: | - Deprecated: CheckDuplicate is now always enabled. - type: "boolean" - example: true Driver: description: "Name of the network driver plugin to use." type: "string" @@ -11366,6 +11726,7 @@ paths: Mode: 384 SecretID: "fpjqlhnwb19zds35k8wn80lq9" SecretName: "example_org_domain_key" + OomScoreAdj: 0 LogDriver: Name: "json-file" Options: @@ -11518,6 +11879,7 @@ paths: Image: "busybox" Args: - "top" + OomScoreAdj: 0 Resources: Limits: {} Reservations: {} diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go index 882201f0e..df791f02a 100644 --- a/vendor/github.com/docker/docker/api/types/client.go +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -2,43 +2,15 @@ package types // import "github.com/docker/docker/api/types" import ( "bufio" + "context" "io" "net" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/registry" - units "github.com/docker/go-units" ) -// ContainerExecInspect holds information returned by exec inspect. -type ContainerExecInspect struct { - ExecID string `json:"ID"` - ContainerID string - Running bool - ExitCode int - Pid int -} - -// CopyToContainerOptions holds information -// about files to copy into a container -type CopyToContainerOptions struct { - AllowOverwriteDirWithFile bool - CopyUIDGID bool -} - -// EventsOptions holds parameters to filter events with. -type EventsOptions struct { - Since string - Until string - Filters filters.Args -} - -// NetworkListOptions holds parameters to filter the list of networks with. -type NetworkListOptions struct { - Filters filters.Args -} - // NewHijackedResponse intializes a HijackedResponse type func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse { return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType} @@ -101,7 +73,7 @@ type ImageBuildOptions struct { NetworkMode string ShmSize int64 Dockerfile string - Ulimits []*units.Ulimit + Ulimits []*container.Ulimit // BuildArgs needs to be a *string instead of just a string so that // we can tell the difference between "" (empty string) and no value // at all (nil). See the parsing of buildArgs in @@ -122,7 +94,7 @@ type ImageBuildOptions struct { Target string SessionID string Platform string - // Version specifies the version of the unerlying builder to use + // Version specifies the version of the underlying builder to use Version BuilderVersion // BuildID is an optional identifier that can be passed together with the // build request. The same identifier can be used to gracefully cancel the @@ -157,34 +129,13 @@ type ImageBuildResponse struct { OSType string } -// ImageImportSource holds source information for ImageImport -type ImageImportSource struct { - Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this. - SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute. -} - -// ImageLoadResponse returns information to the client about a load process. -type ImageLoadResponse struct { - // Body must be closed to avoid a resource leak - Body io.ReadCloser - JSON bool -} - // RequestPrivilegeFunc is a function interface that // clients can supply to retry operations after // getting an authorization error. // This function returns the registry authentication // header value in base 64 format, or an error // if the privilege request fails. -type RequestPrivilegeFunc func() (string, error) - -// ImageSearchOptions holds parameters to search images with. -type ImageSearchOptions struct { - RegistryAuth string - PrivilegeFunc RequestPrivilegeFunc - Filters filters.Args - Limit int -} +type RequestPrivilegeFunc func(context.Context) (string, error) // NodeListOptions holds parameters to list nodes with. type NodeListOptions struct { @@ -289,7 +240,7 @@ type PluginInstallOptions struct { RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry RemoteRef string // RemoteRef is the plugin name on the registry PrivilegeFunc RequestPrivilegeFunc - AcceptPermissionsFunc func(PluginPrivileges) (bool, error) + AcceptPermissionsFunc func(context.Context, PluginPrivileges) (bool, error) Args []string } diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go deleted file mode 100644 index 945b6efad..000000000 --- a/vendor/github.com/docker/docker/api/types/configs.go +++ /dev/null @@ -1,18 +0,0 @@ -package types // import "github.com/docker/docker/api/types" - -// ExecConfig is a small subset of the Config struct that holds the configuration -// for the exec feature of docker. -type ExecConfig struct { - User string // User that will run the command - Privileged bool // Is the container in privileged mode - Tty bool // Attach standard streams to a tty. - ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width] - AttachStdin bool // Attach the standard input, makes possible user interaction - AttachStderr bool // Attach the standard error - AttachStdout bool // Attach the standard output - Detach bool // Execute in detach mode - DetachKeys string // Escape keys for detach - Env []string // Environment variables - WorkingDir string // Working directory - Cmd []string // Execution commands and args -} diff --git a/vendor/github.com/docker/docker/api/types/container/config.go b/vendor/github.com/docker/docker/api/types/container/config.go index 86f46b74a..d6b03e8b2 100644 --- a/vendor/github.com/docker/docker/api/types/container/config.go +++ b/vendor/github.com/docker/docker/api/types/container/config.go @@ -1,7 +1,6 @@ package container // import "github.com/docker/docker/api/types/container" import ( - "io" "time" "github.com/docker/docker/api/types/strslice" @@ -36,14 +35,6 @@ type StopOptions struct { // HealthConfig holds configuration settings for the HEALTHCHECK feature. type HealthConfig = dockerspec.HealthcheckConfig -// ExecStartOptions holds the options to start container's exec. -type ExecStartOptions struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - ConsoleSize *[2]uint `json:",omitempty"` -} - // Config contains the configuration data about a container. // It should hold only portable information about the container. // Here, "portable" means "independent from the host we are running on". diff --git a/vendor/github.com/docker/docker/api/types/container/container.go b/vendor/github.com/docker/docker/api/types/container/container.go new file mode 100644 index 000000000..711af12c9 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/container.go @@ -0,0 +1,44 @@ +package container + +import ( + "io" + "os" + "time" +) + +// PruneReport contains the response for Engine API: +// POST "/containers/prune" +type PruneReport struct { + ContainersDeleted []string + SpaceReclaimed uint64 +} + +// PathStat is used to encode the header from +// GET "/containers/{name:.*}/archive" +// "Name" is the file or directory name. +type PathStat struct { + Name string `json:"name"` + Size int64 `json:"size"` + Mode os.FileMode `json:"mode"` + Mtime time.Time `json:"mtime"` + LinkTarget string `json:"linkTarget"` +} + +// CopyToContainerOptions holds information +// about files to copy into a container +type CopyToContainerOptions struct { + AllowOverwriteDirWithFile bool + CopyUIDGID bool +} + +// StatsResponseReader wraps an io.ReadCloser to read (a stream of) stats +// for a container, as produced by the GET "/stats" endpoint. +// +// The OSType field is set to the server's platform to allow +// platform-specific handling of the response. +// +// TODO(thaJeztah): remove this wrapper, and make OSType part of [StatsResponse]. +type StatsResponseReader struct { + Body io.ReadCloser `json:"body"` + OSType string `json:"ostype"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/create_request.go b/vendor/github.com/docker/docker/api/types/container/create_request.go new file mode 100644 index 000000000..e98dd6ad4 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/create_request.go @@ -0,0 +1,13 @@ +package container + +import "github.com/docker/docker/api/types/network" + +// CreateRequest is the request message sent to the server for container +// create calls. It is a config wrapper that holds the container [Config] +// (portable) and the corresponding [HostConfig] (non-portable) and +// [network.NetworkingConfig]. +type CreateRequest struct { + *Config + HostConfig *HostConfig `json:"HostConfig,omitempty"` + NetworkingConfig *network.NetworkingConfig `json:"NetworkingConfig,omitempty"` +} diff --git a/vendor/github.com/docker/docker/api/types/container/exec.go b/vendor/github.com/docker/docker/api/types/container/exec.go new file mode 100644 index 000000000..96093eb5c --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/container/exec.go @@ -0,0 +1,43 @@ +package container + +// ExecOptions is a small subset of the Config struct that holds the configuration +// for the exec feature of docker. +type ExecOptions struct { + User string // User that will run the command + Privileged bool // Is the container in privileged mode + Tty bool // Attach standard streams to a tty. + ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width] + AttachStdin bool // Attach the standard input, makes possible user interaction + AttachStderr bool // Attach the standard error + AttachStdout bool // Attach the standard output + Detach bool // Execute in detach mode + DetachKeys string // Escape keys for detach + Env []string // Environment variables + WorkingDir string // Working directory + Cmd []string // Execution commands and args +} + +// ExecStartOptions is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +type ExecStartOptions struct { + // ExecStart will first check if it's detached + Detach bool + // Check if there's a tty + Tty bool + // Terminal size [height, width], unused if Tty == false + ConsoleSize *[2]uint `json:",omitempty"` +} + +// ExecAttachOptions is a temp struct used by execAttach. +// +// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached. +type ExecAttachOptions = ExecStartOptions + +// ExecInspect holds information returned by exec inspect. +type ExecInspect struct { + ExecID string `json:"ID"` + ContainerID string + Running bool + ExitCode int + Pid int +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig.go b/vendor/github.com/docker/docker/api/types/container/hostconfig.go index efb96266e..727da8839 100644 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig.go +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig.go @@ -360,6 +360,12 @@ type LogConfig struct { Config map[string]string } +// Ulimit is an alias for [units.Ulimit], which may be moving to a different +// location or become a local type. This alias is to help transitioning. +// +// Users are recommended to use this alias instead of using [units.Ulimit] directly. +type Ulimit = units.Ulimit + // Resources contains container's resources (cgroups config, ulimits...) type Resources struct { // Applicable to all platforms @@ -387,14 +393,14 @@ type Resources struct { // KernelMemory specifies the kernel memory limit (in bytes) for the container. // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes. - KernelMemory int64 `json:",omitempty"` - KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes) - MemoryReservation int64 // Memory soft limit (in bytes) - MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap - MemorySwappiness *int64 // Tuning container memory swappiness behaviour - OomKillDisable *bool // Whether to disable OOM Killer or not - PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change. - Ulimits []*units.Ulimit // List of ulimits to be set in the container + KernelMemory int64 `json:",omitempty"` + KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes) + MemoryReservation int64 // Memory soft limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap + MemorySwappiness *int64 // Tuning container memory swappiness behaviour + OomKillDisable *bool // Whether to disable OOM Killer or not + PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change. + Ulimits []*Ulimit // List of ulimits to be set in the container // Applicable to Windows CPUCount int64 `json:"CpuCount"` // CPU count diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go index 421329237..cdee49ea3 100644 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go @@ -9,24 +9,6 @@ func (i Isolation) IsValid() bool { return i.IsDefault() } -// NetworkName returns the name of the network stack. -func (n NetworkMode) NetworkName() string { - if n.IsBridge() { - return network.NetworkBridge - } else if n.IsHost() { - return network.NetworkHost - } else if n.IsContainer() { - return "container" - } else if n.IsNone() { - return network.NetworkNone - } else if n.IsDefault() { - return network.NetworkDefault - } else if n.IsUserDefined() { - return n.UserDefined() - } - return "" -} - // IsBridge indicates whether container uses the bridge network stack func (n NetworkMode) IsBridge() bool { return n == network.NetworkBridge @@ -41,3 +23,23 @@ func (n NetworkMode) IsHost() bool { func (n NetworkMode) IsUserDefined() bool { return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() } + +// NetworkName returns the name of the network stack. +func (n NetworkMode) NetworkName() string { + switch { + case n.IsDefault(): + return network.NetworkDefault + case n.IsBridge(): + return network.NetworkBridge + case n.IsHost(): + return network.NetworkHost + case n.IsNone(): + return network.NetworkNone + case n.IsContainer(): + return "container" + case n.IsUserDefined(): + return n.UserDefined() + default: + return "" + } +} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go index 154667f4f..f08545542 100644 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go +++ b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go @@ -2,6 +2,11 @@ package container // import "github.com/docker/docker/api/types/container" import "github.com/docker/docker/api/types/network" +// IsValid indicates if an isolation technology is valid +func (i Isolation) IsValid() bool { + return i.IsDefault() || i.IsHyperV() || i.IsProcess() +} + // IsBridge indicates whether container uses the bridge network stack // in windows it is given the name NAT func (n NetworkMode) IsBridge() bool { @@ -19,24 +24,24 @@ func (n NetworkMode) IsUserDefined() bool { return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() } -// IsValid indicates if an isolation technology is valid -func (i Isolation) IsValid() bool { - return i.IsDefault() || i.IsHyperV() || i.IsProcess() -} - // NetworkName returns the name of the network stack. func (n NetworkMode) NetworkName() string { - if n.IsDefault() { + switch { + case n.IsDefault(): return network.NetworkDefault - } else if n.IsBridge() { + case n.IsBridge(): return network.NetworkNat - } else if n.IsNone() { + case n.IsHost(): + // Windows currently doesn't support host network-mode, so + // this would currently never happen.. + return network.NetworkHost + case n.IsNone(): return network.NetworkNone - } else if n.IsContainer() { + case n.IsContainer(): return "container" - } else if n.IsUserDefined() { + case n.IsUserDefined(): return n.UserDefined() + default: + return "" } - - return "" } diff --git a/vendor/github.com/docker/docker/api/types/stats.go b/vendor/github.com/docker/docker/api/types/container/stats.go similarity index 96% rename from vendor/github.com/docker/docker/api/types/stats.go rename to vendor/github.com/docker/docker/api/types/container/stats.go index 20daebed1..3b3fb131a 100644 --- a/vendor/github.com/docker/docker/api/types/stats.go +++ b/vendor/github.com/docker/docker/api/types/container/stats.go @@ -1,6 +1,4 @@ -// Package types is used for API stability in the types and response to the -// consumers of the API stats endpoint. -package types // import "github.com/docker/docker/api/types" +package container import "time" @@ -169,8 +167,10 @@ type Stats struct { MemoryStats MemoryStats `json:"memory_stats,omitempty"` } -// StatsJSON is newly used Networks -type StatsJSON struct { +// StatsResponse is newly used Networks. +// +// TODO(thaJeztah): unify with [Stats]. This wrapper was to account for pre-api v1.21 changes, see https://github.com/moby/moby/commit/d3379946ec96fb6163cb8c4517d7d5a067045801 +type StatsResponse struct { Stats Name string `json:"name,omitempty"` diff --git a/vendor/github.com/docker/docker/api/types/events/events.go b/vendor/github.com/docker/docker/api/types/events/events.go index 6dbcd9223..e225df4ec 100644 --- a/vendor/github.com/docker/docker/api/types/events/events.go +++ b/vendor/github.com/docker/docker/api/types/events/events.go @@ -1,4 +1,5 @@ package events // import "github.com/docker/docker/api/types/events" +import "github.com/docker/docker/api/types/filters" // Type is used for event-types. type Type string @@ -125,3 +126,10 @@ type Message struct { Time int64 `json:"time,omitempty"` TimeNano int64 `json:"timeNano,omitempty"` } + +// ListOptions holds parameters to filter events with. +type ListOptions struct { + Since string + Until string + Filters filters.Args +} diff --git a/vendor/github.com/docker/docker/api/types/image/image.go b/vendor/github.com/docker/docker/api/types/image/image.go index 167df28c7..abb7ffd80 100644 --- a/vendor/github.com/docker/docker/api/types/image/image.go +++ b/vendor/github.com/docker/docker/api/types/image/image.go @@ -1,9 +1,47 @@ package image -import "time" +import ( + "io" + "time" +) // Metadata contains engine-local data about the image. type Metadata struct { // LastTagTime is the date and time at which the image was last tagged. LastTagTime time.Time `json:",omitempty"` } + +// PruneReport contains the response for Engine API: +// POST "/images/prune" +type PruneReport struct { + ImagesDeleted []DeleteResponse + SpaceReclaimed uint64 +} + +// LoadResponse returns information to the client about a load process. +// +// TODO(thaJeztah): remove this type, and just use an io.ReadCloser +// +// This type was added in https://github.com/moby/moby/pull/18878, related +// to https://github.com/moby/moby/issues/19177; +// +// Make docker load to output json when the response content type is json +// Swarm hijacks the response from docker load and returns JSON rather +// than plain text like the Engine does. This makes the API library to return +// information to figure that out. +// +// However the "load" endpoint unconditionally returns JSON; +// https://github.com/moby/moby/blob/7b9d2ef6e5518a3d3f3cc418459f8df786cfbbd1/api/server/router/image/image_routes.go#L248-L255 +// +// PR https://github.com/moby/moby/pull/21959 made the response-type depend +// on whether "quiet" was set, but this logic got changed in a follow-up +// https://github.com/moby/moby/pull/25557, which made the JSON response-type +// unconditionally, but the output produced depend on whether"quiet" was set. +// +// We should deprecated the "quiet" option, as it's really a client +// responsibility. +type LoadResponse struct { + // Body must be closed to avoid a resource leak + Body io.ReadCloser + JSON bool +} diff --git a/vendor/github.com/docker/docker/api/types/image/opts.go b/vendor/github.com/docker/docker/api/types/image/opts.go index c6b1f351b..8e32c9af8 100644 --- a/vendor/github.com/docker/docker/api/types/image/opts.go +++ b/vendor/github.com/docker/docker/api/types/image/opts.go @@ -1,6 +1,18 @@ package image -import "github.com/docker/docker/api/types/filters" +import ( + "context" + "io" + + "github.com/docker/docker/api/types/filters" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// ImportSource holds source information for ImageImport +type ImportSource struct { + Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this. + SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute. +} // ImportOptions holds information to import images from the client host. type ImportOptions struct { @@ -27,12 +39,28 @@ type PullOptions struct { // privilege request fails. // // Also see [github.com/docker/docker/api/types.RequestPrivilegeFunc]. - PrivilegeFunc func() (string, error) + PrivilegeFunc func(context.Context) (string, error) Platform string } // PushOptions holds information to push images. -type PushOptions PullOptions +type PushOptions struct { + All bool + RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry + + // PrivilegeFunc is a function that clients can supply to retry operations + // after getting an authorization error. This function returns the registry + // authentication header value in base64 encoded format, or an error if the + // privilege request fails. + // + // Also see [github.com/docker/docker/api/types.RequestPrivilegeFunc]. + PrivilegeFunc func(context.Context) (string, error) + + // Platform is an optional field that selects a specific platform to push + // when the image is a multi-platform image. + // Using this will only push a single platform-specific manifest. + Platform *ocispec.Platform `json:",omitempty"` +} // ListOptions holds parameters to list images with. type ListOptions struct { diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 6fe04da25..c68dcf65b 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -119,7 +119,11 @@ type TmpfsOptions struct { SizeBytes int64 `json:",omitempty"` // Mode of the tmpfs upon creation Mode os.FileMode `json:",omitempty"` - + // Options to be passed to the tmpfs mount. An array of arrays. Flag + // options should be provided as 1-length arrays. Other types should be + // provided as 2-length arrays, where the first item is the key and the + // second the value. + Options [][]string `json:",omitempty"` // TODO(stevvooe): There are several more tmpfs flags, specified in the // daemon, that are accepted. Only the most basic are added for now. // diff --git a/vendor/github.com/docker/docker/api/types/network/create_response.go b/vendor/github.com/docker/docker/api/types/network/create_response.go new file mode 100644 index 000000000..c32b35bff --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/network/create_response.go @@ -0,0 +1,19 @@ +package network + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +// CreateResponse NetworkCreateResponse +// +// OK response to NetworkCreate operation +// swagger:model CreateResponse +type CreateResponse struct { + + // The ID of the created network. + // Required: true + ID string `json:"Id"` + + // Warnings encountered when creating the container + // Required: true + Warning string `json:"Warning"` +} diff --git a/vendor/github.com/docker/docker/api/types/network/endpoint.go b/vendor/github.com/docker/docker/api/types/network/endpoint.go index 9edd1c38d..0fbb40b35 100644 --- a/vendor/github.com/docker/docker/api/types/network/endpoint.go +++ b/vendor/github.com/docker/docker/api/types/network/endpoint.go @@ -18,6 +18,7 @@ type EndpointSettings struct { // Once the container is running, it becomes operational data (it may contain a // generated address). MacAddress string + DriverOpts map[string]string // Operational data NetworkID string EndpointID string @@ -27,7 +28,6 @@ type EndpointSettings struct { IPv6Gateway string GlobalIPv6Address string GlobalIPv6PrefixLen int - DriverOpts map[string]string // DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to // generate PTR records. DNSNames []string diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go index f1f300f3d..c8db97a7e 100644 --- a/vendor/github.com/docker/docker/api/types/network/network.go +++ b/vendor/github.com/docker/docker/api/types/network/network.go @@ -1,6 +1,8 @@ package network // import "github.com/docker/docker/api/types/network" import ( + "time" + "github.com/docker/docker/api/types/filters" ) @@ -17,6 +19,82 @@ const ( NetworkNat = "nat" ) +// CreateRequest is the request message sent to the server for network create call. +type CreateRequest struct { + CreateOptions + Name string // Name is the requested name of the network. + + // Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client + // package to older daemons. + CheckDuplicate *bool `json:",omitempty"` +} + +// CreateOptions holds options to create a network. +type CreateOptions struct { + Driver string // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`) + Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level). + EnableIPv6 *bool `json:",omitempty"` // EnableIPv6 represents whether to enable IPv6. + IPAM *IPAM // IPAM is the network's IP Address Management. + Internal bool // Internal represents if the network is used internal only. + Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. + Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. + ConfigOnly bool // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. + ConfigFrom *ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly]. + Options map[string]string // Options specifies the network-specific options to use for when creating the network. + Labels map[string]string // Labels holds metadata specific to the network being created. +} + +// ListOptions holds parameters to filter the list of networks with. +type ListOptions struct { + Filters filters.Args +} + +// InspectOptions holds parameters to inspect network. +type InspectOptions struct { + Scope string + Verbose bool +} + +// ConnectOptions represents the data to be used to connect a container to the +// network. +type ConnectOptions struct { + Container string + EndpointConfig *EndpointSettings `json:",omitempty"` +} + +// DisconnectOptions represents the data to be used to disconnect a container +// from the network. +type DisconnectOptions struct { + Container string + Force bool +} + +// Inspect is the body of the "get network" http response message. +type Inspect struct { + Name string // Name is the name of the network + ID string `json:"Id"` // ID uniquely identifies a network on a single machine + Created time.Time // Created is the time the network created + Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) + Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) + EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 + IPAM IPAM // IPAM is the network's IP Address Management + Internal bool // Internal represents if the network is used internal only + Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. + Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. + ConfigFrom ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. + ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. + Containers map[string]EndpointResource // Containers contains endpoints belonging to the network + Options map[string]string // Options holds the network specific options to use for when creating the network + Labels map[string]string // Labels holds metadata specific to the network being created + Peers []PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network + Services map[string]ServiceInfo `json:",omitempty"` +} + +// Summary is used as response when listing networks. It currently is an alias +// for [Inspect], but may diverge in the future, as not all information may +// be included when listing networks. +type Summary = Inspect + // Address represents an IP address type Address struct { Addr string @@ -45,6 +123,16 @@ type ServiceInfo struct { Tasks []Task } +// EndpointResource contains network resources allocated and used for a +// container in a network. +type EndpointResource struct { + Name string + EndpointID string + MacAddress string + IPv4Address string + IPv6Address string +} + // NetworkingConfig represents the container's networking configuration for each of its interfaces // Carries the networking configs specified in the `docker run` and `docker network connect` commands type NetworkingConfig struct { @@ -70,3 +158,9 @@ var acceptedFilters = map[string]bool{ func ValidateFilters(filter filters.Args) error { return filter.Validate(acceptedFilters) } + +// PruneReport contains the response for Engine API: +// POST "/networks/prune" +type PruneReport struct { + NetworksDeleted []string +} diff --git a/vendor/github.com/docker/docker/api/types/registry/registry.go b/vendor/github.com/docker/docker/api/types/registry/registry.go index 6bbae93ef..75ee07b15 100644 --- a/vendor/github.com/docker/docker/api/types/registry/registry.go +++ b/vendor/github.com/docker/docker/api/types/registry/registry.go @@ -84,32 +84,6 @@ type IndexInfo struct { Official bool } -// SearchResult describes a search result returned from a registry -type SearchResult struct { - // StarCount indicates the number of stars this repository has - StarCount int `json:"star_count"` - // IsOfficial is true if the result is from an official repository. - IsOfficial bool `json:"is_official"` - // Name is the name of the repository - Name string `json:"name"` - // IsAutomated indicates whether the result is automated. - // - // Deprecated: the "is_automated" field is deprecated and will always be "false". - IsAutomated bool `json:"is_automated"` - // Description is a textual description of the repository - Description string `json:"description"` -} - -// SearchResults lists a collection search results returned from a registry -type SearchResults struct { - // Query contains the query string that generated the search results - Query string `json:"query"` - // NumResults indicates the number of results the query returned - NumResults int `json:"num_results"` - // Results is a slice containing the actual results for the search - Results []SearchResult `json:"results"` -} - // DistributionInspect describes the result obtained from contacting the // registry to retrieve image metadata type DistributionInspect struct { diff --git a/vendor/github.com/docker/docker/api/types/registry/search.go b/vendor/github.com/docker/docker/api/types/registry/search.go new file mode 100644 index 000000000..a0a1eec54 --- /dev/null +++ b/vendor/github.com/docker/docker/api/types/registry/search.go @@ -0,0 +1,47 @@ +package registry + +import ( + "context" + + "github.com/docker/docker/api/types/filters" +) + +// SearchOptions holds parameters to search images with. +type SearchOptions struct { + RegistryAuth string + + // PrivilegeFunc is a [types.RequestPrivilegeFunc] the client can + // supply to retry operations after getting an authorization error. + // + // It must return the registry authentication header value in base64 + // format, or an error if the privilege request fails. + PrivilegeFunc func(context.Context) (string, error) + Filters filters.Args + Limit int +} + +// SearchResult describes a search result returned from a registry +type SearchResult struct { + // StarCount indicates the number of stars this repository has + StarCount int `json:"star_count"` + // IsOfficial is true if the result is from an official repository. + IsOfficial bool `json:"is_official"` + // Name is the name of the repository + Name string `json:"name"` + // IsAutomated indicates whether the result is automated. + // + // Deprecated: the "is_automated" field is deprecated and will always be "false". + IsAutomated bool `json:"is_automated"` + // Description is a textual description of the repository + Description string `json:"description"` +} + +// SearchResults lists a collection search results returned from a registry +type SearchResults struct { + // Query contains the query string that generated the search results + Query string `json:"query"` + // NumResults indicates the number of results the query returned + NumResults int `json:"num_results"` + // Results is a slice containing the actual results for the search + Results []SearchResult `json:"results"` +} diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go index 65f61d2d2..30e3de70c 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/container.go +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -5,7 +5,6 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" - "github.com/docker/go-units" ) // DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) @@ -115,5 +114,6 @@ type ContainerSpec struct { Sysctls map[string]string `json:",omitempty"` CapabilityAdd []string `json:",omitempty"` CapabilityDrop []string `json:",omitempty"` - Ulimits []*units.Ulimit `json:",omitempty"` + Ulimits []*container.Ulimit `json:",omitempty"` + OomScoreAdj int64 `json:",omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/system/info.go b/vendor/github.com/docker/docker/api/types/system/info.go index 89d4a0098..6791cf328 100644 --- a/vendor/github.com/docker/docker/api/types/system/info.go +++ b/vendor/github.com/docker/docker/api/types/system/info.go @@ -75,6 +75,8 @@ type Info struct { DefaultAddressPools []NetworkAddressPool `json:",omitempty"` CDISpecDirs []string + Containerd *ContainerdInfo `json:",omitempty"` + // Legacy API fields for older API versions. legacyFields @@ -85,6 +87,43 @@ type Info struct { Warnings []string } +// ContainerdInfo holds information about the containerd instance used by the daemon. +type ContainerdInfo struct { + // Address is the path to the containerd socket. + Address string `json:",omitempty"` + // Namespaces is the containerd namespaces used by the daemon. + Namespaces ContainerdNamespaces +} + +// ContainerdNamespaces reflects the containerd namespaces used by the daemon. +// +// These namespaces can be configured in the daemon configuration, and are +// considered to be used exclusively by the daemon, +// +// As these namespaces are considered to be exclusively accessed +// by the daemon, it is not recommended to change these values, +// or to change them to a value that is used by other systems, +// such as cri-containerd. +type ContainerdNamespaces struct { + // Containers holds the default containerd namespace used for + // containers managed by the daemon. + // + // The default namespace for containers is "moby", but will be + // suffixed with the `.` of the remapped `root` if + // user-namespaces are enabled and the containerd image-store + // is used. + Containers string + + // Plugins holds the default containerd namespace used for + // plugins managed by the daemon. + // + // The default namespace for plugins is "moby", but will be + // suffixed with the `.` of the remapped `root` if + // user-namespaces are enabled and the containerd image-store + // is used. + Plugins string +} + type legacyFields struct { ExecutionDriver string `json:",omitempty"` // Deprecated: deprecated since API v1.25, but returned for older versions. } diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go index 583b9cbec..f0c648e15 100644 --- a/vendor/github.com/docker/docker/api/types/types.go +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -1,8 +1,6 @@ package types // import "github.com/docker/docker/api/types" import ( - "io" - "os" "time" "github.com/docker/docker/api/types/container" @@ -155,36 +153,13 @@ type Container struct { State string Status string HostConfig struct { - NetworkMode string `json:",omitempty"` + NetworkMode string `json:",omitempty"` + Annotations map[string]string `json:",omitempty"` } NetworkSettings *SummaryNetworkSettings Mounts []MountPoint } -// CopyConfig contains request body of Engine API: -// POST "/containers/"+containerID+"/copy" -type CopyConfig struct { - Resource string -} - -// ContainerPathStat is used to encode the header from -// GET "/containers/{name:.*}/archive" -// "Name" is the file or directory name. -type ContainerPathStat struct { - Name string `json:"name"` - Size int64 `json:"size"` - Mode os.FileMode `json:"mode"` - Mtime time.Time `json:"mtime"` - LinkTarget string `json:"linkTarget"` -} - -// ContainerStats contains response of Engine API: -// GET "/stats" -type ContainerStats struct { - Body io.ReadCloser `json:"body"` - OSType string `json:"ostype"` -} - // Ping contains response of Engine API: // GET "/_ping" type Ping struct { @@ -230,17 +205,6 @@ type Version struct { BuildTime string `json:",omitempty"` } -// ExecStartCheck is a temp struct used by execStart -// Config fields is part of ExecConfig in runconfig package -type ExecStartCheck struct { - // ExecStart will first check if it's detached - Detach bool - // Check if there's a tty - Tty bool - // Terminal size [height, width], unused if Tty == false - ConsoleSize *[2]uint `json:",omitempty"` -} - // HealthcheckResult stores information about a single run of a healthcheck probe type HealthcheckResult struct { Start time.Time // Start is the time this check started @@ -423,84 +387,6 @@ type MountPoint struct { Propagation mount.Propagation } -// NetworkResource is the body of the "get network" http response message -type NetworkResource struct { - Name string // Name is the requested name of the network - ID string `json:"Id"` // ID uniquely identifies a network on a single machine - Created time.Time // Created is the time the network created - Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) - Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) - EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6 - IPAM network.IPAM // IPAM is the network's IP Address Management - Internal bool // Internal represents if the network is used internal only - Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. - Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. - ConfigFrom network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. - ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. - Containers map[string]EndpointResource // Containers contains endpoints belonging to the network - Options map[string]string // Options holds the network specific options to use for when creating the network - Labels map[string]string // Labels holds metadata specific to the network being created - Peers []network.PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network - Services map[string]network.ServiceInfo `json:",omitempty"` -} - -// EndpointResource contains network resources allocated and used for a container in a network -type EndpointResource struct { - Name string - EndpointID string - MacAddress string - IPv4Address string - IPv6Address string -} - -// NetworkCreate is the expected body of the "create network" http request message -type NetworkCreate struct { - // Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client - // package to older daemons. - CheckDuplicate bool `json:",omitempty"` - Driver string // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`) - Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level). - EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6. - IPAM *network.IPAM // IPAM is the network's IP Address Management. - Internal bool // Internal represents if the network is used internal only. - Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. - Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. - ConfigOnly bool // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. - ConfigFrom *network.ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [NetworkCreate.ConfigOnly]. - Options map[string]string // Options specifies the network-specific options to use for when creating the network. - Labels map[string]string // Labels holds metadata specific to the network being created. -} - -// NetworkCreateRequest is the request message sent to the server for network create call. -type NetworkCreateRequest struct { - NetworkCreate - Name string // Name is the requested name of the network. -} - -// NetworkCreateResponse is the response message sent by the server for network create call -type NetworkCreateResponse struct { - ID string `json:"Id"` - Warning string -} - -// NetworkConnect represents the data to be used to connect a container to the network -type NetworkConnect struct { - Container string - EndpointConfig *network.EndpointSettings `json:",omitempty"` -} - -// NetworkDisconnect represents the data to be used to disconnect a container from the network -type NetworkDisconnect struct { - Container string - Force bool -} - -// NetworkInspectOptions holds parameters to inspect network -type NetworkInspectOptions struct { - Scope string - Verbose bool -} - // DiskUsageObject represents an object type used for disk usage query filtering. type DiskUsageObject string @@ -533,27 +419,6 @@ type DiskUsage struct { BuilderSize int64 `json:",omitempty"` // Deprecated: deprecated in API 1.38, and no longer used since API 1.40. } -// ContainersPruneReport contains the response for Engine API: -// POST "/containers/prune" -type ContainersPruneReport struct { - ContainersDeleted []string - SpaceReclaimed uint64 -} - -// VolumesPruneReport contains the response for Engine API: -// POST "/volumes/prune" -type VolumesPruneReport struct { - VolumesDeleted []string - SpaceReclaimed uint64 -} - -// ImagesPruneReport contains the response for Engine API: -// POST "/images/prune" -type ImagesPruneReport struct { - ImagesDeleted []image.DeleteResponse - SpaceReclaimed uint64 -} - // BuildCachePruneReport contains the response for Engine API: // POST "/build/prune" type BuildCachePruneReport struct { @@ -561,12 +426,6 @@ type BuildCachePruneReport struct { SpaceReclaimed uint64 } -// NetworksPruneReport contains the response for Engine API: -// POST "/networks/prune" -type NetworksPruneReport struct { - NetworksDeleted []string -} - // SecretCreateResponse contains the information returned to a client // on the creation of a new secret. type SecretCreateResponse struct { diff --git a/vendor/github.com/docker/docker/api/types/types_deprecated.go b/vendor/github.com/docker/docker/api/types/types_deprecated.go index 231a5cca4..8edf70b7c 100644 --- a/vendor/github.com/docker/docker/api/types/types_deprecated.go +++ b/vendor/github.com/docker/docker/api/types/types_deprecated.go @@ -1,35 +1,196 @@ package types import ( + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/api/types/volume" ) -// ImageImportOptions holds information to import images from the client host. +// ImagesPruneReport contains the response for Engine API: +// POST "/images/prune" // -// Deprecated: use [image.ImportOptions]. -type ImageImportOptions = image.ImportOptions +// Deprecated: use [image.PruneReport]. +type ImagesPruneReport = image.PruneReport -// ImageCreateOptions holds information to create images. +// VolumesPruneReport contains the response for Engine API: +// POST "/volumes/prune". // -// Deprecated: use [image.CreateOptions]. -type ImageCreateOptions = image.CreateOptions +// Deprecated: use [volume.PruneReport]. +type VolumesPruneReport = volume.PruneReport -// ImagePullOptions holds information to pull images. +// NetworkCreateRequest is the request message sent to the server for network create call. // -// Deprecated: use [image.PullOptions]. -type ImagePullOptions = image.PullOptions +// Deprecated: use [network.CreateRequest]. +type NetworkCreateRequest = network.CreateRequest -// ImagePushOptions holds information to push images. +// NetworkCreate is the expected body of the "create network" http request message // -// Deprecated: use [image.PushOptions]. -type ImagePushOptions = image.PushOptions +// Deprecated: use [network.CreateOptions]. +type NetworkCreate = network.CreateOptions -// ImageListOptions holds parameters to list images with. +// NetworkListOptions holds parameters to filter the list of networks with. // -// Deprecated: use [image.ListOptions]. -type ImageListOptions = image.ListOptions +// Deprecated: use [network.ListOptions]. +type NetworkListOptions = network.ListOptions -// ImageRemoveOptions holds parameters to remove images. +// NetworkCreateResponse is the response message sent by the server for network create call. // -// Deprecated: use [image.RemoveOptions]. -type ImageRemoveOptions = image.RemoveOptions +// Deprecated: use [network.CreateResponse]. +type NetworkCreateResponse = network.CreateResponse + +// NetworkInspectOptions holds parameters to inspect network. +// +// Deprecated: use [network.InspectOptions]. +type NetworkInspectOptions = network.InspectOptions + +// NetworkConnect represents the data to be used to connect a container to the network +// +// Deprecated: use [network.ConnectOptions]. +type NetworkConnect = network.ConnectOptions + +// NetworkDisconnect represents the data to be used to disconnect a container from the network +// +// Deprecated: use [network.DisconnectOptions]. +type NetworkDisconnect = network.DisconnectOptions + +// EndpointResource contains network resources allocated and used for a container in a network. +// +// Deprecated: use [network.EndpointResource]. +type EndpointResource = network.EndpointResource + +// NetworkResource is the body of the "get network" http response message/ +// +// Deprecated: use [network.Inspect] or [network.Summary] (for list operations). +type NetworkResource = network.Inspect + +// NetworksPruneReport contains the response for Engine API: +// POST "/networks/prune" +// +// Deprecated: use [network.PruneReport]. +type NetworksPruneReport = network.PruneReport + +// ExecConfig is a small subset of the Config struct that holds the configuration +// for the exec feature of docker. +// +// Deprecated: use [container.ExecOptions]. +type ExecConfig = container.ExecOptions + +// ExecStartCheck is a temp struct used by execStart +// Config fields is part of ExecConfig in runconfig package +// +// Deprecated: use [container.ExecStartOptions] or [container.ExecAttachOptions]. +type ExecStartCheck = container.ExecStartOptions + +// ContainerExecInspect holds information returned by exec inspect. +// +// Deprecated: use [container.ExecInspect]. +type ContainerExecInspect = container.ExecInspect + +// ContainersPruneReport contains the response for Engine API: +// POST "/containers/prune" +// +// Deprecated: use [container.PruneReport]. +type ContainersPruneReport = container.PruneReport + +// ContainerPathStat is used to encode the header from +// GET "/containers/{name:.*}/archive" +// "Name" is the file or directory name. +// +// Deprecated: use [container.PathStat]. +type ContainerPathStat = container.PathStat + +// CopyToContainerOptions holds information +// about files to copy into a container. +// +// Deprecated: use [container.CopyToContainerOptions], +type CopyToContainerOptions = container.CopyToContainerOptions + +// ContainerStats contains response of Engine API: +// GET "/stats" +// +// Deprecated: use [container.StatsResponseReader]. +type ContainerStats = container.StatsResponseReader + +// ThrottlingData stores CPU throttling stats of one running container. +// Not used on Windows. +// +// Deprecated: use [container.ThrottlingData]. +type ThrottlingData = container.ThrottlingData + +// CPUUsage stores All CPU stats aggregated since container inception. +// +// Deprecated: use [container.CPUUsage]. +type CPUUsage = container.CPUUsage + +// CPUStats aggregates and wraps all CPU related info of container +// +// Deprecated: use [container.CPUStats]. +type CPUStats = container.CPUStats + +// MemoryStats aggregates all memory stats since container inception on Linux. +// Windows returns stats for commit and private working set only. +// +// Deprecated: use [container.MemoryStats]. +type MemoryStats = container.MemoryStats + +// BlkioStatEntry is one small entity to store a piece of Blkio stats +// Not used on Windows. +// +// Deprecated: use [container.BlkioStatEntry]. +type BlkioStatEntry = container.BlkioStatEntry + +// BlkioStats stores All IO service stats for data read and write. +// This is a Linux specific structure as the differences between expressing +// block I/O on Windows and Linux are sufficiently significant to make +// little sense attempting to morph into a combined structure. +// +// Deprecated: use [container.BlkioStats]. +type BlkioStats = container.BlkioStats + +// StorageStats is the disk I/O stats for read/write on Windows. +// +// Deprecated: use [container.StorageStats]. +type StorageStats = container.StorageStats + +// NetworkStats aggregates the network stats of one container +// +// Deprecated: use [container.NetworkStats]. +type NetworkStats = container.NetworkStats + +// PidsStats contains the stats of a container's pids +// +// Deprecated: use [container.PidsStats]. +type PidsStats = container.PidsStats + +// Stats is Ultimate struct aggregating all types of stats of one container +// +// Deprecated: use [container.Stats]. +type Stats = container.Stats + +// StatsJSON is newly used Networks +// +// Deprecated: use [container.StatsResponse]. +type StatsJSON = container.StatsResponse + +// EventsOptions holds parameters to filter events with. +// +// Deprecated: use [events.ListOptions]. +type EventsOptions = events.ListOptions + +// ImageSearchOptions holds parameters to search images with. +// +// Deprecated: use [registry.SearchOptions]. +type ImageSearchOptions = registry.SearchOptions + +// ImageImportSource holds source information for ImageImport +// +// Deprecated: use [image.ImportSource]. +type ImageImportSource image.ImportSource + +// ImageLoadResponse returns information to the client about a load process. +// +// Deprecated: use [image.LoadResponse]. +type ImageLoadResponse = image.LoadResponse diff --git a/vendor/github.com/docker/docker/api/types/volume/options.go b/vendor/github.com/docker/docker/api/types/volume/options.go index 8b0dd1389..0b9645e00 100644 --- a/vendor/github.com/docker/docker/api/types/volume/options.go +++ b/vendor/github.com/docker/docker/api/types/volume/options.go @@ -6,3 +6,10 @@ import "github.com/docker/docker/api/types/filters" type ListOptions struct { Filters filters.Args } + +// PruneReport contains the response for Engine API: +// POST "/volumes/prune" +type PruneReport struct { + VolumesDeleted []string + SpaceReclaimed uint64 +} diff --git a/vendor/github.com/docker/docker/client/client.go b/vendor/github.com/docker/docker/client/client.go index f2eeb6c57..60d91bc65 100644 --- a/vendor/github.com/docker/docker/client/client.go +++ b/vendor/github.com/docker/docker/client/client.go @@ -49,6 +49,8 @@ import ( "net/url" "path" "strings" + "sync" + "sync/atomic" "time" "github.com/docker/docker/api" @@ -131,7 +133,10 @@ type Client struct { negotiateVersion bool // negotiated indicates that API version negotiation took place - negotiated bool + negotiated atomic.Bool + + // negotiateLock is used to single-flight the version negotiation process + negotiateLock sync.Mutex tp trace.TracerProvider @@ -266,7 +271,16 @@ func (cli *Client) Close() error { // be negotiated when making the actual requests, and for which cases // we cannot do the negotiation lazily. func (cli *Client) checkVersion(ctx context.Context) error { - if !cli.manualOverride && cli.negotiateVersion && !cli.negotiated { + if !cli.manualOverride && cli.negotiateVersion && !cli.negotiated.Load() { + // Ensure exclusive write access to version and negotiated fields + cli.negotiateLock.Lock() + defer cli.negotiateLock.Unlock() + + // May have been set during last execution of critical zone + if cli.negotiated.Load() { + return nil + } + ping, err := cli.Ping(ctx) if err != nil { return err @@ -312,6 +326,10 @@ func (cli *Client) ClientVersion() string { // added (1.24). func (cli *Client) NegotiateAPIVersion(ctx context.Context) { if !cli.manualOverride { + // Avoid concurrent modification of version-related fields + cli.negotiateLock.Lock() + defer cli.negotiateLock.Unlock() + ping, err := cli.Ping(ctx) if err != nil { // FIXME(thaJeztah): Ping returns an error when failing to connect to the API; we should not swallow the error here, and instead returning it. @@ -336,6 +354,10 @@ func (cli *Client) NegotiateAPIVersion(ctx context.Context) { // added (1.24). func (cli *Client) NegotiateAPIVersionPing(pingResponse types.Ping) { if !cli.manualOverride { + // Avoid concurrent modification of version-related fields + cli.negotiateLock.Lock() + defer cli.negotiateLock.Unlock() + cli.negotiateAPIVersionPing(pingResponse) } } @@ -361,7 +383,7 @@ func (cli *Client) negotiateAPIVersionPing(pingResponse types.Ping) { // Store the results, so that automatic API version negotiation (if enabled) // won't be performed on the next request. if cli.negotiateVersion { - cli.negotiated = true + cli.negotiated.Store(true) } } diff --git a/vendor/github.com/docker/docker/client/container_copy.go b/vendor/github.com/docker/docker/client/container_copy.go index 883be7fa3..8490a3b15 100644 --- a/vendor/github.com/docker/docker/client/container_copy.go +++ b/vendor/github.com/docker/docker/client/container_copy.go @@ -11,11 +11,11 @@ import ( "path/filepath" "strings" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" ) // ContainerStatPath returns stat information about a path inside the container filesystem. -func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path string) (types.ContainerPathStat, error) { +func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path string) (container.PathStat, error) { query := url.Values{} query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API. @@ -23,14 +23,14 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri response, err := cli.head(ctx, urlStr, query, nil) defer ensureReaderClosed(response) if err != nil { - return types.ContainerPathStat{}, err + return container.PathStat{}, err } return getContainerPathStatFromHeader(response.header) } // CopyToContainer copies content into the container filesystem. // Note that `content` must be a Reader for a TAR archive -func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options types.CopyToContainerOptions) error { +func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath string, content io.Reader, options container.CopyToContainerOptions) error { query := url.Values{} query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API. // Do not allow for an existing directory to be overwritten by a non-directory and vice versa. @@ -55,14 +55,14 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str // CopyFromContainer gets the content from the container and returns it as a Reader // for a TAR archive to manipulate it in the host. It's up to the caller to close the reader. -func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { +func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath string) (io.ReadCloser, container.PathStat, error) { query := make(url.Values, 1) query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API. apiPath := "/containers/" + containerID + "/archive" response, err := cli.get(ctx, apiPath, query, nil) if err != nil { - return nil, types.ContainerPathStat{}, err + return nil, container.PathStat{}, err } // In order to get the copy behavior right, we need to know information @@ -78,8 +78,8 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s return response.body, stat, err } -func getContainerPathStatFromHeader(header http.Header) (types.ContainerPathStat, error) { - var stat types.ContainerPathStat +func getContainerPathStatFromHeader(header http.Header) (container.PathStat, error) { + var stat container.PathStat encodedStat := header.Get("X-Docker-Container-Path-Stat") statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat)) diff --git a/vendor/github.com/docker/docker/client/container_exec.go b/vendor/github.com/docker/docker/client/container_exec.go index 526a3876a..9379448d1 100644 --- a/vendor/github.com/docker/docker/client/container_exec.go +++ b/vendor/github.com/docker/docker/client/container_exec.go @@ -6,11 +6,12 @@ import ( "net/http" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/versions" ) // ContainerExecCreate creates a new exec configuration to run an exec process. -func (cli *Client) ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) { +func (cli *Client) ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error) { var response types.IDResponse // Make sure we negotiated (if the client is configured to do so), @@ -22,14 +23,14 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co return response, err } - if err := cli.NewVersionError(ctx, "1.25", "env"); len(config.Env) != 0 && err != nil { + if err := cli.NewVersionError(ctx, "1.25", "env"); len(options.Env) != 0 && err != nil { return response, err } if versions.LessThan(cli.ClientVersion(), "1.42") { - config.ConsoleSize = nil + options.ConsoleSize = nil } - resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil) + resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, options, nil) defer ensureReaderClosed(resp) if err != nil { return response, err @@ -39,7 +40,7 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co } // ContainerExecStart starts an exec process already created in the docker host. -func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error { +func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) error { if versions.LessThan(cli.ClientVersion(), "1.42") { config.ConsoleSize = nil } @@ -52,7 +53,7 @@ func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config // It returns a types.HijackedConnection with the hijacked connection // and the a reader to get output. It's up to the called to close // the hijacked connection by calling types.HijackedResponse.Close. -func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) { +func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config container.ExecAttachOptions) (types.HijackedResponse, error) { if versions.LessThan(cli.ClientVersion(), "1.42") { config.ConsoleSize = nil } @@ -62,8 +63,8 @@ func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, confi } // ContainerExecInspect returns information about a specific exec process on the docker host. -func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) { - var response types.ContainerExecInspect +func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error) { + var response container.ExecInspect resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil) if err != nil { return response, err diff --git a/vendor/github.com/docker/docker/client/container_prune.go b/vendor/github.com/docker/docker/client/container_prune.go index ca5092384..29c922da7 100644 --- a/vendor/github.com/docker/docker/client/container_prune.go +++ b/vendor/github.com/docker/docker/client/container_prune.go @@ -5,13 +5,13 @@ import ( "encoding/json" "fmt" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" ) // ContainersPrune requests the daemon to delete unused data -func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) { - var report types.ContainersPruneReport +func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) { + var report container.PruneReport if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil { return report, err diff --git a/vendor/github.com/docker/docker/client/container_stats.go b/vendor/github.com/docker/docker/client/container_stats.go index 3fabb75f3..b5641daee 100644 --- a/vendor/github.com/docker/docker/client/container_stats.go +++ b/vendor/github.com/docker/docker/client/container_stats.go @@ -4,12 +4,12 @@ import ( "context" "net/url" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" ) // ContainerStats returns near realtime stats for a given container. // It's up to the caller to close the io.ReadCloser returned. -func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) { +func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (container.StatsResponseReader, error) { query := url.Values{} query.Set("stream", "0") if stream { @@ -18,10 +18,10 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) if err != nil { - return types.ContainerStats{}, err + return container.StatsResponseReader{}, err } - return types.ContainerStats{ + return container.StatsResponseReader{ Body: resp.body, OSType: getDockerOS(resp.header.Get("Server")), }, nil @@ -29,17 +29,17 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea // ContainerStatsOneShot gets a single stat entry from a container. // It differs from `ContainerStats` in that the API should not wait to prime the stats -func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (types.ContainerStats, error) { +func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (container.StatsResponseReader, error) { query := url.Values{} query.Set("stream", "0") query.Set("one-shot", "1") resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil) if err != nil { - return types.ContainerStats{}, err + return container.StatsResponseReader{}, err } - return types.ContainerStats{ + return container.StatsResponseReader{ Body: resp.body, OSType: getDockerOS(resp.header.Get("Server")), }, nil diff --git a/vendor/github.com/docker/docker/client/events.go b/vendor/github.com/docker/docker/client/events.go index a9c48a928..d3ab26bed 100644 --- a/vendor/github.com/docker/docker/client/events.go +++ b/vendor/github.com/docker/docker/client/events.go @@ -6,7 +6,6 @@ import ( "net/url" "time" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" timetypes "github.com/docker/docker/api/types/time" @@ -16,7 +15,7 @@ import ( // by cancelling the context. Once the stream has been completely read an io.EOF error will // be sent over the error channel. If an error is sent all processing will be stopped. It's up // to the caller to reopen the stream in the event of an error by reinvoking this method. -func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) { +func (cli *Client) Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) { messages := make(chan events.Message) errs := make(chan error, 1) @@ -68,7 +67,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c return messages, errs } -func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) { +func buildEventsQueryParams(cliVersion string, options events.ListOptions) (url.Values, error) { query := url.Values{} ref := time.Now() diff --git a/vendor/github.com/docker/docker/client/image_import.go b/vendor/github.com/docker/docker/client/image_import.go index 5a890b0c5..43d55eda8 100644 --- a/vendor/github.com/docker/docker/client/image_import.go +++ b/vendor/github.com/docker/docker/client/image_import.go @@ -7,13 +7,12 @@ import ( "strings" "github.com/distribution/reference" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/image" ) // ImageImport creates a new image based on the source options. // It returns the JSON content in the response body. -func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) { +func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) { if ref != "" { // Check if the given image name can be resolved if _, err := reference.ParseNormalizedNamed(ref); err != nil { diff --git a/vendor/github.com/docker/docker/client/image_load.go b/vendor/github.com/docker/docker/client/image_load.go index c825206ea..c68f0013e 100644 --- a/vendor/github.com/docker/docker/client/image_load.go +++ b/vendor/github.com/docker/docker/client/image_load.go @@ -6,13 +6,13 @@ import ( "net/http" "net/url" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/image" ) // ImageLoad loads an image in the docker host from the client host. // It's up to the caller to close the io.ReadCloser in the // ImageLoadResponse returned by this function. -func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) { +func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (image.LoadResponse, error) { v := url.Values{} v.Set("quiet", "0") if quiet { @@ -22,9 +22,9 @@ func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, quiet bool) ( "Content-Type": {"application/x-tar"}, }) if err != nil { - return types.ImageLoadResponse{}, err + return image.LoadResponse{}, err } - return types.ImageLoadResponse{ + return image.LoadResponse{ Body: resp.body, JSON: resp.header.Get("Content-Type") == "application/json", }, nil diff --git a/vendor/github.com/docker/docker/client/image_prune.go b/vendor/github.com/docker/docker/client/image_prune.go index 6b82d6ab6..5ee987e24 100644 --- a/vendor/github.com/docker/docker/client/image_prune.go +++ b/vendor/github.com/docker/docker/client/image_prune.go @@ -5,13 +5,13 @@ import ( "encoding/json" "fmt" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/image" ) // ImagesPrune requests the daemon to delete unused data -func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (types.ImagesPruneReport, error) { - var report types.ImagesPruneReport +func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) { + var report image.PruneReport if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil { return report, err diff --git a/vendor/github.com/docker/docker/client/image_pull.go b/vendor/github.com/docker/docker/client/image_pull.go index 6438cf6a9..1634c4c80 100644 --- a/vendor/github.com/docker/docker/client/image_pull.go +++ b/vendor/github.com/docker/docker/client/image_pull.go @@ -36,7 +36,7 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.P resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth) if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { - newAuthHeader, privilegeErr := options.PrivilegeFunc() + newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx) if privilegeErr != nil { return nil, privilegeErr } diff --git a/vendor/github.com/docker/docker/client/image_push.go b/vendor/github.com/docker/docker/client/image_push.go index e6a6b11ee..16f9c4651 100644 --- a/vendor/github.com/docker/docker/client/image_push.go +++ b/vendor/github.com/docker/docker/client/image_push.go @@ -2,7 +2,9 @@ package client // import "github.com/docker/docker/client" import ( "context" + "encoding/json" "errors" + "fmt" "io" "net/http" "net/url" @@ -36,9 +38,23 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options image.Pu } } + if options.Platform != nil { + if err := cli.NewVersionError(ctx, "1.46", "platform"); err != nil { + return nil, err + } + + p := *options.Platform + pJson, err := json.Marshal(p) + if err != nil { + return nil, fmt.Errorf("invalid platform: %v", err) + } + + query.Set("platform", string(pJson)) + } + resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth) if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { - newAuthHeader, privilegeErr := options.PrivilegeFunc() + newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx) if privilegeErr != nil { return nil, privilegeErr } diff --git a/vendor/github.com/docker/docker/client/image_search.go b/vendor/github.com/docker/docker/client/image_search.go index 8971b139a..0a0745757 100644 --- a/vendor/github.com/docker/docker/client/image_search.go +++ b/vendor/github.com/docker/docker/client/image_search.go @@ -7,7 +7,6 @@ import ( "net/url" "strconv" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/registry" "github.com/docker/docker/errdefs" @@ -15,7 +14,7 @@ import ( // ImageSearch makes the docker host search by a term in a remote registry. // The list of results is not sorted in any fashion. -func (cli *Client) ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) { +func (cli *Client) ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error) { var results []registry.SearchResult query := url.Values{} query.Set("term", term) @@ -34,7 +33,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth) defer ensureReaderClosed(resp) if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { - newAuthHeader, privilegeErr := options.PrivilegeFunc() + newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx) if privilegeErr != nil { return results, privilegeErr } diff --git a/vendor/github.com/docker/docker/client/interface.go b/vendor/github.com/docker/docker/client/interface.go index 45d233f25..cc60a5d13 100644 --- a/vendor/github.com/docker/docker/client/interface.go +++ b/vendor/github.com/docker/docker/client/interface.go @@ -50,11 +50,11 @@ type ContainerAPIClient interface { ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (types.IDResponse, error) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error) ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error) - ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error) - ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error) - ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error) + ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (types.HijackedResponse, error) + ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (types.IDResponse, error) + ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error) ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error - ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error + ContainerExecStart(ctx context.Context, execID string, options container.ExecStartOptions) error ContainerExport(ctx context.Context, container string) (io.ReadCloser, error) ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error) ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error) @@ -66,18 +66,18 @@ type ContainerAPIClient interface { ContainerRename(ctx context.Context, container, newContainerName string) error ContainerResize(ctx context.Context, container string, options container.ResizeOptions) error ContainerRestart(ctx context.Context, container string, options container.StopOptions) error - ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error) - ContainerStats(ctx context.Context, container string, stream bool) (types.ContainerStats, error) - ContainerStatsOneShot(ctx context.Context, container string) (types.ContainerStats, error) + ContainerStatPath(ctx context.Context, container, path string) (container.PathStat, error) + ContainerStats(ctx context.Context, container string, stream bool) (container.StatsResponseReader, error) + ContainerStatsOneShot(ctx context.Context, container string) (container.StatsResponseReader, error) ContainerStart(ctx context.Context, container string, options container.StartOptions) error ContainerStop(ctx context.Context, container string, options container.StopOptions) error ContainerTop(ctx context.Context, container string, arguments []string) (container.ContainerTopOKBody, error) ContainerUnpause(ctx context.Context, container string) error ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) - CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) - CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error - ContainersPrune(ctx context.Context, pruneFilters filters.Args) (types.ContainersPruneReport, error) + CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error) + CopyToContainer(ctx context.Context, container, path string, content io.Reader, options container.CopyToContainerOptions) error + ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) } // DistributionAPIClient defines API client methods for the registry @@ -92,29 +92,29 @@ type ImageAPIClient interface { BuildCancel(ctx context.Context, id string) error ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error) - ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) + ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) ImageInspectWithRaw(ctx context.Context, image string) (types.ImageInspect, []byte, error) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) - ImageLoad(ctx context.Context, input io.Reader, quiet bool) (types.ImageLoadResponse, error) + ImageLoad(ctx context.Context, input io.Reader, quiet bool) (image.LoadResponse, error) ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error) ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error) ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error) - ImageSearch(ctx context.Context, term string, options types.ImageSearchOptions) ([]registry.SearchResult, error) + ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error) ImageSave(ctx context.Context, images []string) (io.ReadCloser, error) ImageTag(ctx context.Context, image, ref string) error - ImagesPrune(ctx context.Context, pruneFilter filters.Args) (types.ImagesPruneReport, error) + ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error) } // NetworkAPIClient defines API client methods for the networks type NetworkAPIClient interface { NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error - NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) + NetworkCreate(ctx context.Context, name string, options network.CreateOptions) (network.CreateResponse, error) NetworkDisconnect(ctx context.Context, network, container string, force bool) error - NetworkInspect(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, error) - NetworkInspectWithRaw(ctx context.Context, network string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) - NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) + NetworkInspect(ctx context.Context, network string, options network.InspectOptions) (network.Inspect, error) + NetworkInspectWithRaw(ctx context.Context, network string, options network.InspectOptions) (network.Inspect, []byte, error) + NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error) NetworkRemove(ctx context.Context, network string) error - NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error) + NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error) } // NodeAPIClient defines API client methods for the nodes @@ -165,7 +165,7 @@ type SwarmAPIClient interface { // SystemAPIClient defines API client methods for the system type SystemAPIClient interface { - Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) + Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) Info(ctx context.Context) (system.Info, error) RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error) @@ -179,7 +179,7 @@ type VolumeAPIClient interface { VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error) VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) VolumeRemove(ctx context.Context, volumeID string, force bool) error - VolumesPrune(ctx context.Context, pruneFilter filters.Args) (types.VolumesPruneReport, error) + VolumesPrune(ctx context.Context, pruneFilter filters.Args) (volume.PruneReport, error) VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error } diff --git a/vendor/github.com/docker/docker/client/network_connect.go b/vendor/github.com/docker/docker/client/network_connect.go index 571894613..8daf89063 100644 --- a/vendor/github.com/docker/docker/client/network_connect.go +++ b/vendor/github.com/docker/docker/client/network_connect.go @@ -3,13 +3,12 @@ package client // import "github.com/docker/docker/client" import ( "context" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" ) // NetworkConnect connects a container to an existent network in the docker host. func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error { - nc := types.NetworkConnect{ + nc := network.ConnectOptions{ Container: containerID, EndpointConfig: config, } diff --git a/vendor/github.com/docker/docker/client/network_create.go b/vendor/github.com/docker/docker/client/network_create.go index d510feb3d..850e31cc9 100644 --- a/vendor/github.com/docker/docker/client/network_create.go +++ b/vendor/github.com/docker/docker/client/network_create.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/versions" ) // NetworkCreate creates a new network in the docker host. -func (cli *Client) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) { - var response types.NetworkCreateResponse +func (cli *Client) NetworkCreate(ctx context.Context, name string, options network.CreateOptions) (network.CreateResponse, error) { + var response network.CreateResponse // Make sure we negotiated (if the client is configured to do so), // as code below contains API-version specific handling of options. @@ -21,12 +21,13 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types return response, err } - networkCreateRequest := types.NetworkCreateRequest{ - NetworkCreate: options, + networkCreateRequest := network.CreateRequest{ + CreateOptions: options, Name: name, } if versions.LessThan(cli.version, "1.44") { - networkCreateRequest.CheckDuplicate = true //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44. + enabled := true + networkCreateRequest.CheckDuplicate = &enabled //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44. } serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil) diff --git a/vendor/github.com/docker/docker/client/network_disconnect.go b/vendor/github.com/docker/docker/client/network_disconnect.go index dd1567665..aaf428d85 100644 --- a/vendor/github.com/docker/docker/client/network_disconnect.go +++ b/vendor/github.com/docker/docker/client/network_disconnect.go @@ -3,12 +3,15 @@ package client // import "github.com/docker/docker/client" import ( "context" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/network" ) // NetworkDisconnect disconnects a container from an existent network in the docker host. func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error { - nd := types.NetworkDisconnect{Container: containerID, Force: force} + nd := network.DisconnectOptions{ + Container: containerID, + Force: force, + } resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, nd, nil) ensureReaderClosed(resp) return err diff --git a/vendor/github.com/docker/docker/client/network_inspect.go b/vendor/github.com/docker/docker/client/network_inspect.go index 0f90e2bb9..afc47de6f 100644 --- a/vendor/github.com/docker/docker/client/network_inspect.go +++ b/vendor/github.com/docker/docker/client/network_inspect.go @@ -7,25 +7,20 @@ import ( "io" "net/url" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/network" ) // NetworkInspect returns the information for a specific network configured in the docker host. -func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, error) { +func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options network.InspectOptions) (network.Inspect, error) { networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options) return networkResource, err } // NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation. -func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) { +func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options network.InspectOptions) (network.Inspect, []byte, error) { if networkID == "" { - return types.NetworkResource{}, nil, objectNotFoundError{object: "network", id: networkID} + return network.Inspect{}, nil, objectNotFoundError{object: "network", id: networkID} } - var ( - networkResource types.NetworkResource - resp serverResponse - err error - ) query := url.Values{} if options.Verbose { query.Set("verbose", "true") @@ -33,17 +28,19 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, if options.Scope != "" { query.Set("scope", options.Scope) } - resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) + + resp, err := cli.get(ctx, "/networks/"+networkID, query, nil) defer ensureReaderClosed(resp) if err != nil { - return networkResource, nil, err + return network.Inspect{}, nil, err } - body, err := io.ReadAll(resp.body) + raw, err := io.ReadAll(resp.body) if err != nil { - return networkResource, nil, err + return network.Inspect{}, nil, err } - rdr := bytes.NewReader(body) - err = json.NewDecoder(rdr).Decode(&networkResource) - return networkResource, body, err + + var nw network.Inspect + err = json.NewDecoder(bytes.NewReader(raw)).Decode(&nw) + return nw, raw, err } diff --git a/vendor/github.com/docker/docker/client/network_list.go b/vendor/github.com/docker/docker/client/network_list.go index ed2acb557..72957d47f 100644 --- a/vendor/github.com/docker/docker/client/network_list.go +++ b/vendor/github.com/docker/docker/client/network_list.go @@ -5,12 +5,12 @@ import ( "encoding/json" "net/url" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/network" ) // NetworkList returns the list of networks configured in the docker host. -func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) { +func (cli *Client) NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error) { query := url.Values{} if options.Filters.Len() > 0 { //nolint:staticcheck // ignore SA1019 for old code @@ -21,7 +21,7 @@ func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOpt query.Set("filters", filterJSON) } - var networkResources []types.NetworkResource + var networkResources []network.Summary resp, err := cli.get(ctx, "/networks", query, nil) defer ensureReaderClosed(resp) if err != nil { diff --git a/vendor/github.com/docker/docker/client/network_prune.go b/vendor/github.com/docker/docker/client/network_prune.go index 7b5f831ef..708cc61a4 100644 --- a/vendor/github.com/docker/docker/client/network_prune.go +++ b/vendor/github.com/docker/docker/client/network_prune.go @@ -5,13 +5,13 @@ import ( "encoding/json" "fmt" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/network" ) // NetworksPrune requests the daemon to delete unused networks -func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (types.NetworksPruneReport, error) { - var report types.NetworksPruneReport +func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) { + var report network.PruneReport if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil { return report, err diff --git a/vendor/github.com/docker/docker/client/plugin_install.go b/vendor/github.com/docker/docker/client/plugin_install.go index 69184619a..a0d8c3500 100644 --- a/vendor/github.com/docker/docker/client/plugin_install.go +++ b/vendor/github.com/docker/docker/client/plugin_install.go @@ -84,7 +84,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth) if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { // todo: do inspect before to check existing name before checking privileges - newAuthHeader, privilegeErr := options.PrivilegeFunc() + newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx) if privilegeErr != nil { ensureReaderClosed(resp) return nil, privilegeErr @@ -105,7 +105,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, ensureReaderClosed(resp) if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 { - accept, err := options.AcceptPermissionsFunc(privileges) + accept, err := options.AcceptPermissionsFunc(ctx, privileges) if err != nil { return nil, err } diff --git a/vendor/github.com/docker/docker/client/request.go b/vendor/github.com/docker/docker/client/request.go index 50e213b50..6eea9b4e4 100644 --- a/vendor/github.com/docker/docker/client/request.go +++ b/vendor/github.com/docker/docker/client/request.go @@ -184,10 +184,10 @@ func (cli *Client) doRequest(req *http.Request) (serverResponse, error) { // `open //./pipe/docker_engine: Le fichier spécifié est introuvable.` if strings.Contains(err.Error(), `open //./pipe/docker_engine`) { // Checks if client is running with elevated privileges - if f, elevatedErr := os.Open("\\\\.\\PHYSICALDRIVE0"); elevatedErr == nil { + if f, elevatedErr := os.Open(`\\.\PHYSICALDRIVE0`); elevatedErr != nil { err = errors.Wrap(err, "in the default daemon configuration on Windows, the docker client must be run with elevated privileges to connect") } else { - f.Close() + _ = f.Close() err = errors.Wrap(err, "this error may indicate that the docker daemon is not running") } } @@ -278,7 +278,7 @@ func encodeData(data interface{}) (*bytes.Buffer, error) { func ensureReaderClosed(response serverResponse) { if response.body != nil { // Drain up to 512 bytes and close the body to let the Transport reuse the connection - io.CopyN(io.Discard, response.body, 512) - response.body.Close() + _, _ = io.CopyN(io.Discard, response.body, 512) + _ = response.body.Close() } } diff --git a/vendor/github.com/docker/docker/client/volume_prune.go b/vendor/github.com/docker/docker/client/volume_prune.go index 9333f6ee7..9b09c30fa 100644 --- a/vendor/github.com/docker/docker/client/volume_prune.go +++ b/vendor/github.com/docker/docker/client/volume_prune.go @@ -5,13 +5,13 @@ import ( "encoding/json" "fmt" - "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/volume" ) // VolumesPrune requests the daemon to delete unused data -func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (types.VolumesPruneReport, error) { - var report types.VolumesPruneReport +func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) { + var report volume.PruneReport if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil { return report, err diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/.gitignore b/vendor/github.com/go-jose/go-jose/v4/.gitignore similarity index 50% rename from vendor/gopkg.in/go-jose/go-jose.v2/.gitignore rename to vendor/github.com/go-jose/go-jose/v4/.gitignore index 95a851586..eb29ebaef 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/.gitignore +++ b/vendor/github.com/go-jose/go-jose/v4/.gitignore @@ -1,8 +1,2 @@ -*~ -.*.swp -*.out -*.test -*.pem -*.cov jose-util/jose-util jose-util.t.err \ No newline at end of file diff --git a/vendor/github.com/go-jose/go-jose/v4/.golangci.yml b/vendor/github.com/go-jose/go-jose/v4/.golangci.yml new file mode 100644 index 000000000..2a577a8f9 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/.golangci.yml @@ -0,0 +1,53 @@ +# https://github.com/golangci/golangci-lint + +run: + skip-files: + - doc_test.go + modules-download-mode: readonly + +linters: + enable-all: true + disable: + - gochecknoglobals + - goconst + - lll + - maligned + - nakedret + - scopelint + - unparam + - funlen # added in 1.18 (requires go-jose changes before it can be enabled) + +linters-settings: + gocyclo: + min-complexity: 35 + +issues: + exclude-rules: + - text: "don't use ALL_CAPS in Go names" + linters: + - golint + - text: "hardcoded credentials" + linters: + - gosec + - text: "weak cryptographic primitive" + linters: + - gosec + - path: json/ + linters: + - dupl + - errcheck + - gocritic + - gocyclo + - golint + - govet + - ineffassign + - staticcheck + - structcheck + - stylecheck + - unused + - path: _test\.go + linters: + - scopelint + - path: jwk.go + linters: + - gocyclo diff --git a/vendor/github.com/go-jose/go-jose/v4/.travis.yml b/vendor/github.com/go-jose/go-jose/v4/.travis.yml new file mode 100644 index 000000000..48de631b0 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/.travis.yml @@ -0,0 +1,33 @@ +language: go + +matrix: + fast_finish: true + allow_failures: + - go: tip + +go: + - "1.13.x" + - "1.14.x" + - tip + +before_script: + - export PATH=$HOME/.local/bin:$PATH + +before_install: + - go get -u github.com/mattn/goveralls github.com/wadey/gocovmerge + - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.18.0 + - pip install cram --user + +script: + - go test -v -covermode=count -coverprofile=profile.cov . + - go test -v -covermode=count -coverprofile=cryptosigner/profile.cov ./cryptosigner + - go test -v -covermode=count -coverprofile=cipher/profile.cov ./cipher + - go test -v -covermode=count -coverprofile=jwt/profile.cov ./jwt + - go test -v ./json # no coverage for forked encoding/json package + - golangci-lint run + - cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t # cram tests jose-util + - cd .. + +after_success: + - gocovmerge *.cov */*.cov > merged.coverprofile + - goveralls -coverprofile merged.coverprofile -service=travis-ci diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/CHANGELOG.md b/vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md similarity index 93% rename from vendor/gopkg.in/go-jose/go-jose.v2/CHANGELOG.md rename to vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md index 8e6e91323..28bdd2fc0 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/CHANGELOG.md +++ b/vendor/github.com/go-jose/go-jose/v4/CHANGELOG.md @@ -45,12 +45,6 @@ token". [1]: https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf -# v3.0.3 - -## Fixed - - - Limit decompression output size to prevent a DoS. Backport from v4.0.1. - # v3.0.2 ## Fixed @@ -76,9 +70,3 @@ token". amounts of CPU, causing a DoS. Thanks to Matt Schwager (@mschwager) for the disclosure and to Tom Tervoort for originally publishing the category of attack. https://i.blackhat.com/BH-US-23/Presentations/US-23-Tervoort-Three-New-Attacks-Against-JSON-Web-Tokens.pdf - -# v2.6.3 - -## Fixed - - - Limit decompression output size to prevent a DoS. Backport from v4.0.1. diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/CONTRIBUTING.md b/vendor/github.com/go-jose/go-jose/v4/CONTRIBUTING.md similarity index 75% rename from vendor/gopkg.in/go-jose/go-jose.v2/CONTRIBUTING.md rename to vendor/github.com/go-jose/go-jose/v4/CONTRIBUTING.md index 61b183651..b63e1f8fe 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/CONTRIBUTING.md +++ b/vendor/github.com/go-jose/go-jose/v4/CONTRIBUTING.md @@ -9,6 +9,7 @@ sure all tests pass by running `go test`, and format your code with `go fmt`. We also recommend using `golint` and `errcheck`. Before your code can be accepted into the project you must also sign the -[Individual Contributor License Agreement][1]. +Individual Contributor License Agreement. We use [cla-assistant.io][1] and you +will be prompted to sign once a pull request is opened. - [1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1 +[1]: https://cla-assistant.io/ diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/LICENSE b/vendor/github.com/go-jose/go-jose/v4/LICENSE similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/LICENSE rename to vendor/github.com/go-jose/go-jose/v4/LICENSE diff --git a/vendor/github.com/go-jose/go-jose/v4/README.md b/vendor/github.com/go-jose/go-jose/v4/README.md new file mode 100644 index 000000000..79a7c5ecc --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/README.md @@ -0,0 +1,114 @@ +# Go JOSE + +[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4) +[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4/jwt.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt) +[![license](https://img.shields.io/badge/license-apache_2.0-blue.svg?style=flat)](https://raw.githubusercontent.com/go-jose/go-jose/master/LICENSE) +[![test](https://img.shields.io/github/checks-status/go-jose/go-jose/v4)](https://github.com/go-jose/go-jose/actions) + +Package jose aims to provide an implementation of the Javascript Object Signing +and Encryption set of standards. This includes support for JSON Web Encryption, +JSON Web Signature, and JSON Web Token standards. + +**Disclaimer**: This library contains encryption software that is subject to +the U.S. Export Administration Regulations. You may not export, re-export, +transfer or download this code or any part of it in violation of any United +States law, directive or regulation. In particular this software may not be +exported or re-exported in any form or on any media to Iran, North Sudan, +Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any +US maintained blocked list. + +## Overview + +The implementation follows the +[JSON Web Encryption](https://dx.doi.org/10.17487/RFC7516) (RFC 7516), +[JSON Web Signature](https://dx.doi.org/10.17487/RFC7515) (RFC 7515), and +[JSON Web Token](https://dx.doi.org/10.17487/RFC7519) (RFC 7519) specifications. +Tables of supported algorithms are shown below. The library supports both +the compact and JWS/JWE JSON Serialization formats, and has optional support for +multiple recipients. It also comes with a small command-line utility +([`jose-util`](https://pkg.go.dev/github.com/go-jose/go-jose/jose-util)) +for dealing with JOSE messages in a shell. + +**Note**: We use a forked version of the `encoding/json` package from the Go +standard library which uses case-sensitive matching for member names (instead +of [case-insensitive matching](https://www.ietf.org/mail-archive/web/json/current/msg03763.html)). +This is to avoid differences in interpretation of messages between go-jose and +libraries in other languages. + +### Versions + +[Version 4](https://github.com/go-jose/go-jose) +([branch](https://github.com/go-jose/go-jose/tree/main), +[doc](https://pkg.go.dev/github.com/go-jose/go-jose/v4), [releases](https://github.com/go-jose/go-jose/releases)) is the current stable version: + + import "github.com/go-jose/go-jose/v4" + +The old [square/go-jose](https://github.com/square/go-jose) repo contains the prior v1 and v2 versions, which +are still useable but not actively developed anymore. + +Version 3, in this repo, is still receiving security fixes but not functionality +updates. + +### Supported algorithms + +See below for a table of supported algorithms. Algorithm identifiers match +the names in the [JSON Web Algorithms](https://dx.doi.org/10.17487/RFC7518) +standard where possible. The Godoc reference has a list of constants. + + Key encryption | Algorithm identifier(s) + :------------------------- | :------------------------------ + RSA-PKCS#1v1.5 | RSA1_5 + RSA-OAEP | RSA-OAEP, RSA-OAEP-256 + AES key wrap | A128KW, A192KW, A256KW + AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW + ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW + ECDH-ES (direct) | ECDH-ES1 + Direct encryption | dir1 + +1. Not supported in multi-recipient mode + + Signing / MAC | Algorithm identifier(s) + :------------------------- | :------------------------------ + RSASSA-PKCS#1v1.5 | RS256, RS384, RS512 + RSASSA-PSS | PS256, PS384, PS512 + HMAC | HS256, HS384, HS512 + ECDSA | ES256, ES384, ES512 + Ed25519 | EdDSA2 + +2. Only available in version 2 of the package + + Content encryption | Algorithm identifier(s) + :------------------------- | :------------------------------ + AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 + AES-GCM | A128GCM, A192GCM, A256GCM + + Compression | Algorithm identifiers(s) + :------------------------- | ------------------------------- + DEFLATE (RFC 1951) | DEF + +### Supported key types + +See below for a table of supported key types. These are understood by the +library, and can be passed to corresponding functions such as `NewEncrypter` or +`NewSigner`. Each of these keys can also be wrapped in a JWK if desired, which +allows attaching a key id. + + Algorithm(s) | Corresponding types + :------------------------- | ------------------------------- + RSA | *[rsa.PublicKey](https://pkg.go.dev/crypto/rsa/#PublicKey), *[rsa.PrivateKey](https://pkg.go.dev/crypto/rsa/#PrivateKey) + ECDH, ECDSA | *[ecdsa.PublicKey](https://pkg.go.dev/crypto/ecdsa/#PublicKey), *[ecdsa.PrivateKey](https://pkg.go.dev/crypto/ecdsa/#PrivateKey) + EdDSA1 | [ed25519.PublicKey](https://pkg.go.dev/crypto/ed25519#PublicKey), [ed25519.PrivateKey](https://pkg.go.dev/crypto/ed25519#PrivateKey) + AES, HMAC | []byte + +1. Only available in version 2 or later of the package + +## Examples + +[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4) +[![godoc](https://pkg.go.dev/badge/github.com/go-jose/go-jose/v4/jwt.svg)](https://pkg.go.dev/github.com/go-jose/go-jose/v4/jwt) + +Examples can be found in the Godoc +reference for this package. The +[`jose-util`](https://github.com/go-jose/go-jose/tree/v4/jose-util) +subdirectory also contains a small command-line utility which might be useful +as an example as well. diff --git a/vendor/github.com/go-jose/go-jose/v4/SECURITY.md b/vendor/github.com/go-jose/go-jose/v4/SECURITY.md new file mode 100644 index 000000000..2f18a75a8 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy +This document explains how to contact the Let's Encrypt security team to report security vulnerabilities. + +## Supported Versions +| Version | Supported | +| ------- | ----------| +| >= v3 | ✓ | +| v2 | ✗ | +| v1 | ✗ | + +## Reporting a vulnerability + +Please see [https://letsencrypt.org/contact/#security](https://letsencrypt.org/contact/#security) for the email address to report a vulnerability. Ensure that the subject line for your report contains the word `vulnerability` and is descriptive. Your email should be acknowledged within 24 hours. If you do not receive a response within 24 hours, please follow-up again with another email. diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/asymmetric.go b/vendor/github.com/go-jose/go-jose/v4/asymmetric.go similarity index 99% rename from vendor/gopkg.in/go-jose/go-jose.v2/asymmetric.go rename to vendor/github.com/go-jose/go-jose/v4/asymmetric.go index 43f9ce2fc..f8d5774ef 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/asymmetric.go +++ b/vendor/github.com/go-jose/go-jose/v4/asymmetric.go @@ -20,6 +20,7 @@ import ( "crypto" "crypto/aes" "crypto/ecdsa" + "crypto/ed25519" "crypto/rand" "crypto/rsa" "crypto/sha1" @@ -28,9 +29,8 @@ import ( "fmt" "math/big" - "golang.org/x/crypto/ed25519" - josecipher "gopkg.in/go-jose/go-jose.v2/cipher" - "gopkg.in/go-jose/go-jose.v2/json" + josecipher "github.com/go-jose/go-jose/v4/cipher" + "github.com/go-jose/go-jose/v4/json" ) // A generic RSA-based encrypter/verifier diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/cbc_hmac.go b/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go similarity index 98% rename from vendor/gopkg.in/go-jose/go-jose.v2/cipher/cbc_hmac.go rename to vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go index 87065a5b9..af029cec0 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/cbc_hmac.go +++ b/vendor/github.com/go-jose/go-jose/v4/cipher/cbc_hmac.go @@ -114,7 +114,7 @@ func (ctx *cbcAEAD) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { cbc := cipher.NewCBCDecrypter(ctx.blockCipher, nonce) // Make copy of ciphertext buffer, don't want to modify in place - buffer := append([]byte{}, []byte(ciphertext[:offset])...) + buffer := append([]byte{}, ciphertext[:offset]...) if len(buffer)%ctx.blockCipher.BlockSize() > 0 { return nil, errors.New("go-jose/go-jose: invalid ciphertext (invalid length)") diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/concat_kdf.go b/vendor/github.com/go-jose/go-jose/v4/cipher/concat_kdf.go similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/cipher/concat_kdf.go rename to vendor/github.com/go-jose/go-jose/v4/cipher/concat_kdf.go diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/ecdh_es.go b/vendor/github.com/go-jose/go-jose/v4/cipher/ecdh_es.go similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/cipher/ecdh_es.go rename to vendor/github.com/go-jose/go-jose/v4/cipher/ecdh_es.go diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/key_wrap.go b/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go similarity index 97% rename from vendor/gopkg.in/go-jose/go-jose.v2/cipher/key_wrap.go rename to vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go index 668358f98..b9effbca8 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/cipher/key_wrap.go +++ b/vendor/github.com/go-jose/go-jose/v4/cipher/key_wrap.go @@ -51,7 +51,7 @@ func KeyWrap(block cipher.Block, cek []byte) ([]byte, error) { binary.BigEndian.PutUint64(tBytes, uint64(t+1)) for i := 0; i < 8; i++ { - buffer[i] = buffer[i] ^ tBytes[i] + buffer[i] ^= tBytes[i] } copy(r[t%n], buffer[8:]) } @@ -87,7 +87,7 @@ func KeyUnwrap(block cipher.Block, ciphertext []byte) ([]byte, error) { binary.BigEndian.PutUint64(tBytes, uint64(t+1)) for i := 0; i < 8; i++ { - buffer[i] = buffer[i] ^ tBytes[i] + buffer[i] ^= tBytes[i] } copy(buffer[8:], r[t%n]) diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/crypter.go b/vendor/github.com/go-jose/go-jose/v4/crypter.go similarity index 84% rename from vendor/gopkg.in/go-jose/go-jose.v2/crypter.go rename to vendor/github.com/go-jose/go-jose/v4/crypter.go index 0ae2e5eba..aba08424c 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/crypter.go +++ b/vendor/github.com/go-jose/go-jose/v4/crypter.go @@ -21,9 +21,8 @@ import ( "crypto/rsa" "errors" "fmt" - "reflect" - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // Encrypter represents an encrypter which produces an encrypted JWE object. @@ -76,14 +75,24 @@ type recipientKeyInfo struct { type EncrypterOptions struct { Compression CompressionAlgorithm - // Optional map of additional keys to be inserted into the protected header - // of a JWS object. Some specifications which make use of JWS like to insert - // additional values here. All values must be JSON-serializable. + // Optional map of name/value pairs to be inserted into the protected + // header of a JWS object. Some specifications which make use of + // JWS require additional values here. + // + // Values will be serialized by [json.Marshal] and must be valid inputs to + // that function. + // + // [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal ExtraHeaders map[HeaderKey]interface{} } // WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it -// if necessary. It returns itself and so can be used in a fluent style. +// if necessary, and returns the updated EncrypterOptions. +// +// The v parameter will be serialized by [json.Marshal] and must be a valid +// input to that function. +// +// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal func (eo *EncrypterOptions) WithHeader(k HeaderKey, v interface{}) *EncrypterOptions { if eo.ExtraHeaders == nil { eo.ExtraHeaders = map[HeaderKey]interface{}{} @@ -111,7 +120,17 @@ func (eo *EncrypterOptions) WithType(typ ContentType) *EncrypterOptions { // default of 100000 will be used for the count and a 128-bit random salt will // be generated. type Recipient struct { - Algorithm KeyAlgorithm + Algorithm KeyAlgorithm + // Key must have one of these types: + // - ed25519.PublicKey + // - *ecdsa.PublicKey + // - *rsa.PublicKey + // - *JSONWebKey + // - JSONWebKey + // - []byte (a symmetric key) + // - Any type that satisfies the OpaqueKeyEncrypter interface + // + // The type of Key must match the value of Algorithm. Key interface{} KeyID string PBES2Count int @@ -150,16 +169,17 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions) switch rcpt.Algorithm { case DIRECT: // Direct encryption mode must be treated differently - if reflect.TypeOf(rawKey) != reflect.TypeOf([]byte{}) { + keyBytes, ok := rawKey.([]byte) + if !ok { return nil, ErrUnsupportedKeyType } - if encrypter.cipher.keySize() != len(rawKey.([]byte)) { + if encrypter.cipher.keySize() != len(keyBytes) { return nil, ErrInvalidKeySize } encrypter.keyGenerator = staticKeyGenerator{ - key: rawKey.([]byte), + key: keyBytes, } - recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, rawKey.([]byte)) + recipientInfo, _ := newSymmetricRecipient(rcpt.Algorithm, keyBytes) recipientInfo.keyID = keyID if rcpt.KeyID != "" { recipientInfo.keyID = rcpt.KeyID @@ -168,16 +188,16 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions) return encrypter, nil case ECDH_ES: // ECDH-ES (w/o key wrapping) is similar to DIRECT mode - typeOf := reflect.TypeOf(rawKey) - if typeOf != reflect.TypeOf(&ecdsa.PublicKey{}) { + keyDSA, ok := rawKey.(*ecdsa.PublicKey) + if !ok { return nil, ErrUnsupportedKeyType } encrypter.keyGenerator = ecKeyGenerator{ size: encrypter.cipher.keySize(), algID: string(enc), - publicKey: rawKey.(*ecdsa.PublicKey), + publicKey: keyDSA, } - recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, rawKey.(*ecdsa.PublicKey)) + recipientInfo, _ := newECDHRecipient(rcpt.Algorithm, keyDSA) recipientInfo.keyID = keyID if rcpt.KeyID != "" { recipientInfo.keyID = rcpt.KeyID @@ -201,7 +221,7 @@ func NewMultiEncrypter(enc ContentEncryption, rcpts []Recipient, opts *Encrypter if cipher == nil { return nil, ErrUnsupportedAlgorithm } - if rcpts == nil || len(rcpts) == 0 { + if len(rcpts) == 0 { return nil, fmt.Errorf("go-jose/go-jose: recipients is nil or empty") } @@ -270,9 +290,8 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey recipient, err := makeJWERecipient(alg, encryptionKey.Key) recipient.keyID = encryptionKey.KeyID return recipient, err - } - if encrypter, ok := encryptionKey.(OpaqueKeyEncrypter); ok { - return newOpaqueKeyEncrypter(alg, encrypter) + case OpaqueKeyEncrypter: + return newOpaqueKeyEncrypter(alg, encryptionKey) } return recipientKeyInfo{}, ErrUnsupportedKeyType } @@ -300,11 +319,11 @@ func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) { return newDecrypter(decryptionKey.Key) case *JSONWebKey: return newDecrypter(decryptionKey.Key) + case OpaqueKeyDecrypter: + return &opaqueKeyDecrypter{decrypter: decryptionKey}, nil + default: + return nil, ErrUnsupportedKeyType } - if okd, ok := decryptionKey.(OpaqueKeyDecrypter); ok { - return &opaqueKeyDecrypter{decrypter: okd}, nil - } - return nil, ErrUnsupportedKeyType } // Implementation of encrypt method producing a JWE object. @@ -403,10 +422,25 @@ func (ctx *genericEncrypter) Options() EncrypterOptions { } } -// Decrypt and validate the object and return the plaintext. Note that this -// function does not support multi-recipient, if you desire multi-recipient +// Decrypt and validate the object and return the plaintext. This +// function does not support multi-recipient. If you desire multi-recipient // decryption use DecryptMulti instead. // +// The decryptionKey argument must contain a private or symmetric key +// and must have one of these types: +// - *ecdsa.PrivateKey +// - *rsa.PrivateKey +// - *JSONWebKey +// - JSONWebKey +// - *JSONWebKeySet +// - JSONWebKeySet +// - []byte (a symmetric key) +// - string (a symmetric key) +// - Any type that satisfies the OpaqueKeyDecrypter interface. +// +// Note that ed25519 is only available for signatures, not encryption, so is +// not an option here. +// // Automatically decompresses plaintext, but returns an error if the decompressed // data would be >250kB or >10x the size of the compressed data, whichever is larger. func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) { @@ -425,7 +459,8 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) return nil, fmt.Errorf("go-jose/go-jose: unsupported crit header") } - decrypter, err := newDecrypter(decryptionKey) + key := tryJWKS(decryptionKey, obj.Header) + decrypter, err := newDecrypter(key) if err != nil { return nil, err } @@ -464,9 +499,12 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) // The "zip" header parameter may only be present in the protected header. if comp := obj.protected.getCompression(); comp != "" { plaintext, err = decompress(comp, plaintext) + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err) + } } - return plaintext, err + return plaintext, nil } // DecryptMulti decrypts and validates the object and returns the plaintexts, @@ -474,6 +512,9 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) // for which the decryption was successful, the merged headers for that recipient, // and the plaintext. // +// The decryptionKey argument must have one of the types allowed for the +// decryptionKey argument of Decrypt(). +// // Automatically decompresses plaintext, but returns an error if the decompressed // data would be >250kB or >3x the size of the compressed data, whichever is larger. func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) { @@ -488,7 +529,8 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: unsupported crit header") } - decrypter, err := newDecrypter(decryptionKey) + key := tryJWKS(decryptionKey, obj.Header) + decrypter, err := newDecrypter(key) if err != nil { return -1, Header{}, nil, err } @@ -530,13 +572,16 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade } } - if plaintext == nil || err != nil { + if plaintext == nil { return -1, Header{}, nil, ErrCryptoFailure } // The "zip" header parameter may only be present in the protected header. if comp := obj.protected.getCompression(); comp != "" { plaintext, err = decompress(comp, plaintext) + if err != nil { + return -1, Header{}, nil, fmt.Errorf("go-jose/go-jose: failed to decompress plaintext: %v", err) + } } sanitized, err := headers.sanitized() diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/doc.go b/vendor/github.com/go-jose/go-jose/v4/doc.go similarity index 84% rename from vendor/gopkg.in/go-jose/go-jose.v2/doc.go rename to vendor/github.com/go-jose/go-jose/v4/doc.go index dd1387f3f..0ad40ca08 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/doc.go +++ b/vendor/github.com/go-jose/go-jose/v4/doc.go @@ -15,13 +15,11 @@ */ /* - Package jose aims to provide an implementation of the Javascript Object Signing and Encryption set of standards. It implements encryption and signing based on -the JSON Web Encryption and JSON Web Signature standards, with optional JSON -Web Token support available in a sub-package. The library supports both the -compact and full serialization formats, and has optional support for multiple +the JSON Web Encryption and JSON Web Signature standards, with optional JSON Web +Token support available in a sub-package. The library supports both the compact +and JWS/JWE JSON Serialization formats, and has optional support for multiple recipients. - */ package jose diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/encoding.go b/vendor/github.com/go-jose/go-jose/v4/encoding.go similarity index 87% rename from vendor/gopkg.in/go-jose/go-jose.v2/encoding.go rename to vendor/github.com/go-jose/go-jose/v4/encoding.go index 636f6c8f5..4f6e0d4a5 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/encoding.go +++ b/vendor/github.com/go-jose/go-jose/v4/encoding.go @@ -27,7 +27,7 @@ import ( "strings" "unicode" - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // Helper function to serialize known-good objects. @@ -106,10 +106,7 @@ func inflate(input []byte) ([]byte, error) { output := new(bytes.Buffer) reader := flate.NewReader(bytes.NewBuffer(input)) - maxCompressedSize := 10 * int64(len(input)) - if maxCompressedSize < 250000 { - maxCompressedSize = 250000 - } + maxCompressedSize := max(250_000, 10*int64(len(input))) limit := maxCompressedSize + 1 n, err := io.CopyN(output, reader, limit) @@ -196,3 +193,36 @@ func (b byteBuffer) bigInt() *big.Int { func (b byteBuffer) toInt() int { return int(b.bigInt().Int64()) } + +func base64EncodeLen(sl []byte) int { + return base64.RawURLEncoding.EncodedLen(len(sl)) +} + +func base64JoinWithDots(inputs ...[]byte) string { + if len(inputs) == 0 { + return "" + } + + // Count of dots. + totalCount := len(inputs) - 1 + + for _, input := range inputs { + totalCount += base64EncodeLen(input) + } + + out := make([]byte, totalCount) + startEncode := 0 + for i, input := range inputs { + base64.RawURLEncoding.Encode(out[startEncode:], input) + + if i == len(inputs)-1 { + continue + } + + startEncode += base64EncodeLen(input) + out[startEncode] = '.' + startEncode++ + } + + return string(out) +} diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/LICENSE b/vendor/github.com/go-jose/go-jose/v4/json/LICENSE similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/LICENSE rename to vendor/github.com/go-jose/go-jose/v4/json/LICENSE diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/README.md b/vendor/github.com/go-jose/go-jose/v4/json/README.md similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/README.md rename to vendor/github.com/go-jose/go-jose/v4/json/README.md diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/decode.go b/vendor/github.com/go-jose/go-jose/v4/json/decode.go similarity index 99% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/decode.go rename to vendor/github.com/go-jose/go-jose/v4/json/decode.go index 4dbc4146c..50634dd84 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/json/decode.go +++ b/vendor/github.com/go-jose/go-jose/v4/json/decode.go @@ -75,14 +75,13 @@ import ( // // The JSON null value unmarshals into an interface, map, pointer, or slice // by setting that Go value to nil. Because null is often used in JSON to mean -// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// “not present,” unmarshaling a JSON null into any other Go type has no effect // on the value and produces no error. // // When unmarshaling quoted strings, invalid UTF-8 or // invalid UTF-16 surrogate pairs are not treated as an error. // Instead, they are replaced by the Unicode replacement // character U+FFFD. -// func Unmarshal(data []byte, v interface{}) error { // Check for well-formedness. // Avoids filling out half a data structure diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/encode.go b/vendor/github.com/go-jose/go-jose/v4/json/encode.go similarity index 98% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/encode.go rename to vendor/github.com/go-jose/go-jose/v4/json/encode.go index 1dae8bb7c..98de68ce1 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/json/encode.go +++ b/vendor/github.com/go-jose/go-jose/v4/json/encode.go @@ -58,6 +58,7 @@ import ( // becomes a member of the object unless // - the field's tag is "-", or // - the field is empty and its tag specifies the "omitempty" option. +// // The empty values are false, 0, any // nil pointer or interface value, and any array, slice, map, or string of // length zero. The object's default key string is the struct field name @@ -65,28 +66,28 @@ import ( // the struct field's tag value is the key name, followed by an optional comma // and options. Examples: // -// // Field is ignored by this package. -// Field int `json:"-"` +// // Field is ignored by this package. +// Field int `json:"-"` // -// // Field appears in JSON as key "myName". -// Field int `json:"myName"` +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` // -// // Field appears in JSON as key "myName" and -// // the field is omitted from the object if its value is empty, -// // as defined above. -// Field int `json:"myName,omitempty"` +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` // -// // Field appears in JSON as key "Field" (the default), but -// // the field is skipped if empty. -// // Note the leading comma. -// Field int `json:",omitempty"` +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` // // The "string" option signals that a field is stored as JSON inside a // JSON-encoded string. It applies only to fields of string, floating point, // integer, or boolean types. This extra level of encoding is sometimes used // when communicating with JavaScript programs: // -// Int64String int64 `json:",string"` +// Int64String int64 `json:",string"` // // The key name will be used if it's a non-empty string consisting of // only Unicode letters, digits, dollar signs, percent signs, hyphens, @@ -133,7 +134,6 @@ import ( // JSON cannot represent cyclic data structures and Marshal does not // handle them. Passing cyclic structures to Marshal will result in // an infinite recursion. -// func Marshal(v interface{}) ([]byte, error) { e := &encodeState{} err := e.marshal(v) @@ -648,7 +648,7 @@ func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) { // for large buffers, avoid unnecessary extra temporary // buffer space. enc := base64.NewEncoder(base64.StdEncoding, e) - enc.Write(s) + _, _ = enc.Write(s) enc.Close() } e.WriteByte('"') diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/indent.go b/vendor/github.com/go-jose/go-jose/v4/json/indent.go similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/indent.go rename to vendor/github.com/go-jose/go-jose/v4/json/indent.go diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/scanner.go b/vendor/github.com/go-jose/go-jose/v4/json/scanner.go similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/scanner.go rename to vendor/github.com/go-jose/go-jose/v4/json/scanner.go diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/stream.go b/vendor/github.com/go-jose/go-jose/v4/json/stream.go similarity index 99% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/stream.go rename to vendor/github.com/go-jose/go-jose/v4/json/stream.go index 9b2b926b0..f03b171e6 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/json/stream.go +++ b/vendor/github.com/go-jose/go-jose/v4/json/stream.go @@ -240,7 +240,6 @@ var _ Unmarshaler = (*RawMessage)(nil) // Number, for JSON numbers // string, for JSON string literals // nil, for JSON null -// type Token interface{} const ( diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/json/tags.go b/vendor/github.com/go-jose/go-jose/v4/json/tags.go similarity index 100% rename from vendor/gopkg.in/go-jose/go-jose.v2/json/tags.go rename to vendor/github.com/go-jose/go-jose/v4/json/tags.go diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/jwe.go b/vendor/github.com/go-jose/go-jose/v4/jwe.go similarity index 64% rename from vendor/gopkg.in/go-jose/go-jose.v2/jwe.go rename to vendor/github.com/go-jose/go-jose/v4/jwe.go index a8966ab8e..89f03ee3e 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/jwe.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwe.go @@ -18,10 +18,11 @@ package jose import ( "encoding/base64" + "errors" "fmt" "strings" - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing. @@ -86,11 +87,12 @@ func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader { func (obj JSONWebEncryption) computeAuthData() []byte { var protected string - if obj.original != nil && obj.original.Protected != nil { + switch { + case obj.original != nil && obj.original.Protected != nil: protected = obj.original.Protected.base64() - } else if obj.protected != nil { + case obj.protected != nil: protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected))) - } else { + default: protected = "" } @@ -103,29 +105,75 @@ func (obj JSONWebEncryption) computeAuthData() []byte { return output } -// ParseEncrypted parses an encrypted message in compact or full serialization format. -func ParseEncrypted(input string) (*JSONWebEncryption, error) { +func containsKeyAlgorithm(haystack []KeyAlgorithm, needle KeyAlgorithm) bool { + for _, algorithm := range haystack { + if algorithm == needle { + return true + } + } + return false +} + +func containsContentEncryption(haystack []ContentEncryption, needle ContentEncryption) bool { + for _, algorithm := range haystack { + if algorithm == needle { + return true + } + } + return false +} + +// ParseEncrypted parses an encrypted message in JWE Compact or JWE JSON Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1 +// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2 +// +// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc" +// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in +// parsed data must contain a value that is present in the corresponding parameter. That +// includes the protected and unprotected headers as well as all recipients. To accept +// multiple algorithms, pass a slice of all the algorithms you want to accept. +func ParseEncrypted(input string, + keyEncryptionAlgorithms []KeyAlgorithm, + contentEncryption []ContentEncryption, +) (*JSONWebEncryption, error) { input = stripWhitespace(input) if strings.HasPrefix(input, "{") { - return parseEncryptedFull(input) + return ParseEncryptedJSON(input, keyEncryptionAlgorithms, contentEncryption) } - return parseEncryptedCompact(input) + return ParseEncryptedCompact(input, keyEncryptionAlgorithms, contentEncryption) } -// parseEncryptedFull parses a message in compact format. -func parseEncryptedFull(input string) (*JSONWebEncryption, error) { +// ParseEncryptedJSON parses a message in JWE JSON Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2 +func ParseEncryptedJSON( + input string, + keyEncryptionAlgorithms []KeyAlgorithm, + contentEncryption []ContentEncryption, +) (*JSONWebEncryption, error) { var parsed rawJSONWebEncryption err := json.Unmarshal([]byte(input), &parsed) if err != nil { return nil, err } - return parsed.sanitized() + return parsed.sanitized(keyEncryptionAlgorithms, contentEncryption) } // sanitized produces a cleaned-up JWE object from the raw JSON. -func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) { +func (parsed *rawJSONWebEncryption) sanitized( + keyEncryptionAlgorithms []KeyAlgorithm, + contentEncryption []ContentEncryption, +) (*JSONWebEncryption, error) { + if len(keyEncryptionAlgorithms) == 0 { + return nil, errors.New("go-jose/go-jose: no key algorithms provided") + } + if len(contentEncryption) == 0 { + return nil, errors.New("go-jose/go-jose: no content encryption algorithms provided") + } + obj := &JSONWebEncryption{ original: parsed, unprotected: parsed.Unprotected, @@ -184,10 +232,31 @@ func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) { } } - for _, recipient := range obj.recipients { + for i, recipient := range obj.recipients { headers := obj.mergedHeaders(&recipient) - if headers.getAlgorithm() == "" || headers.getEncryption() == "" { - return nil, fmt.Errorf("go-jose/go-jose: message is missing alg/enc headers") + if headers.getAlgorithm() == "" { + return nil, fmt.Errorf(`go-jose/go-jose: recipient %d: missing header "alg"`, i) + } + if headers.getEncryption() == "" { + return nil, fmt.Errorf(`go-jose/go-jose: recipient %d: missing header "enc"`, i) + } + err := validateAlgEnc(headers, keyEncryptionAlgorithms, contentEncryption) + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: recipient %d: %s", i, err) + } + + } + + if obj.protected != nil { + err := validateAlgEnc(*obj.protected, keyEncryptionAlgorithms, contentEncryption) + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: protected header: %s", err) + } + } + if obj.unprotected != nil { + err := validateAlgEnc(*obj.unprotected, keyEncryptionAlgorithms, contentEncryption) + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: unprotected header: %s", err) } } @@ -199,8 +268,26 @@ func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) { return obj, nil } -// parseEncryptedCompact parses a message in compact format. -func parseEncryptedCompact(input string) (*JSONWebEncryption, error) { +func validateAlgEnc(headers rawHeader, keyAlgorithms []KeyAlgorithm, contentEncryption []ContentEncryption) error { + alg := headers.getAlgorithm() + enc := headers.getEncryption() + if alg != "" && !containsKeyAlgorithm(keyAlgorithms, alg) { + return fmt.Errorf("unexpected key algorithm %q; expected %q", alg, keyAlgorithms) + } + if alg != "" && !containsContentEncryption(contentEncryption, enc) { + return fmt.Errorf("unexpected content encryption algorithm %q; expected %q", enc, contentEncryption) + } + return nil +} + +// ParseEncryptedCompact parses a message in JWE Compact Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1 +func ParseEncryptedCompact( + input string, + keyAlgorithms []KeyAlgorithm, + contentEncryption []ContentEncryption, +) (*JSONWebEncryption, error) { parts := strings.Split(input, ".") if len(parts) != 5 { return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts") @@ -239,7 +326,7 @@ func parseEncryptedCompact(input string) (*JSONWebEncryption, error) { Tag: newBuffer(tag), } - return raw.sanitized() + return raw.sanitized(keyAlgorithms, contentEncryption) } // CompactSerialize serializes an object using the compact serialization format. @@ -251,13 +338,13 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) { serializedProtected := mustSerializeJSON(obj.protected) - return fmt.Sprintf( - "%s.%s.%s.%s.%s", - base64.RawURLEncoding.EncodeToString(serializedProtected), - base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey), - base64.RawURLEncoding.EncodeToString(obj.iv), - base64.RawURLEncoding.EncodeToString(obj.ciphertext), - base64.RawURLEncoding.EncodeToString(obj.tag)), nil + return base64JoinWithDots( + serializedProtected, + obj.recipients[0].encryptedKey, + obj.iv, + obj.ciphertext, + obj.tag, + ), nil } // FullSerialize serializes an object using the full JSON serialization format. diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/jwk.go b/vendor/github.com/go-jose/go-jose/v4/jwk.go similarity index 93% rename from vendor/gopkg.in/go-jose/go-jose.v2/jwk.go rename to vendor/github.com/go-jose/go-jose/v4/jwk.go index ea3d86340..a565aaab2 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/jwk.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwk.go @@ -20,6 +20,7 @@ import ( "bytes" "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "crypto/sha1" @@ -34,9 +35,7 @@ import ( "reflect" "strings" - "golang.org/x/crypto/ed25519" - - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // rawJSONWebKey represents a public or private key in JWK format, used for parsing/serializing. @@ -63,14 +62,26 @@ type rawJSONWebKey struct { Qi *byteBuffer `json:"qi,omitempty"` // Certificates X5c []string `json:"x5c,omitempty"` - X5u *url.URL `json:"x5u,omitempty"` + X5u string `json:"x5u,omitempty"` X5tSHA1 string `json:"x5t,omitempty"` X5tSHA256 string `json:"x5t#S256,omitempty"` } -// JSONWebKey represents a public or private key in JWK format. +// JSONWebKey represents a public or private key in JWK format. It can be +// marshaled into JSON and unmarshaled from JSON. type JSONWebKey struct { - // Cryptographic key, can be a symmetric or asymmetric key. + // Key is the Go in-memory representation of this key. It must have one + // of these types: + // - ed25519.PublicKey + // - ed25519.PrivateKey + // - *ecdsa.PublicKey + // - *ecdsa.PrivateKey + // - *rsa.PublicKey + // - *rsa.PrivateKey + // - []byte (a symmetric key) + // + // When marshaling this JSONWebKey into JSON, the "kty" header parameter + // will be automatically set based on the type of this field. Key interface{} // Key identifier, parsed from `kid` header. KeyID string @@ -156,7 +167,9 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) { } } - raw.X5u = k.CertificatesURL + if k.CertificatesURL != nil { + raw.X5u = k.CertificatesURL.String() + } return json.Marshal(raw) } @@ -238,13 +251,18 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) { if certPub != nil && keyPub != nil { if !reflect.DeepEqual(certPub, keyPub) { - return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields to not match") + return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match") } } *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs} - k.CertificatesURL = raw.X5u + if raw.X5u != "" { + k.CertificatesURL, err = url.Parse(raw.X5u) + if err != nil { + return fmt.Errorf("go-jose/go-jose: invalid JWK, x5u header is invalid URL: %w", err) + } + } // x5t parameters are base64url-encoded SHA thumbprints // See RFC 7517, Section 4.8, https://tools.ietf.org/html/rfc7517#section-4.8 @@ -383,6 +401,8 @@ func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) { input, err = rsaThumbprintInput(key.N, key.E) case ed25519.PrivateKey: input, err = edThumbprintInput(ed25519.PublicKey(key[32:])) + case OpaqueSigner: + return key.Public().Thumbprint(hash) default: return nil, fmt.Errorf("go-jose/go-jose: unknown key type '%s'", reflect.TypeOf(key)) } @@ -392,7 +412,7 @@ func (k *JSONWebKey) Thumbprint(hash crypto.Hash) ([]byte, error) { } h := hash.New() - h.Write([]byte(input)) + _, _ = h.Write([]byte(input)) return h.Sum(nil), nil } @@ -740,7 +760,7 @@ func dSize(curve elliptic.Curve) int { bitLen := order.BitLen() size := bitLen / 8 if bitLen%8 != 0 { - size = size + 1 + size++ } return size } @@ -758,3 +778,35 @@ func (key rawJSONWebKey) symmetricKey() ([]byte, error) { } return key.K.bytes(), nil } + +func tryJWKS(key interface{}, headers ...Header) interface{} { + var jwks JSONWebKeySet + + switch jwksType := key.(type) { + case *JSONWebKeySet: + jwks = *jwksType + case JSONWebKeySet: + jwks = jwksType + default: + return key + } + + var kid string + for _, header := range headers { + if header.KeyID != "" { + kid = header.KeyID + break + } + } + + if kid == "" { + return key + } + + keys := jwks.Key(kid) + if len(keys) == 0 { + return key + } + + return keys[0].Key +} diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/jws.go b/vendor/github.com/go-jose/go-jose/v4/jws.go similarity index 79% rename from vendor/gopkg.in/go-jose/go-jose.v2/jws.go rename to vendor/github.com/go-jose/go-jose/v4/jws.go index 1a24fa468..3a912301a 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/jws.go +++ b/vendor/github.com/go-jose/go-jose/v4/jws.go @@ -23,7 +23,7 @@ import ( "fmt" "strings" - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing. @@ -75,22 +75,41 @@ type Signature struct { original *rawSignatureInfo } -// ParseSigned parses a signed message in compact or full serialization format. -func ParseSigned(signature string) (*JSONWebSignature, error) { +// ParseSigned parses a signed message in JWS Compact or JWS JSON Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7515#section-7 +func ParseSigned( + signature string, + signatureAlgorithms []SignatureAlgorithm, +) (*JSONWebSignature, error) { signature = stripWhitespace(signature) if strings.HasPrefix(signature, "{") { - return parseSignedFull(signature) + return ParseSignedJSON(signature, signatureAlgorithms) } - return parseSignedCompact(signature, nil) + return parseSignedCompact(signature, nil, signatureAlgorithms) +} + +// ParseSignedCompact parses a message in JWS Compact Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1 +func ParseSignedCompact( + signature string, + signatureAlgorithms []SignatureAlgorithm, +) (*JSONWebSignature, error) { + return parseSignedCompact(signature, nil, signatureAlgorithms) } // ParseDetached parses a signed message in compact serialization format with detached payload. -func ParseDetached(signature string, payload []byte) (*JSONWebSignature, error) { +func ParseDetached( + signature string, + payload []byte, + signatureAlgorithms []SignatureAlgorithm, +) (*JSONWebSignature, error) { if payload == nil { return nil, errors.New("go-jose/go-jose: nil payload") } - return parseSignedCompact(stripWhitespace(signature), payload) + return parseSignedCompact(stripWhitespace(signature), payload, signatureAlgorithms) } // Get a header value @@ -137,19 +156,36 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature return authData.Bytes(), nil } -// parseSignedFull parses a message in full format. -func parseSignedFull(input string) (*JSONWebSignature, error) { +// ParseSignedJSON parses a message in JWS JSON Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7515#section-7.2 +func ParseSignedJSON( + input string, + signatureAlgorithms []SignatureAlgorithm, +) (*JSONWebSignature, error) { var parsed rawJSONWebSignature err := json.Unmarshal([]byte(input), &parsed) if err != nil { return nil, err } - return parsed.sanitized() + return parsed.sanitized(signatureAlgorithms) +} + +func containsSignatureAlgorithm(haystack []SignatureAlgorithm, needle SignatureAlgorithm) bool { + for _, algorithm := range haystack { + if algorithm == needle { + return true + } + } + return false } // sanitized produces a cleaned-up JWS object from the raw JSON. -func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) { +func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgorithm) (*JSONWebSignature, error) { + if len(signatureAlgorithms) == 0 { + return nil, errors.New("go-jose/go-jose: no signature algorithms specified") + } if parsed.Payload == nil { return nil, fmt.Errorf("go-jose/go-jose: missing payload in JWS message") } @@ -198,6 +234,12 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) { return nil, err } + alg := SignatureAlgorithm(signature.Header.Algorithm) + if !containsSignatureAlgorithm(signatureAlgorithms, alg) { + return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q", + alg, signatureAlgorithms) + } + if signature.header != nil { signature.Unprotected, err = signature.header.sanitized() if err != nil { @@ -241,6 +283,12 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) { return nil, err } + alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm) + if !containsSignatureAlgorithm(signatureAlgorithms, alg) { + return nil, fmt.Errorf("go-jose/go-jose: unexpected signature algorithm %q; expected %q", + alg, signatureAlgorithms) + } + if obj.Signatures[i].header != nil { obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized() if err != nil { @@ -274,7 +322,11 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) { } // parseSignedCompact parses a message in compact format. -func parseSignedCompact(input string, payload []byte) (*JSONWebSignature, error) { +func parseSignedCompact( + input string, + payload []byte, + signatureAlgorithms []SignatureAlgorithm, +) (*JSONWebSignature, error) { parts := strings.Split(input, ".") if len(parts) != 3 { return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts") @@ -306,7 +358,7 @@ func parseSignedCompact(input string, payload []byte) (*JSONWebSignature, error) Protected: newBuffer(rawProtected), Signature: newBuffer(signature), } - return raw.sanitized() + return raw.sanitized(signatureAlgorithms) } func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) { @@ -314,15 +366,18 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) { return "", ErrNotSupported } - serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected)) - payload := "" - signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature) + serializedProtected := mustSerializeJSON(obj.Signatures[0].protected) + var payload []byte if !detached { - payload = base64.RawURLEncoding.EncodeToString(obj.payload) + payload = obj.payload } - return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil + return base64JoinWithDots( + serializedProtected, + payload, + obj.Signatures[0].Signature, + ), nil } // CompactSerialize serializes an object using the compact serialization format. diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/opaque.go b/vendor/github.com/go-jose/go-jose/v4/opaque.go similarity index 97% rename from vendor/gopkg.in/go-jose/go-jose.v2/opaque.go rename to vendor/github.com/go-jose/go-jose/v4/opaque.go index fc3e8d2ef..68db085ef 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/opaque.go +++ b/vendor/github.com/go-jose/go-jose/v4/opaque.go @@ -121,7 +121,7 @@ func (oke *opaqueKeyEncrypter) encryptKey(cek []byte, alg KeyAlgorithm) (recipie return oke.encrypter.encryptKey(cek, alg) } -//OpaqueKeyDecrypter is an interface that supports decrypting keys with an opaque key. +// OpaqueKeyDecrypter is an interface that supports decrypting keys with an opaque key. type OpaqueKeyDecrypter interface { DecryptKey(encryptedKey []byte, header Header) ([]byte, error) } diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/shared.go b/vendor/github.com/go-jose/go-jose/v4/shared.go similarity index 95% rename from vendor/gopkg.in/go-jose/go-jose.v2/shared.go rename to vendor/github.com/go-jose/go-jose/v4/shared.go index 0fa66a44b..b485e43bd 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/shared.go +++ b/vendor/github.com/go-jose/go-jose/v4/shared.go @@ -23,7 +23,7 @@ import ( "errors" "fmt" - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // KeyAlgorithm represents a key management algorithm. @@ -133,8 +133,8 @@ const ( type HeaderKey string const ( - HeaderType HeaderKey = "typ" // string - HeaderContentType = "cty" // string + HeaderType = "typ" // string + HeaderContentType = "cty" // string // These are set by go-jose and shouldn't need to be set by consumers of the // library. @@ -183,8 +183,13 @@ type Header struct { // Unverified certificate chain parsed from x5c header. certificates []*x509.Certificate - // Any headers not recognised above get unmarshalled - // from JSON in a generic manner and placed in this map. + // At parse time, each header parameter with a name other than "kid", + // "jwk", "alg", "nonce", or "x5c" will have its value passed to + // [json.Unmarshal] to unmarshal it into an interface value. + // The resulting value will be stored in this map, with the header + // parameter name as the key. + // + // [json.Unmarshal]: https://pkg.go.dev/encoding/json#Unmarshal ExtraHeaders map[HeaderKey]interface{} } @@ -452,8 +457,8 @@ func parseCertificateChain(chain []string) ([]*x509.Certificate, error) { return out, nil } -func (dst rawHeader) isSet(k HeaderKey) bool { - dvr := dst[k] +func (parsed rawHeader) isSet(k HeaderKey) bool { + dvr := parsed[k] if dvr == nil { return false } @@ -472,17 +477,17 @@ func (dst rawHeader) isSet(k HeaderKey) bool { } // Merge headers from src into dst, giving precedence to headers from l. -func (dst rawHeader) merge(src *rawHeader) { +func (parsed rawHeader) merge(src *rawHeader) { if src == nil { return } for k, v := range *src { - if dst.isSet(k) { + if parsed.isSet(k) { continue } - dst[k] = v + parsed[k] = v } } diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/signing.go b/vendor/github.com/go-jose/go-jose/v4/signing.go similarity index 84% rename from vendor/gopkg.in/go-jose/go-jose.v2/signing.go rename to vendor/github.com/go-jose/go-jose/v4/signing.go index 5195a1a91..f0b0294f3 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/signing.go +++ b/vendor/github.com/go-jose/go-jose/v4/signing.go @@ -19,14 +19,13 @@ package jose import ( "bytes" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "encoding/base64" "errors" "fmt" - "golang.org/x/crypto/ed25519" - - "gopkg.in/go-jose/go-jose.v2/json" + "github.com/go-jose/go-jose/v4/json" ) // NonceSource represents a source of random nonces to go into JWS objects @@ -41,6 +40,20 @@ type Signer interface { } // SigningKey represents an algorithm/key used to sign a message. +// +// Key must have one of these types: +// - ed25519.PrivateKey +// - *ecdsa.PrivateKey +// - *rsa.PrivateKey +// - *JSONWebKey +// - JSONWebKey +// - []byte (an HMAC key) +// - Any type that satisfies the OpaqueSigner interface +// +// If the key is an HMAC key, it must have at least as many bytes as the relevant hash output: +// - HS256: 32 bytes +// - HS384: 48 bytes +// - HS512: 64 bytes type SigningKey struct { Algorithm SignatureAlgorithm Key interface{} @@ -53,12 +66,22 @@ type SignerOptions struct { // Optional map of additional keys to be inserted into the protected header // of a JWS object. Some specifications which make use of JWS like to insert - // additional values here. All values must be JSON-serializable. + // additional values here. + // + // Values will be serialized by [json.Marshal] and must be valid inputs to + // that function. + // + // [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal ExtraHeaders map[HeaderKey]interface{} } // WithHeader adds an arbitrary value to the ExtraHeaders map, initializing it -// if necessary. It returns itself and so can be used in a fluent style. +// if necessary, and returns the updated SignerOptions. +// +// The v argument will be serialized by [json.Marshal] and must be a valid +// input to that function. +// +// [json.Marshal]: https://pkg.go.dev/encoding/json#Marshal func (so *SignerOptions) WithHeader(k HeaderKey, v interface{}) *SignerOptions { if so.ExtraHeaders == nil { so.ExtraHeaders = map[HeaderKey]interface{}{} @@ -174,11 +197,11 @@ func newVerifier(verificationKey interface{}) (payloadVerifier, error) { return newVerifier(verificationKey.Key) case *JSONWebKey: return newVerifier(verificationKey.Key) + case OpaqueVerifier: + return &opaqueVerifier{verifier: verificationKey}, nil + default: + return nil, ErrUnsupportedKeyType } - if ov, ok := verificationKey.(OpaqueVerifier); ok { - return &opaqueVerifier{verifier: ov}, nil - } - return nil, ErrUnsupportedKeyType } func (ctx *genericSigner) addRecipient(alg SignatureAlgorithm, signingKey interface{}) error { @@ -205,11 +228,11 @@ func makeJWSRecipient(alg SignatureAlgorithm, signingKey interface{}) (recipient return newJWKSigner(alg, signingKey) case *JSONWebKey: return newJWKSigner(alg, *signingKey) + case OpaqueSigner: + return newOpaqueSigner(alg, signingKey) + default: + return recipientSigInfo{}, ErrUnsupportedKeyType } - if signer, ok := signingKey.(OpaqueSigner); ok { - return newOpaqueSigner(alg, signer) - } - return recipientSigInfo{}, ErrUnsupportedKeyType } func newJWKSigner(alg SignatureAlgorithm, signingKey JSONWebKey) (recipientSigInfo, error) { @@ -322,12 +345,26 @@ func (ctx *genericSigner) Options() SignerOptions { } // Verify validates the signature on the object and returns the payload. -// This function does not support multi-signature, if you desire multi-sig +// This function does not support multi-signature. If you desire multi-signature // verification use VerifyMulti instead. // // Be careful when verifying signatures based on embedded JWKs inside the // payload header. You cannot assume that the key received in a payload is // trusted. +// +// The verificationKey argument must have one of these types: +// - ed25519.PublicKey +// - *ecdsa.PublicKey +// - *rsa.PublicKey +// - *JSONWebKey +// - JSONWebKey +// - []byte (an HMAC key) +// - Any type that implements the OpaqueVerifier interface. +// +// If the key is an HMAC key, it must have at least as many bytes as the relevant hash output: +// - HS256: 32 bytes +// - HS384: 48 bytes +// - HS512: 64 bytes func (obj JSONWebSignature) Verify(verificationKey interface{}) ([]byte, error) { err := obj.DetachedVerify(obj.payload, verificationKey) if err != nil { @@ -347,8 +384,12 @@ func (obj JSONWebSignature) UnsafePayloadWithoutVerification() []byte { // most cases, you will probably want to use Verify instead. DetachedVerify // is only useful if you have a payload and signature that are separated from // each other. +// +// The verificationKey argument must have one of the types allowed for the +// verificationKey argument of JSONWebSignature.Verify(). func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey interface{}) error { - verifier, err := newVerifier(verificationKey) + key := tryJWKS(verificationKey, obj.headers()...) + verifier, err := newVerifier(key) if err != nil { return err } @@ -388,6 +429,9 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter // returns the index of the signature that was verified, along with the signature // object and the payload. We return the signature and index to guarantee that // callers are getting the verified value. +// +// The verificationKey argument must have one of the types allowed for the +// verificationKey argument of JSONWebSignature.Verify(). func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signature, []byte, error) { idx, sig, err := obj.DetachedVerifyMulti(obj.payload, verificationKey) if err != nil { @@ -405,8 +449,12 @@ func (obj JSONWebSignature) VerifyMulti(verificationKey interface{}) (int, Signa // DetachedVerifyMulti is only useful if you have a payload and signature that are // separated from each other, and the signature can have multiple signers at the // same time. +// +// The verificationKey argument must have one of the types allowed for the +// verificationKey argument of JSONWebSignature.Verify(). func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey interface{}) (int, Signature, error) { - verifier, err := newVerifier(verificationKey) + key := tryJWKS(verificationKey, obj.headers()...) + verifier, err := newVerifier(key) if err != nil { return -1, Signature{}, err } @@ -439,3 +487,11 @@ outer: return -1, Signature{}, ErrCryptoFailure } + +func (obj JSONWebSignature) headers() []Header { + headers := make([]Header, len(obj.Signatures)) + for i, sig := range obj.Signatures { + headers[i] = sig.Header + } + return headers +} diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/symmetric.go b/vendor/github.com/go-jose/go-jose/v4/symmetric.go similarity index 89% rename from vendor/gopkg.in/go-jose/go-jose.v2/symmetric.go rename to vendor/github.com/go-jose/go-jose/v4/symmetric.go index 52c8b62bf..a69103b08 100644 --- a/vendor/gopkg.in/go-jose/go-jose.v2/symmetric.go +++ b/vendor/github.com/go-jose/go-jose/v4/symmetric.go @@ -31,20 +31,26 @@ import ( "io" "golang.org/x/crypto/pbkdf2" - "gopkg.in/go-jose/go-jose.v2/cipher" + + josecipher "github.com/go-jose/go-jose/v4/cipher" ) -// Random reader (stubbed out in tests) +// RandReader is a cryptographically secure random number generator (stubbed out in tests). var RandReader = rand.Reader const ( // RFC7518 recommends a minimum of 1,000 iterations: - // https://tools.ietf.org/html/rfc7518#section-4.8.1.2 + // - https://tools.ietf.org/html/rfc7518#section-4.8.1.2 + // // NIST recommends a minimum of 10,000: - // https://pages.nist.gov/800-63-3/sp800-63b.html - // 1Password uses 100,000: - // https://support.1password.com/pbkdf2/ - defaultP2C = 100000 + // - https://pages.nist.gov/800-63-3/sp800-63b.html + // + // 1Password increased in 2023 from 100,000 to 650,000: + // - https://support.1password.com/pbkdf2/ + // + // OWASP recommended 600,000 in Dec 2022: + // - https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2 + defaultP2C = 600000 // Default salt size: 128 bits defaultP2SSize = 16 ) @@ -278,8 +284,14 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie } header := &rawHeader{} - header.set(headerIV, newBuffer(parts.iv)) - header.set(headerTag, newBuffer(parts.tag)) + + if err = header.set(headerIV, newBuffer(parts.iv)); err != nil { + return recipientInfo{}, err + } + + if err = header.set(headerTag, newBuffer(parts.tag)); err != nil { + return recipientInfo{}, err + } return recipientInfo{ header: header, @@ -332,8 +344,14 @@ func (ctx *symmetricKeyCipher) encryptKey(cek []byte, alg KeyAlgorithm) (recipie } header := &rawHeader{} - header.set(headerP2C, ctx.p2c) - header.set(headerP2S, newBuffer(ctx.p2s)) + + if err = header.set(headerP2C, ctx.p2c); err != nil { + return recipientInfo{}, err + } + + if err = header.set(headerP2S, newBuffer(ctx.p2s)); err != nil { + return recipientInfo{}, err + } return recipientInfo{ encryptedKey: jek, @@ -436,7 +454,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien func (ctx symmetricMac) signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error) { mac, err := ctx.hmac(payload, alg) if err != nil { - return Signature{}, errors.New("go-jose/go-jose: failed to compute hmac") + return Signature{}, err } return Signature{ @@ -468,12 +486,24 @@ func (ctx symmetricMac) verifyPayload(payload []byte, mac []byte, alg SignatureA func (ctx symmetricMac) hmac(payload []byte, alg SignatureAlgorithm) ([]byte, error) { var hash func() hash.Hash + // https://datatracker.ietf.org/doc/html/rfc7518#section-3.2 + // A key of the same size as the hash output (for instance, 256 bits for + // "HS256") or larger MUST be used switch alg { case HS256: + if len(ctx.key)*8 < 256 { + return nil, ErrInvalidKeySize + } hash = sha256.New case HS384: + if len(ctx.key)*8 < 384 { + return nil, ErrInvalidKeySize + } hash = sha512.New384 case HS512: + if len(ctx.key)*8 < 512 { + return nil, ErrInvalidKeySize + } hash = sha512.New default: return nil, ErrUnsupportedAlgorithm diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/digest.go b/vendor/github.com/google/go-containerregistry/pkg/name/digest.go index c049c1ef4..28f6967ba 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/digest.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/digest.go @@ -17,6 +17,7 @@ package name import ( // nolint: depguard _ "crypto/sha256" // Recommended by go-digest. + "encoding/json" "strings" "github.com/opencontainers/go-digest" @@ -59,6 +60,25 @@ func (d Digest) String() string { 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. func NewDigest(name string, opts ...Option) (Digest, error) { // Split on "@" diff --git a/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s index 9a7655c0f..0782b86e3 100644 --- a/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s +++ b/vendor/github.com/klauspost/compress/flate/matchlen_amd64.s @@ -5,7 +5,6 @@ #include "textflag.h" // func matchLen(a []byte, b []byte) int -// Requires: BMI TEXT ·matchLen(SB), NOSPLIT, $0-56 MOVQ a_base+0(FP), AX MOVQ b_base+24(FP), CX @@ -17,17 +16,16 @@ TEXT ·matchLen(SB), NOSPLIT, $0-56 JB matchlen_match4_standalone matchlen_loopback_standalone: - MOVQ (AX)(SI*1), BX - XORQ (CX)(SI*1), BX - TESTQ BX, BX - JZ matchlen_loop_standalone + MOVQ (AX)(SI*1), BX + XORQ (CX)(SI*1), BX + JZ matchlen_loop_standalone #ifdef GOAMD64_v3 TZCNTQ BX, BX #else BSFQ BX, BX #endif - SARQ $0x03, BX + SHRL $0x03, BX LEAL (SI)(BX*1), SI JMP gen_match_len_end diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go index 8d5567fe6..b7b83164b 100644 --- a/vendor/github.com/klauspost/compress/zstd/dict.go +++ b/vendor/github.com/klauspost/compress/zstd/dict.go @@ -273,6 +273,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { enc.Encode(&block, b) addValues(&remain, block.literals) litTotal += len(block.literals) + if len(block.sequences) == 0 { + continue + } seqs += len(block.sequences) block.genCodes() addHist(&ll, block.coders.llEnc.Histogram()) @@ -286,6 +289,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if offset == 0 { continue } + if int(offset) >= len(o.History) { + continue + } if offset > 3 { newOffsets[offset-3]++ } else { @@ -336,6 +342,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if seqs/nUsed < 512 { // Use 512 as minimum. nUsed = seqs / 512 + if nUsed == 0 { + nUsed = 1 + } } copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) { hist := dst.Histogram() @@ -358,6 +367,28 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { fakeLength += v hist[i] = uint32(v) } + + // Ensure we aren't trying to represent RLE. + if maxCount == fakeLength { + for i := range hist { + if uint8(i) == maxSym { + fakeLength++ + maxSym++ + hist[i+1] = 1 + if maxSym > 1 { + break + } + } + if hist[0] == 0 { + fakeLength++ + hist[i] = 1 + if maxSym > 1 { + break + } + } + } + } + dst.HistogramFinished(maxSym, maxCount) dst.reUsed = false dst.useRLE = false diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s index 17901e080..ae7d4d329 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s @@ -162,12 +162,12 @@ finalize: MOVD h, ret+24(FP) RET -// func writeBlocks(d *Digest, b []byte) int +// func writeBlocks(s *Digest, b []byte) int TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 LDP ·primes+0(SB), (prime1, prime2) // Load state. Assume v[1-4] are stored contiguously. - MOVD d+0(FP), digest + MOVD s+0(FP), digest LDP 0(digest), (v1, v2) LDP 16(digest), (v3, v4) diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s index 9a7655c0f..0782b86e3 100644 --- a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s @@ -5,7 +5,6 @@ #include "textflag.h" // func matchLen(a []byte, b []byte) int -// Requires: BMI TEXT ·matchLen(SB), NOSPLIT, $0-56 MOVQ a_base+0(FP), AX MOVQ b_base+24(FP), CX @@ -17,17 +16,16 @@ TEXT ·matchLen(SB), NOSPLIT, $0-56 JB matchlen_match4_standalone matchlen_loopback_standalone: - MOVQ (AX)(SI*1), BX - XORQ (CX)(SI*1), BX - TESTQ BX, BX - JZ matchlen_loop_standalone + MOVQ (AX)(SI*1), BX + XORQ (CX)(SI*1), BX + JZ matchlen_loop_standalone #ifdef GOAMD64_v3 TZCNTQ BX, BX #else BSFQ BX, BX #endif - SARQ $0x03, BX + SHRL $0x03, BX LEAL (SI)(BX*1), SI JMP gen_match_len_end diff --git a/vendor/github.com/letsencrypt/boulder/core/challenges.go b/vendor/github.com/letsencrypt/boulder/core/challenges.go index 1d7e2408d..d5e7a8729 100644 --- a/vendor/github.com/letsencrypt/boulder/core/challenges.go +++ b/vendor/github.com/letsencrypt/boulder/core/challenges.go @@ -10,27 +10,23 @@ func newChallenge(challengeType AcmeChallenge, token string) Challenge { } } -// HTTPChallenge01 constructs a random http-01 challenge. If token is empty a random token -// will be generated, otherwise the provided token is used. +// HTTPChallenge01 constructs a http-01 challenge. func HTTPChallenge01(token string) Challenge { return newChallenge(ChallengeTypeHTTP01, token) } -// DNSChallenge01 constructs a random dns-01 challenge. If token is empty a random token -// will be generated, otherwise the provided token is used. +// DNSChallenge01 constructs a dns-01 challenge. func DNSChallenge01(token string) Challenge { return newChallenge(ChallengeTypeDNS01, token) } -// TLSALPNChallenge01 constructs a random tls-alpn-01 challenge. If token is empty a random token -// will be generated, otherwise the provided token is used. +// TLSALPNChallenge01 constructs a tls-alpn-01 challenge. func TLSALPNChallenge01(token string) Challenge { return newChallenge(ChallengeTypeTLSALPN01, token) } -// NewChallenge constructs a random challenge of the given kind. It returns an -// error if the challenge type is unrecognized. If token is empty a random token -// will be generated, otherwise the provided token is used. +// NewChallenge constructs a challenge of the given kind. It returns an +// error if the challenge type is unrecognized. func NewChallenge(kind AcmeChallenge, token string) (Challenge, error) { switch kind { case ChallengeTypeHTTP01: diff --git a/vendor/github.com/letsencrypt/boulder/core/interfaces.go b/vendor/github.com/letsencrypt/boulder/core/interfaces.go index 003329c3f..59b55a3f4 100644 --- a/vendor/github.com/letsencrypt/boulder/core/interfaces.go +++ b/vendor/github.com/letsencrypt/boulder/core/interfaces.go @@ -7,7 +7,7 @@ import ( // PolicyAuthority defines the public interface for the Boulder PA // TODO(#5891): Move this interface to a more appropriate location. type PolicyAuthority interface { - WillingToIssueWildcards([]identifier.ACMEIdentifier) error + WillingToIssue([]string) error ChallengesFor(identifier.ACMEIdentifier) ([]Challenge, error) ChallengeTypeEnabled(AcmeChallenge) bool CheckAuthz(*Authorization) error diff --git a/vendor/github.com/letsencrypt/boulder/core/objects.go b/vendor/github.com/letsencrypt/boulder/core/objects.go index b52f0f5e0..64df4a8d8 100644 --- a/vendor/github.com/letsencrypt/boulder/core/objects.go +++ b/vendor/github.com/letsencrypt/boulder/core/objects.go @@ -10,8 +10,8 @@ import ( "strings" "time" + "github.com/go-jose/go-jose/v4" "golang.org/x/crypto/ocsp" - "gopkg.in/go-jose/go-jose.v2" "github.com/letsencrypt/boulder/identifier" "github.com/letsencrypt/boulder/probs" @@ -119,7 +119,7 @@ type Registration struct { } // ValidationRecord represents a validation attempt against a specific URL/hostname -// and the IP addresses that were resolved and used +// and the IP addresses that were resolved and used. type ValidationRecord struct { // SimpleHTTP only URL string `json:"url,omitempty"` @@ -144,6 +144,17 @@ type ValidationRecord struct { // ... // } AddressesTried []net.IP `json:"addressesTried,omitempty"` + // ResolverAddrs is the host:port of the DNS resolver(s) that fulfilled the + // lookup for AddressUsed. During recursive A and AAAA lookups, a record may + // instead look like A:host:port or AAAA:host:port + ResolverAddrs []string `json:"resolverAddrs,omitempty"` + // UsedRSAKEX is a *temporary* addition to the validation record, so we can + // see how many servers that we reach out to during HTTP-01 and TLS-ALPN-01 + // validation are only willing to negotiate RSA key exchange mechanisms. The + // field is not included in the serialized json to avoid cluttering the + // database and log lines. + // TODO(#7321): Remove this when we have collected sufficient data. + UsedRSAKEX bool `json:"-"` } func looksLikeKeyAuthorization(str string) error { @@ -225,6 +236,8 @@ func (ch Challenge) RecordsSane() bool { switch ch.Type { case ChallengeTypeHTTP01: for _, rec := range ch.ValidationRecord { + // TODO(#7140): Add a check for ResolverAddress == "" only after the + // core.proto change has been deployed. if rec.URL == "" || rec.Hostname == "" || rec.Port == "" || rec.AddressUsed == nil || len(rec.AddressesResolved) == 0 { return false @@ -237,6 +250,8 @@ func (ch Challenge) RecordsSane() bool { if ch.ValidationRecord[0].URL != "" { return false } + // TODO(#7140): Add a check for ResolverAddress == "" only after the + // core.proto change has been deployed. if ch.ValidationRecord[0].Hostname == "" || ch.ValidationRecord[0].Port == "" || ch.ValidationRecord[0].AddressUsed == nil || len(ch.ValidationRecord[0].AddressesResolved) == 0 { return false @@ -245,6 +260,8 @@ func (ch Challenge) RecordsSane() bool { if len(ch.ValidationRecord) > 1 { return false } + // TODO(#7140): Add a check for ResolverAddress == "" only after the + // core.proto change has been deployed. if ch.ValidationRecord[0].Hostname == "" { return false } @@ -483,6 +500,12 @@ type SuggestedWindow struct { End time.Time `json:"end"` } +// IsWithin returns true if the given time is within the suggested window, +// inclusive of the start time and exclusive of the end time. +func (window SuggestedWindow) IsWithin(now time.Time) bool { + return !now.Before(window.Start) && now.Before(window.End) +} + // RenewalInfo is a type which is exposed to clients which query the renewalInfo // endpoint specified in draft-aaron-ari. type RenewalInfo struct { diff --git a/vendor/github.com/letsencrypt/boulder/core/util.go b/vendor/github.com/letsencrypt/boulder/core/util.go index d7fe02668..31f6d2fcf 100644 --- a/vendor/github.com/letsencrypt/boulder/core/util.go +++ b/vendor/github.com/letsencrypt/boulder/core/util.go @@ -25,7 +25,9 @@ import ( "time" "unicode" - "gopkg.in/go-jose/go-jose.v2" + "github.com/go-jose/go-jose/v4" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" ) const Unspecified = "Unspecified" @@ -92,8 +94,7 @@ func Fingerprint256(data []byte) string { type Sha256Digest [sha256.Size]byte -// KeyDigest produces a Base64-encoded SHA256 digest of a -// provided public key. +// KeyDigest produces the SHA256 digest of a provided public key. func KeyDigest(key crypto.PublicKey) (Sha256Digest, error) { switch t := key.(type) { case *jose.JSONWebKey: @@ -212,10 +213,83 @@ func IsAnyNilOrZero(vals ...interface{}) bool { switch v := val.(type) { case nil: return true + case bool: + if !v { + return true + } + case string: + if v == "" { + return true + } + case []string: + if len(v) == 0 { + return true + } + case byte: + // Byte is an alias for uint8 and will cover that case. + if v == 0 { + return true + } case []byte: if len(v) == 0 { return true } + case int: + if v == 0 { + return true + } + case int8: + if v == 0 { + return true + } + case int16: + if v == 0 { + return true + } + case int32: + if v == 0 { + return true + } + case int64: + if v == 0 { + return true + } + case uint: + if v == 0 { + return true + } + case uint16: + if v == 0 { + return true + } + case uint32: + if v == 0 { + return true + } + case uint64: + if v == 0 { + return true + } + case float32: + if v == 0 { + return true + } + case float64: + if v == 0 { + return true + } + case time.Time: + if v.IsZero() { + return true + } + case *timestamppb.Timestamp: + if v == nil || v.AsTime().IsZero() { + return true + } + case *durationpb.Duration: + if v == nil || v.AsDuration() == time.Duration(0) { + return true + } default: if reflect.ValueOf(v).IsZero() { return true diff --git a/vendor/github.com/letsencrypt/boulder/probs/probs.go b/vendor/github.com/letsencrypt/boulder/probs/probs.go index 2cc766237..ec6c272ae 100644 --- a/vendor/github.com/letsencrypt/boulder/probs/probs.go +++ b/vendor/github.com/letsencrypt/boulder/probs/probs.go @@ -20,6 +20,8 @@ const ( BadRevocationReasonProblem = ProblemType("badRevocationReason") BadSignatureAlgorithmProblem = ProblemType("badSignatureAlgorithm") CAAProblem = ProblemType("caa") + // ConflictProblem is a problem type that is not defined in RFC8555. + ConflictProblem = ProblemType("conflict") ConnectionProblem = ProblemType("connection") DNSProblem = ProblemType("dns") InvalidContactProblem = ProblemType("invalidContact") @@ -290,11 +292,11 @@ func Canceled(detail string, a ...any) *ProblemDetails { } } -// Conflict returns a ProblemDetails with a MalformedProblem and a 409 Conflict +// Conflict returns a ProblemDetails with a ConflictProblem and a 409 Conflict // status code. func Conflict(detail string) *ProblemDetails { return &ProblemDetails{ - Type: MalformedProblem, + Type: ConflictProblem, Detail: detail, HTTPStatus: http.StatusConflict, } diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md b/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md deleted file mode 100644 index 7e78dce01..000000000 --- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md +++ /dev/null @@ -1,48 +0,0 @@ -## pwalk: parallel implementation of filepath.Walk - -This is a wrapper for [filepath.Walk](https://pkg.go.dev/path/filepath?tab=doc#Walk) -which may speed it up by calling multiple callback functions (WalkFunc) in parallel, -utilizing goroutines. - -By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks. -This can be changed by using WalkN function which has the additional -parameter, specifying the number of goroutines (concurrency). - -### pwalk vs pwalkdir - -This package is deprecated in favor of -[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir), -which is faster, but requires at least Go 1.16. - -### Caveats - -Please note the following limitations of this code: - -* Unlike filepath.Walk, the order of calls is non-deterministic; - -* Only primitive error handling is supported: - - * filepath.SkipDir is not supported; - - * no errors are ever passed to WalkFunc; - - * once any error is returned from any WalkFunc instance, no more new calls - to WalkFunc are made, and the error is returned to the caller of Walk; - - * if more than one walkFunc instance will return an error, only one - of such errors will be propagated and returned by Walk, others - will be silently discarded. - -### Documentation - -For the official documentation, see -https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalk?tab=doc - -### Benchmarks - -For a WalkFunc that consists solely of the return statement, this -implementation is about 10% slower than the standard library's -filepath.Walk. - -Otherwise (if a WalkFunc is doing something) this is usually faster, -except when the WalkN(..., 1) is used. diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go deleted file mode 100644 index a28b4c4bb..000000000 --- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go +++ /dev/null @@ -1,123 +0,0 @@ -package pwalk - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "sync" -) - -// WalkFunc is the type of the function called by Walk to visit each -// file or directory. It is an alias for [filepath.WalkFunc]. -// -// Deprecated: use [github.com/opencontainers/selinux/pkg/pwalkdir] and [fs.WalkDirFunc]. -type WalkFunc = filepath.WalkFunc - -// Walk is a wrapper for filepath.Walk which can call multiple walkFn -// in parallel, allowing to handle each item concurrently. A maximum of -// twice the runtime.NumCPU() walkFn will be called at any one time. -// If you want to change the maximum, use WalkN instead. -// -// The order of calls is non-deterministic. -// -// Note that this implementation only supports primitive error handling: -// -// - no errors are ever passed to walkFn; -// -// - once a walkFn returns any error, all further processing stops -// and the error is returned to the caller of Walk; -// -// - filepath.SkipDir is not supported; -// -// - if more than one walkFn instance will return an error, only one -// of such errors will be propagated and returned by Walk, others -// will be silently discarded. -// -// Deprecated: use [github.com/opencontainers/selinux/pkg/pwalkdir.Walk] -func Walk(root string, walkFn WalkFunc) error { - return WalkN(root, walkFn, runtime.NumCPU()*2) -} - -// WalkN is a wrapper for filepath.Walk which can call multiple walkFn -// in parallel, allowing to handle each item concurrently. A maximum of -// num walkFn will be called at any one time. -// -// Please see Walk documentation for caveats of using this function. -// -// Deprecated: use [github.com/opencontainers/selinux/pkg/pwalkdir.WalkN] -func WalkN(root string, walkFn WalkFunc, num int) error { - // make sure limit is sensible - if num < 1 { - return fmt.Errorf("walk(%q): num must be > 0", root) - } - - files := make(chan *walkArgs, 2*num) - errCh := make(chan error, 1) // get the first error, ignore others - - // Start walking a tree asap - var ( - err error - wg sync.WaitGroup - - rootLen = len(root) - rootEntry *walkArgs - ) - wg.Add(1) - go func() { - err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error { - if err != nil { - close(files) - return err - } - if len(p) == rootLen { - // Root entry is processed separately below. - rootEntry = &walkArgs{path: p, info: &info} - return nil - } - // add a file to the queue unless a callback sent an error - select { - case e := <-errCh: - close(files) - return e - default: - files <- &walkArgs{path: p, info: &info} - return nil - } - }) - if err == nil { - close(files) - } - wg.Done() - }() - - wg.Add(num) - for i := 0; i < num; i++ { - go func() { - for file := range files { - if e := walkFn(file.path, *file.info, nil); e != nil { - select { - case errCh <- e: // sent ok - default: // buffer full - } - } - } - wg.Done() - }() - } - - wg.Wait() - - if err == nil { - err = walkFn(rootEntry.path, *rootEntry.info, nil) - } - - return err -} - -// walkArgs holds the arguments that were passed to the Walk or WalkN -// functions. -type walkArgs struct { - info *os.FileInfo - path string -} diff --git a/vendor/github.com/sylabs/sif/v2/pkg/sif/add.go b/vendor/github.com/sylabs/sif/v2/pkg/sif/add.go new file mode 100644 index 000000000..db1bd6b46 --- /dev/null +++ b/vendor/github.com/sylabs/sif/v2/pkg/sif/add.go @@ -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 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 +} diff --git a/vendor/github.com/sylabs/sif/v2/pkg/sif/create.go b/vendor/github.com/sylabs/sif/v2/pkg/sif/create.go index be3f6dc10..0f41e0a92 100644 --- a/vendor/github.com/sylabs/sif/v2/pkg/sif/create.go +++ b/vendor/github.com/sylabs/sif/v2/pkg/sif/create.go @@ -8,7 +8,6 @@ package sif import ( - "encoding" "encoding/binary" "errors" "fmt" @@ -321,378 +320,3 @@ func CreateContainerAtPath(path string, opts ...CreateOpt) (*FileImage, error) { f.closeOnUnload = true 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 -} diff --git a/vendor/github.com/sylabs/sif/v2/pkg/sif/delete.go b/vendor/github.com/sylabs/sif/v2/pkg/sif/delete.go new file mode 100644 index 000000000..c0f0aba32 --- /dev/null +++ b/vendor/github.com/sylabs/sif/v2/pkg/sif/delete.go @@ -0,0 +1,168 @@ +// Copyright (c) 2018-2023, Sylabs Inc. All rights reserved. +// Copyright (c) 2017, SingularityWare, LLC. All rights reserved. +// Copyright (c) 2017, Yannick Cote 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 ( + "errors" + "fmt" + "io" + "time" +) + +// 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 +} diff --git a/vendor/github.com/sylabs/sif/v2/pkg/sif/descriptor.go b/vendor/github.com/sylabs/sif/v2/pkg/sif/descriptor.go index 3b7a47767..bb191aeef 100644 --- a/vendor/github.com/sylabs/sif/v2/pkg/sif/descriptor.go +++ b/vendor/github.com/sylabs/sif/v2/pkg/sif/descriptor.go @@ -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, Yannick Cote All rights reserved. // 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. 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() } diff --git a/vendor/github.com/sylabs/sif/v2/pkg/sif/set.go b/vendor/github.com/sylabs/sif/v2/pkg/sif/set.go new file mode 100644 index 000000000..0750bd225 --- /dev/null +++ b/vendor/github.com/sylabs/sif/v2/pkg/sif/set.go @@ -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 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 +} diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go deleted file mode 100644 index a7828345f..000000000 --- a/vendor/golang.org/x/crypto/ed25519/ed25519.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ed25519 implements the Ed25519 signature algorithm. See -// https://ed25519.cr.yp.to/. -// -// These functions are also compatible with the “Ed25519” function defined in -// RFC 8032. However, unlike RFC 8032's formulation, this package's private key -// representation includes a public key suffix to make multiple signing -// operations with the same key more efficient. This package refers to the RFC -// 8032 private key as the “seed”. -// -// Beginning with Go 1.13, the functionality of this package was moved to the -// standard library as crypto/ed25519. This package only acts as a compatibility -// wrapper. -package ed25519 - -import ( - "crypto/ed25519" - "io" -) - -const ( - // PublicKeySize is the size, in bytes, of public keys as used in this package. - PublicKeySize = 32 - // PrivateKeySize is the size, in bytes, of private keys as used in this package. - PrivateKeySize = 64 - // SignatureSize is the size, in bytes, of signatures generated and verified by this package. - SignatureSize = 64 - // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. - SeedSize = 32 -) - -// PublicKey is the type of Ed25519 public keys. -// -// This type is an alias for crypto/ed25519's PublicKey type. -// See the crypto/ed25519 package for the methods on this type. -type PublicKey = ed25519.PublicKey - -// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. -// -// This type is an alias for crypto/ed25519's PrivateKey type. -// See the crypto/ed25519 package for the methods on this type. -type PrivateKey = ed25519.PrivateKey - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { - return ed25519.GenerateKey(rand) -} - -// NewKeyFromSeed calculates a private key from a seed. It will panic if -// len(seed) is not SeedSize. This function is provided for interoperability -// with RFC 8032. RFC 8032's private keys correspond to seeds in this -// package. -func NewKeyFromSeed(seed []byte) PrivateKey { - return ed25519.NewKeyFromSeed(seed) -} - -// Sign signs the message with privateKey and returns a signature. It will -// panic if len(privateKey) is not PrivateKeySize. -func Sign(privateKey PrivateKey, message []byte) []byte { - return ed25519.Sign(privateKey, message) -} - -// Verify reports whether sig is a valid signature of message by publicKey. It -// will panic if len(publicKey) is not PublicKeySize. -func Verify(publicKey PublicKey, message, sig []byte) bool { - return ed25519.Verify(publicKey, message, sig) -} diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/.gitcookies.sh.enc b/vendor/gopkg.in/go-jose/go-jose.v2/.gitcookies.sh.enc deleted file mode 100644 index 730e569b0..000000000 --- a/vendor/gopkg.in/go-jose/go-jose.v2/.gitcookies.sh.enc +++ /dev/null @@ -1 +0,0 @@ -'|&{tU|gG(Cy=+c:u:/p#~["4!nADK merged.coverprofile -- $HOME/gopath/bin/goveralls -coverprofile merged.coverprofile -service=travis-ci diff --git a/vendor/gopkg.in/go-jose/go-jose.v2/README.md b/vendor/gopkg.in/go-jose/go-jose.v2/README.md deleted file mode 100644 index b877f412c..000000000 --- a/vendor/gopkg.in/go-jose/go-jose.v2/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# go-jose v2 - -Version 2 of this library is no longer supported. [Please use v4 -instead](https://pkg.go.dev/github.com/go-jose/go-jose/v4). diff --git a/vendor/modules.txt b/vendor/modules.txt index 9af5e7ba3..f148b7cab 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -16,7 +16,7 @@ github.com/Microsoft/go-winio/internal/socket github.com/Microsoft/go-winio/internal/stringbuffer github.com/Microsoft/go-winio/pkg/guid github.com/Microsoft/go-winio/vhd -# github.com/Microsoft/hcsshim v0.12.3 +# github.com/Microsoft/hcsshim v0.12.4 ## explicit; go 1.21 github.com/Microsoft/hcsshim github.com/Microsoft/hcsshim/computestorage @@ -103,7 +103,7 @@ github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.5.1 ## explicit; go 1.20 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/image/v5 v5.31.1 +# github.com/containers/image/v5 v5.31.1-0.20240625185001-825c645ee42e ## explicit; go 1.21 github.com/containers/image/v5/copy github.com/containers/image/v5/directory @@ -189,7 +189,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils/keyprovider -# github.com/containers/storage v1.54.0 +# github.com/containers/storage v1.54.1-0.20240626141655-3b6406632da1 ## explicit; go 1.21 github.com/containers/storage github.com/containers/storage/drivers @@ -259,7 +259,7 @@ github.com/distribution/reference github.com/docker/distribution/registry/api/errcode github.com/docker/distribution/registry/api/v2 github.com/docker/distribution/registry/client/auth/challenge -# github.com/docker/docker v26.1.4+incompatible +# github.com/docker/docker v27.0.1+incompatible ## explicit github.com/docker/docker/api github.com/docker/docker/api/types @@ -283,7 +283,7 @@ github.com/docker/docker/client github.com/docker/docker/errdefs github.com/docker/docker/internal/multierror github.com/docker/docker/pkg/parsers -# github.com/docker/docker-credential-helpers v0.8.1 +# github.com/docker/docker-credential-helpers v0.8.2 ## explicit; go 1.19 github.com/docker/docker-credential-helpers/client github.com/docker/docker-credential-helpers/credentials @@ -306,6 +306,11 @@ github.com/fsnotify/fsnotify github.com/go-jose/go-jose/v3 github.com/go-jose/go-jose/v3/cipher github.com/go-jose/go-jose/v3/json +# github.com/go-jose/go-jose/v4 v4.0.1 +## explicit; go 1.21 +github.com/go-jose/go-jose/v4 +github.com/go-jose/go-jose/v4/cipher +github.com/go-jose/go-jose/v4/json # github.com/go-logr/logr v1.4.1 ## explicit; go 1.18 github.com/go-logr/logr @@ -372,7 +377,7 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/go-containerregistry v0.19.1 +# github.com/google/go-containerregistry v0.19.2 ## explicit; go 1.18 github.com/google/go-containerregistry/pkg/name github.com/google/go-containerregistry/pkg/v1 @@ -407,7 +412,7 @@ github.com/josharian/intern # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go -# github.com/klauspost/compress v1.17.8 +# github.com/klauspost/compress v1.17.9 ## explicit; go 1.20 github.com/klauspost/compress github.com/klauspost/compress/flate @@ -423,8 +428,8 @@ github.com/klauspost/pgzip # github.com/kr/fs v0.1.0 ## explicit github.com/kr/fs -# github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e -## explicit; go 1.20 +# github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 +## explicit; go 1.21 github.com/letsencrypt/boulder/core github.com/letsencrypt/boulder/goodkey github.com/letsencrypt/boulder/identifier @@ -542,7 +547,6 @@ github.com/opencontainers/runtime-tools/validate/capabilities ## explicit; go 1.19 github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label -github.com/opencontainers/selinux/pkg/pwalk github.com/opencontainers/selinux/pkg/pwalkdir # github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f ## explicit @@ -576,8 +580,8 @@ github.com/sigstore/fulcio/pkg/certificate # github.com/sigstore/rekor v1.3.6 ## explicit; go 1.21 github.com/sigstore/rekor/pkg/generated/models -# github.com/sigstore/sigstore v1.8.3 -## explicit; go 1.20 +# github.com/sigstore/sigstore v1.8.4 +## explicit; go 1.21 github.com/sigstore/sigstore/pkg/cryptoutils github.com/sigstore/sigstore/pkg/signature github.com/sigstore/sigstore/pkg/signature/options @@ -598,7 +602,7 @@ github.com/stefanberger/go-pkcs11uri ## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/sylabs/sif/v2 v2.16.0 +# github.com/sylabs/sif/v2 v2.17.0 ## explicit; go 1.21 github.com/sylabs/sif/v2/pkg/sif # github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 @@ -687,7 +691,6 @@ golang.org/x/crypto/cast5 golang.org/x/crypto/chacha20 golang.org/x/crypto/curve25519 golang.org/x/crypto/curve25519/internal/field -golang.org/x/crypto/ed25519 golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 golang.org/x/crypto/nacl/secretbox @@ -856,11 +859,6 @@ google.golang.org/protobuf/types/gofeaturespb google.golang.org/protobuf/types/known/anypb google.golang.org/protobuf/types/known/durationpb google.golang.org/protobuf/types/known/timestamppb -# gopkg.in/go-jose/go-jose.v2 v2.6.3 -## explicit -gopkg.in/go-jose/go-jose.v2 -gopkg.in/go-jose/go-jose.v2/cipher -gopkg.in/go-jose/go-jose.v2/json # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3