mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
feat(metadb): add support for querying for images by a blob digest (#2077)
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
parent
02a8ed7854
commit
0de2210686
10 changed files with 273 additions and 80 deletions
|
@ -160,6 +160,7 @@ var (
|
||||||
ErrBadHTTPStatusCode = errors.New("cli: the response doesn't contain the expected status code")
|
ErrBadHTTPStatusCode = errors.New("cli: the response doesn't contain the expected status code")
|
||||||
ErrFormatNotSupported = errors.New("cli: the given output format is not supported")
|
ErrFormatNotSupported = errors.New("cli: the given output format is not supported")
|
||||||
ErrAPINotSupported = errors.New("registry at the given address doesn't implement the correct API")
|
ErrAPINotSupported = errors.New("registry at the given address doesn't implement the correct API")
|
||||||
|
ErrInvalidSearchQuery = errors.New("invalid search query")
|
||||||
ErrFileAlreadyCancelled = errors.New("storageDriver: file already cancelled")
|
ErrFileAlreadyCancelled = errors.New("storageDriver: file already cancelled")
|
||||||
ErrFileAlreadyClosed = errors.New("storageDriver: file already closed")
|
ErrFileAlreadyClosed = errors.New("storageDriver: file already closed")
|
||||||
ErrFileAlreadyCommitted = errors.New("storageDriver: file already committed")
|
ErrFileAlreadyCommitted = errors.New("storageDriver: file already committed")
|
||||||
|
|
|
@ -76,7 +76,12 @@ func FilterByDigest(digest string) mTypes.FilterFunc {
|
||||||
// imageMeta will always contain 1 manifest
|
// imageMeta will always contain 1 manifest
|
||||||
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
|
return func(repoMeta mTypes.RepoMeta, imageMeta mTypes.ImageMeta) bool {
|
||||||
lookupDigest := digest
|
lookupDigest := digest
|
||||||
contains := false
|
|
||||||
|
// Check in case of an index if the index digest matches the search digest
|
||||||
|
// For Manifests, this is equivalent to imageMeta.Manifests[0]
|
||||||
|
if imageMeta.Digest.String() == lookupDigest {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
manifest := imageMeta.Manifests[0]
|
manifest := imageMeta.Manifests[0]
|
||||||
|
|
||||||
|
@ -85,24 +90,24 @@ func FilterByDigest(digest string) mTypes.FilterFunc {
|
||||||
// Check the image manifest in index.json matches the search digest
|
// Check the image manifest in index.json matches the search digest
|
||||||
// This is a blob with mediaType application/vnd.oci.image.manifest.v1+json
|
// This is a blob with mediaType application/vnd.oci.image.manifest.v1+json
|
||||||
if strings.Contains(manifestDigest, lookupDigest) {
|
if strings.Contains(manifestDigest, lookupDigest) {
|
||||||
contains = true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the image config matches the search digest
|
// Check the image config matches the search digest
|
||||||
// This is a blob with mediaType application/vnd.oci.image.config.v1+json
|
// This is a blob with mediaType application/vnd.oci.image.config.v1+json
|
||||||
if strings.Contains(manifest.Manifest.Config.Digest.String(), lookupDigest) {
|
if strings.Contains(manifest.Manifest.Config.Digest.String(), lookupDigest) {
|
||||||
contains = true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if the individual layers in the oci image manifest match the digest
|
// Check to see if the individual layers in the oci image manifest match the digest
|
||||||
// These are blobs with mediaType application/vnd.oci.image.layer.v1.tar+gzip
|
// These are blobs with mediaType application/vnd.oci.image.layer.v1.tar+gzip
|
||||||
for _, layer := range manifest.Manifest.Layers {
|
for _, layer := range manifest.Manifest.Layers {
|
||||||
if strings.Contains(layer.Digest.String(), lookupDigest) {
|
if strings.Contains(layer.Digest.String(), lookupDigest) {
|
||||||
contains = true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return contains
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,18 +633,10 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if searchingForRepos(query) {
|
switch getSearchTarget(query) {
|
||||||
skip := convert.SkipQGLField{
|
case RepoTarget:
|
||||||
Vulnerabilities: canSkipField(preloads, "Repos.NewestImage.Vulnerabilities"),
|
skip := convert.SkipQGLField{Vulnerabilities: canSkipField(preloads, "Repos.NewestImage.Vulnerabilities")}
|
||||||
}
|
pageInput := getPageInput(requestedPage)
|
||||||
|
|
||||||
pageInput := pagination.PageInput{
|
|
||||||
Limit: deref(requestedPage.Limit, 0),
|
|
||||||
Offset: deref(requestedPage.Offset, 0),
|
|
||||||
SortBy: pagination.SortCriteria(
|
|
||||||
deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
repoMetaList, err := metaDB.SearchRepos(ctx, query)
|
repoMetaList, err := metaDB.SearchRepos(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -667,18 +664,9 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
|
||||||
}
|
}
|
||||||
|
|
||||||
paginatedRepos.Results = repos
|
paginatedRepos.Results = repos
|
||||||
} else { // search for images
|
case ImageTarget:
|
||||||
skip := convert.SkipQGLField{
|
skip := convert.SkipQGLField{Vulnerabilities: canSkipField(preloads, "Images.Vulnerabilities")}
|
||||||
Vulnerabilities: canSkipField(preloads, "Images.Vulnerabilities"),
|
pageInput := getPageInput(requestedPage)
|
||||||
}
|
|
||||||
|
|
||||||
pageInput := pagination.PageInput{
|
|
||||||
Limit: deref(requestedPage.Limit, 0),
|
|
||||||
Offset: deref(requestedPage.Offset, 0),
|
|
||||||
SortBy: pagination.SortCriteria(
|
|
||||||
deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
fullImageMetaList, err := metaDB.SearchTags(ctx, query)
|
fullImageMetaList, err := metaDB.SearchTags(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -697,11 +685,71 @@ func globalSearch(ctx context.Context, query string, metaDB mTypes.MetaDB, filte
|
||||||
TotalCount: pageInfo.TotalCount,
|
TotalCount: pageInfo.TotalCount,
|
||||||
ItemCount: pageInfo.ItemCount,
|
ItemCount: pageInfo.ItemCount,
|
||||||
}
|
}
|
||||||
|
case DigestTarget:
|
||||||
|
skip := convert.SkipQGLField{Vulnerabilities: canSkipField(preloads, "Images.Vulnerabilities")}
|
||||||
|
pageInput := getPageInput(requestedPage)
|
||||||
|
|
||||||
|
searchedDigest := query
|
||||||
|
|
||||||
|
fullImageMetaList, err := metaDB.FilterTags(ctx, mTypes.AcceptAllRepoTag, FilterByDigest(searchedDigest))
|
||||||
|
if err != nil {
|
||||||
|
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
imageSummaries, pageInfo, err := convert.PaginatedFullImageMeta2ImageSummaries(ctx, fullImageMetaList, skip, cveInfo,
|
||||||
|
localFilter, pageInput)
|
||||||
|
if err != nil {
|
||||||
|
return &gql_generated.PaginatedReposResult{}, []*gql_generated.ImageSummary{}, []*gql_generated.LayerSummary{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
images = imageSummaries
|
||||||
|
|
||||||
|
paginatedRepos.Page = &gql_generated.PageInfo{
|
||||||
|
TotalCount: pageInfo.TotalCount,
|
||||||
|
ItemCount: pageInfo.ItemCount,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return &paginatedRepos, images, layers, zerr.ErrInvalidSearchQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
return &paginatedRepos, images, layers, nil
|
return &paginatedRepos, images, layers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPageInput(requestedPage *gql_generated.PageInput) pagination.PageInput {
|
||||||
|
return pagination.PageInput{
|
||||||
|
Limit: deref(requestedPage.Limit, 0),
|
||||||
|
Offset: deref(requestedPage.Offset, 0),
|
||||||
|
SortBy: pagination.SortCriteria(
|
||||||
|
deref(requestedPage.SortBy, gql_generated.SortCriteriaRelevance),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchTarget int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RepoTarget = iota
|
||||||
|
ImageTarget
|
||||||
|
DigestTarget
|
||||||
|
InvalidTarget
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSearchTarget(query string) SearchTarget {
|
||||||
|
if !strings.ContainsAny(query, ":@") {
|
||||||
|
return RepoTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(query, string(godigest.SHA256)+":") {
|
||||||
|
return DigestTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
if before, _, found := strings.Cut(query, ":"); found && before != "" {
|
||||||
|
return ImageTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
return InvalidTarget
|
||||||
|
}
|
||||||
|
|
||||||
func canSkipField(preloads map[string]bool, s string) bool {
|
func canSkipField(preloads map[string]bool, s string) bool {
|
||||||
fieldIsPresent := preloads[s]
|
fieldIsPresent := preloads[s]
|
||||||
|
|
||||||
|
@ -1100,10 +1148,6 @@ func deref[T any](pointer *T, defaultVal T) T {
|
||||||
return defaultVal
|
return defaultVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchingForRepos(query string) bool {
|
|
||||||
return !strings.Contains(query, ":")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getImageList(ctx context.Context, repo string, metaDB mTypes.MetaDB, cveInfo cveinfo.CveInfo,
|
func getImageList(ctx context.Context, repo string, metaDB mTypes.MetaDB, cveInfo cveinfo.CveInfo,
|
||||||
requestedPage *gql_generated.PageInput, log log.Logger, //nolint:unparam
|
requestedPage *gql_generated.PageInput, log log.Logger, //nolint:unparam
|
||||||
) (*gql_generated.PaginatedImagesResult, error) {
|
) (*gql_generated.PaginatedImagesResult, error) {
|
||||||
|
|
|
@ -88,6 +88,52 @@ func TestResolverGlobalSearch(t *testing.T) {
|
||||||
So(layers, ShouldBeEmpty)
|
So(layers, ShouldBeEmpty)
|
||||||
So(repos.Results, ShouldBeEmpty)
|
So(repos.Results, ShouldBeEmpty)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("Searching by digest", func() {
|
||||||
|
ctx := context.Background()
|
||||||
|
query := "sha256:aabb12341baf2"
|
||||||
|
mockMetaDB := mocks.MetaDBMock{
|
||||||
|
FilterTagsFn: func(ctx context.Context, filterRepoTag mTypes.FilterRepoTagFunc,
|
||||||
|
filterFunc mTypes.FilterFunc,
|
||||||
|
) ([]mTypes.FullImageMeta, error) {
|
||||||
|
return []mTypes.FullImageMeta{}, ErrTestError
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter, graphql.DefaultRecover)
|
||||||
|
repos, images, layers, err := globalSearch(responseContext, query, mockMetaDB, &gql_generated.Filter{},
|
||||||
|
&gql_generated.PageInput{}, mocks.CveInfoMock{}, log.NewLogger("debug", ""))
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(images, ShouldBeEmpty)
|
||||||
|
So(layers, ShouldBeEmpty)
|
||||||
|
So(repos.Results, ShouldBeEmpty)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Searching by digest with bad pagination", func() {
|
||||||
|
ctx := context.Background()
|
||||||
|
query := "sha256:aabb12341baf2"
|
||||||
|
|
||||||
|
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter, graphql.DefaultRecover)
|
||||||
|
repos, images, layers, err := globalSearch(responseContext, query, mocks.MetaDBMock{}, &gql_generated.Filter{},
|
||||||
|
&gql_generated.PageInput{Limit: ref(-10)}, mocks.CveInfoMock{}, log.NewLogger("debug", ""))
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(images, ShouldBeEmpty)
|
||||||
|
So(layers, ShouldBeEmpty)
|
||||||
|
So(repos.Results, ShouldBeEmpty)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Searching with a bad query", func() {
|
||||||
|
ctx := context.Background()
|
||||||
|
query := ":test"
|
||||||
|
|
||||||
|
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter, graphql.DefaultRecover)
|
||||||
|
repos, images, layers, err := globalSearch(responseContext, query, mocks.MetaDBMock{}, &gql_generated.Filter{},
|
||||||
|
&gql_generated.PageInput{}, mocks.CveInfoMock{}, log.NewLogger("debug", ""))
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
So(images, ShouldBeEmpty)
|
||||||
|
So(layers, ShouldBeEmpty)
|
||||||
|
So(repos.Results, ShouldBeEmpty)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +693,7 @@ func TestQueryResolverErrors(t *testing.T) {
|
||||||
}, mocks.CveInfoMock{})
|
}, mocks.CveInfoMock{})
|
||||||
resolver := queryResolver{resolverConfig}
|
resolver := queryResolver{resolverConfig}
|
||||||
|
|
||||||
_, err := resolver.GlobalSearch(ctx, "some_string", &gql_generated.Filter{}, getPageInput(1, 1))
|
_, err := resolver.GlobalSearch(ctx, "some_string", &gql_generated.Filter{}, getGQLPageInput(1, 1))
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1240,7 +1286,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("context done", func() {
|
Convey("context done", func() {
|
||||||
pageInput := getPageInput(1, 0)
|
pageInput := getGQLPageInput(1, 0)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
cancel()
|
cancel()
|
||||||
|
@ -1270,7 +1316,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
graphql.DefaultRecover,
|
graphql.DefaultRecover,
|
||||||
)
|
)
|
||||||
|
|
||||||
pageInput := getPageInput(1, 0)
|
pageInput := getGQLPageInput(1, 0)
|
||||||
|
|
||||||
images, err := getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err := getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1284,7 +1330,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 1)
|
pageInput = getGQLPageInput(1, 1)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1298,19 +1344,19 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 2)
|
pageInput = getGQLPageInput(1, 2)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(1, 5)
|
pageInput = getGQLPageInput(1, 5)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(2, 0)
|
pageInput = getGQLPageInput(2, 0)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1325,7 +1371,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1340,7 +1386,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 1)
|
pageInput = getGQLPageInput(5, 1)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1354,19 +1400,19 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 2)
|
pageInput = getGQLPageInput(5, 2)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(5, 5)
|
pageInput = getGQLPageInput(5, 5)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE2", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE2", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1382,7 +1428,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 3)
|
pageInput = getGQLPageInput(5, 3)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE2", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE2", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1397,7 +1443,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1412,7 +1458,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 5)
|
pageInput = getGQLPageInput(5, 5)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1427,7 +1473,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 10)
|
pageInput = getGQLPageInput(5, 10)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1442,7 +1488,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
}
|
}
|
||||||
|
|
||||||
amdFilter := &gql_generated.Filter{Arch: []*string{&AMD}}
|
amdFilter := &gql_generated.Filter{Arch: []*string{&AMD}}
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, amdFilter, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, amdFilter, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1458,7 +1504,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(2, 2)
|
pageInput = getGQLPageInput(2, 2)
|
||||||
|
|
||||||
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, amdFilter, pageInput, metaDB, log)
|
images, err = getImageListForCVE(responseContext, "CVE3", cveInfo, amdFilter, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1548,7 +1594,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
graphql.DefaultRecover,
|
graphql.DefaultRecover,
|
||||||
)
|
)
|
||||||
|
|
||||||
pageInput := getPageInput(1, 0)
|
pageInput := getGQLPageInput(1, 0)
|
||||||
|
|
||||||
images, err := getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err := getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1562,7 +1608,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 1)
|
pageInput = getGQLPageInput(1, 1)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1576,7 +1622,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 2)
|
pageInput = getGQLPageInput(1, 2)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1590,19 +1636,19 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 3)
|
pageInput = getGQLPageInput(1, 3)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(1, 10)
|
pageInput = getGQLPageInput(1, 10)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(images.Results), ShouldEqual, 0)
|
So(len(images.Results), ShouldEqual, 0)
|
||||||
|
|
||||||
pageInput = getPageInput(2, 0)
|
pageInput = getGQLPageInput(2, 0)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1616,7 +1662,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(2, 1)
|
pageInput = getGQLPageInput(2, 1)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1630,7 +1676,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(2, 2)
|
pageInput = getGQLPageInput(2, 2)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1644,7 +1690,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1658,7 +1704,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 0)
|
pageInput = getGQLPageInput(5, 0)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE2", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE2", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1672,7 +1718,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(5, 2)
|
pageInput = getGQLPageInput(5, 2)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE2", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE2", "repo1", cveInfo, nil, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1681,7 +1727,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
amdFilter := &gql_generated.Filter{Arch: []*string{&AMD}}
|
amdFilter := &gql_generated.Filter{Arch: []*string{&AMD}}
|
||||||
armFilter := &gql_generated.Filter{Arch: []*string{&ARM}}
|
armFilter := &gql_generated.Filter{Arch: []*string{&ARM}}
|
||||||
|
|
||||||
pageInput = getPageInput(3, 0)
|
pageInput = getGQLPageInput(3, 0)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, amdFilter, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, amdFilter, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -1703,7 +1749,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
|
||||||
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageInput = getPageInput(1, 1)
|
pageInput = getGQLPageInput(1, 1)
|
||||||
|
|
||||||
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, armFilter, pageInput, metaDB, log)
|
images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, armFilter, pageInput, metaDB, log)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
@ -2213,7 +2259,7 @@ func ref[T any](input T) *T {
|
||||||
return &ref
|
return &ref
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPageInput(limit int, offset int) *gql_generated.PageInput {
|
func getGQLPageInput(limit int, offset int) *gql_generated.PageInput {
|
||||||
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
sortCriteria := gql_generated.SortCriteriaAlphabeticAsc
|
||||||
|
|
||||||
return &gql_generated.PageInput{
|
return &gql_generated.PageInput{
|
||||||
|
|
|
@ -3651,6 +3651,71 @@ func TestGlobalSearch(t *testing.T) {
|
||||||
So(actualImageSummary.Vulnerabilities.Count, ShouldEqual, 4)
|
So(actualImageSummary.Vulnerabilities.Count, ShouldEqual, 4)
|
||||||
So(actualImageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
|
So(actualImageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey("global searching by digest", t, func() {
|
||||||
|
log := log.NewLogger("debug", "")
|
||||||
|
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)
|
||||||
|
|
||||||
|
storeCtlr := ociutils.GetDefaultStoreController(rootDir, log)
|
||||||
|
|
||||||
|
image1 := CreateRandomImage()
|
||||||
|
image2 := CreateRandomImage()
|
||||||
|
multiArch := CreateRandomMultiarch()
|
||||||
|
|
||||||
|
err := WriteImageToFileSystem(image1, "repo1", "tag1", storeCtlr)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = WriteImageToFileSystem(image2, "repo1", "tag2", storeCtlr)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
err = WriteMultiArchImageToFileSystem(multiArch, "repo1", "tag-multi", storeCtlr)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = WriteImageToFileSystem(image2, "repo2", "tag2", storeCtlr)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
ctlrManager.StartAndWait(port)
|
||||||
|
defer ctlrManager.StopServer()
|
||||||
|
|
||||||
|
// simple image
|
||||||
|
results := GlobalSearchGQL(image1.DigestStr(), baseURL).GlobalSearch
|
||||||
|
So(len(results.Images), ShouldEqual, 1)
|
||||||
|
So(results.Images[0].Digest, ShouldResemble, image1.DigestStr())
|
||||||
|
So(results.Images[0].RepoName, ShouldResemble, "repo1")
|
||||||
|
|
||||||
|
results = GlobalSearchGQL(image2.DigestStr(), baseURL).GlobalSearch
|
||||||
|
So(len(results.Images), ShouldEqual, 2)
|
||||||
|
|
||||||
|
repos := AccumulateField(results.Images,
|
||||||
|
func(is zcommon.ImageSummary) string { return is.RepoName })
|
||||||
|
So(repos, ShouldContain, "repo1")
|
||||||
|
So(repos, ShouldContain, "repo2")
|
||||||
|
|
||||||
|
// multiarch
|
||||||
|
results = GlobalSearchGQL(multiArch.DigestStr(), baseURL).GlobalSearch
|
||||||
|
So(len(results.Images), ShouldEqual, 1)
|
||||||
|
So(results.Images[0].Digest, ShouldResemble, multiArch.DigestStr())
|
||||||
|
So(len(results.Images[0].Manifests), ShouldEqual, len(multiArch.Images))
|
||||||
|
So(results.Images[0].RepoName, ShouldResemble, "repo1")
|
||||||
|
|
||||||
|
results = GlobalSearchGQL(multiArch.Images[0].DigestStr(), baseURL).GlobalSearch
|
||||||
|
So(len(results.Images), ShouldEqual, 1)
|
||||||
|
So(results.Images[0].Digest, ShouldResemble, multiArch.DigestStr())
|
||||||
|
So(len(results.Images[0].Manifests), ShouldEqual, 1)
|
||||||
|
So(results.Images[0].Manifests[0].Digest, ShouldResemble, multiArch.Images[0].DigestStr())
|
||||||
|
So(results.Images[0].RepoName, ShouldResemble, "repo1")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCleaningFilteringParamsGlobalSearch(t *testing.T) {
|
func TestCleaningFilteringParamsGlobalSearch(t *testing.T) {
|
||||||
|
|
|
@ -639,16 +639,17 @@ func (bdw *BoltDB) FilterTags(ctx context.Context, filterRepoTag mTypes.FilterRe
|
||||||
case ispec.MediaTypeImageIndex:
|
case ispec.MediaTypeImageIndex:
|
||||||
indexDigest := descriptor.Digest
|
indexDigest := descriptor.Digest
|
||||||
|
|
||||||
imageIndexData, err := getProtoImageMeta(imageMetaBuck, indexDigest)
|
protoImageIndexMeta, err := getProtoImageMeta(imageMetaBuck, indexDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
viewError = errors.Join(viewError, err)
|
viewError = errors.Join(viewError, err)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imageIndexMeta := mConvert.GetImageMeta(protoImageIndexMeta)
|
||||||
matchedManifests := []*proto_go.ManifestMeta{}
|
matchedManifests := []*proto_go.ManifestMeta{}
|
||||||
|
|
||||||
for _, manifest := range imageIndexData.Index.Index.Manifests {
|
for _, manifest := range protoImageIndexMeta.Index.Index.Manifests {
|
||||||
manifestDigest := manifest.Digest
|
manifestDigest := manifest.Digest
|
||||||
|
|
||||||
imageManifestData, err := getProtoImageMeta(imageMetaBuck, manifestDigest)
|
imageManifestData, err := getProtoImageMeta(imageMetaBuck, manifestDigest)
|
||||||
|
@ -659,16 +660,17 @@ func (bdw *BoltDB) FilterTags(ctx context.Context, filterRepoTag mTypes.FilterRe
|
||||||
}
|
}
|
||||||
|
|
||||||
imageMeta := mConvert.GetImageMeta(imageManifestData)
|
imageMeta := mConvert.GetImageMeta(imageManifestData)
|
||||||
|
partialImageMeta := common.GetPartialImageMeta(imageIndexMeta, imageMeta)
|
||||||
|
|
||||||
if filterFunc(repoMeta, imageMeta) {
|
if filterFunc(repoMeta, partialImageMeta) {
|
||||||
matchedManifests = append(matchedManifests, imageManifestData.Manifests[0])
|
matchedManifests = append(matchedManifests, imageManifestData.Manifests[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matchedManifests) > 0 {
|
if len(matchedManifests) > 0 {
|
||||||
imageIndexData.Manifests = matchedManifests
|
protoImageIndexMeta.Manifests = matchedManifests
|
||||||
|
|
||||||
images = append(images, mConvert.GetFullImageMetaFromProto(tag, protoRepoMeta, imageIndexData))
|
images = append(images, mConvert.GetFullImageMetaFromProto(tag, protoRepoMeta, protoImageIndexMeta))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
bdw.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type")
|
bdw.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type")
|
||||||
|
|
|
@ -386,3 +386,35 @@ func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey s
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPartialImageMeta(imageIndexMeta mTypes.ImageMeta, imageMeta mTypes.ImageMeta) mTypes.ImageMeta {
|
||||||
|
partialImageMeta := imageIndexMeta
|
||||||
|
partialImageMeta.Manifests = imageMeta.Manifests
|
||||||
|
|
||||||
|
partialIndex := deref(imageIndexMeta.Index, ispec.Index{})
|
||||||
|
partialIndex.Manifests = getPartialManifestList(partialIndex.Manifests, imageMeta.Digest.String())
|
||||||
|
|
||||||
|
partialImageMeta.Index = &partialIndex
|
||||||
|
|
||||||
|
return partialImageMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPartialManifestList(descriptors []ispec.Descriptor, manifestDigest string) []ispec.Descriptor {
|
||||||
|
result := []ispec.Descriptor{}
|
||||||
|
|
||||||
|
for i := range descriptors {
|
||||||
|
if descriptors[i].Digest.String() == manifestDigest {
|
||||||
|
result = append(result, descriptors[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func deref[T any](pointer *T, defaultVal T) T {
|
||||||
|
if pointer != nil {
|
||||||
|
return *pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@ import (
|
||||||
var ErrTestError = errors.New("test error")
|
var ErrTestError = errors.New("test error")
|
||||||
|
|
||||||
func TestUtils(t *testing.T) {
|
func TestUtils(t *testing.T) {
|
||||||
|
Convey("GetPartialImageMeta", t, func() {
|
||||||
|
So(func() { common.GetPartialImageMeta(mTypes.ImageMeta{}, mTypes.ImageMeta{}) }, ShouldNotPanic)
|
||||||
|
})
|
||||||
|
|
||||||
Convey("MatchesArtifactTypes", t, func() {
|
Convey("MatchesArtifactTypes", t, func() {
|
||||||
res := common.MatchesArtifactTypes("", nil)
|
res := common.MatchesArtifactTypes("", nil)
|
||||||
So(res, ShouldBeTrue)
|
So(res, ShouldBeTrue)
|
||||||
|
|
|
@ -528,9 +528,9 @@ func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta {
|
||||||
if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
|
if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
|
||||||
manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
|
manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
|
||||||
|
|
||||||
for _, manifest := range dbImageMeta.Manifests {
|
for _, manifest := range deref(dbImageMeta.Index, proto_go.IndexMeta{}).Index.Manifests {
|
||||||
manifests = append(manifests, ispec.Descriptor{
|
manifests = append(manifests, ispec.Descriptor{
|
||||||
MediaType: deref(manifest.Manifest.MediaType, ""),
|
MediaType: manifest.MediaType,
|
||||||
Digest: godigest.Digest(manifest.Digest),
|
Digest: godigest.Digest(manifest.Digest),
|
||||||
Size: manifest.Size,
|
Size: manifest.Size,
|
||||||
})
|
})
|
||||||
|
|
|
@ -729,16 +729,17 @@ func (dwr *DynamoDB) FilterTags(ctx context.Context, filterRepoTag mTypes.Filter
|
||||||
case ispec.MediaTypeImageIndex:
|
case ispec.MediaTypeImageIndex:
|
||||||
indexDigest := descriptor.Digest
|
indexDigest := descriptor.Digest
|
||||||
|
|
||||||
imageIndexData, err := dwr.GetProtoImageMeta(ctx, godigest.Digest(indexDigest))
|
protoImageIndexMeta, err := dwr.GetProtoImageMeta(ctx, godigest.Digest(indexDigest))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
viewError = errors.Join(viewError, err)
|
viewError = errors.Join(viewError, err)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imageIndexMeta := mConvert.GetImageMeta(protoImageIndexMeta)
|
||||||
matchedManifests := []*proto_go.ManifestMeta{}
|
matchedManifests := []*proto_go.ManifestMeta{}
|
||||||
|
|
||||||
for _, manifest := range imageIndexData.Index.Index.Manifests {
|
for _, manifest := range protoImageIndexMeta.Index.Index.Manifests {
|
||||||
manifestDigest := manifest.Digest
|
manifestDigest := manifest.Digest
|
||||||
|
|
||||||
imageManifestData, err := dwr.GetProtoImageMeta(ctx, godigest.Digest(manifestDigest))
|
imageManifestData, err := dwr.GetProtoImageMeta(ctx, godigest.Digest(manifestDigest))
|
||||||
|
@ -749,16 +750,17 @@ func (dwr *DynamoDB) FilterTags(ctx context.Context, filterRepoTag mTypes.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
imageMeta := mConvert.GetImageMeta(imageManifestData)
|
imageMeta := mConvert.GetImageMeta(imageManifestData)
|
||||||
|
partialImageMeta := common.GetPartialImageMeta(imageIndexMeta, imageMeta)
|
||||||
|
|
||||||
if filterFunc(repoMeta, imageMeta) {
|
if filterFunc(repoMeta, partialImageMeta) {
|
||||||
matchedManifests = append(matchedManifests, imageManifestData.Manifests[0])
|
matchedManifests = append(matchedManifests, imageManifestData.Manifests[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matchedManifests) > 0 {
|
if len(matchedManifests) > 0 {
|
||||||
imageIndexData.Manifests = matchedManifests
|
protoImageIndexMeta.Manifests = matchedManifests
|
||||||
|
|
||||||
images = append(images, mConvert.GetFullImageMetaFromProto(tag, protoRepoMeta, imageIndexData))
|
images = append(images, mConvert.GetFullImageMetaFromProto(tag, protoRepoMeta, protoImageIndexMeta))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
dwr.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type")
|
dwr.Log.Error().Str("mediaType", descriptor.MediaType).Msg("Unsupported media type")
|
||||||
|
|
|
@ -57,9 +57,6 @@ type MetaDBMock struct {
|
||||||
|
|
||||||
SearchTagsFn func(ctx context.Context, searchText string) ([]mTypes.FullImageMeta, error)
|
SearchTagsFn func(ctx context.Context, searchText string) ([]mTypes.FullImageMeta, error)
|
||||||
|
|
||||||
FilterTagFn func(ctx context.Context, filterFunc mTypes.FilterFunc,
|
|
||||||
) ([]mTypes.RepoMeta, map[string]mTypes.ImageMeta, error)
|
|
||||||
|
|
||||||
GetImageMetaFn func(digest godigest.Digest) (mTypes.ImageMeta, error)
|
GetImageMetaFn func(digest godigest.Digest) (mTypes.ImageMeta, error)
|
||||||
|
|
||||||
GetMultipleRepoMetaFn func(ctx context.Context, filter func(repoMeta mTypes.RepoMeta) bool,
|
GetMultipleRepoMetaFn func(ctx context.Context, filter func(repoMeta mTypes.RepoMeta) bool,
|
||||||
|
|
Loading…
Reference in a new issue