Skip to content

Commit

Permalink
Update embedded Docker reference, if any, in copy.Image
Browse files Browse the repository at this point in the history
Add EmbbeddedDockerReference to types.ManifestUpdateOptions, and use it
in copy.Image.  Pushing signed schema1 images to a different location
is impossible (skopeo users can use --remove-signatures), but signing an
unsigned schema1 image while pushing it does work.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
  • Loading branch information
mtrmac committed Apr 12, 2017
1 parent 05e525f commit 01c6ac1
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 2 deletions.
31 changes: 31 additions & 0 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe
canModifyManifest := len(sigs) == 0
manifestUpdates := types.ManifestUpdateOptions{}

if err := updateEmbeddedDockerReference(&manifestUpdates, dest, src, canModifyManifest); err != nil {
return err
}

if err := determineManifestConversion(&manifestUpdates, src, destSupportedManifestMIMETypes, canModifyManifest); err != nil {
return err
}
Expand Down Expand Up @@ -270,6 +274,33 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe
return nil
}

// updateEmbeddedDockerReference handles the Docker reference embedded in Docker schema1 manifests.
func updateEmbeddedDockerReference(manifestUpdates *types.ManifestUpdateOptions, dest types.ImageDestination, src types.Image, canModifyManifest bool) error {
manifestRef, err := src.EmbeddedDockerReference()
if err != nil {
return errors.Wrapf(err, "Error parsing source image for embedded Docker reference")
}
if manifestRef == nil {
return nil // No embedded manifest
}

destRef := dest.Reference().DockerReference()
if destRef == nil {
return nil // Destination does not care about Docker references
}

if destRef.String() == manifestRef.String() {
return nil // The reference matches
}

if !canModifyManifest {
return errors.Errorf("Copying a schema1 image with embedded Docker reference %s to %s (Docker reference %s) would invalidate existing signatures. Explicitly enable signature removal to proceed anyway",
manifestRef.String(), transports.ImageName(dest.Reference()), destRef.String())
}
manifestUpdates.EmbeddedDockerReference = destRef
return nil
}

// copyLayers copies layers from src/rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
func (ic *imageCopier) copyLayers() error {
srcInfos := ic.src.LayerInfos()
Expand Down
8 changes: 8 additions & 0 deletions image/docker_schema1.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ func (m *manifestSchema1) UpdatedImage(options types.ManifestUpdateOptions) (typ
copy.FSLayers[(len(options.LayerInfos)-1)-i].BlobSum = info.Digest
}
}
if options.EmbeddedDockerReference != nil {
copy.Name = options.EmbeddedDockerReference.Name()
if tagged, isTagged := options.EmbeddedDockerReference.(reference.NamedTagged); isTagged {
copy.Tag = tagged.Tag()
} else {
copy.Tag = ""
}
}

switch options.ManifestMIMEType {
case "": // No conversion, OK
Expand Down
1 change: 1 addition & 0 deletions image/docker_schema2.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func (m *manifestSchema2) UpdatedImage(options types.ManifestUpdateOptions) (typ
copy.LayersDescriptors[i].URLs = info.URLs
}
}
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1 to schema2, but we really don't care.

switch options.ManifestMIMEType {
case "": // No conversion, OK
Expand Down
12 changes: 12 additions & 0 deletions image/docker_schema2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,18 @@ func TestManifestSchema2UpdatedImage(t *testing.T) {
})
assert.Error(t, err)

// EmbeddedDockerReference:
// … is ignored
embeddedRef, err := reference.ParseNormalizedNamed("busybox")
require.NoError(t, err)
res, err = original.UpdatedImage(types.ManifestUpdateOptions{
EmbeddedDockerReference: embeddedRef,
})
require.NoError(t, err)
embeddedRef, err = res.EmbeddedDockerReference()
require.NoError(t, err)
assert.Nil(t, embeddedRef)

// ManifestMIMEType:
// Only smoke-test the valid conversions, detailed tests are below. (This also verifies that “original” is not affected.)
for _, mime := range []string{
Expand Down
1 change: 1 addition & 0 deletions image/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ func (m *manifestOCI1) UpdatedImage(options types.ManifestUpdateOptions) (types.
copy.LayersDescriptors[i].Size = info.Size
}
}
// Ignore options.EmbeddedDockerReference: it may be set when converting from schema1, but we really don't care.

switch options.ManifestMIMEType {
case "": // No conversion, OK
Expand Down
12 changes: 12 additions & 0 deletions image/oci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,18 @@ func TestManifestOCI1UpdatedImage(t *testing.T) {
})
assert.Error(t, err)

// EmbeddedDockerReference:
// … is ignored
embeddedRef, err := reference.ParseNormalizedNamed("busybox")
require.NoError(t, err)
res, err = original.UpdatedImage(types.ManifestUpdateOptions{
EmbeddedDockerReference: embeddedRef,
})
require.NoError(t, err)
embeddedRef, err = res.EmbeddedDockerReference()
require.NoError(t, err)
assert.Nil(t, embeddedRef)

// ManifestMIMEType:
// Only smoke-test the valid conversions, detailed tests are below. (This also verifies that “original” is not affected.)
for _, mime := range []string{
Expand Down
5 changes: 3 additions & 2 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,9 @@ type Image interface {

// ManifestUpdateOptions is a way to pass named optional arguments to Image.UpdatedManifest
type ManifestUpdateOptions struct {
LayerInfos []BlobInfo // Complete BlobInfos (size+digest+urls) which should replace the originals, in order (the root layer first, and then successive layered layers)
ManifestMIMEType string
LayerInfos []BlobInfo // Complete BlobInfos (size+digest+urls) which should replace the originals, in order (the root layer first, and then successive layered layers)
EmbeddedDockerReference reference.Named
ManifestMIMEType string
// The values below are NOT requests to modify the image; they provide optional context which may or may not be used.
InformationOnly ManifestUpdateInformation
}
Expand Down

0 comments on commit 01c6ac1

Please sign in to comment.