0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-30 22:34:13 -05:00

feat(graphql): filter CVEs by severity (#2246)

Signed-off-by: Andreea-Lupu <andreealupu1470@yahoo.com>
This commit is contained in:
Andreea Lupu 2024-02-14 19:11:57 +02:00 committed by GitHub
parent de90abd5dc
commit 55acce6923
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 107 additions and 52 deletions

View file

@ -78,7 +78,7 @@ func DerivedImageListQuery() GQLQuery {
func CVEListForImageQuery() GQLQuery { func CVEListForImageQuery() GQLQuery {
return GQLQuery{ return GQLQuery{
Name: "CVEListForImage", Name: "CVEListForImage",
Args: []string{"image", "requestedPage", "searchedCVE", "excludedCVE"}, Args: []string{"image", "requestedPage", "searchedCVE", "excludedCVE", "severity"},
ReturnType: CVEResultForImage(), ReturnType: CVEResultForImage(),
} }
} }

View file

@ -21,7 +21,7 @@ import (
type CveInfo interface { type CveInfo interface {
GetImageListForCVE(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) GetImageListForCVE(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
GetImageListWithCVEFixed(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) GetImageListWithCVEFixed(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
GetCVEListForImage(ctx context.Context, repo, tag string, searchedCVE string, excludedCVE string, GetCVEListForImage(ctx context.Context, repo, tag string, searchedCVE string, excludedCVE string, severity string,
pageinput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error) pageinput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error)
GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string) (cvemodel.ImageCVESummary, error) GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string) (cvemodel.ImageCVESummary, error)
} }
@ -329,10 +329,16 @@ func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.I
return manifestData.Manifests[0].Config, manifestDigest, err return manifestData.Manifests[0].Config, manifestDigest, err
} }
func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) { func filterCVEList(
cveMap map[string]cvemodel.CVE, searchedCVE, excludedCVE, severity string, pageFinder *CvePageFinder,
) {
searchedCVE = strings.ToUpper(searchedCVE) searchedCVE = strings.ToUpper(searchedCVE)
for _, cve := range cveMap { for _, cve := range cveMap {
if severity != "" && (cvemodel.CompareSeverities(cve.Severity, severity) != 0) {
continue
}
if excludedCVE != "" && cve.ContainsStr(excludedCVE) { if excludedCVE != "" && cve.ContainsStr(excludedCVE) {
continue continue
} }
@ -344,7 +350,7 @@ func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE, excludedCVE stri
} }
func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref string, searchedCVE string, func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref string, searchedCVE string,
excludedCVE string, pageInput cvemodel.PageInput, excludedCVE string, severity string, pageInput cvemodel.PageInput,
) ( ) (
[]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error, []cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error,
) { ) {
@ -373,7 +379,7 @@ func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref str
return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err
} }
filterCVEList(cveMap, searchedCVE, excludedCVE, pageFinder) filterCVEList(cveMap, searchedCVE, excludedCVE, severity, pageFinder)
cveList, pageInfo := pageFinder.Page() cveList, pageInfo := pageFinder.Page()

View file

