mirror of
https://github.com/project-zot/zot.git
synced 2024-12-23 22:27:35 -05:00
b997176363
Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro> add page info to dynamo-> feat(repodb): add PageInfo to GlobalSearch and RepoListWithNewestImage results (cherry picked from commit 4fed42bb4bbc68199281d9d9a4e09b97fbd4759b) Signed-off-by: Andrei Aaron <aaaron@luxoft.com> Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro> Signed-off-by: Andrei Aaron <aaaron@luxoft.com> Co-authored-by: Alex Stan <alexandrustan96@yahoo.ro>
1474 lines
42 KiB
Go
1474 lines
42 KiB
Go
package search //nolint
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/99designs/gqlgen/graphql"
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
"zotregistry.io/zot/pkg/extensions/search/common"
|
|
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
|
|
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
|
|
"zotregistry.io/zot/pkg/log"
|
|
"zotregistry.io/zot/pkg/meta/repodb"
|
|
localCtx "zotregistry.io/zot/pkg/requestcontext"
|
|
"zotregistry.io/zot/pkg/storage"
|
|
"zotregistry.io/zot/pkg/test/mocks"
|
|
)
|
|
|
|
var ErrTestError = errors.New("TestError")
|
|
|
|
func TestGlobalSearch(t *testing.T) {
|
|
Convey("globalSearch", t, func() {
|
|
const query = "repo1"
|
|
Convey("RepoDB SearchRepos error", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
|
|
},
|
|
}
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB, &gql_generated.Filter{},
|
|
&gql_generated.PageInput{}, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldNotBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchRepo is successful", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
"1.0.2": {
|
|
Digest: "digestTag1.0.2",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
createTime := time.Now()
|
|
configBlob1, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{
|
|
ispec.AnnotationVendor: "TestVendor1",
|
|
},
|
|
},
|
|
Created: &createTime,
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
configBlob2, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{
|
|
ispec.AnnotationVendor: "TestVendor2",
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob1,
|
|
},
|
|
"digestTag1.0.2": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob2,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
|
|
const query = "repo1"
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldNotBeEmpty)
|
|
So(len(repos.Results[0].Vendors), ShouldEqual, 2)
|
|
})
|
|
|
|
Convey("RepoDB SearchRepo Bad manifest referenced", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: []byte("bad manifest blob"),
|
|
ConfigBlob: configBlob,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
|
|
query := "repo1"
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos, ShouldNotBeEmpty)
|
|
|
|
query = "repo1:1.0.1"
|
|
|
|
responseContext = graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
repos, images, layers, err = globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchRepo good manifest referenced and bad config blob", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: []byte("bad config blob"),
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
|
|
query := "repo1"
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldNotBeEmpty)
|
|
|
|
query = "repo1:1.0.1"
|
|
responseContext = graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
repos, images, layers, err = globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchTags gives error", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchTagsFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
|
|
},
|
|
}
|
|
const query = "repo1:1.0.1"
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB, &gql_generated.Filter{},
|
|
&gql_generated.PageInput{}, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldNotBeNil)
|
|
So(images, ShouldBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchTags is successful", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchTagsFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
configBlob1, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{
|
|
ispec.AnnotationVendor: "TestVendor1",
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
configBlob2, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{
|
|
ispec.AnnotationVendor: "TestVendor2",
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob1,
|
|
},
|
|
"digestTag1.0.2": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob2,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
|
|
const query = "repo1:1.0.1"
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
repos, images, layers, err := globalSearch(responseContext, query, mockRepoDB,
|
|
&gql_generated.Filter{}, &pageInput, mockCve, log.NewLogger("debug", ""))
|
|
So(err, ShouldBeNil)
|
|
So(images, ShouldNotBeEmpty)
|
|
So(layers, ShouldBeEmpty)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRepoListWithNewestImage(t *testing.T) {
|
|
Convey("RepoListWithNewestImage", t, func() {
|
|
Convey("RepoDB SearchRepos error", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
return make([]repodb.RepoMetadata, 0), make(map[string]repodb.ManifestMetadata), repodb.PageInfo{}, ErrTestError
|
|
},
|
|
}
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaUpdateTime
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), &pageInput, mockRepoDB)
|
|
So(err, ShouldNotBeNil)
|
|
So(repos.Results, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchRepo Bad manifest referenced", func() {
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
{
|
|
Name: "repo2",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.2": {
|
|
Digest: "digestTag1.0.2",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
configBlob1, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: []byte("bad manifest blob"),
|
|
ConfigBlob: configBlob1,
|
|
},
|
|
"digestTag1.0.2": {
|
|
ManifestBlob: []byte("bad manifest blob"),
|
|
ConfigBlob: configBlob1,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaUpdateTime
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), &pageInput, mockRepoDB)
|
|
So(err, ShouldBeNil)
|
|
So(repos.Results, ShouldNotBeEmpty)
|
|
})
|
|
|
|
Convey("Working SearchRepo function", func() {
|
|
createTime := time.Now()
|
|
createTime2 := createTime.Add(time.Second)
|
|
mockRepoDB := mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
pageFinder, err := repodb.NewBaseRepoPageFinder(requestedPage.Limit, requestedPage.Offset, requestedPage.SortBy)
|
|
So(err, ShouldBeNil)
|
|
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "repo1",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {
|
|
Digest: "digestTag1.0.1",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
{
|
|
Name: "repo2",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.2": {
|
|
Digest: "digestTag1.0.2",
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
for _, repoMeta := range repos {
|
|
pageFinder.Add(repodb.DetailedRepoMeta{
|
|
RepoMeta: repoMeta,
|
|
UpdateTime: createTime,
|
|
})
|
|
createTime = createTime.Add(time.Second)
|
|
}
|
|
|
|
repos, _ = pageFinder.Page()
|
|
|
|
configBlob1, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{},
|
|
},
|
|
Created: &createTime,
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
configBlob2, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{},
|
|
},
|
|
Created: &createTime2,
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob1,
|
|
},
|
|
"digestTag1.0.2": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob2,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetas, repodb.PageInfo{}, nil
|
|
},
|
|
}
|
|
Convey("RepoDB missing requestedPage", func() {
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
mockCve := mocks.CveInfoMock{}
|
|
repos, err := repoListWithNewestImage(responseContext, mockCve, log.NewLogger("debug", ""), nil, mockRepoDB)
|
|
So(err, ShouldBeNil)
|
|
So(repos.Results, ShouldNotBeEmpty)
|
|
})
|
|
|
|
Convey("RepoDB SearchRepo is successful", func() {
|
|
limit := 2
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaUpdateTime
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
mockCve := mocks.CveInfoMock{}
|
|
repos, err := repoListWithNewestImage(responseContext, mockCve,
|
|
log.NewLogger("debug", ""), &pageInput, mockRepoDB)
|
|
So(err, ShouldBeNil)
|
|
So(repos, ShouldNotBeEmpty)
|
|
So(len(repos.Results), ShouldEqual, 2)
|
|
So(*repos.Results[0].Name, ShouldEqual, "repo2")
|
|
So(*repos.Results[0].LastUpdated, ShouldEqual, createTime2)
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestImageListForDigest(t *testing.T) {
|
|
Convey("getImageList", t, func() {
|
|
Convey("no page requested, FilterTagsFn returns error", func() {
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
return []repodb.RepoMetadata{}, map[string]repodb.ManifestMetadata{}, ErrTestError
|
|
},
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
_, err := getImageListForDigest(responseContext, "invalid", mockSearchDB, mocks.CveInfoMock{}, nil)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("invalid manifest blob", func() {
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: "digestTag1.0.1", MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{
|
|
Config: ispec.ImageConfig{
|
|
Labels: map[string]string{},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestBlob := []byte("invalid")
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
"digestTag1.0.1": {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageList, err := getImageListForDigest(responseContext, "test", mockSearchDB, mocks.CveInfoMock{}, nil)
|
|
So(err, ShouldBeNil)
|
|
So(imageList, ShouldBeEmpty)
|
|
})
|
|
|
|
Convey("valid imageListForDigest returned for matching manifest digest", func() {
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBlob).String()
|
|
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
configBlob, err := json.Marshal(ispec.ImageConfig{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
manifestDigest: {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
matchedTags := repos[0].Tags
|
|
for tag, descriptor := range repos[0].Tags {
|
|
if !filter(repos[0], manifestMetaDatas[descriptor.Digest]) {
|
|
delete(matchedTags, tag)
|
|
delete(manifestMetaDatas, descriptor.Digest)
|
|
|
|
continue
|
|
}
|
|
}
|
|
|
|
repos[0].Tags = matchedTags
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageSummaries, err := getImageListForDigest(responseContext, manifestDigest,
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 1)
|
|
|
|
imageSummaries, err = getImageListForDigest(responseContext, "invalid",
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 0)
|
|
})
|
|
|
|
Convey("valid imageListForDigest returned for matching config digest", func() {
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBlob).String()
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{})
|
|
So(err, ShouldBeNil)
|
|
|
|
configDigest := godigest.FromBytes(configBlob)
|
|
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{
|
|
Config: ispec.Descriptor{
|
|
Digest: configDigest,
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
manifestDigest: {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
matchedTags := repos[0].Tags
|
|
for tag, descriptor := range repos[0].Tags {
|
|
if !filter(repos[0], manifestMetaDatas[descriptor.Digest]) {
|
|
delete(matchedTags, tag)
|
|
delete(manifestMetaDatas, descriptor.Digest)
|
|
|
|
continue
|
|
}
|
|
}
|
|
|
|
repos[0].Tags = matchedTags
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageSummaries, err := getImageListForDigest(responseContext, configDigest.String(),
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 1)
|
|
})
|
|
|
|
Convey("valid imageListForDigest returned for matching layer digest", func() {
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBlob).String()
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{})
|
|
So(err, ShouldBeNil)
|
|
|
|
layerDigest := godigest.Digest("validDigest")
|
|
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{
|
|
Layers: []ispec.Descriptor{
|
|
{
|
|
Digest: layerDigest,
|
|
},
|
|
},
|
|
})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
manifestDigest: {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
matchedTags := repos[0].Tags
|
|
for tag, descriptor := range repos[0].Tags {
|
|
if !filter(repos[0], manifestMetaDatas[descriptor.Digest]) {
|
|
delete(matchedTags, tag)
|
|
delete(manifestMetaDatas, descriptor.Digest)
|
|
|
|
continue
|
|
}
|
|
}
|
|
|
|
repos[0].Tags = matchedTags
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageSummaries, err := getImageListForDigest(responseContext, layerDigest.String(),
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 1)
|
|
})
|
|
|
|
Convey("valid imageListForDigest, multiple matching tags", func() {
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBlob).String()
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{})
|
|
So(err, ShouldBeNil)
|
|
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
"1.0.2": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
manifestDigest: {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
for i, repo := range repos {
|
|
matchedTags := repo.Tags
|
|
|
|
for tag, descriptor := range repo.Tags {
|
|
if !filter(repo, manifestMetaDatas[descriptor.Digest]) {
|
|
delete(matchedTags, tag)
|
|
delete(manifestMetaDatas, descriptor.Digest)
|
|
|
|
continue
|
|
}
|
|
}
|
|
|
|
repos[i].Tags = matchedTags
|
|
}
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageSummaries, err := getImageListForDigest(responseContext, manifestDigest,
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 2)
|
|
})
|
|
|
|
Convey("valid imageListForDigest, multiple matching tags limited by pageInput", func() {
|
|
manifestBlob, err := json.Marshal(ispec.Manifest{})
|
|
So(err, ShouldBeNil)
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBlob).String()
|
|
|
|
configBlob, err := json.Marshal(ispec.Image{})
|
|
So(err, ShouldBeNil)
|
|
|
|
mockSearchDB := mocks.RepoDBMock{
|
|
FilterTagsFn: func(ctx context.Context, filter repodb.FilterFunc,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, error) {
|
|
pageFinder, err := repodb.NewBaseImagePageFinder(requestedPage.Limit, requestedPage.Offset, requestedPage.SortBy)
|
|
if err != nil {
|
|
return []repodb.RepoMetadata{}, map[string]repodb.ManifestMetadata{}, err
|
|
}
|
|
|
|
repos := []repodb.RepoMetadata{
|
|
{
|
|
Name: "test",
|
|
Tags: map[string]repodb.Descriptor{
|
|
"1.0.1": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
"1.0.2": {Digest: manifestDigest, MediaType: ispec.MediaTypeImageManifest},
|
|
},
|
|
Stars: 100,
|
|
},
|
|
}
|
|
|
|
manifestMetaDatas := map[string]repodb.ManifestMetadata{
|
|
manifestDigest: {
|
|
ManifestBlob: manifestBlob,
|
|
ConfigBlob: configBlob,
|
|
DownloadCount: 0,
|
|
},
|
|
}
|
|
|
|
for i, repo := range repos {
|
|
matchedTags := repo.Tags
|
|
|
|
for tag, descriptor := range repo.Tags {
|
|
if !filter(repo, manifestMetaDatas[descriptor.Digest]) {
|
|
delete(matchedTags, tag)
|
|
delete(manifestMetaDatas, descriptor.Digest)
|
|
|
|
continue
|
|
}
|
|
}
|
|
|
|
repos[i].Tags = matchedTags
|
|
|
|
pageFinder.Add(repodb.DetailedRepoMeta{
|
|
RepoMeta: repo,
|
|
})
|
|
}
|
|
|
|
repos, _ = pageFinder.Page()
|
|
|
|
return repos, manifestMetaDatas, nil
|
|
},
|
|
}
|
|
|
|
limit := 1
|
|
offset := 0
|
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
|
pageInput := gql_generated.PageInput{
|
|
Limit: &limit,
|
|
Offset: &offset,
|
|
SortBy: &sortCriteria,
|
|
}
|
|
|
|
responseContext := graphql.WithResponseContext(context.Background(), graphql.DefaultErrorPresenter,
|
|
graphql.DefaultRecover)
|
|
|
|
imageSummaries, err := getImageListForDigest(responseContext, manifestDigest,
|
|
mockSearchDB, mocks.CveInfoMock{}, &pageInput)
|
|
So(err, ShouldBeNil)
|
|
So(len(imageSummaries), ShouldEqual, 1)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetReferrers(t *testing.T) {
|
|
Convey("getReferrers", t, func() {
|
|
Convey("GetReferrers returns error", func() {
|
|
testLogger := log.NewLogger("debug", "")
|
|
mockedStore := mocks.MockedImageStore{
|
|
GetReferrersFn: func(repo string, digest godigest.Digest, artifactType string) (ispec.Index, error) {
|
|
return ispec.Index{}, ErrTestError
|
|
},
|
|
}
|
|
|
|
_, err := getReferrers(mockedStore, "test", "", "", testLogger)
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("GetReferrers return index of descriptors", func() {
|
|
testLogger := log.NewLogger("debug", "")
|
|
referrerDescriptor := ispec.Descriptor{
|
|
MediaType: ispec.MediaTypeArtifactManifest,
|
|
ArtifactType: "com.artifact.test",
|
|
Size: 403,
|
|
Digest: godigest.FromString("test"),
|
|
Annotations: map[string]string{
|
|
"key": "value",
|
|
},
|
|
}
|
|
mockedStore := mocks.MockedImageStore{
|
|
GetReferrersFn: func(repo string, digest godigest.Digest, artifactType string) (ispec.Index, error) {
|
|
return ispec.Index{
|
|
Manifests: []ispec.Descriptor{
|
|
referrerDescriptor,
|
|
},
|
|
}, nil
|
|
},
|
|
}
|
|
|
|
referrers, err := getReferrers(mockedStore, "test", "", "", testLogger)
|
|
So(err, ShouldBeNil)
|
|
So(*referrers[0].ArtifactType, ShouldEqual, referrerDescriptor.ArtifactType)
|
|
So(*referrers[0].MediaType, ShouldEqual, referrerDescriptor.MediaType)
|
|
So(*referrers[0].Size, ShouldEqual, referrerDescriptor.Size)
|
|
So(*referrers[0].Digest, ShouldEqual, referrerDescriptor.Digest)
|
|
So(*referrers[0].Annotations[0].Value, ShouldEqual, referrerDescriptor.Annotations["key"])
|
|
})
|
|
})
|
|
}
|
|
|
|
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", "")
|
|
ctx := context.Background()
|
|
|
|
Convey("ImageListForCve olu.GetRepositories() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageListForCve(ctx, "id")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageListForCve cveInfo.GetImageListForCVE() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo"}, nil
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{
|
|
GetImageListForCVEFn: func(repo, cveID string) ([]cveinfo.ImageInfoByCVE, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageListForCve(ctx, "a")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageListForCve olu.GetImageConfigInfo() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo"}, nil
|
|
},
|
|
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{
|
|
GetImageListForCVEFn: func(repo, cveID string) ([]cveinfo.ImageInfoByCVE, error) {
|
|
return []cveinfo.ImageInfoByCVE{{}}, nil
|
|
},
|
|
},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageListForCve(ctx, "a")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("RepoListWithNewestImage repoListWithNewestImage errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{},
|
|
},
|
|
mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string, filter repodb.Filter,
|
|
requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
return nil, nil, repodb.PageInfo{}, ErrTestError
|
|
},
|
|
},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.RepoListWithNewestImage(ctx, &gql_generated.PageInput{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageListWithCVEFixed olu.GetImageBlobManifest() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{
|
|
GetImageListWithCVEFixedFn: func(repo, cveID string) ([]common.TagInfo, error) {
|
|
return []common.TagInfo{{}}, nil
|
|
},
|
|
},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageListWithCVEFixed(ctx, "a", "d")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageListWithCVEFixed olu.GetImageConfigInfo() errors", func() {
|
|
getBlobContentCallCounter := 0
|
|
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
|
|
if getBlobContentCallCounter == 1 {
|
|
getBlobContentCallCounter++
|
|
|
|
return nil, ErrTestError
|
|
}
|
|
getBlobContentCallCounter++
|
|
|
|
return []byte("{}"), nil
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{
|
|
GetImageListWithCVEFixedFn: func(repo, cveID string) ([]common.TagInfo, error) {
|
|
return []common.TagInfo{{}}, nil
|
|
},
|
|
},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageListWithCVEFixed(ctx, "a", "d")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("RepoListWithNewestImage repoListWithNewestImage() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{},
|
|
mocks.RepoDBMock{
|
|
SearchReposFn: func(ctx context.Context, searchText string,
|
|
filter repodb.Filter, requestedPage repodb.PageInput,
|
|
) ([]repodb.RepoMetadata, map[string]repodb.ManifestMetadata, repodb.PageInfo, error) {
|
|
return nil, nil, repodb.PageInfo{}, ErrTestError
|
|
},
|
|
},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.RepoListWithNewestImage(ctx, &gql_generated.PageInput{})
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageList getImageList() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageList(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("ImageList subpaths getImageList() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"sub1/repo"}, nil
|
|
},
|
|
},
|
|
SubStore: map[string]storage.ImageStore{
|
|
"/sub1": mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return nil, ErrTestError
|
|
},
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.ImageList(ctx, "repo")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("DerivedImageList ExpandedRepoInfo() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"sub1/repo"}, nil
|
|
},
|
|
GetImageManifestFn: func(repo, reference string) ([]byte, godigest.Digest, string, error) {
|
|
return []byte("{}"), "digest", "str", nil
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{
|
|
GetRepoMetaFn: func(repo string) (repodb.RepoMetadata, error) {
|
|
return repodb.RepoMetadata{}, ErrTestError
|
|
},
|
|
},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.DerivedImageList(ctx, "repo:tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
|
|
Convey("BaseImageList ExpandedRepoInfo() errors", func() {
|
|
resolverConfig := NewResolver(
|
|
log,
|
|
storage.StoreController{
|
|
DefaultStore: mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"sub1/repo"}, nil
|
|
},
|
|
GetImageManifestFn: func(repo, reference string) ([]byte, godigest.Digest, string, error) {
|
|
return []byte("{}"), "digest", "str", nil
|
|
},
|
|
},
|
|
},
|
|
mocks.RepoDBMock{
|
|
GetRepoMetaFn: func(repo string) (repodb.RepoMetadata, error) {
|
|
return repodb.RepoMetadata{}, ErrTestError
|
|
},
|
|
},
|
|
mocks.CveInfoMock{},
|
|
)
|
|
|
|
qr := queryResolver{
|
|
resolverConfig,
|
|
}
|
|
|
|
_, err := qr.BaseImageList(ctx, "repo:tag")
|
|
So(err, ShouldNotBeNil)
|
|
})
|
|
})
|
|
}
|