diff --git a/go.mod b/go.mod index 2597b56e6fa..5cceb58c578 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/containerd/containerd v1.7.18 github.com/containernetworking/cni v1.2.2 github.com/containers/common v0.59.1-0.20240712101718-237a317152ae - github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516 + github.com/containers/image/v5 v5.31.1 github.com/containers/luksy v0.0.0-20240618143119-a8846e21c08c github.com/containers/ocicrypt v1.2.0 github.com/containers/storage v1.54.1-0.20240712125645-98ad80d6d165 diff --git a/go.sum b/go.sum index 7c26fb728aa..bc0b95d492d 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+ github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM= github.com/containers/common v0.59.1-0.20240712101718-237a317152ae h1:KtbMAKs/DMU2UOrAUd381rXld5UAJdkHZRn2BLEfmCM= github.com/containers/common v0.59.1-0.20240712101718-237a317152ae/go.mod h1:KrQ9y5qa7TBVzp7qs7I1MVi6Uxntu0hM5wjd5bmvMnM= -github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516 h1:BVyB11XLbT7s0tMF1qzdc5R04gO2BRAdjbftRwNoLXM= -github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516/go.mod h1:iAUT9Iy/z0QPrYeILorryErMUxm4GlRzBE0Yz65l/uE= +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/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/luksy v0.0.0-20240618143119-a8846e21c08c h1:gJDiBJYc8JFD46IJmr8SqGOcueGSRGnuhW6wgXiAjr0= @@ -90,8 +90,8 @@ github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWh github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8= github.com/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 v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ= -github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +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/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 v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE= diff --git a/vendor/github.com/containers/image/v5/copy/single.go b/vendor/github.com/containers/image/v5/copy/single.go index 17cc8c833ea..9d544f56183 100644 --- a/vendor/github.com/containers/image/v5/copy/single.go +++ b/vendor/github.com/containers/image/v5/copy/single.go @@ -409,6 +409,7 @@ func (ic *imageCopier) compareImageDestinationManifestEqual(ctx context.Context, // copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.cannotModifyManifestReason == "". func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algorithm, error) { srcInfos := ic.src.LayerInfos() + numLayers := len(srcInfos) updatedSrcInfos, err := ic.src.LayerInfosForCopy(ctx) if err != nil { return nil, err @@ -439,7 +440,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor // copyGroup is used to determine if all layers are copied copyGroup := sync.WaitGroup{} - data := make([]copyLayerData, len(srcInfos)) + data := make([]copyLayerData, numLayers) copyLayerHelper := func(index int, srcLayer types.BlobInfo, toEncrypt bool, pool *mpb.Progress, srcRef reference.Named) { defer ic.c.concurrentBlobCopiesSemaphore.Release(1) defer copyGroup.Done() @@ -462,7 +463,9 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor // Decide which layers to encrypt layersToEncrypt := set.New[int]() + var encryptAll bool if ic.c.options.OciEncryptLayers != nil { + encryptAll = len(*ic.c.options.OciEncryptLayers) == 0 totalLayers := len(srcInfos) for _, l := range *ic.c.options.OciEncryptLayers { switch { @@ -475,7 +478,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor } } - if len(*ic.c.options.OciEncryptLayers) == 0 { // “encrypt all layers” + if encryptAll { for i := 0; i < len(srcInfos); i++ { layersToEncrypt.Add(i) } @@ -490,7 +493,8 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor defer copyGroup.Wait() for i, srcLayer := range srcInfos { - if err := ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1); err != nil { + err = ic.c.concurrentBlobCopiesSemaphore.Acquire(ctx, 1) + if err != nil { // This can only fail with ctx.Err(), so no need to blame acquiring the semaphore. return fmt.Errorf("copying layer: %w", err) } @@ -505,8 +509,8 @@ func (ic *imageCopier) copyLayers(ctx context.Context) ([]compressiontypes.Algor } compressionAlgos := set.New[string]() - destInfos := make([]types.BlobInfo, len(srcInfos)) - diffIDs := make([]digest.Digest, len(srcInfos)) + destInfos := make([]types.BlobInfo, numLayers) + diffIDs := make([]digest.Digest, numLayers) for i, cld := range data { if cld.err != nil { return nil, cld.err 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 97d97fed5f6..94cbcb1d994 100644 --- a/vendor/github.com/containers/image/v5/docker/docker_client.go +++ b/vendor/github.com/containers/image/v5/docker/docker_client.go @@ -86,9 +86,11 @@ type extensionSignatureList struct { Signatures []extensionSignature `json:"signatures"` } -// bearerToken records a cached token we can use to authenticate. type bearerToken struct { - token string + Token string `json:"token"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + IssuedAt time.Time `json:"issued_at"` expirationTime time.Time } @@ -145,6 +147,25 @@ const ( noAuth ) +func newBearerTokenFromJSONBlob(blob []byte) (*bearerToken, error) { + token := new(bearerToken) + if err := json.Unmarshal(blob, &token); err != nil { + return nil, err + } + if token.Token == "" { + token.Token = token.AccessToken + } + if token.ExpiresIn < minimumTokenLifetimeSeconds { + token.ExpiresIn = minimumTokenLifetimeSeconds + logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn) + } + if token.IssuedAt.IsZero() { + token.IssuedAt = time.Now().UTC() + } + token.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second) + return token, nil +} + // dockerCertDir returns a path to a directory to be consumed by tlsclientconfig.SetupCertificates() depending on ctx and hostPort. func dockerCertDir(sys *types.SystemContext, hostPort string) (string, error) { if sys != nil && sys.DockerCertPath != "" { @@ -753,7 +774,7 @@ func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope token = *t c.tokenCache.Store(cacheKey, token) } - registryToken = token.token + registryToken = token.Token } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", registryToken)) return nil @@ -806,7 +827,12 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall return nil, err } - return newBearerTokenFromHTTPResponseBody(res) + tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) + if err != nil { + return nil, err + } + + return newBearerTokenFromJSONBlob(tokenBlob) } func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, @@ -852,50 +878,12 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge, if err := httpResponseToError(res, "Requesting bearer token"); err != nil { return nil, err } - - return newBearerTokenFromHTTPResponseBody(res) -} - -// newBearerTokenFromHTTPResponseBody parses a http.Response to obtain a bearerToken. -// The caller is still responsible for ensuring res.Body is closed. -func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error) { - blob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) + tokenBlob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize) if err != nil { return nil, err } - var token struct { - Token string `json:"token"` - AccessToken string `json:"access_token"` - ExpiresIn int `json:"expires_in"` - IssuedAt time.Time `json:"issued_at"` - expirationTime time.Time - } - if err := json.Unmarshal(blob, &token); err != nil { - const bodySampleLength = 50 - bodySample := blob - if len(bodySample) > bodySampleLength { - bodySample = bodySample[:bodySampleLength] - } - return nil, fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err) - } - - bt := &bearerToken{ - token: token.Token, - } - if bt.token == "" { - bt.token = token.AccessToken - } - - if token.ExpiresIn < minimumTokenLifetimeSeconds { - token.ExpiresIn = minimumTokenLifetimeSeconds - logrus.Debugf("Increasing token expiration to: %d seconds", token.ExpiresIn) - } - if token.IssuedAt.IsZero() { - token.IssuedAt = time.Now().UTC() - } - bt.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second) - return bt, nil + return newBearerTokenFromJSONBlob(tokenBlob) } // 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 c8f6ba30552..a2b6dbed787 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,9 +1,7 @@ package docker import ( - "bytes" "context" - "encoding/json" "errors" "fmt" "io" @@ -13,7 +11,6 @@ import ( "net/http" "net/url" "os" - "os/exec" "strings" "sync" @@ -165,34 +162,6 @@ 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/internal/manifest/oci_index.go b/vendor/github.com/containers/image/v5/internal/manifest/oci_index.go index fe78efaebe7..67b4cfeba62 100644 --- a/vendor/github.com/containers/image/v5/internal/manifest/oci_index.go +++ b/vendor/github.com/containers/image/v5/internal/manifest/oci_index.go @@ -1,7 +1,6 @@ package manifest import ( - "bytes" "encoding/json" "fmt" "maps" @@ -297,51 +296,29 @@ func OCI1IndexPublicFromComponents(components []imgspecv1.Descriptor, annotation }, } for i, component := range components { - index.Manifests[i] = oci1DescriptorClone(component) + var platform *imgspecv1.Platform + if component.Platform != nil { + platformCopy := ociPlatformClone(*component.Platform) + platform = &platformCopy + } + m := imgspecv1.Descriptor{ + MediaType: component.MediaType, + ArtifactType: component.ArtifactType, + Size: component.Size, + Digest: component.Digest, + URLs: slices.Clone(component.URLs), + Annotations: maps.Clone(component.Annotations), + Platform: platform, + } + index.Manifests[i] = m } return &index } -func oci1DescriptorClone(d imgspecv1.Descriptor) imgspecv1.Descriptor { - var platform *imgspecv1.Platform - if d.Platform != nil { - platformCopy := ociPlatformClone(*d.Platform) - platform = &platformCopy - } - return imgspecv1.Descriptor{ - MediaType: d.MediaType, - Digest: d.Digest, - Size: d.Size, - URLs: slices.Clone(d.URLs), - Annotations: maps.Clone(d.Annotations), - Data: bytes.Clone(d.Data), - Platform: platform, - ArtifactType: d.ArtifactType, - } -} - // OCI1IndexPublicClone creates a deep copy of the passed-in index. // This is publicly visible as c/image/manifest.OCI1IndexClone. func OCI1IndexPublicClone(index *OCI1IndexPublic) *OCI1IndexPublic { - var subject *imgspecv1.Descriptor - if index.Subject != nil { - s := oci1DescriptorClone(*index.Subject) - subject = &s - } - manifests := make([]imgspecv1.Descriptor, len(index.Manifests)) - for i, m := range index.Manifests { - manifests[i] = oci1DescriptorClone(m) - } - return &OCI1IndexPublic{ - Index: imgspecv1.Index{ - Versioned: index.Versioned, - MediaType: index.MediaType, - ArtifactType: index.ArtifactType, - Manifests: manifests, - Subject: subject, - Annotations: maps.Clone(index.Annotations), - }, - } + return OCI1IndexPublicFromComponents(index.Manifests, index.Annotations) } // ToOCI1Index returns the index encoded as an OCI1 index. 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 b413ec5131b..037572b0eec 100644 --- a/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go +++ b/vendor/github.com/containers/image/v5/pkg/blobinfocache/default.go @@ -74,15 +74,3 @@ 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 1b161474da5..45427a350fc 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,11 +248,6 @@ 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. @@ -830,16 +825,6 @@ 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() @@ -1066,11 +1051,6 @@ 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/signature/mechanism_openpgp.go b/vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go index bd1979aefbd..5d6c1ac8397 100644 --- a/vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go +++ b/vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go @@ -15,7 +15,6 @@ import ( "github.com/containers/image/v5/signature/internal" "github.com/containers/storage/pkg/homedir" - // This is a fallback code; the primary recommendation is to use the gpgme mechanism // implementation, which is out-of-process and more appropriate for handling long-term private key material // than any Go implementation. @@ -151,7 +150,7 @@ func (m *openpgpSigningMechanism) Verify(unverifiedSignature []byte) (contents [ return nil, "", fmt.Errorf("signature error: %v", md.SignatureError) } if md.SignedBy == nil { - return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Key not found for key ID %x in signature", md.SignedByKeyId)) + return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("Invalid GPG signature: %#v", md.Signature)) } if md.Signature != nil { if md.Signature.SigLifetimeSecs != nil { diff --git a/vendor/github.com/containers/image/v5/storage/storage_dest.go b/vendor/github.com/containers/image/v5/storage/storage_dest.go index 92dfebd333b..a0b347410d7 100644 --- a/vendor/github.com/containers/image/v5/storage/storage_dest.go +++ b/vendor/github.com/containers/image/v5/storage/storage_dest.go @@ -325,13 +325,7 @@ func (s *storageImageDestination) PutBlobPartial(ctx context.Context, chunkAcces if out.UncompressedDigest != "" { // The computation of UncompressedDigest means the whole layer has been consumed; while doing that, chunked.GetDiffer is // responsible for ensuring blobDigest has been validated. - if out.CompressedDigest != blobDigest { - return private.UploadedBlob{}, fmt.Errorf("internal error: ApplyDiffWithDiffer returned CompressedDigest %q not matching expected %q", - out.CompressedDigest, blobDigest) - } s.lockProtected.blobDiffIDs[blobDigest] = out.UncompressedDigest - // We trust ApplyDiffWithDiffer to validate or create both values correctly. - options.Cache.RecordDigestUncompressedPair(out.CompressedDigest, out.UncompressedDigest) } else { // Don’t identify layers by TOC if UncompressedDigest is available. // - Using UncompressedDigest allows image reuse with non-partially-pulled layers diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go index 7eee412273a..9e033815876 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 = 32 + VersionMinor = 31 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 0 + VersionPatch = 1 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "-dev" + VersionDev = "" ) // Version is the specification version that the package types support. diff --git a/vendor/modules.txt b/vendor/modules.txt index 5f0ec19cff3..051367eb9de 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -159,8 +159,8 @@ github.com/containers/common/pkg/umask github.com/containers/common/pkg/util github.com/containers/common/pkg/version github.com/containers/common/version -# github.com/containers/image/v5 v5.31.1-0.20240711123249-1dbd8fbbe516 -## explicit; go 1.21.0 +# github.com/containers/image/v5 v5.31.1 +## explicit; go 1.21 github.com/containers/image/v5/copy github.com/containers/image/v5/directory github.com/containers/image/v5/directory/explicitfilepath