Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gql): add new query for diff of cves for 2 images #2185

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,6 @@ var (
ErrAPINotSupported = errors.New("registry at the given address doesn't implement the correct API")
ErrURLNotFound = errors.New("url not found")
ErrInvalidSearchQuery = errors.New("invalid search query")
ErrImageNotFound = errors.New("image not found")
ErrAmbiguousInput = errors.New("input is not specific enough")
)
107 changes: 104 additions & 3 deletions pkg/extensions/search/cve/cve.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import (
type CveInfo interface {
GetImageListForCVE(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, excludedCVE string,
pageinput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error)
GetCVEDiffListForImages(ctx context.Context, minuend, subtrahend, searchedCVE, excludedCVE string,
pageInput cvemodel.PageInput) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error)
GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string) (cvemodel.ImageCVESummary, error)
}

Expand Down Expand Up @@ -329,7 +331,21 @@ func getConfigAndDigest(metaDB mTypes.MetaDB, manifestDigestStr string) (ispec.I
return manifestData.Manifests[0].Config, manifestDigest, err
}

func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) {
func filterCVEMap(cveMap map[string]cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) {
searchedCVE = strings.ToUpper(searchedCVE)

for _, cve := range cveMap {
if excludedCVE != "" && cve.ContainsStr(excludedCVE) {
continue
}

if cve.ContainsStr(searchedCVE) {
pageFinder.Add(cve)
}
}
}

func filterCVEList(cveMap []cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func filterCVEList(cveMap []cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) {
func filterCVEList(cveList []cvemodel.CVE, searchedCVE, excludedCVE string, pageFinder *CvePageFinder) {

searchedCVE = strings.ToUpper(searchedCVE)

for _, cve := range cveMap {
Expand Down Expand Up @@ -373,13 +389,98 @@ func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref str
return []cvemodel.CVE{}, imageCVESummary, zcommon.PageInfo{}, err
}

filterCVEList(cveMap, searchedCVE, excludedCVE, pageFinder)
filterCVEMap(cveMap, searchedCVE, excludedCVE, pageFinder)

cveList, pageInfo := pageFinder.Page()

return cveList, imageCVESummary, pageInfo, nil
}

func (cveinfo BaseCveInfo) GetCVEDiffListForImages(ctx context.Context, minuend, subtrahend, searchedCVE string,
excludedCVE string, pageInput cvemodel.PageInput,
) ([]cvemodel.CVE, cvemodel.ImageCVESummary, zcommon.PageInfo, error) {
minuendRepo, minuendRef, _ := zcommon.GetImageDirAndReference(minuend)
subtrahendRepo, subtrahendRef, _ := zcommon.GetImageDirAndReference(subtrahend)

// get the CVEs of image and comparedImage
minuendCVEList, _, _, err := cveinfo.GetCVEListForImage(ctx, minuendRepo, minuendRef, searchedCVE, excludedCVE,
cvemodel.PageInput{})
if err != nil {
return nil, cvemodel.ImageCVESummary{}, zcommon.PageInfo{}, err
}

subtrahendCVEList, _, _, err := cveinfo.GetCVEListForImage(ctx, subtrahendRepo, subtrahendRef,
searchedCVE, excludedCVE, cvemodel.PageInput{})
if err != nil {
return nil, cvemodel.ImageCVESummary{}, zcommon.PageInfo{}, err
}

subtrahendCVEMap := map[string]cvemodel.CVE{}

for _, cve := range subtrahendCVEList {
cve := cve
subtrahendCVEMap[cve.ID] = cve
}

var (
count int
unknownCount int
lowCount int
mediumCount int
highCount int
criticalCount int
maxSeverity string

diffCVEs = []cvemodel.CVE{}
)

for i := range minuendCVEList {
if _, ok := subtrahendCVEMap[minuendCVEList[i].ID]; !ok {
diffCVEs = append(diffCVEs, minuendCVEList[i])

switch minuendCVEList[i].Severity {
case cvemodel.SeverityUnknown:
unknownCount++
case cvemodel.SeverityLow:
lowCount++
case cvemodel.SeverityMedium:
mediumCount++
case cvemodel.SeverityHigh:
highCount++
case cvemodel.SeverityCritical:
criticalCount++
}

if cvemodel.CompareSeverities(maxSeverity, minuendCVEList[i].Severity) > 0 {
maxSeverity = minuendCVEList[i].Severity
}
}
}

pageFinder, err := NewCvePageFinder(pageInput.Limit, pageInput.Offset, pageInput.SortBy)
if err != nil {
return nil, cvemodel.ImageCVESummary{}, zcommon.PageInfo{}, err
}

filterCVEList(diffCVEs, "", "", pageFinder)

cveList, pageInfo := pageFinder.Page()

count = unknownCount + lowCount + mediumCount + highCount + criticalCount

diffCVESummary := cvemodel.ImageCVESummary{
Count: count,
UnknownCount: unknownCount,
LowCount: lowCount,
MediumCount: mediumCount,
HighCount: highCount,
CriticalCount: criticalCount,
MaxSeverity: maxSeverity,
}

return cveList, diffCVESummary, pageInfo, nil
}

func (cveinfo BaseCveInfo) GetCVESummaryForImageMedia(ctx context.Context, repo, digestStr, mediaType string,
) (cvemodel.ImageCVESummary, error) {
// There are several cases, expected returned values below:
Expand Down
34 changes: 34 additions & 0 deletions pkg/extensions/search/cve/cve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,11 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(cveSummary.CriticalCount, ShouldEqual, 2)
So(cveSummary.MaxSeverity, ShouldEqual, "CRITICAL")

_, _, _, err = cveInfo.GetCVEDiffListForImages(ctx, "repo8:1.0.0", "repo1@"+image13Digest, "", "", pageInput)
So(err, ShouldBeNil)
_, _, _, err = cveInfo.GetCVEDiffListForImages(ctx, "repo8:1.0.0", "repo1:0.1.0", "", "", pageInput)
So(err, ShouldBeNil)

// Image is multiarch
cveList, cveSummary, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", "", pageInput)
So(err, ShouldBeNil)
Expand Down Expand Up @@ -1625,6 +1630,35 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo

_, err = cveInfo.GetImageListForCVE(ctx, repoMultiarch, "CVE1")
So(err, ShouldBeNil)

cveInfo = cveinfo.BaseCveInfo{Log: log, Scanner: mocks.CveScannerMock{
IsImageFormatScannableFn: func(repo, reference string) (bool, error) {
return true, nil
},
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
return nil, zerr.ErrTypeAssertionFailed
},
}, MetaDB: metaDB}
_, _, _, err = cveInfo.GetCVEDiffListForImages(ctx, "repo8:1.0.0", "repo1:0.1.0", "", "", pageInput)
So(err, ShouldNotBeNil)

try := 0
cveInfo = cveinfo.BaseCveInfo{Log: log, Scanner: mocks.CveScannerMock{
IsImageFormatScannableFn: func(repo, reference string) (bool, error) {
return true, nil
},
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
if try == 1 {
return nil, zerr.ErrTypeAssertionFailed
}

try++

return make(map[string]cvemodel.CVE), nil
},
}, MetaDB: metaDB}
_, _, _, err = cveInfo.GetCVEDiffListForImages(ctx, "repo8:1.0.0", "repo6:0.1.0", "", "", pageInput)
So(err, ShouldNotBeNil)
})
}

Expand Down
Loading
Loading