@ -1192,7 +1192,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
ctx := context.Background() ctx := context.Background()
// Image is found // Image is found
cveList, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", "", pageInput) cveList, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1) So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE1") So(cveList[0].ID, ShouldEqual, "CVE1")
@ -1206,7 +1206,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM") So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.0", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 3) So(len(cveList), ShouldEqual, 3)
So(cveList[0].ID, ShouldEqual, "CVE2") So(cveList[0].ID, ShouldEqual, "CVE2")
@ -1222,7 +1222,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "HIGH") So(cveSummary.MaxSeverity, ShouldEqual, "HIGH")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.1", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.1", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 2) So(len(cveList), ShouldEqual, 2)
So(cveList[0].ID, ShouldEqual, "CVE1") So(cveList[0].ID, ShouldEqual, "CVE1")
@ -1237,7 +1237,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM") So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.1.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.1.0", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1) So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE3") So(cveList[0].ID, ShouldEqual, "CVE3")
@ -1251,7 +1251,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "LOW") So(cveSummary.MaxSeverity, ShouldEqual, "LOW")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo6, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo6, "1.0.0", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1264,7 +1264,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "NONE") So(cveSummary.MaxSeverity, ShouldEqual, "NONE")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo8, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo8, "1.0.0", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 7) So(len(cveList), ShouldEqual, 7)
So(pageInfo.ItemCount, ShouldEqual, 7) So(pageInfo.ItemCount, ShouldEqual, 7)
@ -1278,7 +1278,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL") So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
// Image is multiarch // Image is multiarch
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", "", "", pageInput)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1) So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE1") So(cveList[0].ID, ShouldEqual, "CVE1")
@ -1293,7 +1293,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM") So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
// Image is not scannable // Image is not scannable
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo2, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo2, "1.0.0", "", "", "", pageInput)
So(err, ShouldEqual, zerr.ErrScanNotSupported) So(err, ShouldEqual, zerr.ErrScanNotSupported)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1307,7 +1307,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
// Tag is not found // Tag is not found
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo3, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo3, "1.0.0", "", "", "", pageInput)
So(err, ShouldEqual, zerr.ErrTagMetaNotFound) So(err, ShouldEqual, zerr.ErrTagMetaNotFound)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1321,7 +1321,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
// Scan failed // Scan failed
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo7, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo7, "1.0.0", "", "", "", pageInput)
So(err, ShouldEqual, ErrFailedScan) So(err, ShouldEqual, ErrFailedScan)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1335,7 +1335,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
// Tag is not found // Tag is not found
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo-with-bad-tag-digest", "tag", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo-with-bad-tag-digest", "tag", "", "", "", pageInput)
So(err, ShouldEqual, zerr.ErrImageMetaNotFound) So(err, ShouldEqual, zerr.ErrImageMetaNotFound)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1349,7 +1349,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
// Repo is not found // Repo is not found
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo100, "1.0.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo100, "1.0.0", "", "", "", pageInput)
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound) So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
So(len(cveList), ShouldEqual, 0) So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)
@ -1580,7 +1580,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 0) So(cveSummary.CriticalCount, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "") So(cveSummary.MaxSeverity, ShouldEqual, "")
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", "", pageInput) cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", "", "", pageInput)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(cveList, ShouldBeEmpty) So(cveList, ShouldBeEmpty)
So(pageInfo.ItemCount, ShouldEqual, 0) So(pageInfo.ItemCount, ShouldEqual, 0)

View file

@ -140,7 +140,8 @@ func TestCVEPagination(t *testing.T) {
Convey("Page", func() { Convey("Page", func() {
Convey("defaults", func() { Convey("defaults", func() {
// By default expect unlimitted results sorted by severity // By default expect unlimitted results sorted by severity
cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{}) cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "",
"", cvemodel.PageInput{})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5) So(len(cves), ShouldEqual, 5)
So(pageInfo.ItemCount, ShouldEqual, 5) So(pageInfo.ItemCount, ShouldEqual, 5)
@ -158,7 +159,8 @@ func TestCVEPagination(t *testing.T) {
previousSeverity = severityToInt[cve.Severity] previousSeverity = severityToInt[cve.Severity]
} }
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", cvemodel.PageInput{}) cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", "",
cvemodel.PageInput{})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30) So(len(cves), ShouldEqual, 30)
So(pageInfo.ItemCount, ShouldEqual, 30) So(pageInfo.ItemCount, ShouldEqual, 30)
@ -183,7 +185,7 @@ func TestCVEPagination(t *testing.T) {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i)) cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
} }
cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc}) cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5) So(len(cves), ShouldEqual, 5)
@ -201,7 +203,7 @@ func TestCVEPagination(t *testing.T) {
} }
sort.Strings(cveIds) sort.Strings(cveIds)
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc}) cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30) So(len(cves), ShouldEqual, 30)
@ -219,7 +221,7 @@ func TestCVEPagination(t *testing.T) {
} }
sort.Sort(sort.Reverse(sort.StringSlice(cveIds))) sort.Sort(sort.Reverse(sort.StringSlice(cveIds)))
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticDsc}) cvemodel.PageInput{SortBy: cveinfo.AlphabeticDsc})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30) So(len(cves), ShouldEqual, 30)
@ -236,7 +238,7 @@ func TestCVEPagination(t *testing.T) {
So(cve.ID, ShouldEqual, cveIds[i]) So(cve.ID, ShouldEqual, cveIds[i])
} }
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", "",
cvemodel.PageInput{SortBy: cveinfo.SeverityDsc}) cvemodel.PageInput{SortBy: cveinfo.SeverityDsc})
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30) So(len(cves), ShouldEqual, 30)
@ -262,7 +264,7 @@ func TestCVEPagination(t *testing.T) {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i)) cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
} }
cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 3, Limit: 3,
Offset: 1, Offset: 1,
SortBy: cveinfo.AlphabeticAsc, SortBy: cveinfo.AlphabeticAsc,
@ -283,7 +285,7 @@ func TestCVEPagination(t *testing.T) {
So(cveSummary.CriticalCount, ShouldEqual, 1) So(cveSummary.CriticalCount, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL") So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 2, Limit: 2,
Offset: 1, Offset: 1,
SortBy: cveinfo.AlphabeticDsc, SortBy: cveinfo.AlphabeticDsc,
@ -303,7 +305,7 @@ func TestCVEPagination(t *testing.T) {
So(cveSummary.CriticalCount, ShouldEqual, 1) So(cveSummary.CriticalCount, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL") So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 3, Limit: 3,
Offset: 1, Offset: 1,
SortBy: cveinfo.SeverityDsc, SortBy: cveinfo.SeverityDsc,
@ -327,7 +329,7 @@ func TestCVEPagination(t *testing.T) {
} }
sort.Strings(cveIds) sort.Strings(cveIds)
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", "", "", cvemodel.PageInput{
Limit: 5, Limit: 5,
Offset: 20, Offset: 20,
SortBy: cveinfo.AlphabeticAsc, SortBy: cveinfo.AlphabeticAsc,
@ -350,7 +352,7 @@ func TestCVEPagination(t *testing.T) {
}) })
Convey("limit > len(cves)", func() { Convey("limit > len(cves)", func() {
cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 6, Limit: 6,
Offset: 3, Offset: 3,
SortBy: cveinfo.AlphabeticAsc, SortBy: cveinfo.AlphabeticAsc,
@ -370,7 +372,7 @@ func TestCVEPagination(t *testing.T) {
So(cveSummary.CriticalCount, ShouldEqual, 1) So(cveSummary.CriticalCount, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL") So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 6, Limit: 6,
Offset: 3, Offset: 3,
SortBy: cveinfo.AlphabeticDsc, SortBy: cveinfo.AlphabeticDsc,
@ -390,7 +392,7 @@ func TestCVEPagination(t *testing.T) {
So(cveSummary.CriticalCount, ShouldEqual, 1) So(cveSummary.CriticalCount, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL") So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")
cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", cvemodel.PageInput{ cves, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", "", "", cvemodel.PageInput{
Limit: 6, Limit: 6,
Offset: 3, Offset: 3,
SortBy: cveinfo.SeverityDsc, SortBy: cveinfo.SeverityDsc,

View file

@ -170,7 +170,7 @@ type ComplexityRoot struct {
Query struct { Query struct {
BaseImageList func(childComplexity int, image string, digest *string, requestedPage *PageInput) int BaseImageList func(childComplexity int, image string, digest *string, requestedPage *PageInput) int
BookmarkedRepos func(childComplexity int, requestedPage *PageInput) int BookmarkedRepos func(childComplexity int, requestedPage *PageInput) int
CVEListForImage func(childComplexity int, image string, requestedPage *PageInput, searchedCve *string, excludedCve *string) int CVEListForImage func(childComplexity int, image string, requestedPage *PageInput, searchedCve *string, excludedCve *string, severity *string) int
DerivedImageList func(childComplexity int, image string, digest *string, requestedPage *PageInput) int DerivedImageList func(childComplexity int, image string, digest *string, requestedPage *PageInput) int
ExpandedRepoInfo func(childComplexity int, repo string) int ExpandedRepoInfo func(childComplexity int, repo string) int
GlobalSearch func(childComplexity int, query string, filter *Filter, requestedPage *PageInput) int GlobalSearch func(childComplexity int, query string, filter *Filter, requestedPage *PageInput) int
@ -219,7 +219,7 @@ type ComplexityRoot struct {
} }
type QueryResolver interface { type QueryResolver interface {
CVEListForImage(ctx context.Context, image string, requestedPage *PageInput, searchedCve *string, excludedCve *string) (*CVEResultForImage, error) CVEListForImage(ctx context.Context, image string, requestedPage *PageInput, searchedCve *string, excludedCve *string, severity *string) (*CVEResultForImage, error)
ImageListForCve(ctx context.Context, id string, filter *Filter, requestedPage *PageInput) (*PaginatedImagesResult, error) ImageListForCve(ctx context.Context, id string, filter *Filter, requestedPage *PageInput) (*PaginatedImagesResult, error)
ImageListWithCVEFixed(ctx context.Context, id string, image string, filter *Filter, requestedPage *PageInput) (*PaginatedImagesResult, error) ImageListWithCVEFixed(ctx context.Context, id string, image string, filter *Filter, requestedPage *PageInput) (*PaginatedImagesResult, error)
ImageListForDigest(ctx context.Context, id string, requestedPage *PageInput) (*PaginatedImagesResult, error) ImageListForDigest(ctx context.Context, id string, requestedPage *PageInput) (*PaginatedImagesResult, error)
@ -827,7 +827,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false return 0, false
} }
return e.complexity.Query.CVEListForImage(childComplexity, args["image"].(string), args["requestedPage"].(*PageInput), args["searchedCVE"].(*string), args["excludedCVE"].(*string)), true return e.complexity.Query.CVEListForImage(childComplexity, args["image"].(string), args["requestedPage"].(*PageInput), args["searchedCVE"].(*string), args["excludedCVE"].(*string), args["severity"].(*string)), true
case "Query.DerivedImageList": case "Query.DerivedImageList":
if e.complexity.Query.DerivedImageList == nil { if e.complexity.Query.DerivedImageList == nil {
@ -1839,6 +1839,8 @@ type Query {
searchedCVE: String searchedCVE: String
"Search term that must not be present in the returned results" "Search term that must not be present in the returned results"
excludedCVE: String excludedCVE: String
"Severity of the CVEs that should be present in the returned results"
severity: String
): CVEResultForImage! ): CVEResultForImage!
""" """
@ -2075,6 +2077,15 @@ func (ec *executionContext) field_Query_CVEListForImage_args(ctx context.Context
} }
} }
args["excludedCVE"] = arg3 args["excludedCVE"] = arg3
var arg4 *string
if tmp, ok := rawArgs["severity"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("severity"))
arg4, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
if err != nil {
return nil, err
}
}
args["severity"] = arg4
return args, nil return args, nil
} }
@ -5936,7 +5947,7 @@ func (ec *executionContext) _Query_CVEListForImage(ctx context.Context, field gr
}() }()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().CVEListForImage(rctx, fc.Args["image"].(string), fc.Args["requestedPage"].(*PageInput), fc.Args["searchedCVE"].(*string), fc.Args["excludedCVE"].(*string)) return ec.resolvers.Query().CVEListForImage(rctx, fc.Args["image"].(string), fc.Args["requestedPage"].(*PageInput), fc.Args["searchedCVE"].(*string), fc.Args["excludedCVE"].(*string), fc.Args["severity"].(*string))
}) })
if err != nil { if err != nil {
ec.Error(ctx, err) ec.Error(ctx, err)

View file

@ -197,6 +197,7 @@ func getCVEListForImage(
requestedPage *gql_generated.PageInput, requestedPage *gql_generated.PageInput,
searchedCVE string, searchedCVE string,
excludedCVE string, excludedCVE string,
severity string,
log log.Logger, //nolint:unparam // may be used by devs for debugging log log.Logger, //nolint:unparam // may be used by devs for debugging
) (*gql_generated.CVEResultForImage, error) { ) (*gql_generated.CVEResultForImage, error) {
if requestedPage == nil { if requestedPage == nil {
@ -218,7 +219,7 @@ func getCVEListForImage(
} }
cveList, imageCveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo, ref, cveList, imageCveSummary, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo, ref,
searchedCVE, excludedCVE, pageInput) searchedCVE, excludedCVE, severity, pageInput)
if err != nil { if err != nil {
return &gql_generated.CVEResultForImage{}, err return &gql_generated.CVEResultForImage{}, err
} }

View file

@ -1166,10 +1166,10 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
dig := godigest.FromString("dig") dig := godigest.FromString("dig")
repoWithDigestRef := fmt.Sprintf("repo@%s", dig) repoWithDigestRef := fmt.Sprintf("repo@%s", dig)
_, err := getCVEListForImage(responseContext, repoWithDigestRef, cveInfo, pageInput, "", "", log) _, err := getCVEListForImage(responseContext, repoWithDigestRef, cveInfo, pageInput, "", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
cveResult, err := getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "", "", log) cveResult, err := getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1181,7 +1181,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
} }
// test searching CVE by id in results // test searching CVE by id in results
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "CVE3", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "CVE3", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1193,13 +1193,13 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
} }
// test searching CVE by id in results - no matches // test searching CVE by id in results - no matches
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "CVE100", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "CVE100", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
So(len(cveResult.CVEList), ShouldEqual, 0) So(len(cveResult.CVEList), ShouldEqual, 0)
// test searching CVE by id in results - partial name // test searching CVE by id in results - partial name
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "VE3", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "VE3", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1211,7 +1211,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
} }
// test searching CVE by title in results // test searching CVE by title in results
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Title CVE", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Title CVE", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1222,7 +1222,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
So(expectedCves, ShouldContain, *cve.ID) So(expectedCves, ShouldContain, *cve.ID)
} }
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.1", cveInfo, pageInput, "", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.1", cveInfo, pageInput, "", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.1") So(*cveResult.Tag, ShouldEqual, "1.0.1")
@ -1233,7 +1233,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
So(expectedCves, ShouldContain, *cve.ID) So(expectedCves, ShouldContain, *cve.ID)
} }
cveResult, err = getCVEListForImage(responseContext, "repo1:1.1.0", cveInfo, pageInput, "", "", log) cveResult, err = getCVEListForImage(responseContext, "repo1:1.1.0", cveInfo, pageInput, "", "", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.1.0") So(*cveResult.Tag, ShouldEqual, "1.1.0")
@ -1254,7 +1254,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
graphql.DefaultRecover) graphql.DefaultRecover)
cveResult, err := getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Title CVE", cveResult, err := getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Title CVE",
"Title CVE2", log) "Title CVE2", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1266,7 +1266,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
} }
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Description", cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Description",
"Description CVE2", log) "Description CVE2", "", log)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0") So(*cveResult.Tag, ShouldEqual, "1.0.0")
@ -1278,6 +1278,39 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
} }
}) })
Convey("Unpaginated request to get all CVEs in an image filtered by severity", func() {
pageInput := &gql_generated.PageInput{
SortBy: ref(gql_generated.SortCriteriaAlphabeticAsc),
}
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover)
cveResult, err := getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "",
"", "HIGH", log)
So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0")
expectedCves := []string{"CVE1"}
So(len(cveResult.CVEList), ShouldEqual, len(expectedCves))
for _, cve := range cveResult.CVEList {
So(expectedCves, ShouldContain, *cve.ID)
}
cveResult, err = getCVEListForImage(responseContext, "repo1:1.0.0", cveInfo, pageInput, "Description",
"Description CVE2", "LOW", log)
So(err, ShouldBeNil)
So(*cveResult.Tag, ShouldEqual, "1.0.0")
expectedCves = []string{"CVE3", "CVE34"}
So(len(cveResult.CVEList), ShouldEqual, len(expectedCves))
for _, cve := range cveResult.CVEList {
So(expectedCves, ShouldContain, *cve.ID)
}
})
Convey("paginated fail", func() { Convey("paginated fail", func() {
pageInput := &gql_generated.PageInput{ pageInput := &gql_generated.PageInput{
Limit: ref(-1), Limit: ref(-1),
@ -1286,7 +1319,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter, responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover) graphql.DefaultRecover)
_, err = getCVEListForImage(responseContext, "repo1:1.1.0", cveInfo, pageInput, "", "", log) _, err = getCVEListForImage(responseContext, "repo1:1.1.0", cveInfo, pageInput, "", "", "", log)
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
}) })
}) })

