perf: update the ImageList queries to return PaginatedImagesResult (#1182)

Signed-off-by: Nicol Draghici <idraghic@cisco.com>
This commit is contained in:
Nicol 2023-02-15 21:34:07 +02:00 committed by GitHub
parent d79ad863e4
commit f00a9e6e48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 397 additions and 513 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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"`
}

View File

@ -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)
})
})
}

View File

@ -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)
})

View File

@ -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)
})
}

View File

@ -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

View File

@ -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) (

View File

@ -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)
})
})
}

View File

@ -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

View File

@ -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)

View File

@ -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"
}
}
]
}

View File

@ -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"