Skip to content

Commit

Permalink
Cleaner refactoring to determineManifestConversion
Browse files Browse the repository at this point in the history
Signed-off-by: Brandon Lum <[email protected]>
  • Loading branch information
lumjjb committed Nov 6, 2019
1 parent e161f21 commit db4e46b
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 55 deletions.
47 changes: 3 additions & 44 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,6 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
return nil, "", "", errors.Errorf("Encryption request but not supported by source transport %s", src.Reference().Transport().Name())
}

// TODO(LUMJJB): Move into determine manifest conversion
if options.OciEncryptLayers != nil && !supportsEncryption(c.dest) {
return nil, "", "", errors.Errorf("Encryption request but not supported by destination transport %s", c.dest.Reference().Transport().Name())
}

// If the destination is a digested reference, make a note of that, determine what digest value we're
// expecting, and check that the source manifest matches it. If the source manifest doesn't, but it's
// one item from a manifest list that matches it, accept that as a match.
Expand Down Expand Up @@ -616,19 +611,19 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
return nil, "", "", err
}

requiresOciEncryption := isEncrypted(src) || options.OciEncryptLayers != nil
destRequiresOciEncryption := (isEncrypted(src) && ic.ociDecryptConfig != nil) || options.OciEncryptLayers != nil

// We compute preferredManifestMIMEType only to show it in error messages.
// Without having to add this context in an error message, we would be happy enough to know only that no conversion is needed.
preferredManifestMIMEType, otherManifestMIMETypeCandidates, err := ic.determineManifestConversion(ctx, c.dest.SupportedManifestMIMETypes(), options.ForceManifestMIMEType, requiresOciEncryption)
preferredManifestMIMEType, otherManifestMIMETypeCandidates, err := ic.determineManifestConversion(ctx, c.dest.SupportedManifestMIMETypes(), options.ForceManifestMIMEType, destRequiresOciEncryption)
if err != nil {
return nil, "", "", err
}

// If src.UpdatedImageNeedsLayerDiffIDs(ic.manifestUpdates) will be true, it needs to be true by the time we get here.
ic.diffIDsAreNeeded = src.UpdatedImageNeedsLayerDiffIDs(*ic.manifestUpdates)
// If encrypted and decryption keys provided, we should try to decrypt
ic.diffIDsAreNeeded = ic.diffIDsAreNeeded || (isEncrypted(src) && ic.ociDecryptConfig != nil)
ic.diffIDsAreNeeded = ic.diffIDsAreNeeded || (isEncrypted(src) && ic.ociDecryptConfig != nil) || ic.ociEncryptConfig != nil

if err := ic.copyLayers(ctx); err != nil {
return nil, "", "", err
Expand Down Expand Up @@ -1390,39 +1385,3 @@ func (c *copier) compressGoroutine(dest *io.PipeWriter, src io.Reader, compressi

_, err = io.CopyBuffer(compressor, src, buf) // Sets err to nil, i.e. causes dest.Close()
}

// isOciEncrypted returns if a mediatype is encrypted
func isOciEncrypted(mediatype string) bool {
return strings.HasSuffix(mediatype, "+encrypted")
}

// isEncrypted checks if an image is encrypted
func isEncrypted(i types.Image) bool {
layers := i.LayerInfos()
for _, l := range layers {
if isOciEncrypted(l.MediaType) {
return true
}
}
return false
}

// supportsEncryption checks if the image destination supports use of encrypted images
func supportsEncryption(dst types.ImageDestination) bool {
mimeTypes := dst.SupportedManifestMIMETypes()
if len(mimeTypes) == 0 {
return true
}

for _, m := range mimeTypes {
if manifestSupportsEncryption(m) {
return true
}
}
return false
}

// manifestSupportsEncryption returns if the manifest type supports encryption
func manifestSupportsEncryption(m string) bool {
return m == imgspecv1.MediaTypeImageManifest
}
24 changes: 24 additions & 0 deletions copy/encrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package copy

import (
"strings"

"github.com/containers/image/v5/types"
)

// isOciEncrypted returns if a mediatype is encrypted
// This function will be moved to be part of OCI spec when adopted.
func isOciEncrypted(mediatype string) bool {
return strings.HasSuffix(mediatype, "+encrypted")
}

// isEncrypted checks if an image is encrypted
func isEncrypted(i types.Image) bool {
layers := i.LayerInfos()
for _, l := range layers {
if isOciEncrypted(l.MediaType) {
return true
}
}
return false
}
18 changes: 7 additions & 11 deletions copy/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp
destSupportedManifestMIMETypes = []string{forceManifestMIMEType}
}

if len(destSupportedManifestMIMETypes) == 0 && (!requiresOciEncryption || manifestSupportsEncryption(srcType)) {
if len(destSupportedManifestMIMETypes) == 0 && (!requiresOciEncryption || manifest.MIMETypeSupportsEncryption(srcType)) {
return srcType, []string{}, nil // Anything goes; just use the original as is, do not try any conversions.
}
supportedByDest := map[string]struct{}{}
for _, t := range destSupportedManifestMIMETypes {
supportedByDest[t] = struct{}{}
if !requiresOciEncryption || manifest.MIMETypeSupportsEncryption(t) {
supportedByDest[t] = struct{}{}
}
}

// destSupportedManifestMIMETypes is a static guess; a particular registry may still only support a subset of the types.
Expand All @@ -75,9 +77,7 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp

// First of all, prefer to keep the original manifest unmodified.
if _, ok := supportedByDest[srcType]; ok {
if !requiresOciEncryption || manifestSupportsEncryption(srcType) {
prioritizedTypes.append(srcType)
}
prioritizedTypes.append(srcType)
}
if !ic.canModifyManifest {
// We could also drop the !ic.canModifyManifest check and have the caller
Expand All @@ -91,17 +91,13 @@ func (ic *imageCopier) determineManifestConversion(ctx context.Context, destSupp
// Then use our list of preferred types.
for _, t := range preferredManifestMIMETypes {
if _, ok := supportedByDest[t]; ok {
if !requiresOciEncryption || manifestSupportsEncryption(t) {
prioritizedTypes.append(t)
}
prioritizedTypes.append(t)
}
}

// Finally, try anything else the destination supports.
for _, t := range destSupportedManifestMIMETypes {
if !requiresOciEncryption || manifestSupportsEncryption(t) {
prioritizedTypes.append(t)
}
prioritizedTypes.append(t)
}

logrus.Debugf("Manifest has MIME type %s, ordered candidate list [%s]", srcType, strings.Join(prioritizedTypes.list, ", "))
Expand Down
5 changes: 5 additions & 0 deletions manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ func MIMETypeIsMultiImage(mimeType string) bool {
return mimeType == DockerV2ListMediaType || mimeType == imgspecv1.MediaTypeImageIndex
}

// MIMETypeSupportsEncryption returns true if the mimeType supports encryption
func MIMETypeSupportsEncryption(mimeType string) bool {
return mimeType == imgspecv1.MediaTypeImageManifest
}

// NormalizedMIMEType returns the effective MIME type of a manifest MIME type returned by a server,
// centralizing various workarounds.
func NormalizedMIMEType(input string) string {
Expand Down

0 comments on commit db4e46b

Please sign in to comment.