mirror of
https://github.com/project-zot/zot.git
synced 2026-06-16 04:17:55 +08:00
feat: add additional manifest validations (#1609)
Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
This commit is contained in:
@@ -51,6 +51,7 @@ import (
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/meta/repodb"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
storageCommon "zotregistry.io/zot/pkg/storage/common"
|
||||
"zotregistry.io/zot/pkg/test/inject"
|
||||
)
|
||||
|
||||
@@ -1020,6 +1021,11 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate manifest
|
||||
if err := storageCommon.ValidateManifestSchema(manifestBlob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if img.Reference == "" {
|
||||
img.Reference = godigest.FromBytes(manifestBlob).String()
|
||||
}
|
||||
@@ -1886,6 +1892,8 @@ func GetRandomMultiarchImage(reference string) (MultiarchImage, error) {
|
||||
return MultiarchImage{}, err
|
||||
}
|
||||
|
||||
index.SchemaVersion = 2
|
||||
|
||||
return MultiarchImage{
|
||||
Index: index, Images: images, Reference: reference,
|
||||
}, err
|
||||
@@ -1905,6 +1913,8 @@ func GetMultiarchImageForImages(reference string, images []Image) MultiarchImage
|
||||
images[i].Reference = getManifestDigest(image.Manifest).String()
|
||||
}
|
||||
|
||||
index.SchemaVersion = 2
|
||||
|
||||
return MultiarchImage{Index: index, Images: images, Reference: reference}
|
||||
}
|
||||
|
||||
@@ -1940,6 +1950,11 @@ func UploadMultiarchImage(multiImage MultiarchImage, baseURL string, repo string
|
||||
return err
|
||||
}
|
||||
|
||||
// validate manifest
|
||||
if err := storageCommon.ValidateImageIndexSchema(indexBlob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
SetHeader("Content-type", ispec.MediaTypeImageIndex).
|
||||
SetBody(indexBlob).
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
notconfig "github.com/notaryproject/notation-go/config"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -377,7 +378,125 @@ func TestUploadBlob(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadMultiarchImage(t *testing.T) {
|
||||
Convey("make controller", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
conf.Storage.RootDirectory = t.TempDir()
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlrManager := test.NewControllerManager(ctlr)
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
layerBlob := []byte("test")
|
||||
|
||||
img := test.Image{
|
||||
Layers: [][]byte{
|
||||
layerBlob,
|
||||
},
|
||||
Manifest: ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
Digest: godigest.FromBytes(layerBlob),
|
||||
Size: int64(len(layerBlob)),
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
},
|
||||
},
|
||||
Config: ispec.DescriptorEmptyJSON,
|
||||
},
|
||||
Config: ispec.Image{},
|
||||
}
|
||||
|
||||
manifestBuf, err := json.Marshal(img.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Multiarch image uploaded successfully", func() {
|
||||
err = test.UploadMultiarchImage(test.MultiarchImage{
|
||||
Index: ispec.Index{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
Manifests: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromBytes(manifestBuf),
|
||||
Size: int64(len(manifestBuf)),
|
||||
},
|
||||
},
|
||||
},
|
||||
Images: []test.Image{img},
|
||||
Reference: "index",
|
||||
}, baseURL, "test")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Multiarch image without schemaVersion should fail validation", func() {
|
||||
err = test.UploadMultiarchImage(test.MultiarchImage{
|
||||
Index: ispec.Index{
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
Manifests: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromBytes(manifestBuf),
|
||||
Size: int64(len(manifestBuf)),
|
||||
},
|
||||
},
|
||||
},
|
||||
Images: []test.Image{img},
|
||||
Reference: "index",
|
||||
}, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestUploadImage(t *testing.T) {
|
||||
Convey("Manifest without schemaVersion should fail validation", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
conf.Storage.RootDirectory = t.TempDir()
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlrManager := test.NewControllerManager(ctlr)
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
layerBlob := []byte("test")
|
||||
|
||||
img := test.Image{
|
||||
Layers: [][]byte{
|
||||
layerBlob,
|
||||
},
|
||||
Manifest: ispec.Manifest{
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
Digest: godigest.FromBytes(layerBlob),
|
||||
Size: int64(len(layerBlob)),
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
},
|
||||
},
|
||||
Config: ispec.DescriptorEmptyJSON,
|
||||
},
|
||||
Config: ispec.Image{},
|
||||
}
|
||||
|
||||
err := test.UploadImage(img, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Post request results in an error", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
@@ -465,6 +584,19 @@ func TestUploadImage(t *testing.T) {
|
||||
Layers: [][]byte{
|
||||
layerBlob,
|
||||
},
|
||||
Manifest: ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
Digest: godigest.FromBytes(layerBlob),
|
||||
Size: int64(len(layerBlob)),
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
},
|
||||
},
|
||||
Config: ispec.DescriptorEmptyJSON,
|
||||
},
|
||||
Config: ispec.Image{},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user