0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-01-06 22:40:28 -05:00
zot/pkg/extensions/search/cve/pagination_test.go
peusebiu 6222dae1f0
feat(scheduler): gracefully shutdown (#1951)
wait for workers to finish before exiting

should fix tests reporting they couldn't remove rootDir because it's being
written by tasks

Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
2023-11-24 00:40:10 -08:00

327 lines
10 KiB
Go

//go:build search
// +build search
package cveinfo_test
import (
"context"
"fmt"
"sort"
"testing"
"time"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/boltdb"
. "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks"
)
func TestCVEPagination(t *testing.T) {
Convey("CVE Pagination", t, func() {
params := boltdb.DBParameters{
RootDir: t.TempDir(),
}
boltDriver, err := boltdb.GetBoltDriver(params)
So(err, ShouldBeNil)
metaDB, err := boltdb.New(boltDriver, log.NewLogger("debug", ""))
So(err, ShouldBeNil)
// Create metadb data for scannable image with vulnerabilities
timeStamp11 := time.Date(2008, 1, 1, 12, 0, 0, 0, time.UTC)
image := CreateImageWith().
Layers([]Layer{{
MediaType: ispec.MediaTypeImageLayerGzip,
Digest: ispec.DescriptorEmptyJSON.Digest,
Blob: ispec.DescriptorEmptyJSON.Data,
}}).ImageConfig(ispec.Image{Created: &timeStamp11}).Build()
err = metaDB.SetRepoReference(context.Background(), "repo1", "0.1.0", image.AsImageMeta())
So(err, ShouldBeNil)
timeStamp12 := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
image2 := CreateImageWith().
Layers([]Layer{{
MediaType: ispec.MediaTypeImageLayerGzip,
Digest: ispec.DescriptorEmptyJSON.Digest,
Blob: ispec.DescriptorEmptyJSON.Data,
}}).ImageConfig(ispec.Image{Created: &timeStamp12}).Build()
err = metaDB.SetRepoReference(context.Background(), "repo1", "1.0.0", image2.AsImageMeta())
So(err, ShouldBeNil)
// MetaDB loaded with initial data, mock the scanner
severityToInt := map[string]int{
"UNKNOWN": 0,
"LOW": 1,
"MEDIUM": 2,
"HIGH": 3,
"CRITICAL": 4,
}
intToSeverity := make(map[int]string, len(severityToInt))
for k, v := range severityToInt {
intToSeverity[v] = k
}
// Setup test CVE data in mock scanner
scanner := mocks.CveScannerMock{
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
cveMap := map[string]cvemodel.CVE{}
if image == "repo1:0.1.0" {
for i := 0; i < 5; i++ {
cveMap[fmt.Sprintf("CVE%d", i)] = cvemodel.CVE{
ID: fmt.Sprintf("CVE%d", i),
Severity: intToSeverity[i%5],
Title: fmt.Sprintf("Title for CVE%d", i),
Description: fmt.Sprintf("Description for CVE%d", i),
}
}
}
if image == "repo1:1.0.0" {
for i := 0; i < 30; i++ {
cveMap[fmt.Sprintf("CVE%d", i)] = cvemodel.CVE{
ID: fmt.Sprintf("CVE%d", i),
Severity: intToSeverity[i%5],
Title: fmt.Sprintf("Title for CVE%d", i),
Description: fmt.Sprintf("Description for CVE%d", i),
}
}
}
// By default the image has no vulnerabilities
return cveMap, nil
},
}
log := log.NewLogger("debug", "")
cveInfo := cveinfo.BaseCveInfo{Log: log, Scanner: scanner, MetaDB: metaDB}
ctx := context.Background()
Convey("create new paginator errors", func() {
paginator, err := cveinfo.NewCvePageFinder(-1, 10, cveinfo.AlphabeticAsc)
So(paginator, ShouldBeNil)
So(err, ShouldNotBeNil)
paginator, err = cveinfo.NewCvePageFinder(2, -1, cveinfo.AlphabeticAsc)
So(paginator, ShouldBeNil)
So(err, ShouldNotBeNil)
paginator, err = cveinfo.NewCvePageFinder(2, 1, "wrong sorting criteria")
So(paginator, ShouldBeNil)
So(err, ShouldNotBeNil)
})
Convey("Reset", func() {
paginator, err := cveinfo.NewCvePageFinder(1, 0, cveinfo.AlphabeticAsc)
So(err, ShouldBeNil)
So(paginator, ShouldNotBeNil)
paginator.Add(cvemodel.CVE{})
paginator.Add(cvemodel.CVE{})
paginator.Add(cvemodel.CVE{})
paginator.Reset()
result, _ := paginator.Page()
So(result, ShouldBeEmpty)
})
Convey("Page", func() {
Convey("defaults", func() {
// By default expect unlimitted results sorted by severity
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5)
So(pageInfo.ItemCount, ShouldEqual, 5)
So(pageInfo.TotalCount, ShouldEqual, 5)
previousSeverity := 4
for _, cve := range cves {
So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
previousSeverity = severityToInt[cve.Severity]
}
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
So(pageInfo.ItemCount, ShouldEqual, 30)
So(pageInfo.TotalCount, ShouldEqual, 30)
previousSeverity = 4
for _, cve := range cves {
So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
previousSeverity = severityToInt[cve.Severity]
}
})
Convey("no limit or offset", func() {
cveIds := []string{}
for i := 0; i < 30; i++ {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
}
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5)
So(pageInfo.ItemCount, ShouldEqual, 5)
So(pageInfo.TotalCount, ShouldEqual, 5)
for i, cve := range cves {
So(cve.ID, ShouldEqual, cveIds[i])
}
sort.Strings(cveIds)
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
So(pageInfo.ItemCount, ShouldEqual, 30)
So(pageInfo.TotalCount, ShouldEqual, 30)
for i, cve := range cves {
So(cve.ID, ShouldEqual, cveIds[i])
}
sort.Sort(sort.Reverse(sort.StringSlice(cveIds)))
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticDsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
So(pageInfo.ItemCount, ShouldEqual, 30)
So(pageInfo.TotalCount, ShouldEqual, 30)
for i, cve := range cves {
So(cve.ID, ShouldEqual, cveIds[i])
}
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.SeverityDsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
So(pageInfo.ItemCount, ShouldEqual, 30)
So(pageInfo.TotalCount, ShouldEqual, 30)
previousSeverity := 4
for _, cve := range cves {
So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
previousSeverity = severityToInt[cve.Severity]
}
})
Convey("limit < len(cves)", func() {
cveIds := []string{}
for i := 0; i < 30; i++ {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
}
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 3,
Offset: 1,
SortBy: cveinfo.AlphabeticAsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 3)
So(pageInfo.ItemCount, ShouldEqual, 3)
So(pageInfo.TotalCount, ShouldEqual, 5)
So(cves[0].ID, ShouldEqual, "CVE1") // CVE0 is first ID and is not part of the page
So(cves[1].ID, ShouldEqual, "CVE2")
So(cves[2].ID, ShouldEqual, "CVE3")
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 2,
Offset: 1,
SortBy: cveinfo.AlphabeticDsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
So(cves[0].ID, ShouldEqual, "CVE3")
So(cves[1].ID, ShouldEqual, "CVE2")
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 3,
Offset: 1,
SortBy: cveinfo.SeverityDsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 3)
So(pageInfo.ItemCount, ShouldEqual, 3)
So(pageInfo.TotalCount, ShouldEqual, 5)
previousSeverity := 4
for _, cve := range cves {
So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
previousSeverity = severityToInt[cve.Severity]
}
sort.Strings(cveIds)
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{
Limit: 5,
Offset: 20,
SortBy: cveinfo.AlphabeticAsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5)
So(pageInfo.ItemCount, ShouldEqual, 5)
So(pageInfo.TotalCount, ShouldEqual, 30)
for i, cve := range cves {
So(cve.ID, ShouldEqual, cveIds[i+20])
}
})
Convey("limit > len(cves)", func() {
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.AlphabeticAsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
So(cves[0].ID, ShouldEqual, "CVE3")
So(cves[1].ID, ShouldEqual, "CVE4")
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.AlphabeticDsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
So(cves[0].ID, ShouldEqual, "CVE1")
So(cves[1].ID, ShouldEqual, "CVE0")
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.SeverityDsc,
},
)
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 2)
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 5)
previousSeverity := 4
for _, cve := range cves {
So(severityToInt[cve.Severity], ShouldBeLessThanOrEqualTo, previousSeverity)
previousSeverity = severityToInt[cve.Severity]
}
})
})
})
}