vendor: upgrade containers/storage
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
5addc8caf0
commit
ecd0006e80
114 changed files with 11464 additions and 1003 deletions
192
vendor/github.com/containers/image/copy/copy.go
generated
vendored
192
vendor/github.com/containers/image/copy/copy.go
generated
vendored
|
@ -7,13 +7,13 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pb "gopkg.in/cheggaaa/pb.v1"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/containers/image/image"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/pkg/compression"
|
||||
"github.com/containers/image/signature"
|
||||
"github.com/containers/image/transports"
|
||||
|
@ -22,11 +22,6 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// preferredManifestMIMETypes lists manifest MIME types in order of our preference, if we can't use the original manifest and need to convert.
|
||||
// Prefer v2s2 to v2s1 because v2s2 does not need to be changed when uploading to a different location.
|
||||
// Include v2s1 signed but not v2s1 unsigned, because docker/distribution requires a signature even if the unsigned MIME type is used.
|
||||
var preferredManifestMIMETypes = []string{manifest.DockerV2Schema2MediaType, manifest.DockerV2Schema1SignedMediaType}
|
||||
|
||||
type digestingReader struct {
|
||||
source io.Reader
|
||||
digester digest.Digester
|
||||
|
@ -186,8 +181,16 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe
|
|||
|
||||
canModifyManifest := len(sigs) == 0
|
||||
manifestUpdates := types.ManifestUpdateOptions{}
|
||||
manifestUpdates.InformationOnly.Destination = dest
|
||||
|
||||
if err := determineManifestConversion(&manifestUpdates, src, destSupportedManifestMIMETypes, canModifyManifest); err != nil {
|
||||
if err := updateEmbeddedDockerReference(&manifestUpdates, dest, src, canModifyManifest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 := determineManifestConversion(&manifestUpdates, src, destSupportedManifestMIMETypes, canModifyManifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -210,54 +213,58 @@ func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageRe
|
|||
return err
|
||||
}
|
||||
|
||||
pendingImage := src
|
||||
if !reflect.DeepEqual(manifestUpdates, types.ManifestUpdateOptions{InformationOnly: manifestUpdates.InformationOnly}) {
|
||||
if !canModifyManifest {
|
||||
return errors.Errorf("Internal error: copy needs an updated manifest but that was known to be forbidden")
|
||||
}
|
||||
manifestUpdates.InformationOnly.Destination = dest
|
||||
pendingImage, err = src.UpdatedImage(manifestUpdates)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error creating an updated image manifest")
|
||||
}
|
||||
}
|
||||
manifest, _, err := pendingImage.Manifest()
|
||||
// With docker/distribution registries we do not know whether the registry accepts schema2 or schema1 only;
|
||||
// and at least with the OpenShift registry "acceptschema2" option, there is no way to detect the support
|
||||
// without actually trying to upload something and getting a types.ManifestTypeRejectedError.
|
||||
// So, try the preferred manifest MIME type. If the process succeeds, fine…
|
||||
manifest, err := ic.copyUpdatedConfigAndManifest()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error reading manifest")
|
||||
}
|
||||
logrus.Debugf("Writing manifest using preferred type %s failed: %v", preferredManifestMIMEType, err)
|
||||
// … if it fails, _and_ the failure is because the manifest is rejected, we may have other options.
|
||||
if _, isManifestRejected := errors.Cause(err).(types.ManifestTypeRejectedError); !isManifestRejected || len(otherManifestMIMETypeCandidates) == 0 {
|
||||
// We don’t have other options.
|
||||
// In principle the code below would handle this as well, but the resulting error message is fairly ugly.
|
||||
// Don’t bother the user with MIME types if we have no choice.
|
||||
return err
|
||||
}
|
||||
// If the original MIME type is acceptable, determineManifestConversion always uses it as preferredManifestMIMEType.
|
||||
// So if we are here, we will definitely be trying to convert the manifest.
|
||||
// With !canModifyManifest, that would just be a string of repeated failures for the same reason,
|
||||
// so let’s bail out early and with a better error message.
|
||||
if !canModifyManifest {
|
||||
return errors.Wrap(err, "Writing manifest failed (and converting it is not possible)")
|
||||
}
|
||||
|
||||
if err := ic.copyConfig(pendingImage); err != nil {
|
||||
return err
|
||||
// errs is a list of errors when trying various manifest types. Also serves as an "upload succeeded" flag when set to nil.
|
||||
errs := []string{fmt.Sprintf("%s(%v)", preferredManifestMIMEType, err)}
|
||||
for _, manifestMIMEType := range otherManifestMIMETypeCandidates {
|
||||
logrus.Debugf("Trying to use manifest type %s…", manifestMIMEType)
|
||||
manifestUpdates.ManifestMIMEType = manifestMIMEType
|
||||
attemptedManifest, err := ic.copyUpdatedConfigAndManifest()
|
||||
if err != nil {
|
||||
logrus.Debugf("Upload of manifest type %s failed: %v", manifestMIMEType, err)
|
||||
errs = append(errs, fmt.Sprintf("%s(%v)", manifestMIMEType, err))
|
||||
continue
|
||||
}
|
||||
|
||||
// We have successfully uploaded a manifest.
|
||||
manifest = attemptedManifest
|
||||
errs = nil // Mark this as a success so that we don't abort below.
|
||||
break
|
||||
}
|
||||
if errs != nil {
|
||||
return fmt.Errorf("Uploading manifest failed, attempted the following formats: %s", strings.Join(errs, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
if options.SignBy != "" {
|
||||
mech, err := signature.NewGPGSigningMechanism()
|
||||
newSig, err := createSignature(dest, manifest, options.SignBy, reportWriter)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error initializing GPG")
|
||||
}
|
||||
defer mech.Close()
|
||||
if err := mech.SupportsSigning(); err != nil {
|
||||
return errors.Wrap(err, "Signing not supported")
|
||||
}
|
||||
|
||||
dockerReference := dest.Reference().DockerReference()
|
||||
if dockerReference == nil {
|
||||
return errors.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(dest.Reference()))
|
||||
}
|
||||
|
||||
writeReport("Signing manifest\n")
|
||||
newSig, err := signature.SignDockerManifest(manifest, dockerReference.String(), mech, options.SignBy)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error creating signature")
|
||||
return err
|
||||
}
|
||||
sigs = append(sigs, newSig)
|
||||
}
|
||||
|
||||
writeReport("Writing manifest to image destination\n")
|
||||
if err := dest.PutManifest(manifest); err != nil {
|
||||
return errors.Wrap(err, "Error writing manifest")
|
||||
}
|
||||
|
||||
writeReport("Storing signatures\n")
|
||||
if err := dest.PutSignatures(sigs); err != nil {
|
||||
return errors.Wrap(err, "Error writing signatures")
|
||||
|
@ -270,6 +277,24 @@ 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 {
|
||||
destRef := dest.Reference().DockerReference()
|
||||
if destRef == nil {
|
||||
return nil // Destination does not care about Docker references
|
||||
}
|
||||
if !src.EmbeddedDockerReferenceConflicts(destRef) {
|
||||
return nil // No reference embedded in the manifest, or it matches destRef already.
|
||||
}
|
||||
|
||||
if !canModifyManifest {
|
||||
return errors.Errorf("Copying a schema1 image with an embedded Docker reference to %s (Docker reference %s) would invalidate existing signatures. Explicitly enable signature removal to proceed anyway",
|
||||
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()
|
||||
|
@ -322,6 +347,45 @@ func layerDigestsDiffer(a, b []types.BlobInfo) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// copyUpdatedConfigAndManifest updates the image per ic.manifestUpdates, if necessary,
|
||||
// stores the resulting config and manifest to the destination, and returns the stored manifest.
|
||||
func (ic *imageCopier) copyUpdatedConfigAndManifest() ([]byte, error) {
|
||||
pendingImage := ic.src
|
||||
if !reflect.DeepEqual(*ic.manifestUpdates, types.ManifestUpdateOptions{InformationOnly: ic.manifestUpdates.InformationOnly}) {
|
||||
if !ic.canModifyManifest {
|
||||
return nil, errors.Errorf("Internal error: copy needs an updated manifest but that was known to be forbidden")
|
||||
}
|
||||
if !ic.diffIDsAreNeeded && ic.src.UpdatedImageNeedsLayerDiffIDs(*ic.manifestUpdates) {
|
||||
// We have set ic.diffIDsAreNeeded based on the preferred MIME type returned by determineManifestConversion.
|
||||
// So, this can only happen if we are trying to upload using one of the other MIME type candidates.
|
||||
// Because UpdatedImageNeedsLayerDiffIDs is true only when converting from s1 to s2, this case should only arise
|
||||
// when ic.dest.SupportedManifestMIMETypes() includes both s1 and s2, the upload using s1 failed, and we are now trying s2.
|
||||
// Supposedly s2-only registries do not exist or are extremely rare, so failing with this error message is good enough for now.
|
||||
// If handling such registries turns out to be necessary, we could compute ic.diffIDsAreNeeded based on the full list of manifest MIME type candidates.
|
||||
return nil, errors.Errorf("Can not convert image to %s, preparing DiffIDs for this case is not supported", ic.manifestUpdates.ManifestMIMEType)
|
||||
}
|
||||
pi, err := ic.src.UpdatedImage(*ic.manifestUpdates)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error creating an updated image manifest")
|
||||
}
|
||||
pendingImage = pi
|
||||
}
|
||||
manifest, _, err := pendingImage.Manifest()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error reading manifest")
|
||||
}
|
||||
|
||||
if err := ic.copyConfig(pendingImage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Fprintf(ic.reportWriter, "Writing manifest to image destination\n")
|
||||
if err := ic.dest.PutManifest(manifest); err != nil {
|
||||
return nil, errors.Wrap(err, "Error writing manifest")
|
||||
}
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
// copyConfig copies config.json, if any, from src to dest.
|
||||
func (ic *imageCopier) copyConfig(src types.Image) error {
|
||||
srcInfo := src.ConfigInfo()
|
||||
|
@ -575,41 +639,3 @@ func compressGoroutine(dest *io.PipeWriter, src io.Reader) {
|
|||
|
||||
_, err = io.Copy(zipper, src) // Sets err to nil, i.e. causes dest.Close()
|
||||
}
|
||||
|
||||
// determineManifestConversion updates manifestUpdates to convert manifest to a supported MIME type, if necessary and canModifyManifest.
|
||||
// Note that the conversion will only happen later, through src.UpdatedImage
|
||||
func determineManifestConversion(manifestUpdates *types.ManifestUpdateOptions, src types.Image, destSupportedManifestMIMETypes []string, canModifyManifest bool) error {
|
||||
if len(destSupportedManifestMIMETypes) == 0 {
|
||||
return nil // Anything goes
|
||||
}
|
||||
supportedByDest := map[string]struct{}{}
|
||||
for _, t := range destSupportedManifestMIMETypes {
|
||||
supportedByDest[t] = struct{}{}
|
||||
}
|
||||
|
||||
_, srcType, err := src.Manifest()
|
||||
if err != nil { // This should have been cached?!
|
||||
return errors.Wrap(err, "Error reading manifest")
|
||||
}
|
||||
if _, ok := supportedByDest[srcType]; ok {
|
||||
logrus.Debugf("Manifest MIME type %s is declared supported by the destination", srcType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// OK, we should convert the manifest.
|
||||
if !canModifyManifest {
|
||||
logrus.Debugf("Manifest MIME type %s is not supported by the destination, but we can't modify the manifest, hoping for the best...")
|
||||
return nil // Take our chances - FIXME? Or should we fail without trying?
|
||||
}
|
||||
|
||||
var chosenType = destSupportedManifestMIMETypes[0] // This one is known to be supported.
|
||||
for _, t := range preferredManifestMIMETypes {
|
||||
if _, ok := supportedByDest[t]; ok {
|
||||
chosenType = t
|
||||
break
|
||||
}
|
||||
}
|
||||
logrus.Debugf("Will convert manifest from MIME type %s to %s", srcType, chosenType)
|
||||
manifestUpdates.ManifestMIMEType = chosenType
|
||||
return nil
|
||||
}
|
||||
|
|
102
vendor/github.com/containers/image/copy/manifest.go
generated
vendored
Normal file
102
vendor/github.com/containers/image/copy/manifest.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
package copy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// preferredManifestMIMETypes lists manifest MIME types in order of our preference, if we can't use the original manifest and need to convert.
|
||||
// Prefer v2s2 to v2s1 because v2s2 does not need to be changed when uploading to a different location.
|
||||
// Include v2s1 signed but not v2s1 unsigned, because docker/distribution requires a signature even if the unsigned MIME type is used.
|
||||
var preferredManifestMIMETypes = []string{manifest.DockerV2Schema2MediaType, manifest.DockerV2Schema1SignedMediaType}
|
||||
|
||||
// orderedSet is a list of strings (MIME types in our case), with each string appearing at most once.
|
||||
type orderedSet struct {
|
||||
list []string
|
||||
included map[string]struct{}
|
||||
}
|
||||
|
||||
// newOrderedSet creates a correctly initialized orderedSet.
|
||||
// [Sometimes it would be really nice if Golang had constructors…]
|
||||
func newOrderedSet() *orderedSet {
|
||||
return &orderedSet{
|
||||
list: []string{},
|
||||
included: map[string]struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// append adds s to the end of os, only if it is not included already.
|
||||
func (os *orderedSet) append(s string) {
|
||||
if _, ok := os.included[s]; !ok {
|
||||
os.list = append(os.list, s)
|
||||
os.included[s] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// determineManifestConversion updates manifestUpdates to convert manifest to a supported MIME type, if necessary and canModifyManifest.
|
||||
// Note that the conversion will only happen later, through src.UpdatedImage
|
||||
// Returns the preferred manifest MIME type (whether we are converting to it or using it unmodified),
|
||||
// and a list of other possible alternatives, in order.
|
||||
func determineManifestConversion(manifestUpdates *types.ManifestUpdateOptions, src types.Image, destSupportedManifestMIMETypes []string, canModifyManifest bool) (string, []string, error) {
|
||||
_, srcType, err := src.Manifest()
|
||||
if err != nil { // This should have been cached?!
|
||||
return "", nil, errors.Wrap(err, "Error reading manifest")
|
||||
}
|
||||
|
||||
if len(destSupportedManifestMIMETypes) == 0 {
|
||||
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{}{}
|
||||
}
|
||||
|
||||
// destSupportedManifestMIMETypes is a static guess; a particular registry may still only support a subset of the types.
|
||||
// So, build a list of types to try in order of decreasing preference.
|
||||
// FIXME? This treats manifest.DockerV2Schema1SignedMediaType and manifest.DockerV2Schema1MediaType as distinct,
|
||||
// although we are not really making any conversion, and it is very unlikely that a destination would support one but not the other.
|
||||
// In practice, schema1 is probably the lowest common denominator, so we would expect to try the first one of the MIME types
|
||||
// and never attempt the other one.
|
||||
prioritizedTypes := newOrderedSet()
|
||||
|
||||
// First of all, prefer to keep the original manifest unmodified.
|
||||
if _, ok := supportedByDest[srcType]; ok {
|
||||
prioritizedTypes.append(srcType)
|
||||
}
|
||||
if !canModifyManifest {
|
||||
// We could also drop the !canModifyManifest parameter and have the caller
|
||||
// make the choice; it is already doing that to an extent, to improve error
|
||||
// messages. But it is nice to hide the “if !canModifyManifest, do no conversion”
|
||||
// special case in here; the caller can then worry (or not) only about a good UI.
|
||||
logrus.Debugf("We can't modify the manifest, hoping for the best...")
|
||||
return srcType, []string{}, nil // Take our chances - FIXME? Or should we fail without trying?
|
||||
}
|
||||
|
||||
// Then use our list of preferred types.
|
||||
for _, t := range preferredManifestMIMETypes {
|
||||
if _, ok := supportedByDest[t]; ok {
|
||||
prioritizedTypes.append(t)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, try anything else the destination supports.
|
||||
for _, t := range destSupportedManifestMIMETypes {
|
||||
prioritizedTypes.append(t)
|
||||
}
|
||||
|
||||
logrus.Debugf("Manifest has MIME type %s, ordered candidate list [%s]", srcType, strings.Join(prioritizedTypes.list, ", "))
|
||||
if len(prioritizedTypes.list) == 0 { // Coverage: destSupportedManifestMIMETypes is not empty (or we would have exited in the “Anything goes” case above), so this should never happen.
|
||||
return "", nil, errors.New("Internal error: no candidate MIME types")
|
||||
}
|
||||
preferredType := prioritizedTypes.list[0]
|
||||
if preferredType != srcType {
|
||||
manifestUpdates.ManifestMIMEType = preferredType
|
||||
} else {
|
||||
logrus.Debugf("... will first try using the original manifest unmodified")
|
||||
}
|
||||
return preferredType, prioritizedTypes.list[1:], nil
|
||||
}
|
164
vendor/github.com/containers/image/copy/manifest_test.go
generated
vendored
Normal file
164
vendor/github.com/containers/image/copy/manifest_test.go
generated
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
package copy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOrderedSet(t *testing.T) {
|
||||
for _, c := range []struct{ input, expected []string }{
|
||||
{[]string{}, []string{}},
|
||||
{[]string{"a", "b", "c"}, []string{"a", "b", "c"}},
|
||||
{[]string{"a", "b", "a", "c"}, []string{"a", "b", "c"}},
|
||||
} {
|
||||
os := newOrderedSet()
|
||||
for _, s := range c.input {
|
||||
os.append(s)
|
||||
}
|
||||
assert.Equal(t, c.expected, os.list, fmt.Sprintf("%#v", c.input))
|
||||
}
|
||||
}
|
||||
|
||||
// fakeImageSource is an implementation of types.Image which only returns itself as a MIME type in Manifest
|
||||
// except that "" means “reading the manifest should fail”
|
||||
type fakeImageSource string
|
||||
|
||||
func (f fakeImageSource) Reference() types.ImageReference {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) Close() error {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) Manifest() ([]byte, string, error) {
|
||||
if string(f) == "" {
|
||||
return nil, "", errors.New("Manifest() directed to fail")
|
||||
}
|
||||
return nil, string(f), nil
|
||||
}
|
||||
func (f fakeImageSource) Signatures() ([][]byte, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) ConfigInfo() types.BlobInfo {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) ConfigBlob() ([]byte, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) OCIConfig() (*v1.Image, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) LayerInfos() []types.BlobInfo {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) EmbeddedDockerReferenceConflicts(ref reference.Named) bool {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) Inspect() (*types.ImageInspectInfo, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) UpdatedImageNeedsLayerDiffIDs(options types.ManifestUpdateOptions) bool {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) UpdatedImage(options types.ManifestUpdateOptions) (types.Image, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) IsMultiImage() bool {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
func (f fakeImageSource) Size() (int64, error) {
|
||||
panic("Unexpected call to a mock function")
|
||||
}
|
||||
|
||||
func TestDetermineManifestConversion(t *testing.T) {
|
||||
supportS1S2OCI := []string{
|
||||
v1.MediaTypeImageManifest,
|
||||
manifest.DockerV2Schema2MediaType,
|
||||
manifest.DockerV2Schema1SignedMediaType,
|
||||
manifest.DockerV2Schema1MediaType,
|
||||
}
|
||||
supportS1OCI := []string{
|
||||
v1.MediaTypeImageManifest,
|
||||
manifest.DockerV2Schema1SignedMediaType,
|
||||
manifest.DockerV2Schema1MediaType,
|
||||
}
|
||||
supportS1S2 := []string{
|
||||
manifest.DockerV2Schema2MediaType,
|
||||
manifest.DockerV2Schema1SignedMediaType,
|
||||
manifest.DockerV2Schema1MediaType,
|
||||
}
|
||||
supportOnlyS1 := []string{
|
||||
manifest.DockerV2Schema1SignedMediaType,
|
||||
manifest.DockerV2Schema1MediaType,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
description string
|
||||
sourceType string
|
||||
destTypes []string
|
||||
expectedUpdate string
|
||||
expectedOtherCandidates []string
|
||||
}{
|
||||
// Destination accepts anything — no conversion necessary
|
||||
{"s1→anything", manifest.DockerV2Schema1SignedMediaType, nil, "", []string{}},
|
||||
{"s2→anything", manifest.DockerV2Schema2MediaType, nil, "", []string{}},
|
||||
// Destination accepts the unmodified original
|
||||
{"s1→s1s2", manifest.DockerV2Schema1SignedMediaType, supportS1S2, "", []string{manifest.DockerV2Schema2MediaType, manifest.DockerV2Schema1MediaType}},
|
||||
{"s2→s1s2", manifest.DockerV2Schema2MediaType, supportS1S2, "", supportOnlyS1},
|
||||
{"s1→s1", manifest.DockerV2Schema1SignedMediaType, supportOnlyS1, "", []string{manifest.DockerV2Schema1MediaType}},
|
||||
// Conversion necessary, a preferred format is acceptable
|
||||
{"s2→s1", manifest.DockerV2Schema2MediaType, supportOnlyS1, manifest.DockerV2Schema1SignedMediaType, []string{manifest.DockerV2Schema1MediaType}},
|
||||
// Conversion necessary, a preferred format is not acceptable
|
||||
{"s2→OCI", manifest.DockerV2Schema2MediaType, []string{v1.MediaTypeImageManifest}, v1.MediaTypeImageManifest, []string{}},
|
||||
// Conversion necessary, try the preferred formats in order.
|
||||
{
|
||||
"special→s2", "this needs conversion", supportS1S2OCI, manifest.DockerV2Schema2MediaType,
|
||||
[]string{manifest.DockerV2Schema1SignedMediaType, v1.MediaTypeImageManifest, manifest.DockerV2Schema1MediaType},
|
||||
},
|
||||
{
|
||||
"special→s1", "this needs conversion", supportS1OCI, manifest.DockerV2Schema1SignedMediaType,
|
||||
[]string{v1.MediaTypeImageManifest, manifest.DockerV2Schema1MediaType},
|
||||
},
|
||||
{
|
||||
"special→OCI", "this needs conversion", []string{v1.MediaTypeImageManifest, "other options", "with lower priority"}, v1.MediaTypeImageManifest,
|
||||
[]string{"other options", "with lower priority"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
src := fakeImageSource(c.sourceType)
|
||||
mu := types.ManifestUpdateOptions{}
|
||||
preferredMIMEType, otherCandidates, err := determineManifestConversion(&mu, src, c.destTypes, true)
|
||||
require.NoError(t, err, c.description)
|
||||
assert.Equal(t, c.expectedUpdate, mu.ManifestMIMEType, c.description)
|
||||
if c.expectedUpdate == "" {
|
||||
assert.Equal(t, c.sourceType, preferredMIMEType, c.description)
|
||||
} else {
|
||||
assert.Equal(t, c.expectedUpdate, preferredMIMEType, c.description)
|
||||
}
|
||||
assert.Equal(t, c.expectedOtherCandidates, otherCandidates, c.description)
|
||||
}
|
||||
|
||||
// Whatever the input is, with !canModifyManifest we return "keep the original as is"
|
||||
for _, c := range cases {
|
||||
src := fakeImageSource(c.sourceType)
|
||||
mu := types.ManifestUpdateOptions{}
|
||||
preferredMIMEType, otherCandidates, err := determineManifestConversion(&mu, src, c.destTypes, false)
|
||||
require.NoError(t, err, c.description)
|
||||
assert.Equal(t, "", mu.ManifestMIMEType, c.description)
|
||||
assert.Equal(t, c.sourceType, preferredMIMEType, c.description)
|
||||
assert.Equal(t, []string{}, otherCandidates, c.description)
|
||||
}
|
||||
|
||||
// Error reading the manifest — smoke test only.
|
||||
mu := types.ManifestUpdateOptions{}
|
||||
_, _, err := determineManifestConversion(&mu, fakeImageSource(""), supportS1S2, true)
|
||||
assert.Error(t, err)
|
||||
}
|
35
vendor/github.com/containers/image/copy/sign.go
generated
vendored
Normal file
35
vendor/github.com/containers/image/copy/sign.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package copy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/containers/image/signature"
|
||||
"github.com/containers/image/transports"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// createSignature creates a new signature of manifest at (identified by) dest using keyIdentity.
|
||||
func createSignature(dest types.ImageDestination, manifest []byte, keyIdentity string, reportWriter io.Writer) ([]byte, error) {
|
||||
mech, err := signature.NewGPGSigningMechanism()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error initializing GPG")
|
||||
}
|
||||
defer mech.Close()
|
||||
if err := mech.SupportsSigning(); err != nil {
|
||||
return nil, errors.Wrap(err, "Signing not supported")
|
||||
}
|
||||
|
||||
dockerReference := dest.Reference().DockerReference()
|
||||
if dockerReference == nil {
|
||||
return nil, errors.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(dest.Reference()))
|
||||
}
|
||||
|
||||
fmt.Fprintf(reportWriter, "Signing manifest\n")
|
||||
newSig, err := signature.SignDockerManifest(manifest, dockerReference.String(), mech, keyIdentity)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error creating signature")
|
||||
}
|
||||
return newSig, nil
|
||||
}
|
72
vendor/github.com/containers/image/copy/sign_test.go
generated
vendored
Normal file
72
vendor/github.com/containers/image/copy/sign_test.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
package copy
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/directory"
|
||||
"github.com/containers/image/docker"
|
||||
"github.com/containers/image/manifest"
|
||||
"github.com/containers/image/signature"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
testGPGHomeDirectory = "../signature/fixtures"
|
||||
// TestKeyFingerprint is the fingerprint of the private key in testGPGHomeDirectory.
|
||||
// Keep this in sync with signature/fixtures_info_test.go
|
||||
testKeyFingerprint = "1D8230F6CDB6A06716E414C1DB72F2188BB46CC8"
|
||||
)
|
||||
|
||||
func TestCreateSignature(t *testing.T) {
|
||||
manifestBlob := []byte("Something")
|
||||
manifestDigest, err := manifest.Digest(manifestBlob)
|
||||
require.NoError(t, err)
|
||||
|
||||
mech, _, err := signature.NewEphemeralGPGSigningMechanism([]byte{})
|
||||
require.NoError(t, err)
|
||||
defer mech.Close()
|
||||
if err := mech.SupportsSigning(); err != nil {
|
||||
t.Skipf("Signing not supported: %v", err)
|
||||
}
|
||||
|
||||
os.Setenv("GNUPGHOME", testGPGHomeDirectory)
|
||||
defer os.Unsetenv("GNUPGHOME")
|
||||
|
||||
// Signing a directory: reference, which does not have a DockerRefrence(), fails.
|
||||
tempDir, err := ioutil.TempDir("", "signature-dir-dest")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
dirRef, err := directory.NewReference(tempDir)
|
||||
require.NoError(t, err)
|
||||
dirDest, err := dirRef.NewImageDestination(nil)
|
||||
require.NoError(t, err)
|
||||
defer dirDest.Close()
|
||||
_, err = createSignature(dirDest, manifestBlob, testKeyFingerprint, ioutil.Discard)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Set up a docker: reference
|
||||
dockerRef, err := docker.ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
dockerDest, err := dockerRef.NewImageDestination(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist"})
|
||||
assert.NoError(t, err)
|
||||
defer dockerDest.Close()
|
||||
|
||||
// Signing with an unknown key fails
|
||||
_, err = createSignature(dockerDest, manifestBlob, "this key does not exist", ioutil.Discard)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Success
|
||||
mech, err = signature.NewGPGSigningMechanism()
|
||||
require.NoError(t, err)
|
||||
defer mech.Close()
|
||||
sig, err := createSignature(dockerDest, manifestBlob, testKeyFingerprint, ioutil.Discard)
|
||||
require.NoError(t, err)
|
||||
verified, err := signature.VerifyDockerManifestSignature(sig, manifestBlob, "docker.io/library/busybox:latest", mech, testKeyFingerprint)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "docker.io/library/busybox:latest", verified.DockerReference)
|
||||
assert.Equal(t, manifestDigest, verified.DockerManifestDigest)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue