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:
Nicol
2023-04-07 19:52:26 +03:00
committed by GitHub
parent f35ff53146
commit 3510ef0fb0
7 changed files with 517 additions and 1032 deletions
+6 -320
View File
@@ -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()
-552
View File
@@ -1,552 +0,0 @@
// Package common ...
package common
import (
"encoding/json"
goerrors "errors"
"fmt"
"path"
"strconv"
"strings"
"time"
notreg "github.com/notaryproject/notation-go/registry"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/storage"
)
type OciLayoutUtils interface { //nolint: interfacebloat
GetImageManifest(repo string, reference string) (ispec.Manifest, godigest.Digest, error)
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)
GetImagePlatform(imageInfo ispec.Image) (string, string)
GetImageManifestSize(repo string, manifestDigest godigest.Digest) int64
GetRepoLastUpdated(repo string) (TagInfo, error)
GetExpandedRepoInfo(name string) (RepoInfo, error)
GetImageConfigInfo(repo string, manifestDigest godigest.Digest) (ispec.Image, error)
CheckManifestSignature(name string, digest godigest.Digest) bool
GetRepositories() ([]string, error)
}
// OciLayoutInfo ...
type BaseOciLayoutUtils struct {
Log log.Logger
StoreController storage.StoreController
}
// NewBaseOciLayoutUtils initializes a new OciLayoutUtils object.
func NewBaseOciLayoutUtils(storeController storage.StoreController, log log.Logger) *BaseOciLayoutUtils {
return &BaseOciLayoutUtils{Log: log, StoreController: storeController}
}
func (olu BaseOciLayoutUtils) GetImageManifest(repo string, reference string) (ispec.Manifest, godigest.Digest, error) {
imageStore := olu.StoreController.GetImageStore(repo)
if reference == "" {
reference = "latest"
}
manifestBlob, digest, _, err := imageStore.GetImageManifest(repo, reference)
if err != nil {
return ispec.Manifest{}, "", err
}
var manifest ispec.Manifest
err = json.Unmarshal(manifestBlob, &manifest)
if err != nil {
return ispec.Manifest{}, "", err
}
return manifest, digest, nil
}
// Provide a list of repositories from all the available image stores.
func (olu BaseOciLayoutUtils) GetRepositories() ([]string, error) {
defaultStore := olu.StoreController.DefaultStore
substores := olu.StoreController.SubStore
repoList, err := defaultStore.GetRepositories()
if err != nil {
return []string{}, err
}
for _, sub := range substores {
repoListForSubstore, err := sub.GetRepositories()
if err != nil {
return []string{}, err
}
repoList = append(repoList, repoListForSubstore...)
}
return repoList, nil
}
// Below method will return image path including root dir, root dir is determined by splitting.
func (olu BaseOciLayoutUtils) GetImageManifests(repo string) ([]ispec.Descriptor, error) {
var lockLatency time.Time
imageStore := olu.StoreController.GetImageStore(repo)
imageStore.RLock(&lockLatency)
defer imageStore.RUnlock(&lockLatency)
buf, err := imageStore.GetIndexContent(repo)
if err != nil {
if goerrors.Is(errors.ErrRepoNotFound, err) {
olu.Log.Error().Err(err).Msg("index.json doesn't exist")
return nil, errors.ErrRepoNotFound
}
olu.Log.Error().Err(err).Msg("unable to open index.json")
return nil, errors.ErrRepoNotFound
}
var index ispec.Index
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 index.Manifests, nil
}
func (olu BaseOciLayoutUtils) GetImageBlobManifest(repo string, digest godigest.Digest) (ispec.Manifest, error) {
var blobIndex ispec.Manifest
var lockLatency time.Time
imageStore := olu.StoreController.GetImageStore(repo)
imageStore.RLock(&lockLatency)
defer imageStore.RUnlock(&lockLatency)
blobBuf, err := imageStore.GetBlobContent(repo, digest)
if err != nil {
olu.Log.Error().Err(err).Msg("unable to open image metadata file")
return blobIndex, err
}
if err := json.Unmarshal(blobBuf, &blobIndex); err != nil {
olu.Log.Error().Err(err).Msg("unable to marshal blob index")
return blobIndex, err
}
return blobIndex, nil
}
func (olu BaseOciLayoutUtils) GetImageInfo(repo string, configDigest godigest.Digest) (ispec.Image, error) {
var imageInfo ispec.Image
var lockLatency time.Time
imageStore := olu.StoreController.GetImageStore(repo)
imageStore.RLock(&lockLatency)
defer imageStore.RUnlock(&lockLatency)
blobBuf, err := imageStore.GetBlobContent(repo, configDigest)
if err != nil {
olu.Log.Error().Err(err).Msg("unable to open image layers file")
return imageInfo, err
}
if err := json.Unmarshal(blobBuf, &imageInfo); err != nil {
olu.Log.Error().Err(err).Msg("unable to marshal blob index")
return imageInfo, err
}
return imageInfo, err
}
// 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)
manifests, err := olu.GetImageManifests(repo)
if err != nil {
olu.Log.Error().Err(err).Msg("unable to read image manifests")
return tagsInfo, err
}
for _, manifest := range manifests {
digest := manifest.Digest
val, ok := manifest.Annotations[ispec.AnnotationRefName]
if ok {
imageBlobManifest, err := olu.GetImageBlobManifest(repo, digest)
if err != nil {
olu.Log.Error().Err(err).Msg("unable to read image blob manifest")
return tagsInfo, err
}
imageInfo, err := olu.GetImageInfo(repo, imageBlobManifest.Config.Digest)
if err != nil {
olu.Log.Error().Err(err).Msg("unable to read image info")
return tagsInfo, err
}
timeStamp := GetImageLastUpdated(imageInfo)
tagsInfo = append(tagsInfo,
TagInfo{
Name: val,
Timestamp: timeStamp,
Descriptor: Descriptor{
Digest: digest,
MediaType: manifest.MediaType,
},
},
)
}
}
return tagsInfo, nil
}
// check notary signature corresponding to repo name, manifest digest and mediatype.
func (olu BaseOciLayoutUtils) checkNotarySignature(name string, digest godigest.Digest) bool {
imageStore := olu.StoreController.GetImageStore(name)
mediaType := notreg.ArtifactTypeNotation
referrers, err := imageStore.GetReferrers(name, digest, []string{mediaType})
if err != nil {
olu.Log.Info().Err(err).Str("repo", name).Str("digest",
digest.String()).Str("mediatype", mediaType).Msg("invalid notary signature")
return false
}
if len(referrers.Manifests) == 0 {
return false
}
return true
}
// check cosign signature corresponding to manifest.
func (olu BaseOciLayoutUtils) checkCosignSignature(name string, digest godigest.Digest) bool {
if digest.Validate() != nil {
return false
}
imageStore := olu.StoreController.GetImageStore(name)
// if manifest is signed using cosign mechanism, cosign adds a new manifest.
// new manifest is tagged as sha256-<manifest-digest>.sig.
reference := fmt.Sprintf("sha256-%s.sig", digest.Encoded())
_, _, _, err := imageStore.GetImageManifest(name, reference) //nolint: dogsled
if err != nil {
olu.Log.Info().Err(err).Str("repo", name).Str("digest",
digest.String()).Msg("invalid cosign signature")
return false
}
return true
}
// checks if manifest is signed or not
// checks for notary or cosign signature
// if cosign signature found it does not looks for notary signature.
func (olu BaseOciLayoutUtils) CheckManifestSignature(name string, digest godigest.Digest) bool {
if !olu.checkCosignSignature(name, digest) {
return olu.checkNotarySignature(name, digest)
}
return true
}
func (olu BaseOciLayoutUtils) GetImagePlatform(imageConfig ispec.Image) (
string, string,
) {
return imageConfig.OS, imageConfig.Architecture
}
func (olu BaseOciLayoutUtils) GetImageConfigInfo(repo string, manifestDigest godigest.Digest) (ispec.Image, error) {
imageBlobManifest, err := olu.GetImageBlobManifest(repo, manifestDigest)
if err != nil {
return ispec.Image{}, err
}
imageInfo, err := olu.GetImageInfo(repo, imageBlobManifest.Config.Digest)
if err != nil {
return ispec.Image{}, err
}
return imageInfo, nil
}
func (olu BaseOciLayoutUtils) GetImageManifestSize(repo string, manifestDigest godigest.Digest) int64 {
imageStore := olu.StoreController.GetImageStore(repo)
var lockLatency time.Time
imageStore.RLock(&lockLatency)
defer imageStore.RUnlock(&lockLatency)
manifestBlob, err := imageStore.GetBlobContent(repo, manifestDigest)
if err != nil {
olu.Log.Error().Err(err).Msg("error when getting manifest blob content")
return int64(len(manifestBlob))
}
return int64(len(manifestBlob))
}
func (olu BaseOciLayoutUtils) GetImageConfigSize(repo string, manifestDigest godigest.Digest) int64 {
imageBlobManifest, err := olu.GetImageBlobManifest(repo, manifestDigest)
if err != nil {
olu.Log.Error().Err(err).Msg("can't get image blob manifest")
return 0
}
return imageBlobManifest.Config.Size
}
func (olu BaseOciLayoutUtils) GetRepoLastUpdated(repo string) (TagInfo, error) {
tagsInfo, err := olu.GetImageTagsWithTimestamp(repo)
if err != nil || len(tagsInfo) == 0 {
return TagInfo{}, err
}
latestTag := GetLatestTag(tagsInfo)
return latestTag, nil
}
func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(repoName string) (RepoInfo, error) {
repo := RepoInfo{}
repoBlob2Size := make(map[string]int64, 10)
// made up of all manifests, configs and image layers
repoSize := int64(0)
imageSummaries := make([]ImageSummary, 0)
manifestList, err := olu.GetImageManifests(repoName)
if err != nil {
olu.Log.Error().Err(err).Msg("error getting image manifests")
return 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
}
repoVendorsSet := make(map[string]bool, len(manifestList))
repoPlatformsSet := make(map[string]Platform, len(manifestList))
var lastUpdatedImageSummary ImageSummary
for _, man := range manifestList {
imageLayersSize := int64(0)
tag, ok := man.Annotations[ispec.AnnotationRefName]
if !ok {
olu.Log.Info().Msgf("skipping manifest with digest %s because it doesn't have a tag",
man.Digest.String())
continue
}
manifest, err := olu.GetImageBlobManifest(repoName, man.Digest)
if err != nil {
olu.Log.Error().Err(err).Msg("error getting image manifest blob")
return RepoInfo{}, err
}
isSigned := olu.CheckManifestSignature(repoName, man.Digest)
manifestSize := olu.GetImageManifestSize(repoName, man.Digest)
olu.Log.Debug().Msg(fmt.Sprintf("%v", man.Digest.String()))
configSize := manifest.Config.Size
repoBlob2Size[man.Digest.String()] = manifestSize
repoBlob2Size[manifest.Config.Digest.String()] = configSize
imageConfigInfo, err := olu.GetImageConfigInfo(repoName, man.Digest)
if err != nil {
olu.Log.Error().Err(err).Msgf("can't retrieve config info for the image %s %s", repoName, man.Digest)
continue
}
opSys, arch := olu.GetImagePlatform(imageConfigInfo)
platform := Platform{
Os: opSys,
Arch: arch,
}
if opSys != "" || arch != "" {
platformString := strings.TrimSpace(fmt.Sprintf("%s %s", opSys, arch))
repoPlatformsSet[platformString] = platform
}
layers := make([]LayerSummary, 0)
for _, layer := range manifest.Layers {
layerInfo := LayerSummary{}
layerInfo.Digest = layer.Digest.String()
repoBlob2Size[layerInfo.Digest] = layer.Size
layerInfo.Size = strconv.FormatInt(layer.Size, 10)
imageLayersSize += layer.Size
layers = append(layers, layerInfo)
}
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)
if annotations.Vendor != "" {
repoVendorsSet[annotations.Vendor] = true
}
imageConfigHistory := imageConfigInfo.History
allHistory := []LayerHistory{}
if len(imageConfigHistory) == 0 {
for _, layer := range layers {
allHistory = append(allHistory, LayerHistory{
Layer: layer,
HistoryDescription: HistoryDescription{},
})
}
} else {
// 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 imageConfigHistory {
allHistory = append(allHistory, LayerHistory{
HistoryDescription: HistoryDescription{
Created: *imageConfigHistory[i].Created,
CreatedBy: imageConfigHistory[i].CreatedBy,
Author: imageConfigHistory[i].Author,
Comment: imageConfigHistory[i].Comment,
EmptyLayer: imageConfigHistory[i].EmptyLayer,
},
})
if imageConfigHistory[i].EmptyLayer {
continue
}
if layersIterator+1 > len(layers) {
olu.Log.Error().Err(errors.ErrBadLayerCount).
Msgf("error on creating layer history for image %s %s", repoName, man.Digest)
break
}
allHistory[i].Layer = layers[layersIterator]
layersIterator++
}
}
olu.Log.Debug().Msgf("all history %v", allHistory)
size := strconv.Itoa(int(imageSize))
manifestDigest := man.Digest.String()
configDigest := manifest.Config.Digest.String()
lastUpdated := GetImageLastUpdated(imageConfigInfo)
imageSummary := ImageSummary{
RepoName: repoName,
Tag: tag,
Manifests: []ManifestSummary{
{
Digest: manifestDigest,
ConfigDigest: configDigest,
LastUpdated: lastUpdated,
Size: size,
Platform: platform,
Layers: layers,
History: allHistory,
},
},
LastUpdated: lastUpdated,
IsSigned: isSigned,
Size: size,
Description: annotations.Description,
Title: annotations.Title,
Documentation: annotations.Documentation,
Licenses: annotations.Licenses,
Labels: annotations.Labels,
Vendor: annotations.Vendor,
Source: annotations.Source,
}
imageSummaries = append(imageSummaries, imageSummary)
if man.Digest.String() == lastUpdatedTag.Descriptor.Digest.String() {
lastUpdatedImageSummary = imageSummary
}
}
repo.ImageSummaries = imageSummaries
for blob := range repoBlob2Size {
repoSize += repoBlob2Size[blob]
}
size := strconv.FormatInt(repoSize, 10)
repoPlatforms := make([]Platform, 0, len(repoPlatformsSet))
for _, platform := range repoPlatformsSet {
repoPlatforms = append(repoPlatforms, platform)
}
repoVendors := make([]string, 0, len(repoVendorsSet))
for vendor := range repoVendorsSet {
vendor := vendor
repoVendors = append(repoVendors, vendor)
}
summary := RepoSummary{
Name: repoName,
LastUpdated: lastUpdatedTag.Timestamp,
Size: size,
Platforms: repoPlatforms,
NewestImage: lastUpdatedImageSummary,
Vendors: repoVendors,
}
repo.Summary = summary
return repo, nil
}
@@ -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)
})
}
-186
View File
@@ -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 {
-64
View File
@@ -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
}
-143
View File
@@ -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", "")