View file

@ -637,6 +637,8 @@ type Query {
searchedCVE: String searchedCVE: String
"Search term that must not be present in the returned results" "Search term that must not be present in the returned results"
excludedCVE: String excludedCVE: String
"Severity of the CVEs that should be present in the returned results"
severity: String
): CVEResultForImage! ): CVEResultForImage!
""" """

View file

@ -15,12 +15,12 @@ import (
) )
// CVEListForImage is the resolver for the CVEListForImage field. // CVEListForImage is the resolver for the CVEListForImage field.
func (r *queryResolver) CVEListForImage(ctx context.Context, image string, requestedPage *gql_generated.PageInput, searchedCve *string, excludedCve *string) (*gql_generated.CVEResultForImage, error) { func (r *queryResolver) CVEListForImage(ctx context.Context, image string, requestedPage *gql_generated.PageInput, searchedCve *string, excludedCve *string, severity *string) (*gql_generated.CVEResultForImage, error) {
if r.cveInfo == nil { if r.cveInfo == nil {
return &gql_generated.CVEResultForImage{}, zerr.ErrCVESearchDisabled return &gql_generated.CVEResultForImage{}, zerr.ErrCVESearchDisabled
} }
return getCVEListForImage(ctx, image, r.cveInfo, requestedPage, deref(searchedCve, ""), deref(excludedCve, ""), r.log) return getCVEListForImage(ctx, image, r.cveInfo, requestedPage, deref(searchedCve, ""), deref(excludedCve, ""), deref(severity, ""), r.log)
} }
// ImageListForCve is the resolver for the ImageListForCVE field. // ImageListForCve is the resolver for the ImageListForCVE field.

View file

@ -10,7 +10,7 @@ import (
type CveInfoMock struct { type CveInfoMock struct {
GetImageListForCVEFn func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) GetImageListForCVEFn func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
GetImageListWithCVEFixedFn func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) GetImageListWithCVEFixedFn func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error)
GetCVEListForImageFn func(ctx context.Context, repo, reference, searchedCVE, excludedCVE string, GetCVEListForImageFn func(ctx context.Context, repo, reference, searchedCVE, excludedCVE, severity string,
pageInput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, common.PageInfo, error) pageInput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, common.PageInfo, error)
GetCVESummaryForImageMediaFn func(ctx context.Context, repo string, digest, mediaType string, GetCVESummaryForImageMediaFn func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) ) (cvemodel.ImageCVESummary, error)
@ -34,7 +34,7 @@ func (cveInfo CveInfoMock) GetImageListWithCVEFixed(ctx context.Context, repo, c
} }
func (cveInfo CveInfoMock) GetCVEListForImage(ctx context.Context, repo string, reference string, func (cveInfo CveInfoMock) GetCVEListForImage(ctx context.Context, repo string, reference string,
searchedCVE string, excludedCVE string, pageInput cvemodel.PageInput, searchedCVE string, excludedCVE string, severity string, pageInput cvemodel.PageInput,
) ( ) (
[]cvemodel.CVE, []cvemodel.CVE,
cvemodel.ImageCVESummary, cvemodel.ImageCVESummary,
@ -42,7 +42,7 @@ func (cveInfo CveInfoMock) GetCVEListForImage(ctx context.Context, repo string,
error, error,
) { ) {
if cveInfo.GetCVEListForImageFn != nil { if cveInfo.GetCVEListForImageFn != nil {
return cveInfo.GetCVEListForImageFn(ctx, repo, reference, searchedCVE, excludedCVE, pageInput) return cveInfo.GetCVEListForImageFn(ctx, repo, reference, searchedCVE, excludedCVE, severity, pageInput)
} }
return []cvemodel.CVE{}, cvemodel.ImageCVESummary{}, common.PageInfo{}, nil return []cvemodel.CVE{}, cvemodel.ImageCVESummary{}, common.PageInfo{}, nil