mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
refactor: move pkg/extensions/search/common/oci_layout.go under pkg/test/ (#1325)
Signed-off-by: Nicol Draghici <idraghic@cisco.com>
This commit is contained in:
parent
f35ff53146
commit
3510ef0fb0
7 changed files with 517 additions and 1032 deletions
|
@ -2390,7 +2390,7 @@ func TestGetImageManifest(t *testing.T) {
|
|||
storeController := storage.StoreController{
|
||||
DefaultStore: mockImageStore,
|
||||
}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, _, err := olu.GetImageManifest("nonexistent-repo", "latest")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
@ -2406,7 +2406,7 @@ func TestGetImageManifest(t *testing.T) {
|
|||
storeController := storage.StoreController{
|
||||
DefaultStore: mockImageStore,
|
||||
}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, _, err := olu.GetImageManifest("test-repo", "latest") //nolint:goconst
|
||||
So(err, ShouldNotBeNil)
|
||||
|
@ -3068,7 +3068,7 @@ func TestGetRepositories(t *testing.T) {
|
|||
DefaultStore: mockImageStore,
|
||||
SubStore: map[string]storage.ImageStore{"test": mockImageStore},
|
||||
}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
repoList, err := olu.GetRepositories()
|
||||
So(repoList, ShouldBeEmpty)
|
||||
|
@ -3078,7 +3078,7 @@ func TestGetRepositories(t *testing.T) {
|
|||
DefaultStore: mocks.MockedImageStore{},
|
||||
SubStore: map[string]storage.ImageStore{"test": mockImageStore},
|
||||
}
|
||||
olu = common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
olu = NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
repoList, err = olu.GetRepositories()
|
||||
So(repoList, ShouldBeEmpty)
|
||||
|
@ -3388,7 +3388,7 @@ func TestGlobalSearch(t *testing.T) {
|
|||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
olu := common.NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
olu := NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
|
||||
// Initialize the objects containing the expected data
|
||||
repos, err := olu.GetRepositories()
|
||||
|
@ -3717,7 +3717,7 @@ func TestGlobalSearch(t *testing.T) {
|
|||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
olu := common.NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
olu := NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
|
||||
// Initialize the objects containing the expected data
|
||||
repos, err := olu.GetRepositories()
|
||||
|
@ -5998,320 +5998,6 @@ func updateManifestConfig(manifest ispec.Manifest, config ispec.Image) (ispec.Ma
|
|||
return manifest, err
|
||||
}
|
||||
|
||||
func TestBaseOciLayoutUtils(t *testing.T) {
|
||||
manifestDigest := GetTestBlobDigest("zot-test", "config").String()
|
||||
|
||||
Convey("GetImageManifestSize fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageManifestSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetImageConfigSize: fail GetImageBlobManifest", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageConfigSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetImageConfigSize: config GetBlobContent fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
if digest.String() == manifestDigest {
|
||||
return []byte{}, ErrTestError
|
||||
}
|
||||
|
||||
return []byte(
|
||||
`
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": manifestDigest,
|
||||
"size": 1476
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "` + GetTestBlobDigest("zot-test", "layer").String() + `",
|
||||
"size": 76097157
|
||||
}
|
||||
]
|
||||
}`), nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageConfigSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetRepoLastUpdated: config GetBlobContent fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err := olu.GetRepoLastUpdated("")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageTagsWithTimestamp: GetImageBlobManifest fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{Annotations: map[string]string{ispec.AnnotationRefName: "w"}}, {},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return nil, ErrTestError
|
||||
},
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetImageTagsWithTimestamp("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageTagsWithTimestamp: GetImageInfo fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{Annotations: map[string]string{ispec.AnnotationRefName: "w"}}, {},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: "configDigest",
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{},
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
if digest.String() == "configDigest" {
|
||||
return nil, ErrTestError
|
||||
}
|
||||
|
||||
return manifestBlob, nil
|
||||
},
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetImageTagsWithTimestamp("repo")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetExpandedRepoInfo: fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{},
|
||||
{
|
||||
Annotations: map[string]string{
|
||||
ispec.AnnotationRefName: "w",
|
||||
ispec.AnnotationVendor: "vend",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
Annotations: map[string]string{
|
||||
ispec.AnnotationRefName: "w",
|
||||
ispec.AnnotationVendor: "vend",
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{},
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return nil, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// GetRepoLastUpdated fails
|
||||
mockStoreController = mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController = storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu = common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// anotations
|
||||
|
||||
mockStoreController = mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return manifestBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController = storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu = common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageInfo fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err := olu.GetImageInfo("", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("CheckManifestSignature: notation", t, func() {
|
||||
// GetReferrers - fails => checkNotarySignature returns false
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetImageManifestFn: func(name, reference string) ([]byte, godigest.Digest, string, error) {
|
||||
return []byte{}, "", "", zerr.ErrRepoNotFound
|
||||
},
|
||||
GetReferrersFn: func(name string, digest godigest.Digest, mediaTypes []string) (ispec.Index, error) {
|
||||
return ispec.Index{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := common.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
check := olu.CheckManifestSignature("rep", godigest.FromString(""))
|
||||
So(check, ShouldBeFalse)
|
||||
|
||||
// checkNotarySignature -> true
|
||||
dir := t.TempDir()
|
||||
|
||||
port := GetFreePort()
|
||||
baseURL := GetBaseURL(port)
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
conf.Storage.RootDirectory = dir
|
||||
defaultVal := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||
}
|
||||
|
||||
conf.Extensions.Search.CVE = nil
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlrManager := NewControllerManager(ctlr)
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
// push test image to repo
|
||||
config, layers, manifest, err := GetImageComponents(100)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
layersSize1 := 0
|
||||
for _, l := range layers {
|
||||
layersSize1 += len(l)
|
||||
}
|
||||
|
||||
repo := "repo"
|
||||
tag := "1.0.1"
|
||||
err = UploadImage(
|
||||
Image{
|
||||
Manifest: manifest,
|
||||
Config: config,
|
||||
Layers: layers,
|
||||
Reference: tag,
|
||||
},
|
||||
baseURL,
|
||||
repo,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
olu = common.NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
manifestList, err := olu.GetImageManifests(repo)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(manifestList), ShouldEqual, 1)
|
||||
|
||||
isSigned := olu.CheckManifestSignature(repo, manifestList[0].Digest)
|
||||
So(isSigned, ShouldBeFalse)
|
||||
|
||||
err = SignImageUsingNotary(fmt.Sprintf("%s:%s", repo, tag), port)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSigned = olu.CheckManifestSignature(repo, manifestList[0].Digest)
|
||||
So(isSigned, ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSearchSize(t *testing.T) {
|
||||
Convey("Repo sizes", t, func() {
|
||||
port := GetFreePort()
|
||||
|
|
|
@ -4,20 +4,14 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
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"
|
||||
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/search/common"
|
||||
"zotregistry.io/zot/pkg/extensions/search/convert"
|
||||
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
||||
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
|
||||
|
@ -25,7 +19,6 @@ import (
|
|||
"zotregistry.io/zot/pkg/meta/bolt"
|
||||
"zotregistry.io/zot/pkg/meta/repodb"
|
||||
boltdb_wrapper "zotregistry.io/zot/pkg/meta/repodb/boltdb-wrapper"
|
||||
. "zotregistry.io/zot/pkg/test"
|
||||
"zotregistry.io/zot/pkg/test/mocks"
|
||||
)
|
||||
|
||||
|
@ -340,274 +333,3 @@ func TestUpdateLastUpdatedTimestam(t *testing.T) {
|
|||
So(*img.LastUpdated, ShouldResemble, after)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildImageInfo(t *testing.T) {
|
||||
rootDir := t.TempDir()
|
||||
|
||||
port := GetFreePort()
|
||||
baseURL := GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
conf.Storage.RootDirectory = rootDir
|
||||
defaultVal := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||
}
|
||||
|
||||
conf.Extensions.Search.CVE = nil
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
ctlrManager := NewControllerManager(ctlr)
|
||||
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
olu := &common.BaseOciLayoutUtils{
|
||||
StoreController: ctlr.StoreController,
|
||||
Log: ctlr.Log,
|
||||
}
|
||||
|
||||
Convey("Check image summary when the image has no history", t, func() {
|
||||
imageName := "nohistory"
|
||||
|
||||
config := ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{},
|
||||
},
|
||||
Author: "ZotUser",
|
||||
}
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
layerDigest := godigest.FromString(imageName)
|
||||
layerblob := []byte(imageName)
|
||||
schemaVersion := 2
|
||||
ispecManifest := ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: configDigest,
|
||||
Size: int64(len(configBlob)),
|
||||
},
|
||||
Layers: []ispec.Descriptor{ // just 1 layer in manifest
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: layerDigest,
|
||||
Size: int64(len(layerblob)),
|
||||
},
|
||||
},
|
||||
}
|
||||
manifestLayersSize := ispecManifest.Layers[0].Size
|
||||
manifestBlob, err := json.Marshal(ispecManifest)
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := godigest.FromBytes(manifestBlob)
|
||||
err = UploadImage(
|
||||
Image{
|
||||
Manifest: ispecManifest,
|
||||
Config: config,
|
||||
Layers: [][]byte{
|
||||
layerblob,
|
||||
},
|
||||
Reference: "0.0.1",
|
||||
},
|
||||
baseURL,
|
||||
imageName,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
imageConfig, err := olu.GetImageConfigInfo(imageName, manifestDigest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSigned := false
|
||||
|
||||
imageSummary := convert.BuildImageInfo(imageName, imageName, manifestDigest, ispecManifest,
|
||||
imageConfig, isSigned)
|
||||
|
||||
So(len(imageSummary.Manifests[0].Layers), ShouldEqual, len(ispecManifest.Layers))
|
||||
imageSummaryLayerSize, err := strconv.Atoi(*imageSummary.Size)
|
||||
So(err, ShouldBeNil)
|
||||
So(imageSummaryLayerSize, ShouldEqual, manifestLayersSize)
|
||||
})
|
||||
|
||||
Convey("Check image summary when layer count matche history entries", t, func() {
|
||||
imageName := "valid"
|
||||
|
||||
config := ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{},
|
||||
},
|
||||
Author: "ZotUser",
|
||||
History: []ispec.History{ // should contain 3 elements, 2 of which corresponding to layers
|
||||
{
|
||||
EmptyLayer: false,
|
||||
},
|
||||
{
|
||||
EmptyLayer: false,
|
||||
},
|
||||
{
|
||||
EmptyLayer: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
layerDigest := godigest.FromString("layer1")
|
||||
layerblob := []byte("layer1")
|
||||
layerDigest2 := godigest.FromString("layer2")
|
||||
layerblob2 := []byte("layer2")
|
||||
schemaVersion := 2
|
||||
ispecManifest := ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: configDigest,
|
||||
Size: int64(len(configBlob)),
|
||||
},
|
||||
Layers: []ispec.Descriptor{ // just 1 layer in manifest
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: layerDigest,
|
||||
Size: int64(len(layerblob)),
|
||||
},
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: layerDigest2,
|
||||
Size: int64(len(layerblob2)),
|
||||
},
|
||||
},
|
||||
}
|
||||
manifestLayersSize := ispecManifest.Layers[0].Size + ispecManifest.Layers[1].Size
|
||||
manifestBlob, err := json.Marshal(ispecManifest)
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := godigest.FromBytes(manifestBlob)
|
||||
err = UploadImage(
|
||||
Image{
|
||||
Manifest: ispecManifest,
|
||||
Config: config,
|
||||
Layers: [][]byte{
|
||||
layerblob,
|
||||
layerblob2,
|
||||
},
|
||||
Reference: "0.0.1",
|
||||
},
|
||||
baseURL,
|
||||
imageName,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
imageConfig, err := olu.GetImageConfigInfo(imageName, manifestDigest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSigned := false
|
||||
|
||||
imageSummary := convert.BuildImageInfo(imageName, imageName, manifestDigest, ispecManifest,
|
||||
imageConfig, isSigned)
|
||||
|
||||
So(len(imageSummary.Manifests[0].Layers), ShouldEqual, len(ispecManifest.Layers))
|
||||
imageSummaryLayerSize, err := strconv.Atoi(*imageSummary.Size)
|
||||
So(err, ShouldBeNil)
|
||||
So(imageSummaryLayerSize, ShouldEqual, manifestLayersSize)
|
||||
})
|
||||
|
||||
Convey("Check image summary when layer count does not match history", t, func() {
|
||||
imageName := "invalid"
|
||||
|
||||
config := ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{},
|
||||
},
|
||||
Author: "ZotUser",
|
||||
History: []ispec.History{ // should contain 3 elements, 2 of which corresponding to layers
|
||||
{
|
||||
EmptyLayer: false,
|
||||
},
|
||||
{
|
||||
EmptyLayer: false,
|
||||
},
|
||||
{
|
||||
EmptyLayer: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
layerDigest := godigest.FromString(imageName)
|
||||
layerblob := []byte(imageName)
|
||||
schemaVersion := 2
|
||||
ispecManifest := ispec.Manifest{
|
||||
Versioned: specs.Versioned{
|
||||
SchemaVersion: schemaVersion,
|
||||
},
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: configDigest,
|
||||
Size: int64(len(configBlob)),
|
||||
},
|
||||
Layers: []ispec.Descriptor{ // just 1 layer in manifest
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: layerDigest,
|
||||
Size: int64(len(layerblob)),
|
||||
},
|
||||
},
|
||||
}
|
||||
manifestLayersSize := ispecManifest.Layers[0].Size
|
||||
manifestBlob, err := json.Marshal(ispecManifest)
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := godigest.FromBytes(manifestBlob)
|
||||
err = UploadImage(
|
||||
Image{
|
||||
Manifest: ispecManifest,
|
||||
Config: config,
|
||||
Layers: [][]byte{
|
||||
layerblob,
|
||||
},
|
||||
Reference: "0.0.1",
|
||||
},
|
||||
baseURL,
|
||||
imageName,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
imageConfig, err := olu.GetImageConfigInfo(imageName, manifestDigest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSigned := false
|
||||
|
||||
imageSummary := convert.BuildImageInfo(imageName, imageName, manifestDigest, ispecManifest,
|
||||
imageConfig, isSigned)
|
||||
|
||||
So(len(imageSummary.Manifests[0].Layers), ShouldEqual, len(ispecManifest.Layers))
|
||||
imageSummaryLayerSize, err := strconv.Atoi(*imageSummary.Size)
|
||||
So(err, ShouldBeNil)
|
||||
So(imageSummaryLayerSize, ShouldEqual, manifestLayersSize)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,198 +3,12 @@ package convert
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/extensions/search/common"
|
||||
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
||||
func BuildImageInfo(repo string, tag string, manifestDigest godigest.Digest,
|
||||
manifest ispec.Manifest, imageConfig ispec.Image, isSigned bool,
|
||||
) *gql_generated.ImageSummary {
|
||||
layers := []*gql_generated.LayerSummary{}
|
||||
size := int64(0)
|
||||
log := log.NewLogger("debug", "")
|
||||
allHistory := []*gql_generated.LayerHistory{}
|
||||
formattedManifestDigest := manifestDigest.String()
|
||||
configDigest := manifest.Config.Digest.String()
|
||||
annotations := common.GetAnnotations(manifest.Annotations, imageConfig.Config.Labels)
|
||||
lastUpdated := common.GetImageLastUpdated(imageConfig)
|
||||
|
||||
authors := annotations.Authors
|
||||
if authors == "" {
|
||||
authors = imageConfig.Author
|
||||
}
|
||||
|
||||
history := imageConfig.History
|
||||
if len(history) == 0 {
|
||||
for _, layer := range manifest.Layers {
|
||||
size += layer.Size
|
||||
digest := layer.Digest.String()
|
||||
layerSize := strconv.FormatInt(layer.Size, 10)
|
||||
|
||||
layer := &gql_generated.LayerSummary{
|
||||
Size: &layerSize,
|
||||
Digest: &digest,
|
||||
}
|
||||
|
||||
layers = append(
|
||||
layers,
|
||||
layer,
|
||||
)
|
||||
|
||||
allHistory = append(allHistory, &gql_generated.LayerHistory{
|
||||
Layer: layer,
|
||||
HistoryDescription: &gql_generated.HistoryDescription{},
|
||||
})
|
||||
}
|
||||
|
||||
formattedSize := strconv.FormatInt(size, 10)
|
||||
|
||||
imageInfo := &gql_generated.ImageSummary{
|
||||
RepoName: &repo,
|
||||
Tag: &tag,
|
||||
Manifests: []*gql_generated.ManifestSummary{
|
||||
{
|
||||
Digest: &formattedManifestDigest,
|
||||
ConfigDigest: &configDigest,
|
||||
Layers: layers,
|
||||
Size: &formattedSize,
|
||||
History: allHistory,
|
||||
Platform: &gql_generated.Platform{
|
||||
Os: &imageConfig.OS,
|
||||
Arch: &imageConfig.Architecture,
|
||||
},
|
||||
LastUpdated: &lastUpdated,
|
||||
},
|
||||
},
|
||||
Size: &formattedSize,
|
||||
Description: &annotations.Description,
|
||||
Title: &annotations.Title,
|
||||
Documentation: &annotations.Documentation,
|
||||
Licenses: &annotations.Licenses,
|
||||
Labels: &annotations.Labels,
|
||||
Source: &annotations.Source,
|
||||
Authors: &authors,
|
||||
Vendor: &annotations.Vendor,
|
||||
LastUpdated: &lastUpdated,
|
||||
IsSigned: &isSigned,
|
||||
}
|
||||
|
||||
return imageInfo
|
||||
}
|
||||
|
||||
// iterator over manifest layers
|
||||
var layersIterator int
|
||||
// since we are appending pointers, it is important to iterate with an index over slice
|
||||
for i := range history {
|
||||
allHistory = append(allHistory, &gql_generated.LayerHistory{
|
||||
HistoryDescription: &gql_generated.HistoryDescription{
|
||||
Created: history[i].Created,
|
||||
CreatedBy: &history[i].CreatedBy,
|
||||
Author: &history[i].Author,
|
||||
Comment: &history[i].Comment,
|
||||
EmptyLayer: &history[i].EmptyLayer,
|
||||
},
|
||||
})
|
||||
|
||||
if history[i].EmptyLayer {
|
||||
continue
|
||||
}
|
||||
|
||||
if layersIterator+1 > len(manifest.Layers) {
|
||||
formattedSize := strconv.FormatInt(size, 10)
|
||||
|
||||
log.Error().Err(zerr.ErrBadLayerCount).Msg("error on creating layer history for ImageSummary")
|
||||
|
||||
return &gql_generated.ImageSummary{
|
||||
RepoName: &repo,
|
||||
Tag: &tag,
|
||||
Manifests: []*gql_generated.ManifestSummary{
|
||||
{
|
||||
Digest: &formattedManifestDigest,
|
||||
ConfigDigest: &configDigest,
|
||||
Layers: layers,
|
||||
Size: &formattedSize,
|
||||
History: allHistory,
|
||||
Platform: &gql_generated.Platform{
|
||||
Os: &imageConfig.OS,
|
||||
Arch: &imageConfig.Architecture,
|
||||
},
|
||||
LastUpdated: &lastUpdated,
|
||||
},
|
||||
},
|
||||
Size: &formattedSize,
|
||||
Description: &annotations.Description,
|
||||
Vendor: &annotations.Vendor,
|
||||
Title: &annotations.Title,
|
||||
Documentation: &annotations.Documentation,
|
||||
Licenses: &annotations.Licenses,
|
||||
Labels: &annotations.Labels,
|
||||
Source: &annotations.Source,
|
||||
Authors: &authors,
|
||||
LastUpdated: &lastUpdated,
|
||||
IsSigned: &isSigned,
|
||||
}
|
||||
}
|
||||
|
||||
size += manifest.Layers[layersIterator].Size
|
||||
digest := manifest.Layers[layersIterator].Digest.String()
|
||||
layerSize := strconv.FormatInt(manifest.Layers[layersIterator].Size, 10)
|
||||
|
||||
layer := &gql_generated.LayerSummary{
|
||||
Size: &layerSize,
|
||||
Digest: &digest,
|
||||
}
|
||||
|
||||
layers = append(
|
||||
layers,
|
||||
layer,
|
||||
)
|
||||
|
||||
allHistory[i].Layer = layer
|
||||
|
||||
layersIterator++
|
||||
}
|
||||
|
||||
formattedSize := strconv.FormatInt(size, 10)
|
||||
|
||||
imageInfo := &gql_generated.ImageSummary{
|
||||
RepoName: &repo,
|
||||
Tag: &tag,
|
||||
Manifests: []*gql_generated.ManifestSummary{
|
||||
{
|
||||
Digest: &formattedManifestDigest,
|
||||
ConfigDigest: &configDigest,
|
||||
Layers: layers,
|
||||
History: allHistory,
|
||||
Platform: &gql_generated.Platform{
|
||||
Os: &imageConfig.OS,
|
||||
Arch: &imageConfig.Architecture,
|
||||
},
|
||||
Size: &formattedSize,
|
||||
LastUpdated: &lastUpdated,
|
||||
},
|
||||
},
|
||||
Size: &formattedSize,
|
||||
Description: &annotations.Description,
|
||||
Title: &annotations.Title,
|
||||
Documentation: &annotations.Documentation,
|
||||
Licenses: &annotations.Licenses,
|
||||
Labels: &annotations.Labels,
|
||||
Source: &annotations.Source,
|
||||
Vendor: &annotations.Vendor,
|
||||
Authors: &authors,
|
||||
LastUpdated: &lastUpdated,
|
||||
IsSigned: &isSigned,
|
||||
}
|
||||
|
||||
return imageInfo
|
||||
}
|
||||
|
||||
// updateRepoBlobsMap adds all the image blobs and their respective size to the repo blobs map
|
||||
// and returnes the total size of the image.
|
||||
func updateRepoBlobsMap(imageBlobs map[string]int64, repoBlob2Size map[string]int64) int64 {
|
||||
|
|
|
@ -1213,67 +1213,3 @@ func getReferrers(repoDB repodb.RepoDB, repo string, referredDigest string, arti
|
|||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// get passed context from authzHandler and filter out repos based on permissions.
|
||||
func userAvailableRepos(ctx context.Context, repoList []string) ([]string, error) {
|
||||
var availableRepos []string
|
||||
|
||||
// authz request context (set in authz middleware)
|
||||
acCtx, err := localCtx.GetAccessControlContext(ctx)
|
||||
if err != nil {
|
||||
err := zerr.ErrBadType
|
||||
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
if acCtx != nil {
|
||||
for _, r := range repoList {
|
||||
if acCtx.IsAdmin || acCtx.CanReadRepo(r) {
|
||||
availableRepos = append(availableRepos, r)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
availableRepos = repoList
|
||||
}
|
||||
|
||||
return availableRepos, nil
|
||||
}
|
||||
|
||||
func extractImageDetails(
|
||||
ctx context.Context,
|
||||
layoutUtils common.OciLayoutUtils,
|
||||
repo, tag string, //nolint:unparam // function only called in the tests
|
||||
log log.Logger) (
|
||||
godigest.Digest, *ispec.Manifest, *ispec.Image, error,
|
||||
) {
|
||||
validRepoList, err := userAvailableRepos(ctx, []string{repo})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("unable to retrieve access token")
|
||||
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
if len(validRepoList) == 0 {
|
||||
log.Error().Err(err).Msg("user is not authorized")
|
||||
|
||||
return "", nil, nil, zerr.ErrUnauthorizedAccess
|
||||
}
|
||||
|
||||
manifest, dig, err := layoutUtils.GetImageManifest(repo, tag)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Could not retrieve image ispec manifest")
|
||||
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
digest := dig
|
||||
|
||||
imageConfig, err := layoutUtils.GetImageConfigInfo(repo, digest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Could not retrieve image config")
|
||||
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
return digest, &manifest, &imageConfig, nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -23,7 +22,6 @@ import (
|
|||
"zotregistry.io/zot/pkg/meta/bolt"
|
||||
"zotregistry.io/zot/pkg/meta/repodb"
|
||||
boltdb_wrapper "zotregistry.io/zot/pkg/meta/repodb/boltdb-wrapper"
|
||||
localCtx "zotregistry.io/zot/pkg/requestcontext"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
"zotregistry.io/zot/pkg/test/mocks"
|
||||
)
|
||||
|
@ -1422,147 +1420,6 @@ func TestGetReferrers(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestExtractImageDetails(t *testing.T) {
|
||||
Convey("repoListWithNewestImage", t, func() {
|
||||
// log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
||||
content := []byte("this is a blob5")
|
||||
testLogger := log.NewLogger("debug", "")
|
||||
layerDigest := godigest.FromBytes(content)
|
||||
config := ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
Architecture: "amd64",
|
||||
OS: "linux",
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{},
|
||||
},
|
||||
Author: "some author",
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
authzCtxKey := localCtx.GetContextKey()
|
||||
ctx = context.WithValue(ctx, authzCtxKey,
|
||||
localCtx.AccessControlContext{
|
||||
ReadGlobPatterns: map[string]bool{"*": true, "**": true},
|
||||
Username: "jane_doe",
|
||||
})
|
||||
configBlobContent, _ := json.MarshalIndent(&config, "", "\t")
|
||||
configDigest := godigest.FromBytes(configBlobContent)
|
||||
|
||||
localTestManifest := ispec.Manifest{
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: configDigest,
|
||||
Size: int64(len(configBlobContent)),
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{
|
||||
MediaType: "application/vnd.oci.image.layer.v1.tar",
|
||||
Digest: layerDigest,
|
||||
Size: int64(len(content)),
|
||||
},
|
||||
},
|
||||
}
|
||||
localTestDigestTry, _ := json.Marshal(localTestManifest)
|
||||
localTestDigest := godigest.FromBytes(localTestDigestTry)
|
||||
|
||||
Convey("extractImageDetails good workflow", func() {
|
||||
mockOlum := mocks.OciLayoutUtilsMock{
|
||||
GetImageConfigInfoFn: func(repo string, digest godigest.Digest) (
|
||||
ispec.Image, error,
|
||||
) {
|
||||
return config, nil
|
||||
},
|
||||
GetImageManifestFn: func(repo string, tag string) (
|
||||
ispec.Manifest, godigest.Digest, error,
|
||||
) {
|
||||
return localTestManifest, localTestDigest, nil
|
||||
},
|
||||
}
|
||||
resDigest, resManifest, resIspecImage, resErr := extractImageDetails(ctx,
|
||||
mockOlum, "zot-test", "latest", testLogger)
|
||||
So(string(resDigest), ShouldContainSubstring, "sha256:d004018b9f")
|
||||
So(resManifest.Config.Digest.String(), ShouldContainSubstring, configDigest.Encoded())
|
||||
|
||||
So(resIspecImage.Architecture, ShouldContainSubstring, "amd64")
|
||||
So(resErr, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("extractImageDetails bad ispec.ImageManifest", func() {
|
||||
mockOlum := mocks.OciLayoutUtilsMock{
|
||||
GetImageConfigInfoFn: func(repo string, digest godigest.Digest) (
|
||||
ispec.Image, error,
|
||||
) {
|
||||
return config, nil
|
||||
},
|
||||
GetImageManifestFn: func(repo string, tag string) (
|
||||
ispec.Manifest, godigest.Digest, error,
|
||||
) {
|
||||
return ispec.Manifest{}, localTestDigest, ErrTestError
|
||||
},
|
||||
}
|
||||
resDigest, resManifest, resIspecImage, resErr := extractImageDetails(ctx,
|
||||
mockOlum, "zot-test", "latest", testLogger)
|
||||
So(resErr, ShouldEqual, ErrTestError)
|
||||
So(string(resDigest), ShouldEqual, "")
|
||||
So(resManifest, ShouldBeNil)
|
||||
|
||||
So(resIspecImage, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("extractImageDetails bad imageConfig", func() {
|
||||
mockOlum := mocks.OciLayoutUtilsMock{
|
||||
GetImageConfigInfoFn: func(repo string, digest godigest.Digest) (
|
||||
ispec.Image, error,
|
||||
) {
|
||||
return config, nil
|
||||
},
|
||||
GetImageManifestFn: func(repo string, tag string) (
|
||||
ispec.Manifest, godigest.Digest, error,
|
||||
) {
|
||||
return localTestManifest, localTestDigest, ErrTestError
|
||||
},
|
||||
}
|
||||
resDigest, resManifest, resIspecImage, resErr := extractImageDetails(ctx,
|
||||
mockOlum, "zot-test", "latest", testLogger)
|
||||
So(string(resDigest), ShouldEqual, "")
|
||||
So(resManifest, ShouldBeNil)
|
||||
|
||||
So(resIspecImage, ShouldBeNil)
|
||||
So(resErr, ShouldEqual, ErrTestError)
|
||||
})
|
||||
|
||||
Convey("extractImageDetails without proper authz", func() {
|
||||
ctx = context.WithValue(ctx, authzCtxKey,
|
||||
localCtx.AccessControlContext{
|
||||
ReadGlobPatterns: map[string]bool{},
|
||||
Username: "jane_doe",
|
||||
})
|
||||
mockOlum := mocks.OciLayoutUtilsMock{
|
||||
GetImageConfigInfoFn: func(repo string, digest godigest.Digest) (
|
||||
ispec.Image, error,
|
||||
) {
|
||||
return config, nil
|
||||
},
|
||||
GetImageManifestFn: func(repo string, tag string) (
|
||||
ispec.Manifest, godigest.Digest, error,
|
||||
) {
|
||||
return localTestManifest, localTestDigest, ErrTestError
|
||||
},
|
||||
}
|
||||
resDigest, resManifest, resIspecImage, resErr := extractImageDetails(ctx,
|
||||
mockOlum, "zot-test", "latest", testLogger)
|
||||
So(string(resDigest), ShouldEqual, "")
|
||||
So(resManifest, ShouldBeNil)
|
||||
|
||||
So(resIspecImage, ShouldBeNil)
|
||||
So(resErr, ShouldNotBeNil)
|
||||
So(strings.ToLower(resErr.Error()), ShouldContainSubstring, "unauthorized access")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestQueryResolverErrors(t *testing.T) {
|
||||
Convey("Errors", t, func() {
|
||||
log := log.NewLogger("debug", "")
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Package common ...
|
||||
package common
|
||||
//go:build sync && scrub && metrics && search
|
||||
// +build sync,scrub,metrics,search
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -14,7 +16,8 @@ import (
|
|||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
"zotregistry.io/zot/errors"
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/extensions/search/common"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
)
|
||||
|
@ -24,14 +27,16 @@ type OciLayoutUtils interface { //nolint: interfacebloat
|
|||
GetImageManifests(repo string) ([]ispec.Descriptor, error)
|
||||
GetImageBlobManifest(repo string, digest godigest.Digest) (ispec.Manifest, error)
|
||||
GetImageInfo(repo string, configDigest godigest.Digest) (ispec.Image, error)
|
||||
GetImageTagsWithTimestamp(repo string) ([]TagInfo, error)
|
||||
GetImageTagsWithTimestamp(repo string) ([]common.TagInfo, error)
|
||||
GetImagePlatform(imageInfo ispec.Image) (string, string)
|
||||
GetImageManifestSize(repo string, manifestDigest godigest.Digest) int64
|
||||
GetRepoLastUpdated(repo string) (TagInfo, error)
|
||||
GetExpandedRepoInfo(name string) (RepoInfo, error)
|
||||
GetRepoLastUpdated(repo string) (common.TagInfo, error)
|
||||
GetExpandedRepoInfo(name string) (common.RepoInfo, error)
|
||||
GetImageConfigInfo(repo string, manifestDigest godigest.Digest) (ispec.Image, error)
|
||||
CheckManifestSignature(name string, digest godigest.Digest) bool
|
||||
GetRepositories() ([]string, error)
|
||||
ExtractImageDetails(repo string, tag string, log log.Logger) (godigest.Digest,
|
||||
*ispec.Manifest, *ispec.Image, error)
|
||||
}
|
||||
|
||||
// OciLayoutInfo ...
|
||||
|
@ -100,15 +105,15 @@ func (olu BaseOciLayoutUtils) GetImageManifests(repo string) ([]ispec.Descriptor
|
|||
|
||||
buf, err := imageStore.GetIndexContent(repo)
|
||||
if err != nil {
|
||||
if goerrors.Is(errors.ErrRepoNotFound, err) {
|
||||
if goerrors.Is(zerr.ErrRepoNotFound, err) {
|
||||
olu.Log.Error().Err(err).Msg("index.json doesn't exist")
|
||||
|
||||
return nil, errors.ErrRepoNotFound
|
||||
return nil, zerr.ErrRepoNotFound
|
||||
}
|
||||
|
||||
olu.Log.Error().Err(err).Msg("unable to open index.json")
|
||||
|
||||
return nil, errors.ErrRepoNotFound
|
||||
return nil, zerr.ErrRepoNotFound
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
|
@ -116,7 +121,7 @@ func (olu BaseOciLayoutUtils) GetImageManifests(repo string) ([]ispec.Descriptor
|
|||
if err := json.Unmarshal(buf, &index); err != nil {
|
||||
olu.Log.Error().Err(err).Str("dir", path.Join(imageStore.RootDir(), repo)).Msg("invalid JSON")
|
||||
|
||||
return nil, errors.ErrRepoNotFound
|
||||
return nil, zerr.ErrRepoNotFound
|
||||
}
|
||||
|
||||
return index.Manifests, nil
|
||||
|
@ -175,8 +180,8 @@ func (olu BaseOciLayoutUtils) GetImageInfo(repo string, configDigest godigest.Di
|
|||
}
|
||||
|
||||
// GetImageTagsWithTimestamp returns a list of image tags with timestamp available in the specified repository.
|
||||
func (olu BaseOciLayoutUtils) GetImageTagsWithTimestamp(repo string) ([]TagInfo, error) {
|
||||
tagsInfo := make([]TagInfo, 0)
|
||||
func (olu BaseOciLayoutUtils) GetImageTagsWithTimestamp(repo string) ([]common.TagInfo, error) {
|
||||
tagsInfo := make([]common.TagInfo, 0)
|
||||
|
||||
manifests, err := olu.GetImageManifests(repo)
|
||||
if err != nil {
|
||||
|
@ -204,13 +209,13 @@ func (olu BaseOciLayoutUtils) GetImageTagsWithTimestamp(repo string) ([]TagInfo,
|
|||
return tagsInfo, err
|
||||
}
|
||||
|
||||
timeStamp := GetImageLastUpdated(imageInfo)
|
||||
timeStamp := common.GetImageLastUpdated(imageInfo)
|
||||
|
||||
tagsInfo = append(tagsInfo,
|
||||
TagInfo{
|
||||
common.TagInfo{
|
||||
Name: val,
|
||||
Timestamp: timeStamp,
|
||||
Descriptor: Descriptor{
|
||||
Descriptor: common.Descriptor{
|
||||
Digest: digest,
|
||||
MediaType: manifest.MediaType,
|
||||
},
|
||||
|
@ -325,44 +330,44 @@ func (olu BaseOciLayoutUtils) GetImageConfigSize(repo string, manifestDigest god
|
|||
return imageBlobManifest.Config.Size
|
||||
}
|
||||
|
||||
func (olu BaseOciLayoutUtils) GetRepoLastUpdated(repo string) (TagInfo, error) {
|
||||
func (olu BaseOciLayoutUtils) GetRepoLastUpdated(repo string) (common.TagInfo, error) {
|
||||
tagsInfo, err := olu.GetImageTagsWithTimestamp(repo)
|
||||
if err != nil || len(tagsInfo) == 0 {
|
||||
return TagInfo{}, err
|
||||
return common.TagInfo{}, err
|
||||
}
|
||||
|
||||
latestTag := GetLatestTag(tagsInfo)
|
||||
latestTag := common.GetLatestTag(tagsInfo)
|
||||
|
||||
return latestTag, nil
|
||||
}
|
||||
|
||||
func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, error) {
|
||||
repo := RepoInfo{}
|
||||
func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (common.RepoInfo, error) {
|
||||
repo := common.RepoInfo{}
|
||||
repoBlob2Size := make(map[string]int64, 10)
|
||||
|
||||
// made up of all manifests, configs and image layers
|
||||
repoSize := int64(0)
|
||||
|
||||
imageSummaries := make([]ImageSummary, 0)
|
||||
imageSummaries := make([]common.ImageSummary, 0)
|
||||
|
||||
manifestList, err := olu.GetImageManifests(repoName)
|
||||
if err != nil {
|
||||
olu.Log.Error().Err(err).Msg("error getting image manifests")
|
||||
|
||||
return RepoInfo{}, err
|
||||
return common.RepoInfo{}, err
|
||||
}
|
||||
|
||||
lastUpdatedTag, err := olu.GetRepoLastUpdated(repoName)
|
||||
if err != nil {
|
||||
olu.Log.Error().Err(err).Msgf("can't get last updated manifest for repo: %s", repoName)
|
||||
|
||||
return RepoInfo{}, err
|
||||
return common.RepoInfo{}, err
|
||||
}
|
||||
|
||||
repoVendorsSet := make(map[string]bool, len(manifestList))
|
||||
repoPlatformsSet := make(map[string]Platform, len(manifestList))
|
||||
repoPlatformsSet := make(map[string]common.Platform, len(manifestList))
|
||||
|
||||
var lastUpdatedImageSummary ImageSummary
|
||||
var lastUpdatedImageSummary common.ImageSummary
|
||||
|
||||
for _, man := range manifestList {
|
||||
imageLayersSize := int64(0)
|
||||
|
@ -379,7 +384,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
if err != nil {
|
||||
olu.Log.Error().Err(err).Msg("error getting image manifest blob")
|
||||
|
||||
return RepoInfo{}, err
|
||||
return common.RepoInfo{}, err
|
||||
}
|
||||
|
||||
isSigned := olu.CheckManifestSignature(repoName, man.Digest)
|
||||
|
@ -399,7 +404,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
}
|
||||
|
||||
opSys, arch := olu.GetImagePlatform(imageConfigInfo)
|
||||
platform := Platform{
|
||||
platform := common.Platform{
|
||||
Os: opSys,
|
||||
Arch: arch,
|
||||
}
|
||||
|
@ -409,10 +414,10 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
repoPlatformsSet[platformString] = platform
|
||||
}
|
||||
|
||||
layers := make([]LayerSummary, 0)
|
||||
layers := make([]common.LayerSummary, 0)
|
||||
|
||||
for _, layer := range manifest.Layers {
|
||||
layerInfo := LayerSummary{}
|
||||
layerInfo := common.LayerSummary{}
|
||||
|
||||
layerInfo.Digest = layer.Digest.String()
|
||||
|
||||
|
@ -428,20 +433,20 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
imageSize := imageLayersSize + manifestSize + configSize
|
||||
|
||||
// get image info from manifest annotation, if not found get from image config labels.
|
||||
annotations := GetAnnotations(manifest.Annotations, imageConfigInfo.Config.Labels)
|
||||
annotations := common.GetAnnotations(manifest.Annotations, imageConfigInfo.Config.Labels)
|
||||
|
||||
if annotations.Vendor != "" {
|
||||
repoVendorsSet[annotations.Vendor] = true
|
||||
}
|
||||
|
||||
imageConfigHistory := imageConfigInfo.History
|
||||
allHistory := []LayerHistory{}
|
||||
allHistory := []common.LayerHistory{}
|
||||
|
||||
if len(imageConfigHistory) == 0 {
|
||||
for _, layer := range layers {
|
||||
allHistory = append(allHistory, LayerHistory{
|
||||
allHistory = append(allHistory, common.LayerHistory{
|
||||
Layer: layer,
|
||||
HistoryDescription: HistoryDescription{},
|
||||
HistoryDescription: common.HistoryDescription{},
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
@ -449,8 +454,8 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
var layersIterator int
|
||||
// since we are appending pointers, it is important to iterate with an index over slice
|
||||
for i := range imageConfigHistory {
|
||||
allHistory = append(allHistory, LayerHistory{
|
||||
HistoryDescription: HistoryDescription{
|
||||
allHistory = append(allHistory, common.LayerHistory{
|
||||
HistoryDescription: common.HistoryDescription{
|
||||
Created: *imageConfigHistory[i].Created,
|
||||
CreatedBy: imageConfigHistory[i].CreatedBy,
|
||||
Author: imageConfigHistory[i].Author,
|
||||
|
@ -464,7 +469,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
}
|
||||
|
||||
if layersIterator+1 > len(layers) {
|
||||
olu.Log.Error().Err(errors.ErrBadLayerCount).
|
||||
olu.Log.Error().Err(zerr.ErrBadLayerCount).
|
||||
Msgf("error on creating layer history for image %s %s", repoName, man.Digest)
|
||||
|
||||
break
|
||||
|
@ -481,12 +486,12 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
size := strconv.Itoa(int(imageSize))
|
||||
manifestDigest := man.Digest.String()
|
||||
configDigest := manifest.Config.Digest.String()
|
||||
lastUpdated := GetImageLastUpdated(imageConfigInfo)
|
||||
lastUpdated := common.GetImageLastUpdated(imageConfigInfo)
|
||||
|
||||
imageSummary := ImageSummary{
|
||||
imageSummary := common.ImageSummary{
|
||||
RepoName: repoName,
|
||||
Tag: tag,
|
||||
Manifests: []ManifestSummary{
|
||||
Manifests: []common.ManifestSummary{
|
||||
{
|
||||
Digest: manifestDigest,
|
||||
ConfigDigest: configDigest,
|
||||
|
@ -524,7 +529,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
|
||||
size := strconv.FormatInt(repoSize, 10)
|
||||
|
||||
repoPlatforms := make([]Platform, 0, len(repoPlatformsSet))
|
||||
repoPlatforms := make([]common.Platform, 0, len(repoPlatformsSet))
|
||||
|
||||
for _, platform := range repoPlatformsSet {
|
||||
repoPlatforms = append(repoPlatforms, platform)
|
||||
|
@ -537,7 +542,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
repoVendors = append(repoVendors, vendor)
|
||||
}
|
||||
|
||||
summary := RepoSummary{
|
||||
summary := common.RepoSummary{
|
||||
Name: repoName,
|
||||
LastUpdated: lastUpdatedTag.Timestamp,
|
||||
Size: size,
|
||||
|
@ -550,3 +555,27 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, er
|
|||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (olu BaseOciLayoutUtils) ExtractImageDetails(
|
||||
repo, tag string,
|
||||
log log.Logger) (
|
||||
godigest.Digest, *ispec.Manifest, *ispec.Image, error,
|
||||
) {
|
||||
manifest, dig, err := olu.GetImageManifest(repo, tag)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Could not retrieve image ispec manifest")
|
||||
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
digest := dig
|
||||
|
||||
imageConfig, err := olu.GetImageConfigInfo(repo, digest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Could not retrieve image config")
|
||||
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
return digest, &manifest, &imageConfig, nil
|
||||
}
|
441
pkg/test/oci_layout_test.go
Normal file
441
pkg/test/oci_layout_test.go
Normal file
|
@ -0,0 +1,441 @@
|
|||
//go:build sync && scrub && metrics && search
|
||||
// +build sync,scrub,metrics,search
|
||||
|
||||
package test_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
"zotregistry.io/zot/pkg/storage/local"
|
||||
. "zotregistry.io/zot/pkg/test"
|
||||
"zotregistry.io/zot/pkg/test/mocks"
|
||||
)
|
||||
|
||||
func TestBaseOciLayoutUtils(t *testing.T) {
|
||||
manifestDigest := GetTestBlobDigest("zot-test", "config").String()
|
||||
|
||||
Convey("GetImageManifestSize fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageManifestSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetImageConfigSize: fail GetImageBlobManifest", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageConfigSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetImageConfigSize: config GetBlobContent fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
if digest.String() == manifestDigest {
|
||||
return []byte{}, ErrTestError
|
||||
}
|
||||
|
||||
return []byte(
|
||||
`
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"config": {
|
||||
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||
"digest": manifestDigest,
|
||||
"size": 1476
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||
"digest": "` + GetTestBlobDigest("zot-test", "layer").String() + `",
|
||||
"size": 76097157
|
||||
}
|
||||
]
|
||||
}`), nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
size := olu.GetImageConfigSize("", "")
|
||||
So(size, ShouldBeZeroValue)
|
||||
})
|
||||
|
||||
Convey("GetRepoLastUpdated: config GetBlobContent fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err := olu.GetRepoLastUpdated("")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageTagsWithTimestamp: GetImageBlobManifest fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{Annotations: map[string]string{ispec.AnnotationRefName: "w"}}, {},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return nil, ErrTestError
|
||||
},
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetImageTagsWithTimestamp("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageTagsWithTimestamp: GetImageInfo fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{Annotations: map[string]string{ispec.AnnotationRefName: "w"}}, {},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.config.v1+json",
|
||||
Digest: "configDigest",
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{},
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
if digest.String() == "configDigest" {
|
||||
return nil, ErrTestError
|
||||
}
|
||||
|
||||
return manifestBlob, nil
|
||||
},
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetImageTagsWithTimestamp("repo")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("GetExpandedRepoInfo: fails", t, func() {
|
||||
index := ispec.Index{
|
||||
Manifests: []ispec.Descriptor{
|
||||
{},
|
||||
{
|
||||
Annotations: map[string]string{
|
||||
ispec.AnnotationRefName: "w",
|
||||
ispec.AnnotationVendor: "vend",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifest := ispec.Manifest{
|
||||
Annotations: map[string]string{
|
||||
ispec.AnnotationRefName: "w",
|
||||
ispec.AnnotationVendor: "vend",
|
||||
},
|
||||
Layers: []ispec.Descriptor{
|
||||
{},
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return nil, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// GetRepoLastUpdated fails
|
||||
mockStoreController = mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController = storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu = NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// anotations
|
||||
|
||||
mockStoreController = mocks.MockedImageStore{
|
||||
GetIndexContentFn: func(repo string) ([]byte, error) {
|
||||
return indexBlob, nil
|
||||
},
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return manifestBlob, nil
|
||||
},
|
||||
}
|
||||
|
||||
storeController = storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu = NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err = olu.GetExpandedRepoInfo("rep")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("GetImageInfo fail", t, func() {
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
||||
return []byte{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
_, err := olu.GetImageInfo("", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("CheckManifestSignature: notation", t, func() {
|
||||
// GetReferrers - fails => checkNotarySignature returns false
|
||||
mockStoreController := mocks.MockedImageStore{
|
||||
GetImageManifestFn: func(name, reference string) ([]byte, godigest.Digest, string, error) {
|
||||
return []byte{}, "", "", zerr.ErrRepoNotFound
|
||||
},
|
||||
GetReferrersFn: func(name string, digest godigest.Digest, mediaTypes []string) (ispec.Index, error) {
|
||||
return ispec.Index{}, ErrTestError
|
||||
},
|
||||
}
|
||||
|
||||
storeController := storage.StoreController{DefaultStore: mockStoreController}
|
||||
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
|
||||
|
||||
check := olu.CheckManifestSignature("rep", godigest.FromString(""))
|
||||
So(check, ShouldBeFalse)
|
||||
|
||||
// checkNotarySignature -> true
|
||||
dir := t.TempDir()
|
||||
|
||||
port := GetFreePort()
|
||||
baseURL := GetBaseURL(port)
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
conf.Storage.RootDirectory = dir
|
||||
defaultVal := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||
}
|
||||
|
||||
conf.Extensions.Search.CVE = nil
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
|
||||
ctlrManager := NewControllerManager(ctlr)
|
||||
ctlrManager.StartAndWait(port)
|
||||
defer ctlrManager.StopServer()
|
||||
|
||||
// push test image to repo
|
||||
config, layers, manifest, err := GetImageComponents(100)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
layersSize1 := 0
|
||||
for _, l := range layers {
|
||||
layersSize1 += len(l)
|
||||
}
|
||||
|
||||
repo := "repo"
|
||||
tag := "1.0.1"
|
||||
err = UploadImage(
|
||||
Image{
|
||||
Manifest: manifest,
|
||||
Config: config,
|
||||
Layers: layers,
|
||||
Reference: tag,
|
||||
},
|
||||
baseURL,
|
||||
repo,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
olu = NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
|
||||
manifestList, err := olu.GetImageManifests(repo)
|
||||
So(err, ShouldBeNil)
|
||||
So(len(manifestList), ShouldEqual, 1)
|
||||
|
||||
isSigned := olu.CheckManifestSignature(repo, manifestList[0].Digest)
|
||||
So(isSigned, ShouldBeFalse)
|
||||
|
||||
err = SignImageUsingNotary(fmt.Sprintf("%s:%s", repo, tag), port)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSigned = olu.CheckManifestSignature(repo, manifestList[0].Digest)
|
||||
So(isSigned, ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtractImageDetails(t *testing.T) {
|
||||
Convey("extractImageDetails good workflow", t, func() {
|
||||
dir := t.TempDir()
|
||||
testLogger := log.NewLogger("debug", "")
|
||||
imageStore := local.NewImageStore(dir, false, 0, false, false,
|
||||
testLogger, monitoring.NewMetricsServer(false, testLogger), nil, nil)
|
||||
|
||||
storeController := storage.StoreController{
|
||||
DefaultStore: imageStore,
|
||||
}
|
||||
|
||||
num := 10
|
||||
config, layers, manifest, err := GetImageComponents(num)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = WriteImageToFileSystem(
|
||||
Image{
|
||||
Manifest: manifest,
|
||||
Layers: layers,
|
||||
Config: config,
|
||||
Reference: "latest",
|
||||
}, "zot-test", storeController,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
So(err, ShouldBeNil)
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
|
||||
olu := NewBaseOciLayoutUtils(storeController, testLogger)
|
||||
resDigest, resManifest, resIspecImage, resErr := olu.ExtractImageDetails("zot-test", "latest", testLogger)
|
||||
So(string(resDigest), ShouldContainSubstring, "sha256:c52f15d2d4")
|
||||
So(resManifest.Config.Digest.String(), ShouldContainSubstring, configDigest.Encoded())
|
||||
|
||||
So(resIspecImage.Architecture, ShouldContainSubstring, "amd64")
|
||||
So(resErr, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("extractImageDetails bad ispec.ImageManifest", t, func() {
|
||||
dir := t.TempDir()
|
||||
testLogger := log.NewLogger("debug", "")
|
||||
imageStore := local.NewImageStore(dir, false, 0, false, false,
|
||||
testLogger, monitoring.NewMetricsServer(false, testLogger), nil, nil)
|
||||
|
||||
storeController := storage.StoreController{
|
||||
DefaultStore: imageStore,
|
||||
}
|
||||
|
||||
olu := NewBaseOciLayoutUtils(storeController, testLogger)
|
||||
resDigest, resManifest, resIspecImage, resErr := olu.ExtractImageDetails("zot-test",
|
||||
"latest", testLogger)
|
||||
So(resErr, ShouldEqual, zerr.ErrRepoNotFound)
|
||||
So(string(resDigest), ShouldEqual, "")
|
||||
So(resManifest, ShouldBeNil)
|
||||
|
||||
So(resIspecImage, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("extractImageDetails bad imageConfig", t, func() {
|
||||
dir := t.TempDir()
|
||||
testLogger := log.NewLogger("debug", "")
|
||||
imageStore := local.NewImageStore(dir, false, 0, false, false,
|
||||
testLogger, monitoring.NewMetricsServer(false, testLogger), nil, nil)
|
||||
|
||||
storeController := storage.StoreController{
|
||||
DefaultStore: imageStore,
|
||||
}
|
||||
|
||||
num := 10
|
||||
config, layers, manifest, err := GetImageComponents(num)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = WriteImageToFileSystem(
|
||||
Image{
|
||||
Manifest: manifest,
|
||||
Layers: layers,
|
||||
Config: config,
|
||||
Reference: "latest",
|
||||
}, "zot-test", storeController,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
So(err, ShouldBeNil)
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
|
||||
err = os.Remove(path.Join(dir, "zot-test/blobs/sha256", configDigest.Encoded()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
olu := NewBaseOciLayoutUtils(storeController, testLogger)
|
||||
resDigest, resManifest, resIspecImage, resErr := olu.ExtractImageDetails("zot-test", "latest", testLogger)
|
||||
So(resErr, ShouldEqual, zerr.ErrBlobNotFound)
|
||||
So(string(resDigest), ShouldEqual, "")
|
||||
So(resManifest, ShouldBeNil)
|
||||
So(resIspecImage, ShouldBeNil)
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue