|
@@ -19,6 +19,7 @@ package images
|
|
|
import (
|
|
|
"context"
|
|
|
"encoding/json"
|
|
|
+ "fmt"
|
|
|
"sort"
|
|
|
"time"
|
|
|
|
|
@@ -154,6 +155,10 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ if err := validateMediaType(p, desc.MediaType); err != nil {
|
|
|
+ return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
|
|
|
+ }
|
|
|
+
|
|
|
var manifest ocispec.Manifest
|
|
|
if err := json.Unmarshal(p, &manifest); err != nil {
|
|
|
return nil, err
|
|
@@ -194,6 +199,10 @@ func Manifest(ctx context.Context, provider content.Provider, image ocispec.Desc
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ if err := validateMediaType(p, desc.MediaType); err != nil {
|
|
|
+ return nil, errors.Wrapf(err, "manifest: invalid desc %s", desc.Digest)
|
|
|
+ }
|
|
|
+
|
|
|
var idx ocispec.Index
|
|
|
if err := json.Unmarshal(p, &idx); err != nil {
|
|
|
return nil, err
|
|
@@ -336,6 +345,10 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ if err := validateMediaType(p, desc.MediaType); err != nil {
|
|
|
+ return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
|
|
|
+ }
|
|
|
+
|
|
|
// TODO(stevvooe): We just assume oci manifest, for now. There may be
|
|
|
// subtle differences from the docker version.
|
|
|
var manifest ocispec.Manifest
|
|
@@ -351,6 +364,10 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ if err := validateMediaType(p, desc.MediaType); err != nil {
|
|
|
+ return nil, errors.Wrapf(err, "children: invalid desc %s", desc.Digest)
|
|
|
+ }
|
|
|
+
|
|
|
var index ocispec.Index
|
|
|
if err := json.Unmarshal(p, &index); err != nil {
|
|
|
return nil, err
|
|
@@ -368,6 +385,44 @@ func Children(ctx context.Context, provider content.Provider, desc ocispec.Descr
|
|
|
return descs, nil
|
|
|
}
|
|
|
|
|
|
+// unknownDocument represents a manifest, manifest list, or index that has not
|
|
|
+// yet been validated.
|
|
|
+type unknownDocument struct {
|
|
|
+ MediaType string `json:"mediaType,omitempty"`
|
|
|
+ Config json.RawMessage `json:"config,omitempty"`
|
|
|
+ Layers json.RawMessage `json:"layers,omitempty"`
|
|
|
+ Manifests json.RawMessage `json:"manifests,omitempty"`
|
|
|
+ FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1
|
|
|
+}
|
|
|
+
|
|
|
+// validateMediaType returns an error if the byte slice is invalid JSON or if
|
|
|
+// the media type identifies the blob as one format but it contains elements of
|
|
|
+// another format.
|
|
|
+func validateMediaType(b []byte, mt string) error {
|
|
|
+ var doc unknownDocument
|
|
|
+ if err := json.Unmarshal(b, &doc); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if len(doc.FSLayers) != 0 {
|
|
|
+ return fmt.Errorf("media-type: schema 1 not supported")
|
|
|
+ }
|
|
|
+ switch mt {
|
|
|
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
|
|
+ if len(doc.Manifests) != 0 ||
|
|
|
+ doc.MediaType == MediaTypeDockerSchema2ManifestList ||
|
|
|
+ doc.MediaType == ocispec.MediaTypeImageIndex {
|
|
|
+ return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
|
|
|
+ }
|
|
|
+ case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
|
|
+ if len(doc.Config) != 0 || len(doc.Layers) != 0 ||
|
|
|
+ doc.MediaType == MediaTypeDockerSchema2Manifest ||
|
|
|
+ doc.MediaType == ocispec.MediaTypeImageManifest {
|
|
|
+ return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
// RootFS returns the unpacked diffids that make up and images rootfs.
|
|
|
//
|
|
|
// These are used to verify that a set of layers unpacked to the expected
|