From f00a9e6e48f1992876920d83a19e34d1afe99ff9 Mon Sep 17 00:00:00 2001 From: Nicol Date: Wed, 15 Feb 2023 21:34:07 +0200 Subject: [PATCH] perf: update the ImageList queries to return PaginatedImagesResult (#1182) Signed-off-by: Nicol Draghici --- pkg/cli/image_cmd_test.go | 20 +- pkg/cli/searcher.go | 14 +- pkg/cli/service.go | 62 ++-- pkg/extensions/search/common/common_test.go | 60 ++-- pkg/extensions/search/cve/cve_test.go | 28 +- pkg/extensions/search/digest/digest_test.go | 48 +-- .../search/gql_generated/generated.go | 295 ++++-------------- pkg/extensions/search/resolver.go | 65 ++-- pkg/extensions/search/resolver_test.go | 126 ++++---- pkg/extensions/search/schema.graphql | 8 +- pkg/extensions/search/schema.resolvers.go | 12 +- pkg/extensions/search/search.md | 143 +++++---- test/blackbox/annotations.bats | 29 +- 13 files changed, 397 insertions(+), 513 deletions(-) diff --git a/pkg/cli/image_cmd_test.go b/pkg/cli/image_cmd_test.go index 6a1c11db..acce9c19 100644 --- a/pkg/cli/image_cmd_test.go +++ b/pkg/cli/image_cmd_test.go @@ -1536,7 +1536,7 @@ func (service mockService) getDerivedImageListGQL(ctx context.Context, config se derivedImage string, ) (*imageListStructForDerivedImagesGQL, error) { imageListGQLResponse := &imageListStructForDerivedImagesGQL{} - imageListGQLResponse.Data.ImageList.Results = []imageStruct{ + imageListGQLResponse.Data.Results = []imageStruct{ { RepoName: "dummyImageName", Tag: "tag", @@ -1554,7 +1554,7 @@ func (service mockService) getBaseImageListGQL(ctx context.Context, config searc derivedImage string, ) (*imageListStructForBaseImagesGQL, error) { imageListGQLResponse := &imageListStructForBaseImagesGQL{} - imageListGQLResponse.Data.ImageList.Results = []imageStruct{ + imageListGQLResponse.Data.Results = []imageStruct{ { RepoName: "dummyImageName", Tag: "tag", @@ -1572,7 +1572,7 @@ func (service mockService) getImagesGQL(ctx context.Context, config searchConfig imageName string, ) (*imageListStructGQL, error) { imageListGQLResponse := &imageListStructGQL{} - imageListGQLResponse.Data.ImageList = []imageStruct{ + imageListGQLResponse.Data.Results = []imageStruct{ { RepoName: "dummyImageName", Tag: "tag", @@ -1590,7 +1590,7 @@ func (service mockService) getImagesByDigestGQL(ctx context.Context, config sear digest string, ) (*imageListStructForDigestGQL, error) { imageListGQLResponse := &imageListStructForDigestGQL{} - imageListGQLResponse.Data.ImageList = []imageStruct{ + imageListGQLResponse.Data.Results = []imageStruct{ { RepoName: "randomimageName", Tag: "tag", @@ -1610,14 +1610,14 @@ func (service mockService) getImagesByCveIDGQL(ctx context.Context, config searc imagesForCve := &imagesForCve{ Errors: nil, Data: struct { - ImageList []imageStruct `json:"ImageListForCVE"` //nolint:tagliatelle + PaginatedImagesResult `json:"ImageListForCVE"` //nolint:tagliatelle }{}, } imagesForCve.Errors = nil mockedImage := service.getMockedImageByName("anImage") - imagesForCve.Data.ImageList = []imageStruct{mockedImage} + imagesForCve.Data.Results = []imageStruct{mockedImage} return imagesForCve, nil } @@ -1628,14 +1628,14 @@ func (service mockService) getTagsForCVEGQL(ctx context.Context, config searchCo images := &imagesForCve{ Errors: nil, Data: struct { - ImageList []imageStruct `json:"ImageListForCVE"` //nolint:tagliatelle // graphQL schema + PaginatedImagesResult `json:"ImageListForCVE"` //nolint:tagliatelle // graphQL schema }{}, } images.Errors = nil mockedImage := service.getMockedImageByName(imageName) - images.Data.ImageList = []imageStruct{mockedImage} + images.Data.Results = []imageStruct{mockedImage} return images, nil } @@ -1646,14 +1646,14 @@ func (service mockService) getFixedTagsForCVEGQL(ctx context.Context, config sea fixedTags := &fixedTags{ Errors: nil, Data: struct { - ImageList []imageStruct `json:"ImageListWithCVEFixed"` //nolint:tagliatelle // graphQL schema + PaginatedImagesResult `json:"ImageListWithCVEFixed"` //nolint:tagliatelle // graphQL schema }{}, } fixedTags.Errors = nil mockedImage := service.getMockedImageByName(imageName) - fixedTags.Data.ImageList = []imageStruct{mockedImage} + fixedTags.Data.Results = []imageStruct{mockedImage} return fixedTags, nil } diff --git a/pkg/cli/searcher.go b/pkg/cli/searcher.go index 914eac62..0eaf8936 100644 --- a/pkg/cli/searcher.go +++ b/pkg/cli/searcher.go @@ -188,7 +188,7 @@ func getImages(config searchConfig) error { return err } - return printResult(config, imageList.Data.ImageList) + return printResult(config, imageList.Data.Results) } type imagesByDigestSearcher struct{} @@ -241,7 +241,7 @@ func (search derivedImageListSearcherGQL) search(config searchConfig) (bool, err return true, err } - if err := printResult(config, imageList.Data.ImageList.Results); err != nil { + if err := printResult(config, imageList.Data.Results); err != nil { return true, err } @@ -266,7 +266,7 @@ func (search baseImageListSearcherGQL) search(config searchConfig) (bool, error) return true, err } - if err := printResult(config, imageList.Data.ImageList.Results); err != nil { + if err := printResult(config, imageList.Data.Results); err != nil { return true, err } @@ -292,7 +292,7 @@ func (search imagesByDigestSearcherGQL) search(config searchConfig) (bool, error return true, err } - if err := printResult(config, imageList.Data.ImageList); err != nil { + if err := printResult(config, imageList.Data.Results); err != nil { return true, err } @@ -427,7 +427,7 @@ func (search imagesByCVEIDSearcherGQL) search(config searchConfig) (bool, error) return true, err } - if err := printResult(config, imageList.Data.ImageList); err != nil { + if err := printResult(config, imageList.Data.Results); err != nil { return true, err } @@ -553,7 +553,7 @@ func getTagsByCVE(config searchConfig) error { return err } - imageList = fixedTags.Data.ImageList + imageList = fixedTags.Data.Results } else { tags, err := config.searchService.getTagsForCVEGQL(ctx, config, username, password, *config.params["imageName"], *config.params["cveID"]) @@ -561,7 +561,7 @@ func getTagsByCVE(config searchConfig) error { return err } - imageList = tags.Data.ImageList + imageList = tags.Data.Results } return printResult(config, imageList) diff --git a/pkg/cli/service.go b/pkg/cli/service.go index 4c919b33..c6bc0266 100644 --- a/pkg/cli/service.go +++ b/pkg/cli/service.go @@ -126,8 +126,8 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea func (service searchService) getImagesGQL(ctx context.Context, config searchConfig, username, password string, imageName string, ) (*imageListStructGQL, error) { - query := fmt.Sprintf(`{ImageList(repo: "%s") {`+` - RepoName Tag Digest ConfigDigest Size Layers {Size Digest} IsSigned} + query := fmt.Sprintf(`{ImageList(repo: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Size Layers {Size Digest} IsSigned}} }`, imageName) result := &imageListStructGQL{} @@ -144,8 +144,8 @@ func (service searchService) getImagesGQL(ctx context.Context, config searchConf func (service searchService) getImagesByDigestGQL(ctx context.Context, config searchConfig, username, password string, digest string, ) (*imageListStructForDigestGQL, error) { - query := fmt.Sprintf(`{ImageListForDigest(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Size Layers {Size Digest}} + query := fmt.Sprintf(`{ImageListForDigest(id: "%s") { Results{`+` + RepoName Tag Digest ConfigDigest Size Layers {Size Digest}}} }`, digest) result := &imageListStructForDigestGQL{} @@ -162,8 +162,8 @@ func (service searchService) getImagesByDigestGQL(ctx context.Context, config se func (service searchService) getImagesByCveIDGQL(ctx context.Context, config searchConfig, username, password, cveID string, ) (*imagesForCve, error) { - query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Layers {Size Digest} Size} + query := fmt.Sprintf(`{ImageListForCVE(id: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}} }`, cveID) result := &imagesForCve{} @@ -199,8 +199,8 @@ func (service searchService) getCveByImageGQL(ctx context.Context, config search func (service searchService) getTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, imageName, cveID string, ) (*imagesForCve, error) { - query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Layers {Size Digest} Size} + query := fmt.Sprintf(`{ImageListForCVE(id: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}} }`, cveID) result := &imagesForCve{} @@ -217,8 +217,8 @@ func (service searchService) getTagsForCVEGQL(ctx context.Context, config search func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config searchConfig, username, password, imageName, cveID string, ) (*fixedTags, error) { - query := fmt.Sprintf(`{ImageListWithCVEFixed(id: "%s", image: "%s") {`+` - RepoName Tag Digest ConfigDigest Layers {Size Digest} Size} + query := fmt.Sprintf(`{ImageListWithCVEFixed(id: "%s", image: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}} }`, cveID, imageName) @@ -349,8 +349,8 @@ func (service searchService) getImagesByCveID(ctx context.Context, config search defer wtgrp.Done() defer close(rch) - query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Layers {Size Digest} Size} + query := fmt.Sprintf(`{ImageListForCVE(id: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}} }`, cvid) result := &imagesForCve{} @@ -387,7 +387,7 @@ func (service searchService) getImagesByCveID(ctx context.Context, config search go rlim.startRateLimiter(ctx) - for _, image := range result.Data.ImageList { + for _, image := range result.Data.Results { localWg.Add(1) go addManifestCallToPool(ctx, config, rlim, username, password, image.RepoName, image.Tag, rch, &localWg) @@ -402,8 +402,8 @@ func (service searchService) getImagesByDigest(ctx context.Context, config searc defer wtgrp.Done() defer close(rch) - query := fmt.Sprintf(`{ImageListForDigest(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Size Layers {Size Digest}} + query := fmt.Sprintf(`{ImageListForDigest(id: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Size Layers {Size Digest}}} }`, digest) result := &imagesForDigest{} @@ -440,7 +440,7 @@ func (service searchService) getImagesByDigest(ctx context.Context, config searc go rlim.startRateLimiter(ctx) - for _, image := range result.Data.ImageList { + for _, image := range result.Data.Results { localWg.Add(1) go addManifestCallToPool(ctx, config, rlim, username, password, image.RepoName, image.Tag, rch, &localWg) @@ -455,8 +455,8 @@ func (service searchService) getImageByNameAndCVEID(ctx context.Context, config defer wtgrp.Done() defer close(rch) - query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+` - RepoName Tag Digest ConfigDigest Size Layers {Size Digest}} + query := fmt.Sprintf(`{ImageListForCVE(id: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Size Layers {Size Digest}}} }`, cvid) result := &imagesForCve{} @@ -493,7 +493,7 @@ func (service searchService) getImageByNameAndCVEID(ctx context.Context, config go rlim.startRateLimiter(ctx) - for _, image := range result.Data.ImageList { + for _, image := range result.Data.Results { if !strings.EqualFold(imageName, image.RepoName) { continue } @@ -566,8 +566,8 @@ func (service searchService) getFixedTagsForCVE(ctx context.Context, config sear defer wtgrp.Done() defer close(rch) - query := fmt.Sprintf(`{ImageListWithCVEFixed (id: "%s", image: "%s") {`+` - RepoName Tag Digest ConfigDigest Layers {Size Digest} Size} + query := fmt.Sprintf(`{ImageListWithCVEFixed (id: "%s", image: "%s") { Results {`+` + RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}} }`, cvid, imageName) result := &fixedTags{} @@ -604,7 +604,7 @@ func (service searchService) getFixedTagsForCVE(ctx context.Context, config sear go rlim.startRateLimiter(ctx) - for _, img := range result.Data.ImageList { + for _, img := range result.Data.Results { localWg.Add(1) go addManifestCallToPool(ctx, config, rlim, username, password, imageName, img.Tag, rch, &localWg) @@ -844,17 +844,21 @@ func (cve cveResult) stringYAML() (string, error) { type fixedTags struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList []imageStruct `json:"ImageListWithCVEFixed"` //nolint:tagliatelle // graphQL schema + PaginatedImagesResult `json:"ImageListWithCVEFixed"` //nolint:tagliatelle // graphQL schema } `json:"data"` } type imagesForCve struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList []imageStruct `json:"ImageListForCVE"` //nolint:tagliatelle // graphQL schema + PaginatedImagesResult `json:"ImageListForCVE"` //nolint:tagliatelle // graphQL schema } `json:"data"` } +type PaginatedImagesResult struct { + Results []imageStruct `json:"results"` +} + type imageStruct struct { RepoName string `json:"repoName"` Tag string `json:"tag"` @@ -876,35 +880,35 @@ type BaseImageList struct { type imageListStructGQL struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList []imageStruct `json:"ImageList"` //nolint:tagliatelle + PaginatedImagesResult `json:"ImageList"` //nolint:tagliatelle } `json:"data"` } type imageListStructForDigestGQL struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList []imageStruct `json:"ImageListForDigest"` //nolint:tagliatelle + PaginatedImagesResult `json:"ImageListForDigest"` //nolint:tagliatelle } `json:"data"` } type imageListStructForDerivedImagesGQL struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList DerivedImageList `json:"DerivedImageList"` //nolint:tagliatelle + PaginatedImagesResult `json:"DerivedImageList"` //nolint:tagliatelle } `json:"data"` } type imageListStructForBaseImagesGQL struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList BaseImageList `json:"BaseImageList"` //nolint:tagliatelle + PaginatedImagesResult `json:"BaseImageList"` //nolint:tagliatelle } `json:"data"` } type imagesForDigest struct { Errors []errorGraphQL `json:"errors"` Data struct { - ImageList []imageStruct `json:"ImageListForDigest"` //nolint:tagliatelle // graphQL schema + PaginatedImagesResult `json:"ImageListForDigest"` //nolint:tagliatelle // graphQL schema } `json:"data"` } diff --git a/pkg/extensions/search/common/common_test.go b/pkg/extensions/search/common/common_test.go index e20e21db..881cb7e0 100644 --- a/pkg/extensions/search/common/common_test.go +++ b/pkg/extensions/search/common/common_test.go @@ -81,14 +81,14 @@ type ImageListResponse struct { } type ImageList struct { - SummaryList []common.ImageSummary `json:"imageList"` + PaginatedImagesResult `json:"imageList"` } type DerivedImageList struct { - DerivedList []common.ImageSummary `json:"derivedImageList"` + PaginatedImagesResult `json:"derivedImageList"` } type BaseImageList struct { - BaseList []common.ImageSummary `json:"baseImageList"` + PaginatedImagesResult `json:"baseImageList"` } type ExpandedRepoInfoResp struct { @@ -3582,17 +3582,19 @@ func TestImageList(t *testing.T) { Convey("without pagination, valid response", func() { query := fmt.Sprintf(`{ ImageList(repo:"%s"){ - History{ - HistoryDescription{ - Author - Comment - Created - CreatedBy - EmptyLayer - }, - Layer{ - Digest - Size + Results{ + History{ + HistoryDescription{ + Author + Comment + Created + CreatedBy + EmptyLayer + }, + Layer{ + Digest + Size + } } } } @@ -3607,25 +3609,27 @@ func TestImageList(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) - So(len(responseStruct.ImageList.SummaryList), ShouldEqual, len(tags)) - So(len(responseStruct.ImageList.SummaryList[0].History), ShouldEqual, len(imageConfigInfo.History)) + So(len(responseStruct.ImageList.Results), ShouldEqual, len(tags)) + So(len(responseStruct.ImageList.Results[0].History), ShouldEqual, len(imageConfigInfo.History)) }) Convey("Pagination with valid params", func() { limit := 1 query := fmt.Sprintf(`{ ImageList(repo:"%s", requestedPage:{limit: %d, offset: 0, sortBy:RELEVANCE}){ - History{ - HistoryDescription{ - Author - Comment - Created - CreatedBy - EmptyLayer - }, - Layer{ - Digest - Size + Results{ + History{ + HistoryDescription{ + Author + Comment + Created + CreatedBy + EmptyLayer + }, + Layer{ + Digest + Size + } } } } @@ -3640,7 +3644,7 @@ func TestImageList(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) - So(len(responseStruct.ImageList.SummaryList), ShouldEqual, limit) + So(len(responseStruct.ImageList.Results), ShouldEqual, limit) }) }) } diff --git a/pkg/extensions/search/cve/cve_test.go b/pkg/extensions/search/cve/cve_test.go index d177c750..1dac242c 100644 --- a/pkg/extensions/search/cve/cve_test.go +++ b/pkg/extensions/search/cve/cve_test.go @@ -423,11 +423,11 @@ func TestCVESearchDisabled(t *testing.T) { So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){RepoName%20Tag}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + "randomId" + "\",image:\"zot-test\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + "randomId" + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) @@ -547,7 +547,7 @@ func TestCVESearch(t *testing.T) { cvid := cveResult.ImgList.CVEResultForImage.CVEList[0].ID - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -556,7 +556,7 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) So(len(imgListWithCVEFixed.Images), ShouldEqual, 0) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-cve-test\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-cve-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -564,7 +564,7 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) So(len(imgListWithCVEFixed.Images), ShouldEqual, 0) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -581,7 +581,7 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noindex\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noindex\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -589,7 +589,7 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-index\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-index\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -597,11 +597,11 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noblob\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-noblob\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-test\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -609,7 +609,7 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-blob\"){RepoName%20LastUpdated}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cvid + "\",image:\"zot-squashfs-invalid-blob\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -621,7 +621,7 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){RepoName%20Tag}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -662,11 +662,11 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(tet:\"CVE-2018-20482\"){RepoName%20Tag}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(tet:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageistForCVE(id:\"CVE-2018-20482\"){RepoName%20Tag}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageistForCVE(id:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) @@ -678,7 +678,7 @@ func TestCVESearch(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"" + cvid + "\"){RepoName%20Tag}}") + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"" + cvid + "\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) }) diff --git a/pkg/extensions/search/digest/digest_test.go b/pkg/extensions/search/digest/digest_test.go index ca152a0e..bc919db5 100644 --- a/pkg/extensions/search/digest/digest_test.go +++ b/pkg/extensions/search/digest/digest_test.go @@ -20,6 +20,7 @@ import ( "zotregistry.io/zot/pkg/extensions/monitoring" digestinfo "zotregistry.io/zot/pkg/extensions/search/digest" "zotregistry.io/zot/pkg/log" + "zotregistry.io/zot/pkg/meta/repodb" "zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage/local" . "zotregistry.io/zot/pkg/test" @@ -32,7 +33,7 @@ type ImgResponseForDigest struct { //nolint:tagliatelle // graphQL schema type ImgListForDigest struct { - Images []ImgInfo `json:"ImageListForDigest"` + PaginatedImagesResult `json:"ImageListForDigest"` } //nolint:tagliatelle // graphQL schema @@ -49,6 +50,11 @@ type ErrorGQL struct { Path []string `json:"path"` } +type PaginatedImagesResult struct { + Results []ImgInfo `json:"results"` + Page repodb.PageInfo `json:"page"` +} + func testSetup(t *testing.T) (string, string, *digestinfo.DigestInfo) { t.Helper() dir := t.TempDir() @@ -155,7 +161,7 @@ func TestDigestSearchHTTP(t *testing.T) { // "sha" should match all digests in all images resp, err = resty.R().Get( baseURL + constants.FullSearchPrefix + `?query={ImageListForDigest(id:"sha")` + - `{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}`, + `{Results{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}}`, ) So(resp, ShouldNotBeNil) So(err, ShouldBeNil) @@ -165,14 +171,14 @@ func TestDigestSearchHTTP(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) So(len(responseStruct.Errors), ShouldEqual, 0) - So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 2) - So(responseStruct.ImgListForDigest.Images[0].Tag, ShouldEqual, "0.0.1") + So(len(responseStruct.ImgListForDigest.Results), ShouldEqual, 2) + So(responseStruct.ImgListForDigest.Results[0].Tag, ShouldEqual, "0.0.1") // Call should return {"data":{"ImageListForDigest":[{"Name":"zot-test","Tags":["0.0.1"]}]}} // GetTestBlobDigest("zot-test", "manifest").Encoded() should match the manifest of 1 image gqlQuery := url.QueryEscape(`{ImageListForDigest(id:"` + GetTestBlobDigest("zot-test", "manifest").Encoded() + `") - {RepoName Tag Digest ConfigDigest Size Layers { Digest }}}`) + {Results{RepoName Tag Digest ConfigDigest Size Layers { Digest }}}}`) targetURL := baseURL + constants.FullSearchPrefix + `?query=` + gqlQuery resp, err = resty.R().Get(targetURL) @@ -184,13 +190,13 @@ func TestDigestSearchHTTP(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) So(len(responseStruct.Errors), ShouldEqual, 0) - So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 1) - So(responseStruct.ImgListForDigest.Images[0].RepoName, ShouldEqual, "zot-test") - So(responseStruct.ImgListForDigest.Images[0].Tag, ShouldEqual, "0.0.1") + So(len(responseStruct.ImgListForDigest.Results), ShouldEqual, 1) + So(responseStruct.ImgListForDigest.Results[0].RepoName, ShouldEqual, "zot-test") + So(responseStruct.ImgListForDigest.Results[0].Tag, ShouldEqual, "0.0.1") // GetTestBlobDigest("zot-test", "config").Encoded() should match the config of 1 image. gqlQuery = url.QueryEscape(`{ImageListForDigest(id:"` + GetTestBlobDigest("zot-test", "config").Encoded() + `") - {RepoName Tag Digest ConfigDigest Size Layers { Digest }}}`) + {Results{RepoName Tag Digest ConfigDigest Size Layers { Digest }}}}`) targetURL = baseURL + constants.FullSearchPrefix + `?query=` + gqlQuery resp, err = resty.R().Get(targetURL) @@ -202,14 +208,14 @@ func TestDigestSearchHTTP(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) So(len(responseStruct.Errors), ShouldEqual, 0) - So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 1) - So(responseStruct.ImgListForDigest.Images[0].RepoName, ShouldEqual, "zot-test") - So(responseStruct.ImgListForDigest.Images[0].Tag, ShouldEqual, "0.0.1") + So(len(responseStruct.ImgListForDigest.Results), ShouldEqual, 1) + So(responseStruct.ImgListForDigest.Results[0].RepoName, ShouldEqual, "zot-test") + So(responseStruct.ImgListForDigest.Results[0].Tag, ShouldEqual, "0.0.1") // Call should return {"data":{"ImageListForDigest":[{"Name":"zot-cve-test","Tags":["0.0.1"]}]}} // GetTestBlobDigest("zot-cve-test", "layer").Encoded() should match the layer of 1 image gqlQuery = url.QueryEscape(`{ImageListForDigest(id:"` + GetTestBlobDigest("zot-cve-test", "layer").Encoded() + `") - {RepoName Tag Digest ConfigDigest Size Layers { Digest }}}`) + {Results{RepoName Tag Digest ConfigDigest Size Layers { Digest }}}}`) targetURL = baseURL + constants.FullSearchPrefix + `?query=` + gqlQuery resp, err = resty.R().Get( @@ -224,15 +230,15 @@ func TestDigestSearchHTTP(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct2) So(err, ShouldBeNil) So(len(responseStruct2.Errors), ShouldEqual, 0) - So(len(responseStruct2.ImgListForDigest.Images), ShouldEqual, 1) - So(responseStruct2.ImgListForDigest.Images[0].RepoName, ShouldEqual, "zot-cve-test") - So(responseStruct2.ImgListForDigest.Images[0].Tag, ShouldEqual, "0.0.1") + So(len(responseStruct2.ImgListForDigest.Results), ShouldEqual, 1) + So(responseStruct2.ImgListForDigest.Results[0].RepoName, ShouldEqual, "zot-cve-test") + So(responseStruct2.ImgListForDigest.Results[0].Tag, ShouldEqual, "0.0.1") // Call should return {"data":{"ImageListForDigest":[]}} // "1111111" should match 0 images resp, err = resty.R().Get( baseURL + constants.FullSearchPrefix + `?query={ImageListForDigest(id:"1111111")` + - `{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}`, + `{Results{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}}`, ) So(resp, ShouldNotBeNil) So(err, ShouldBeNil) @@ -241,12 +247,12 @@ func TestDigestSearchHTTP(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) So(len(responseStruct.Errors), ShouldEqual, 0) - So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 0) + So(len(responseStruct.ImgListForDigest.Results), ShouldEqual, 0) // Call should return {"errors": [{....}]", data":null}} resp, err = resty.R().Get( baseURL + constants.FullSearchPrefix + `?query={ImageListForDigest(id:"1111111")` + - `{RepoName%20Tag343s}}`, + `{Results{RepoName%20Tag343s}}}`, ) So(resp, ShouldNotBeNil) So(err, ShouldBeNil) @@ -302,7 +308,7 @@ func TestDigestSearchHTTPSubPaths(t *testing.T) { resp, err = resty.R().Get( baseURL + constants.FullSearchPrefix + `?query={ImageListForDigest(id:"sha")` + - `{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}`, + `{Results{RepoName%20Tag%20Digest%20ConfigDigest%20Size%20Layers%20{%20Digest}}}}`, ) So(resp, ShouldNotBeNil) So(err, ShouldBeNil) @@ -312,7 +318,7 @@ func TestDigestSearchHTTPSubPaths(t *testing.T) { err = json.Unmarshal(resp.Body(), &responseStruct) So(err, ShouldBeNil) So(len(responseStruct.Errors), ShouldEqual, 0) - So(len(responseStruct.ImgListForDigest.Images), ShouldEqual, 2) + So(len(responseStruct.ImgListForDigest.Results), ShouldEqual, 2) }) } diff --git a/pkg/extensions/search/gql_generated/generated.go b/pkg/extensions/search/gql_generated/generated.go index 482ef239..3166b0cb 100644 --- a/pkg/extensions/search/gql_generated/generated.go +++ b/pkg/extensions/search/gql_generated/generated.go @@ -188,11 +188,11 @@ type ComplexityRoot struct { type QueryResolver interface { CVEListForImage(ctx context.Context, image string, requestedPage *PageInput) (*CVEResultForImage, error) - ImageListForCve(ctx context.Context, id string, requestedPage *PageInput) ([]*ImageSummary, error) - ImageListWithCVEFixed(ctx context.Context, id string, image string, requestedPage *PageInput) ([]*ImageSummary, error) - ImageListForDigest(ctx context.Context, id string, requestedPage *PageInput) ([]*ImageSummary, error) + ImageListForCve(ctx context.Context, id string, requestedPage *PageInput) (*PaginatedImagesResult, error) + ImageListWithCVEFixed(ctx context.Context, id string, image string, requestedPage *PageInput) (*PaginatedImagesResult, error) + ImageListForDigest(ctx context.Context, id string, requestedPage *PageInput) (*PaginatedImagesResult, error) RepoListWithNewestImage(ctx context.Context, requestedPage *PageInput) (*PaginatedReposResult, error) - ImageList(ctx context.Context, repo string, requestedPage *PageInput) ([]*ImageSummary, error) + ImageList(ctx context.Context, repo string, requestedPage *PageInput) (*PaginatedImagesResult, error) ExpandedRepoInfo(ctx context.Context, repo string) (*RepoInfo, error) GlobalSearch(ctx context.Context, query string, filter *Filter, requestedPage *PageInput) (*GlobalSearchResult, error) DerivedImageList(ctx context.Context, image string, requestedPage *PageInput) (*PaginatedImagesResult, error) @@ -1483,7 +1483,7 @@ type Query { id: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of images that are no longer vulnerable to the CVE of the specified ID, @@ -1496,7 +1496,7 @@ type Query { image: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of images which contain the specified digest @@ -1506,7 +1506,7 @@ type Query { id: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of repositories with the newest tag (most recently created timestamp) @@ -1524,7 +1524,7 @@ type Query { repo: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Obtain detailed information about a repository and container images within @@ -4647,11 +4647,14 @@ func (ec *executionContext) _Query_ImageListForCVE(ctx context.Context, field gr return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.([]*ImageSummary) + res := resTmp.(*PaginatedImagesResult) fc.Result = res - return ec.marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res) + return ec.marshalNPaginatedImagesResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedImagesResult(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_ImageListForCVE(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -4662,50 +4665,12 @@ func (ec *executionContext) fieldContext_Query_ImageListForCVE(ctx context.Conte IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "RepoName": - return ec.fieldContext_ImageSummary_RepoName(ctx, field) - case "Tag": - return ec.fieldContext_ImageSummary_Tag(ctx, field) - case "Digest": - return ec.fieldContext_ImageSummary_Digest(ctx, field) - case "ConfigDigest": - return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field) - case "LastUpdated": - return ec.fieldContext_ImageSummary_LastUpdated(ctx, field) - case "IsSigned": - return ec.fieldContext_ImageSummary_IsSigned(ctx, field) - case "Size": - return ec.fieldContext_ImageSummary_Size(ctx, field) - case "Platform": - return ec.fieldContext_ImageSummary_Platform(ctx, field) - case "Vendor": - return ec.fieldContext_ImageSummary_Vendor(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) - case "DownloadCount": - return ec.fieldContext_ImageSummary_DownloadCount(ctx, field) - case "Layers": - return ec.fieldContext_ImageSummary_Layers(ctx, field) - case "Description": - return ec.fieldContext_ImageSummary_Description(ctx, field) - case "Licenses": - return ec.fieldContext_ImageSummary_Licenses(ctx, field) - case "Labels": - return ec.fieldContext_ImageSummary_Labels(ctx, field) - case "Title": - return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Source": - return ec.fieldContext_ImageSummary_Source(ctx, field) - case "Documentation": - return ec.fieldContext_ImageSummary_Documentation(ctx, field) - case "History": - return ec.fieldContext_ImageSummary_History(ctx, field) - case "Vulnerabilities": - return ec.fieldContext_ImageSummary_Vulnerabilities(ctx, field) - case "Authors": - return ec.fieldContext_ImageSummary_Authors(ctx, field) + case "Page": + return ec.fieldContext_PaginatedImagesResult_Page(ctx, field) + case "Results": + return ec.fieldContext_PaginatedImagesResult_Results(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name) + return nil, fmt.Errorf("no field named %q was found under type PaginatedImagesResult", field.Name) }, } defer func() { @@ -4743,11 +4708,14 @@ func (ec *executionContext) _Query_ImageListWithCVEFixed(ctx context.Context, fi return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.([]*ImageSummary) + res := resTmp.(*PaginatedImagesResult) fc.Result = res - return ec.marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res) + return ec.marshalNPaginatedImagesResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedImagesResult(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_ImageListWithCVEFixed(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -4758,50 +4726,12 @@ func (ec *executionContext) fieldContext_Query_ImageListWithCVEFixed(ctx context IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "RepoName": - return ec.fieldContext_ImageSummary_RepoName(ctx, field) - case "Tag": - return ec.fieldContext_ImageSummary_Tag(ctx, field) - case "Digest": - return ec.fieldContext_ImageSummary_Digest(ctx, field) - case "ConfigDigest": - return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field) - case "LastUpdated": - return ec.fieldContext_ImageSummary_LastUpdated(ctx, field) - case "IsSigned": - return ec.fieldContext_ImageSummary_IsSigned(ctx, field) - case "Size": - return ec.fieldContext_ImageSummary_Size(ctx, field) - case "Platform": - return ec.fieldContext_ImageSummary_Platform(ctx, field) - case "Vendor": - return ec.fieldContext_ImageSummary_Vendor(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) - case "DownloadCount": - return ec.fieldContext_ImageSummary_DownloadCount(ctx, field) - case "Layers": - return ec.fieldContext_ImageSummary_Layers(ctx, field) - case "Description": - return ec.fieldContext_ImageSummary_Description(ctx, field) - case "Licenses": - return ec.fieldContext_ImageSummary_Licenses(ctx, field) - case "Labels": - return ec.fieldContext_ImageSummary_Labels(ctx, field) - case "Title": - return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Source": - return ec.fieldContext_ImageSummary_Source(ctx, field) - case "Documentation": - return ec.fieldContext_ImageSummary_Documentation(ctx, field) - case "History": - return ec.fieldContext_ImageSummary_History(ctx, field) - case "Vulnerabilities": - return ec.fieldContext_ImageSummary_Vulnerabilities(ctx, field) - case "Authors": - return ec.fieldContext_ImageSummary_Authors(ctx, field) + case "Page": + return ec.fieldContext_PaginatedImagesResult_Page(ctx, field) + case "Results": + return ec.fieldContext_PaginatedImagesResult_Results(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name) + return nil, fmt.Errorf("no field named %q was found under type PaginatedImagesResult", field.Name) }, } defer func() { @@ -4839,11 +4769,14 @@ func (ec *executionContext) _Query_ImageListForDigest(ctx context.Context, field return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.([]*ImageSummary) + res := resTmp.(*PaginatedImagesResult) fc.Result = res - return ec.marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res) + return ec.marshalNPaginatedImagesResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedImagesResult(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_ImageListForDigest(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -4854,50 +4787,12 @@ func (ec *executionContext) fieldContext_Query_ImageListForDigest(ctx context.Co IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "RepoName": - return ec.fieldContext_ImageSummary_RepoName(ctx, field) - case "Tag": - return ec.fieldContext_ImageSummary_Tag(ctx, field) - case "Digest": - return ec.fieldContext_ImageSummary_Digest(ctx, field) - case "ConfigDigest": - return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field) - case "LastUpdated": - return ec.fieldContext_ImageSummary_LastUpdated(ctx, field) - case "IsSigned": - return ec.fieldContext_ImageSummary_IsSigned(ctx, field) - case "Size": - return ec.fieldContext_ImageSummary_Size(ctx, field) - case "Platform": - return ec.fieldContext_ImageSummary_Platform(ctx, field) - case "Vendor": - return ec.fieldContext_ImageSummary_Vendor(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) - case "DownloadCount": - return ec.fieldContext_ImageSummary_DownloadCount(ctx, field) - case "Layers": - return ec.fieldContext_ImageSummary_Layers(ctx, field) - case "Description": - return ec.fieldContext_ImageSummary_Description(ctx, field) - case "Licenses": - return ec.fieldContext_ImageSummary_Licenses(ctx, field) - case "Labels": - return ec.fieldContext_ImageSummary_Labels(ctx, field) - case "Title": - return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Source": - return ec.fieldContext_ImageSummary_Source(ctx, field) - case "Documentation": - return ec.fieldContext_ImageSummary_Documentation(ctx, field) - case "History": - return ec.fieldContext_ImageSummary_History(ctx, field) - case "Vulnerabilities": - return ec.fieldContext_ImageSummary_Vulnerabilities(ctx, field) - case "Authors": - return ec.fieldContext_ImageSummary_Authors(ctx, field) + case "Page": + return ec.fieldContext_PaginatedImagesResult_Page(ctx, field) + case "Results": + return ec.fieldContext_PaginatedImagesResult_Results(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name) + return nil, fmt.Errorf("no field named %q was found under type PaginatedImagesResult", field.Name) }, } defer func() { @@ -4996,11 +4891,14 @@ func (ec *executionContext) _Query_ImageList(ctx context.Context, field graphql. return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.([]*ImageSummary) + res := resTmp.(*PaginatedImagesResult) fc.Result = res - return ec.marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx, field.Selections, res) + return ec.marshalNPaginatedImagesResult2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐPaginatedImagesResult(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Query_ImageList(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { @@ -5011,50 +4909,12 @@ func (ec *executionContext) fieldContext_Query_ImageList(ctx context.Context, fi IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "RepoName": - return ec.fieldContext_ImageSummary_RepoName(ctx, field) - case "Tag": - return ec.fieldContext_ImageSummary_Tag(ctx, field) - case "Digest": - return ec.fieldContext_ImageSummary_Digest(ctx, field) - case "ConfigDigest": - return ec.fieldContext_ImageSummary_ConfigDigest(ctx, field) - case "LastUpdated": - return ec.fieldContext_ImageSummary_LastUpdated(ctx, field) - case "IsSigned": - return ec.fieldContext_ImageSummary_IsSigned(ctx, field) - case "Size": - return ec.fieldContext_ImageSummary_Size(ctx, field) - case "Platform": - return ec.fieldContext_ImageSummary_Platform(ctx, field) - case "Vendor": - return ec.fieldContext_ImageSummary_Vendor(ctx, field) - case "Score": - return ec.fieldContext_ImageSummary_Score(ctx, field) - case "DownloadCount": - return ec.fieldContext_ImageSummary_DownloadCount(ctx, field) - case "Layers": - return ec.fieldContext_ImageSummary_Layers(ctx, field) - case "Description": - return ec.fieldContext_ImageSummary_Description(ctx, field) - case "Licenses": - return ec.fieldContext_ImageSummary_Licenses(ctx, field) - case "Labels": - return ec.fieldContext_ImageSummary_Labels(ctx, field) - case "Title": - return ec.fieldContext_ImageSummary_Title(ctx, field) - case "Source": - return ec.fieldContext_ImageSummary_Source(ctx, field) - case "Documentation": - return ec.fieldContext_ImageSummary_Documentation(ctx, field) - case "History": - return ec.fieldContext_ImageSummary_History(ctx, field) - case "Vulnerabilities": - return ec.fieldContext_ImageSummary_Vulnerabilities(ctx, field) - case "Authors": - return ec.fieldContext_ImageSummary_Authors(ctx, field) + case "Page": + return ec.fieldContext_PaginatedImagesResult_Page(ctx, field) + case "Results": + return ec.fieldContext_PaginatedImagesResult_Results(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type ImageSummary", field.Name) + return nil, fmt.Errorf("no field named %q was found under type PaginatedImagesResult", field.Name) }, } defer func() { @@ -8935,6 +8795,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_ImageListForCVE(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } return res } @@ -8955,6 +8818,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_ImageListWithCVEFixed(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } return res } @@ -8975,6 +8841,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_ImageListForDigest(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } return res } @@ -9018,6 +8887,9 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } }() res = ec._Query_ImageList(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } return res } @@ -10331,53 +10203,6 @@ func (ec *executionContext) marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋ return ret } -func (ec *executionContext) marshalOImageSummary2ᚕᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummaryᚄ(ctx context.Context, sel ast.SelectionSet, v []*ImageSummary) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNImageSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummary(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - func (ec *executionContext) marshalOImageSummary2ᚖzotregistryᚗioᚋzotᚋpkgᚋextensionsᚋsearchᚋgql_generatedᚐImageSummary(ctx context.Context, sel ast.SelectionSet, v *ImageSummary) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/pkg/extensions/search/resolver.go b/pkg/extensions/search/resolver.go index 77d48346..c29eafd4 100644 --- a/pkg/extensions/search/resolver.go +++ b/pkg/extensions/search/resolver.go @@ -117,7 +117,7 @@ func FilterByDigest(digest string) repodb.FilterFunc { func getImageListForDigest(ctx context.Context, digest string, repoDB repodb.RepoDB, cveInfo cveinfo.CveInfo, requestedPage *gql_generated.PageInput, -) ([]*gql_generated.ImageSummary, error) { +) (*gql_generated.PaginatedImagesResult, error) { imageList := make([]*gql_generated.ImageSummary, 0) if requestedPage == nil { @@ -137,9 +137,9 @@ func getImageListForDigest(ctx context.Context, digest string, repoDB repodb.Rep } // get all repos - reposMeta, manifestMetaMap, _, err := repoDB.FilterTags(ctx, FilterByDigest(digest), pageInput) + reposMeta, manifestMetaMap, pageInfo, err := repoDB.FilterTags(ctx, FilterByDigest(digest), pageInput) if err != nil { - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } for _, repoMeta := range reposMeta { @@ -148,7 +148,13 @@ func getImageListForDigest(ctx context.Context, digest string, repoDB repodb.Rep imageList = append(imageList, imageSummaries...) } - return imageList, nil + return &gql_generated.PaginatedImagesResult{ + Results: imageList, + Page: &gql_generated.PageInfo{ + TotalCount: pageInfo.TotalCount, + ItemCount: pageInfo.ItemCount, + }, + }, nil } func getImageSummary(ctx context.Context, repo, tag string, repoDB repodb.RepoDB, @@ -286,7 +292,7 @@ func getImageListForCVE( requestedPage *gql_generated.PageInput, repoDB repodb.RepoDB, log log.Logger, -) ([]*gql_generated.ImageSummary, error) { +) (*gql_generated.PaginatedImagesResult, error) { // Obtain all repos and tags // Infinite page to make sure we scan all repos in advance, before filtering results // The CVE scan logic is called from here, not in the actual filter, @@ -296,7 +302,7 @@ func getImageListForCVE( repodb.PageInput{Limit: 0, Offset: 0, SortBy: repodb.SortCriteria(gql_generated.SortCriteriaUpdateTime)}, ) if err != nil { - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } affectedImages := []common.TagInfo{} @@ -311,7 +317,7 @@ func getImageListForCVE( log.Error().Str("repo", repo).Str("CVE", cveID).Err(err). Msg("error getting image list for CVE from repo") - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } affectedImages = append(affectedImages, tagsInfo...) @@ -336,9 +342,9 @@ func getImageListForCVE( } // get all repos - reposMeta, manifestMetaMap, _, err := repoDB.FilterTags(ctx, FilterByTagInfo(affectedImages), pageInput) + reposMeta, manifestMetaMap, pageInfo, err := repoDB.FilterTags(ctx, FilterByTagInfo(affectedImages), pageInput) if err != nil { - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } for _, repoMeta := range reposMeta { @@ -347,7 +353,13 @@ func getImageListForCVE( imageList = append(imageList, imageSummaries...) } - return imageList, nil + return &gql_generated.PaginatedImagesResult{ + Results: imageList, + Page: &gql_generated.PageInfo{ + TotalCount: pageInfo.TotalCount, + ItemCount: pageInfo.ItemCount, + }, + }, nil } func getImageListWithCVEFixed( @@ -358,7 +370,7 @@ func getImageListWithCVEFixed( requestedPage *gql_generated.PageInput, repoDB repodb.RepoDB, log log.Logger, -) ([]*gql_generated.ImageSummary, error) { +) (*gql_generated.PaginatedImagesResult, error) { imageList := make([]*gql_generated.ImageSummary, 0) log.Info().Str("repo", repo).Str("CVE", cveID).Msg("extracting list of tags where CVE is fixed") @@ -368,7 +380,10 @@ func getImageListWithCVEFixed( log.Error().Str("repo", repo).Str("CVE", cveID).Err(err). Msg("error getting image list with CVE fixed from repo") - return imageList, err + return &gql_generated.PaginatedImagesResult{ + Page: &gql_generated.PageInfo{}, + Results: imageList, + }, err } // We're not interested in other vulnerabilities @@ -388,9 +403,9 @@ func getImageListWithCVEFixed( } // get all repos - reposMeta, manifestMetaMap, _, err := repoDB.FilterTags(ctx, FilterByTagInfo(tagsInfo), pageInput) + reposMeta, manifestMetaMap, pageInfo, err := repoDB.FilterTags(ctx, FilterByTagInfo(tagsInfo), pageInput) if err != nil { - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } for _, repoMeta := range reposMeta { @@ -402,7 +417,13 @@ func getImageListWithCVEFixed( imageList = append(imageList, imageSummaries...) } - return imageList, nil + return &gql_generated.PaginatedImagesResult{ + Results: imageList, + Page: &gql_generated.PageInfo{ + TotalCount: pageInfo.TotalCount, + ItemCount: pageInfo.ItemCount, + }, + }, nil } func repoListWithNewestImage( @@ -964,7 +985,7 @@ func searchingForRepos(query string) bool { func getImageList(ctx context.Context, repo string, repoDB repodb.RepoDB, cveInfo cveinfo.CveInfo, requestedPage *gql_generated.PageInput, log log.Logger, //nolint:unparam -) ([]*gql_generated.ImageSummary, error) { +) (*gql_generated.PaginatedImagesResult, error) { imageList := make([]*gql_generated.ImageSummary, 0) if requestedPage == nil { @@ -984,13 +1005,13 @@ func getImageList(ctx context.Context, repo string, repoDB repodb.RepoDB, cveInf } // reposMeta, manifestMetaMap, err := repoDB.SearchRepos(ctx, repo, repodb.Filter{}, pageInput) - reposMeta, manifestMetaMap, _, err := repoDB.FilterTags(ctx, + reposMeta, manifestMetaMap, pageInfo, err := repoDB.FilterTags(ctx, func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool { return true }, pageInput) if err != nil { - return []*gql_generated.ImageSummary{}, err + return &gql_generated.PaginatedImagesResult{}, err } for _, repoMeta := range reposMeta { @@ -1002,7 +1023,13 @@ func getImageList(ctx context.Context, repo string, repoDB repodb.RepoDB, cveInf imageList = append(imageList, imageSummaries...) } - return imageList, nil + return &gql_generated.PaginatedImagesResult{ + Results: imageList, + Page: &gql_generated.PageInfo{ + TotalCount: pageInfo.TotalCount, + ItemCount: pageInfo.ItemCount, + }, + }, nil } func getReferrers(store storage.ImageStore, repoName string, digest string, artifactTypes []string, log log.Logger) ( diff --git a/pkg/extensions/search/resolver_test.go b/pkg/extensions/search/resolver_test.go index 0b3ae293..b1864e27 100644 --- a/pkg/extensions/search/resolver_test.go +++ b/pkg/extensions/search/resolver_test.go @@ -614,7 +614,7 @@ func TestImageListForDigest(t *testing.T) { imageList, err := getImageListForDigest(responseContext, "test", mockSearchDB, mocks.CveInfoMock{}, nil) So(err, ShouldBeNil) - So(imageList, ShouldBeEmpty) + So(imageList.Results, ShouldBeEmpty) }) Convey("valid imageListForDigest returned for matching manifest digest", func() { @@ -677,12 +677,12 @@ func TestImageListForDigest(t *testing.T) { imageSummaries, err := getImageListForDigest(responseContext, manifestDigest, mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 1) + So(len(imageSummaries.Results), ShouldEqual, 1) imageSummaries, err = getImageListForDigest(responseContext, "invalid", mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 0) + So(len(imageSummaries.Results), ShouldEqual, 0) }) Convey("valid imageListForDigest returned for matching config digest", func() { @@ -756,7 +756,7 @@ func TestImageListForDigest(t *testing.T) { imageSummaries, err := getImageListForDigest(responseContext, configDigest.String(), mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 1) + So(len(imageSummaries.Results), ShouldEqual, 1) }) Convey("valid imageListForDigest returned for matching layer digest", func() { @@ -832,7 +832,7 @@ func TestImageListForDigest(t *testing.T) { imageSummaries, err := getImageListForDigest(responseContext, layerDigest.String(), mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 1) + So(len(imageSummaries.Results), ShouldEqual, 1) }) Convey("valid imageListForDigest, multiple matching tags", func() { @@ -901,7 +901,7 @@ func TestImageListForDigest(t *testing.T) { imageSummaries, err := getImageListForDigest(responseContext, manifestDigest, mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 2) + So(len(imageSummaries.Results), ShouldEqual, 2) }) Convey("valid imageListForDigest, multiple matching tags limited by pageInput", func() { @@ -981,7 +981,7 @@ func TestImageListForDigest(t *testing.T) { imageSummaries, err := getImageListForDigest(responseContext, manifestDigest, mockSearchDB, mocks.CveInfoMock{}, &pageInput) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 1) + So(len(imageSummaries.Results), ShouldEqual, 1) }) }) } @@ -1072,12 +1072,12 @@ func TestImageList(t *testing.T) { imageSummaries, err := getImageList(responseContext, "test", mockSearchDB, mocks.CveInfoMock{}, &pageInput, testLogger) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 1) + So(len(imageSummaries.Results), ShouldEqual, 1) imageSummaries, err = getImageList(responseContext, "invalid", mockSearchDB, mocks.CveInfoMock{}, &pageInput, testLogger) So(err, ShouldBeNil) - So(len(imageSummaries), ShouldEqual, 0) + So(len(imageSummaries.Results), ShouldEqual, 0) }) }) } @@ -1878,9 +1878,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo1:1.0.0", "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1892,9 +1892,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo2:2.0.0", "repo2:2.0.1", "repo3:3.0.1", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1906,9 +1906,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo2:2.0.0", "repo2:2.0.1", "repo2:2.1.0", "repo2:latest", "repo3:3.0.1", "repo3:3.1.0", "repo3:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } }) @@ -1926,9 +1926,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages := []string{ "repo1:1.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1940,9 +1940,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1950,13 +1950,13 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(1, 5) images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(2, 0) @@ -1967,9 +1967,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo1:1.0.0", "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1982,9 +1982,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo1:1.0.0", "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -1996,9 +1996,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2006,13 +2006,13 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(5, 5) images, err = getImageListForCVE(responseContext, "CVE1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(5, 0) @@ -2024,9 +2024,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo2:2.0.0", "repo2:2.0.1", "repo3:3.0.1", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2039,9 +2039,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo2:2.0.1", "repo3:3.0.1", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2054,9 +2054,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo1:1.0.0", "repo1:1.0.1", "repo1:1.1.0", "repo1:latest", "repo2:2.0.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2069,9 +2069,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo "repo2:2.0.1", "repo2:2.1.0", "repo2:latest", "repo3:3.0.1", "repo3:3.1.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2083,9 +2083,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo3:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } }) @@ -2102,9 +2102,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages := []string{ "repo1:1.0.1", "repo1:1.1.0", "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2114,15 +2114,15 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.1.0", "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } images, err = getImageListWithCVEFixed(responseContext, "CVE3", "repo1", cveInfo, nil, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) }) Convey("Paginated requests", func() { @@ -2138,9 +2138,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages := []string{ "repo1:1.0.1", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2152,9 +2152,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.1.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2166,9 +2166,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2176,13 +2176,13 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(1, 10) images, err = getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) pageInput = getPageInput(2, 0) @@ -2192,9 +2192,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.0.1", "repo1:1.1.0", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2206,9 +2206,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.1.0", "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2220,9 +2220,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2234,9 +2234,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.0.1", "repo1:1.1.0", "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2248,9 +2248,9 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo expectedImages = []string{ "repo1:1.1.0", "repo1:latest", } - So(len(images), ShouldEqual, len(expectedImages)) + So(len(images.Results), ShouldEqual, len(expectedImages)) - for _, image := range images { + for _, image := range images.Results { So(fmt.Sprintf("%s:%s", *image.RepoName, *image.Tag), ShouldBeIn, expectedImages) } @@ -2258,7 +2258,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo images, err = getImageListWithCVEFixed(responseContext, "CVE2", "repo1", cveInfo, pageInput, repoDB, log) So(err, ShouldBeNil) - So(len(images), ShouldEqual, 0) + So(len(images.Results), ShouldEqual, 0) }) }) } diff --git a/pkg/extensions/search/schema.graphql b/pkg/extensions/search/schema.graphql index efd67301..2445ebf2 100644 --- a/pkg/extensions/search/schema.graphql +++ b/pkg/extensions/search/schema.graphql @@ -534,7 +534,7 @@ type Query { id: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of images that are no longer vulnerable to the CVE of the specified ID, @@ -547,7 +547,7 @@ type Query { image: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of images which contain the specified digest @@ -557,7 +557,7 @@ type Query { id: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Returns a list of repositories with the newest tag (most recently created timestamp) @@ -575,7 +575,7 @@ type Query { repo: String!, "Sets the parameters of the requested page" requestedPage: PageInput - ): [ImageSummary!] + ): PaginatedImagesResult! """ Obtain detailed information about a repository and container images within diff --git a/pkg/extensions/search/schema.resolvers.go b/pkg/extensions/search/schema.resolvers.go index e0b9d629..1791fc34 100644 --- a/pkg/extensions/search/schema.resolvers.go +++ b/pkg/extensions/search/schema.resolvers.go @@ -23,25 +23,25 @@ func (r *queryResolver) CVEListForImage(ctx context.Context, image string, reque } // ImageListForCve is the resolver for the ImageListForCVE field. -func (r *queryResolver) ImageListForCve(ctx context.Context, id string, requestedPage *gql_generated.PageInput) ([]*gql_generated.ImageSummary, error) { +func (r *queryResolver) ImageListForCve(ctx context.Context, id string, requestedPage *gql_generated.PageInput) (*gql_generated.PaginatedImagesResult, error) { if r.cveInfo == nil { - return []*gql_generated.ImageSummary{}, zerr.ErrCVESearchDisabled + return &gql_generated.PaginatedImagesResult{}, zerr.ErrCVESearchDisabled } return getImageListForCVE(ctx, id, r.cveInfo, requestedPage, r.repoDB, r.log) } // ImageListWithCVEFixed is the resolver for the ImageListWithCVEFixed field. -func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, image string, requestedPage *gql_generated.PageInput) ([]*gql_generated.ImageSummary, error) { +func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, image string, requestedPage *gql_generated.PageInput) (*gql_generated.PaginatedImagesResult, error) { if r.cveInfo == nil { - return []*gql_generated.ImageSummary{}, zerr.ErrCVESearchDisabled + return &gql_generated.PaginatedImagesResult{}, zerr.ErrCVESearchDisabled } return getImageListWithCVEFixed(ctx, id, image, r.cveInfo, requestedPage, r.repoDB, r.log) } // ImageListForDigest is the resolver for the ImageListForDigest field. -func (r *queryResolver) ImageListForDigest(ctx context.Context, id string, requestedPage *gql_generated.PageInput) ([]*gql_generated.ImageSummary, error) { +func (r *queryResolver) ImageListForDigest(ctx context.Context, id string, requestedPage *gql_generated.PageInput) (*gql_generated.PaginatedImagesResult, error) { r.log.Info().Msg("extracting repositories") imgResultForDigest, err := getImageListForDigest(ctx, id, r.repoDB, r.cveInfo, requestedPage) @@ -64,7 +64,7 @@ func (r *queryResolver) RepoListWithNewestImage(ctx context.Context, requestedPa } // ImageList is the resolver for the ImageList field. -func (r *queryResolver) ImageList(ctx context.Context, repo string, requestedPage *gql_generated.PageInput) ([]*gql_generated.ImageSummary, error) { +func (r *queryResolver) ImageList(ctx context.Context, repo string, requestedPage *gql_generated.PageInput) (*gql_generated.PaginatedImagesResult, error) { r.log.Info().Msg("extension api: getting a list of all images") imageList, err := getImageList(ctx, repo, r.repoDB, r.cveInfo, requestedPage, r.log) diff --git a/pkg/extensions/search/search.md b/pkg/extensions/search/search.md index c76814bc..587ec9cd 100644 --- a/pkg/extensions/search/search.md +++ b/pkg/extensions/search/search.md @@ -20,7 +20,7 @@ The examples below only include the GraphQL query without any additional details on how to send them to a server. They were made with the GraphQL playground from the debug binary. You can also use curl to make these queries, here's an example: ```bash -curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForCVE (id:\"CVE-2002-1119\") { Name Tags } }" }' http://localhost:8080/v2/_zot/ext/search +curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageListForCVE (id:\"CVE-2002-1119\") { Results { Name Tags } } }" }' http://localhost:8080/v2/_zot/ext/search ``` ## List CVEs of given image @@ -88,22 +88,24 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList ```graphql { ImageListForCVE(id: "CVE-2018-20651") { - RepoName - Tag - Digest - ConfigDigest - LastUpdated - IsSigned - Size - Platform { - Os - Arch + Results{ + RepoName + Tag + Digest + ConfigDigest + LastUpdated + IsSigned + Size + Platform { + Os + Arch + } + Vendor + Score + DownloadCount + Licenses + Title } - Vendor - Score - DownloadCount - Licenses - Title } } ``` @@ -114,24 +116,26 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList { "data": { "ImageListForCVE": [ - { - "RepoName": "centos", - "Tag": "centos8", - "Digest": "sha256:ac0dc62b48b7f683b49365fecef3b1f4d99fbd249b762e99f13f74938d85a6c8", - "ConfigDigest": "sha256:98a5843635a2ccc7d72b269923a65721480de929f882143c6c0a0eb43f9a2869", - "LastUpdated": "2022-10-17T16:36:09.1751694+03:00", - "IsSigned": true, - "Size": "83545800", - "Platform": { - "Os": "linux", - "Arch": "amd64" + { + "Results": { + "RepoName": "centos", + "Tag": "centos8", + "Digest": "sha256:ac0dc62b48b7f683b49365fecef3b1f4d99fbd249b762e99f13f74938d85a6c8", + "ConfigDigest": "sha256:98a5843635a2ccc7d72b269923a65721480de929f882143c6c0a0eb43f9a2869", + "LastUpdated": "2022-10-17T16:36:09.1751694+03:00", + "IsSigned": true, + "Size": "83545800", + "Platform": { + "Os": "linux", + "Arch": "amd64" + }, + "Vendor": "[The CentOS Project](https://github.com/CentOS/sig-cloud-instance-images)\n", + "Score": null, + "DownloadCount": 0, + "Licenses": "View [license information](https://www.centos.org/legal/) for the software contained in this image.", + "Title": "centos" }, - "Vendor": "[The CentOS Project](https://github.com/CentOS/sig-cloud-instance-images)\n", - "Score": null, - "DownloadCount": 0, - "Licenses": "View [license information](https://www.centos.org/legal/) for the software contained in this image.", - "Title": "centos" - }, + } ] } } @@ -144,11 +148,13 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList ```graphql { ImageListWithCVEFixed(id: "CVE-2018-20651", image: "ubuntu") { - RepoName - Tag - Digest - ConfigDigest - LastUpdated + Results { + RepoName + Tag + Digest + ConfigDigest + LastUpdated + } } } ``` @@ -160,11 +166,13 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList "data": { "ImageListWithCVEFixed": [ { - "RepoName": "ubuntu", - "Tag": "latest", - "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", - "ConfigDigest": "sha256:88eef892e29d5b11be933f13424ef885644a6a6978924fedfb51ba555278fe74", - "LastUpdated": "2022-10-25T01:53:41.769246372Z" + "Results": { + "RepoName": "ubuntu", + "Tag": "latest", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", + "ConfigDigest": "sha256:88eef892e29d5b11be933f13424ef885644a6a6978924fedfb51ba555278fe74", + "LastUpdated": "2022-10-25T01:53:41.769246372Z" + } } ] } @@ -180,9 +188,11 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList ImageListForDigest( id: "5f34d0bb0261d32d0b0bc91024b7d4e98d94b08a49615e08c8a5a65bc3a7e09f" ) { - RepoName - Tag - Title + Results{ + RepoName + Tag + Title + } } } ``` @@ -194,9 +204,11 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList "data": { "ImageListForDigest": [ { - "RepoName": "centos", - "Tag": "8", - "Title": "CentOS Base Image" + "Results": { + "RepoName": "centos", + "Tag": "8", + "Title": "CentOS Base Image" + } } ] } @@ -285,10 +297,12 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList ```graphql { ImageList (repo: "ubuntu") { - Tag - Digest - LastUpdated - Size + Results { + Tag + Digest + LastUpdated + Size + } } } ``` @@ -300,16 +314,19 @@ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList "data": { "ImageList": [ { - "Tag": "latest", - "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", - "LastUpdated": "2022-10-25T01:53:41.769246372Z", - "Size": "30426374" - }, - { - "Tag": "xenial", - "Digest": "sha256:34de800b5da88feb7723a87ecbbf238afb63dbfe0c828838e26ac7458bef0ac5", - "LastUpdated": "2021-08-31T01:21:30.672229355Z", - "Size": "46499103" + "Results": + { + "Tag": "latest", + "Digest": "sha256:650d596072ad45c6b74f4923e2cfea8158da2fb3a7b8dbb0b9ae4da3088d0591", + "LastUpdated": "2022-10-25T01:53:41.769246372Z", + "Size": "30426374" + }, + { + "Tag": "xenial", + "Digest": "sha256:34de800b5da88feb7723a87ecbbf238afb63dbfe0c828838e26ac7458bef0ac5", + "LastUpdated": "2021-08-31T01:21:30.672229355Z", + "Size": "46499103" + } } ] } diff --git a/test/blackbox/annotations.bats b/test/blackbox/annotations.bats index 588edbd8..764b8359 100644 --- a/test/blackbox/annotations.bats +++ b/test/blackbox/annotations.bats @@ -74,11 +74,12 @@ function teardown_file() { [ "$status" -eq 0 ] run podman push 127.0.0.1:8080/annotations:latest --tls-verify=false --format=oci [ "$status" -eq 0 ] - run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Vendor Licenses }}"}' http://localhost:8080/v2/_zot/ext/search + run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Vendor Licenses }}}"}' http://localhost:8080/v2/_zot/ext/search [ "$status" -eq 0 ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].RepoName') = '"annotations"' ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].Vendor') = '"CentOS"' ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].Licenses') = '"GPLv2"' ] + # [ $(echo "${lines[-1]}" | jq '.data.ImageList') ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Vendor') = '"CentOS"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Licenses') = '"GPLv2"' ] } @test "build image with stacker and specify annotations" { @@ -86,19 +87,19 @@ function teardown_file() { [ "$status" -eq 0 ] run stacker --oci-dir ${BATS_FILE_TMPDIR}/stackeroci --stacker-dir ${BATS_FILE_TMPDIR}/.stacker --roots-dir ${BATS_FILE_TMPDIR}/roots publish -f ${BATS_FILE_TMPDIR}/stacker.yaml --substitute IMAGE_NAME="ghcr.io/project-zot/golang" --substitute IMAGE_TAG="1.19" --substitute DESCRIPTION="mydesc" --substitute VENDOR="CentOs" --substitute LICENSES="GPLv2" --url docker://127.0.0.1:8080 --tag 1.19 --skip-tls [ "$status" -eq 0 ] - run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"ghcr.io/project-zot/golang\") { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Description Vendor Licenses }}"}' http://localhost:8080/v2/_zot/ext/search + run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"ghcr.io/project-zot/golang\") { Results { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Description Vendor Licenses }}}"}' http://localhost:8080/v2/_zot/ext/search [ "$status" -eq 0 ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].RepoName') = '"ghcr.io/project-zot/golang"' ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].Description') = '"mydesc"' ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].Vendor') = '"CentOs"' ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].Licenses') = '"GPLv2"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"ghcr.io/project-zot/golang"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Description') = '"mydesc"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Vendor') = '"CentOs"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Licenses') = '"GPLv2"' ] } @test "sign/verify with cosign" { - run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Vendor Licenses }}"}' http://localhost:8080/v2/_zot/ext/search + run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } Vendor Licenses }}}"}' http://localhost:8080/v2/_zot/ext/search [ "$status" -eq 0 ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].RepoName') = '"annotations"' ] - local digest=$(echo "${lines[-1]}" | jq -r '.data.ImageList[0].Digest') + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] + local digest=$(echo "${lines[-1]}" | jq -r '.data.ImageList.Results[0].Digest') run cosign initialize [ "$status" -eq 0 ] @@ -114,9 +115,9 @@ function teardown_file() { } @test "sign/verify with notation" { - run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } }}"}' http://localhost:8080/v2/_zot/ext/search + run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Digest ConfigDigest Size Layers {Size Digest } }}}"}' http://localhost:8080/v2/_zot/ext/search [ "$status" -eq 0 ] - [ $(echo "${lines[-1]}" | jq '.data.ImageList[0].RepoName') = '"annotations"' ] + [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] [ "$status" -eq 0 ] run notation cert generate-test "notation-sign-test"