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/scan_test.go
Andrei Aaron ba6f347d8d
refactor(pkg/test): split logic in pkg/test/common.go into multiple packages (#1861)
Which could be imported independently. See more details:
1. "zotregistry.io/zot/pkg/test/common" - currently used as
   tcommon "zotregistry.io/zot/pkg/test/common" - inside pkg/test
   test "zotregistry.io/zot/pkg/test/common" - in tests
   . "zotregistry.io/zot/pkg/test/common" - in tests
Decouple zb from code in test/pkg in order to keep the size small.

2. "zotregistry.io/zot/pkg/test/image-utils" - curently used as
   . "zotregistry.io/zot/pkg/test/image-utils"

3. "zotregistry.io/zot/pkg/test/deprecated" -  curently used as
   "zotregistry.io/zot/pkg/test/deprecated"
This one will bre replaced gradually by image-utils in the future.

4. "zotregistry.io/zot/pkg/test/signature" - (cosign + notation) use as
   "zotregistry.io/zot/pkg/test/signature"

5. "zotregistry.io/zot/pkg/test/auth" - (bearer + oidc)  curently used as
   authutils "zotregistry.io/zot/pkg/test/auth"

 6. "zotregistry.io/zot/pkg/test/oci-utils" -  curently used as
   ociutils "zotregistry.io/zot/pkg/test/oci-utils"

Some unused functions were removed, some were replaced, and in
a few cases specific funtions were moved to the files they were used in.

Added an interface for the StoreController, this reduces the number of imports
of the entire image store, decreasing binary size for tests.
If the zb code was still coupled with pkg/test, this would have reflected in zb size.

Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
2023-09-27 11:34:48 -07:00

670 lines
21 KiB
Go

//go:build search
// +build search
package cveinfo_test
import (
"context"
"encoding/json"
"errors"
"io"
"os"
"testing"
"time"
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/api/config"
zcommon "zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/monitoring"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvecache "zotregistry.io/zot/pkg/extensions/search/cve/cache"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta"
"zotregistry.io/zot/pkg/meta/boltdb"
mTypes "zotregistry.io/zot/pkg/meta/types"
"zotregistry.io/zot/pkg/scheduler"
"zotregistry.io/zot/pkg/storage"
"zotregistry.io/zot/pkg/storage/local"
test "zotregistry.io/zot/pkg/test/common"
. "zotregistry.io/zot/pkg/test/image-utils"
"zotregistry.io/zot/pkg/test/mocks"
)
var (
ErrBadTest = errors.New("there is a bug in the test")
ErrFailedScan = errors.New("scan has failed intentionally")
)
func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
Convey("Test CVE scanning task scheduler with diverse mocked data", t, func() {
repo1 := "repo1"
repoIndex := "repoIndex"
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
logPath := logFile.Name()
So(err, ShouldBeNil)
defer os.Remove(logFile.Name()) // clean up
logger := log.NewLogger("debug", logPath)
writers := io.MultiWriter(os.Stdout, logFile)
logger.Logger = logger.Output(writers)
cfg := config.New()
cfg.Scheduler = &config.SchedulerConfig{NumWorkers: 3}
sch := scheduler.NewScheduler(cfg, logger)
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
image11 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2008, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta11 := mTypes.ManifestMetadata{
ManifestBlob: image11.ManifestDescriptor.Data,
ConfigBlob: image11.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image11.ManifestDescriptor.Digest, repoMeta11)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "0.1.0", image11.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
image12 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta12 := mTypes.ManifestMetadata{
ManifestBlob: image12.ManifestDescriptor.Data,
ConfigBlob: image12.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image12.ManifestDescriptor.Digest, repoMeta12)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.0.0", image12.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
image13 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2010, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta13 := mTypes.ManifestMetadata{
ManifestBlob: image13.ManifestDescriptor.Data,
ConfigBlob: image13.ConfigDescriptor.Data,
DownloadCount: 0,
Signatures: mTypes.ManifestSignatures{},
}
err = metaDB.SetManifestMeta("repo1", image13.ManifestDescriptor.Digest, repoMeta13)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.1.0", image13.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
image14 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2011, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta14 := mTypes.ManifestMetadata{
ManifestBlob: image14.ManifestDescriptor.Data,
ConfigBlob: image14.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo1", image14.ManifestDescriptor.Digest, repoMeta14)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo1", "1.0.1", image14.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// Create metadb data for scannable image with no vulnerabilities
image61 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2016, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta61 := mTypes.ManifestMetadata{
ManifestBlob: image61.ManifestDescriptor.Data,
ConfigBlob: image61.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo6", image61.ManifestDescriptor.Digest, repoMeta61)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo6", "1.0.0", image61.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// Create metadb data for image not supporting scanning
image21 := CreateImageWith().Layers([]Layer{{
MediaType: ispec.MediaTypeImageLayerNonDistributableGzip, //nolint:staticcheck
Blob: []byte{10, 10, 10},
Digest: godigest.FromBytes([]byte{10, 10, 10}),
}}).ImageConfig(ispec.Image{Created: DateRef(2009, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta21 := mTypes.ManifestMetadata{
ManifestBlob: image21.ManifestDescriptor.Data,
ConfigBlob: image21.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo2", image21.ManifestDescriptor.Digest, repoMeta21)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo2", "1.0.0", image21.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// Create metadb data for invalid images/negative tests
manifestBlob31 := []byte("invalid manifest blob")
So(err, ShouldBeNil)
repoMeta31 := mTypes.ManifestMetadata{
ManifestBlob: manifestBlob31,
}
digest31 := godigest.FromBytes(manifestBlob31)
err = metaDB.SetManifestMeta("repo3", digest31, repoMeta31)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo3", "invalid-manifest", digest31, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
image41 := CreateImageWith().DefaultLayers().
CustomConfigBlob([]byte("invalid config blob"), ispec.MediaTypeImageConfig).Build()
repoMeta41 := mTypes.ManifestMetadata{
ManifestBlob: image41.ManifestDescriptor.Data,
ConfigBlob: image41.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo4", image41.ManifestDescriptor.Digest, repoMeta41)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo4", "invalid-config", image41.ManifestDescriptor.Digest,
ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
digest51 := godigest.FromString("abc8")
err = metaDB.SetRepoReference("repo5", "nonexitent-manifest", digest51, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// Create metadb data for scannable image which errors during scan
image71 := CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{Created: DateRef(2000, 1, 1, 12, 0, 0, 0, time.UTC)}).Build()
repoMeta71 := mTypes.ManifestMetadata{
ManifestBlob: image71.ManifestDescriptor.Data,
ConfigBlob: image71.ConfigDescriptor.Data,
}
err = metaDB.SetManifestMeta("repo7", image71.ManifestDescriptor.Digest, repoMeta71)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference("repo7", "1.0.0", image71.ManifestDescriptor.Digest, ispec.MediaTypeImageManifest)
So(err, ShouldBeNil)
// Create multiarch image with vulnerabilities
multiarchImage := CreateRandomMultiarch()
err = metaDB.SetIndexData(
multiarchImage.IndexDescriptor.Digest,
mTypes.IndexData{IndexBlob: multiarchImage.IndexDescriptor.Data},
)
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[0].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[0].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[0].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[1].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[1].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[1].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetManifestData(
multiarchImage.Images[2].ManifestDescriptor.Digest,
mTypes.ManifestData{
ManifestBlob: multiarchImage.Images[2].ManifestDescriptor.Data,
ConfigBlob: multiarchImage.Images[2].ConfigDescriptor.Data,
},
)
So(err, ShouldBeNil)
err = metaDB.SetRepoReference(
repoIndex,
"tagIndex",
multiarchImage.IndexDescriptor.Digest,
ispec.MediaTypeImageIndex,
)
So(err, ShouldBeNil)
// Keep a record of all the image references / digest pairings
// This is normally done in MetaDB, but we want to verify
// the whole flow, including MetaDB
imageMap := map[string]string{}
image11Digest := image11.ManifestDescriptor.Digest.String()
image11Name := "repo1:0.1.0"
imageMap[image11Name] = image11Digest
image12Digest := image12.ManifestDescriptor.Digest.String()
image12Name := "repo1:1.0.0"
imageMap[image12Name] = image12Digest
image13Digest := image13.ManifestDescriptor.Digest.String()
image13Name := "repo1:1.1.0"
imageMap[image13Name] = image13Digest
image14Digest := image14.ManifestDescriptor.Digest.String()
image14Name := "repo1:1.0.1"
imageMap[image14Name] = image14Digest
image21Digest := image21.ManifestDescriptor.Digest.String()
image21Name := "repo2:1.0.0"
imageMap[image21Name] = image21Digest
image31Name := "repo3:invalid-manifest"
imageMap[image31Name] = digest31.String()
image41Digest := image41.ManifestDescriptor.Digest.String()
image41Name := "repo4:invalid-config"
imageMap[image41Name] = image41Digest
image51Name := "repo5:nonexitent-manifest"
imageMap[image51Name] = digest51.String()
image61Digest := image61.ManifestDescriptor.Digest.String()
image61Name := "repo6:1.0.0"
imageMap[image61Name] = image61Digest
image71Digest := image71.ManifestDescriptor.Digest.String()
image71Name := "repo7:1.0.0"
imageMap[image71Name] = image71Digest
indexDigest := multiarchImage.IndexDescriptor.Digest.String()
indexName := "repoIndex:tagIndex"
imageMap[indexName] = indexDigest
indexM1Digest := multiarchImage.Images[0].ManifestDescriptor.Digest.String()
indexM1Name := "repoIndex@" + indexM1Digest
imageMap[indexM1Name] = indexM1Digest
indexM2Digest := multiarchImage.Images[1].ManifestDescriptor.Digest.String()
indexM2Name := "repoIndex@" + indexM2Digest
imageMap[indexM2Name] = indexM2Digest
indexM3Digest := multiarchImage.Images[2].ManifestDescriptor.Digest.String()
indexM3Name := "repoIndex@" + indexM3Digest
imageMap[indexM3Name] = indexM3Digest
// Initialize a test CVE cache
cache := cvecache.NewCveCache(10, logger)
// MetaDB loaded with initial data, now mock the scanner
// Setup test CVE data in mock scanner
scanner := mocks.CveScannerMock{
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
result := cache.Get(image)
// Will not match sending the repo:tag as a parameter, but we don't care
if result != nil {
return result, nil
}
repo, ref, isTag := zcommon.GetImageDirAndReference(image)
if isTag {
foundRef, ok := imageMap[image]
if !ok {
return nil, ErrBadTest
}
ref = foundRef
}
// Images in chronological order
if repo == repo1 && ref == image11Digest {
result := map[string]cvemodel.CVE{
"CVE1": {
ID: "CVE1",
Severity: "MEDIUM",
Title: "Title CVE1",
Description: "Description CVE1",
},
}
cache.Add(ref, result)
return result, nil
}
if repo == repo1 && zcommon.Contains([]string{image12Digest, image21Digest}, ref) {
result := map[string]cvemodel.CVE{
"CVE1": {
ID: "CVE1",
Severity: "MEDIUM",
Title: "Title CVE1",
Description: "Description CVE1",
},
"CVE2": {
ID: "CVE2",
Severity: "HIGH",
Title: "Title CVE2",
Description: "Description CVE2",
},
"CVE3": {
ID: "CVE3",
Severity: "LOW",
Title: "Title CVE3",
Description: "Description CVE3",
},
}
cache.Add(ref, result)
return result, nil
}
if repo == repo1 && ref == image13Digest {
result := map[string]cvemodel.CVE{
"CVE3": {
ID: "CVE3",
Severity: "LOW",
Title: "Title CVE3",
Description: "Description CVE3",
},
}
cache.Add(ref, result)
return result, nil
}
// As a minor release on 1.0.0 banch
// does not include all fixes published in 1.1.0
if repo == repo1 && ref == image14Digest {
result := map[string]cvemodel.CVE{
"CVE1": {
ID: "CVE1",
Severity: "MEDIUM",
Title: "Title CVE1",
Description: "Description CVE1",
},
"CVE3": {
ID: "CVE3",
Severity: "LOW",
Title: "Title CVE3",
Description: "Description CVE3",
},
}
cache.Add(ref, result)
return result, nil
}
// Unexpected error while scanning
if repo == "repo7" {
return map[string]cvemodel.CVE{}, ErrFailedScan
}
if (repo == repoIndex && ref == indexDigest) ||
(repo == repoIndex && ref == indexM1Digest) {
result := map[string]cvemodel.CVE{
"CVE1": {
ID: "CVE1",
Severity: "MEDIUM",
Title: "Title CVE1",
Description: "Description CVE1",
},
}
// Simulate scanning an index results in scanning its manifests
if ref == indexDigest {
cache.Add(indexM1Digest, result)
cache.Add(indexM2Digest, map[string]cvemodel.CVE{})
cache.Add(indexM3Digest, map[string]cvemodel.CVE{})
}
cache.Add(ref, result)
return result, nil
}
// By default the image has no vulnerabilities
result = map[string]cvemodel.CVE{}
cache.Add(ref, result)
return result, nil
},
IsImageFormatScannableFn: func(repo string, reference string) (bool, error) {
if repo == repoIndex {
return true, nil
}
// Almost same logic compared to actual Trivy specific implementation
imageDir, inputTag := repo, reference
repoMeta, err := metaDB.GetRepoMeta(imageDir)
if err != nil {
return false, err
}
manifestDigestStr := reference
if zcommon.IsTag(reference) {
var ok bool
descriptor, ok := repoMeta.Tags[inputTag]
if !ok {
return false, zerr.ErrTagMetaNotFound
}
manifestDigestStr = descriptor.Digest
}
manifestDigest, err := godigest.Parse(manifestDigestStr)
if err != nil {
return false, err
}
manifestData, err := metaDB.GetManifestData(manifestDigest)
if err != nil {
return false, err
}
var manifestContent ispec.Manifest
err = json.Unmarshal(manifestData.ManifestBlob, &manifestContent)
if err != nil {
return false, zerr.ErrScanNotSupported
}
for _, imageLayer := range manifestContent.Layers {
switch imageLayer.MediaType {
case ispec.MediaTypeImageLayerGzip, ispec.MediaTypeImageLayer, string(regTypes.DockerLayer):
return true, nil
default:
return false, zerr.ErrScanNotSupported
}
}
return false, nil
},
IsImageMediaScannableFn: func(repo, digest, mediaType string) (bool, error) {
if repo == "repo2" {
if digest == image21Digest {
return false, nil
}
}
return true, nil
},
IsResultCachedFn: func(digest string) bool {
return cache.Contains(digest)
},
UpdateDBFn: func() error {
cache.Purge()
return nil
},
}
// Purge scan, it should not be needed
So(scanner.UpdateDB(), ShouldBeNil)
// Verify none of the entries are cached to begin with
t.Log("verify cache is initially empty")
for image, digestStr := range imageMap {
t.Log("expecting " + image + " " + digestStr + " to be absent from cache")
So(scanner.IsResultCached(digestStr), ShouldBeFalse)
}
// Start the generator
generator := cveinfo.NewScanTaskGenerator(metaDB, scanner, logger)
sch.SubmitGenerator(generator, 10*time.Second, scheduler.MediumPriority)
ctx, cancel := context.WithCancel(context.Background())
sch.RunScheduler(ctx)
defer cancel()
// Make sure the scanner generator has completed despite errors
found, err := test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: finished for available images", 20*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
t.Log("verify cache is up to date after scanner generator ran")
// Verify all of the entries are cached
for image, digestStr := range imageMap {
repo, _, _ := zcommon.GetImageDirAndReference(image)
ok, err := scanner.IsImageFormatScannable(repo, digestStr)
if ok && err == nil && repo != "repo7" {
t.Log("expecting " + image + " " + digestStr + " to be present in cache")
So(scanner.IsResultCached(digestStr), ShouldBeTrue)
} else {
// We don't cache results for unscannable manifests
t.Log("expecting " + image + " " + digestStr + " to be absent from cache")
So(scanner.IsResultCached(digestStr), ShouldBeFalse)
}
}
// Make sure the scanner generator is catching the metadb error for repo5:nonexitent-manifest
found, err = test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: error while obtaining repo metadata", 20*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
// Make sure the scanner generator is catching the scanning error for repo7
found, err = test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan errored for image", 20*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
// Make sure the scanner generator is triggered at least twice
found, err = test.ReadLogFileAndCountStringOccurence(logPath,
"Scheduled CVE scan: finished for available images", 30*time.Second, 2)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
})
}
func TestScanGeneratorWithRealData(t *testing.T) {
Convey("Test CVE scanning task scheduler real data", t, func() {
rootDir := t.TempDir()
logFile, err := os.CreateTemp(t.TempDir(), "zot-log*.txt")
logPath := logFile.Name()
So(err, ShouldBeNil)
defer os.Remove(logFile.Name()) // clean up
logger := log.NewLogger("debug", logPath)
writers := io.MultiWriter(os.Stdout, logFile)
logger.Logger = logger.Output(writers)
cfg := config.New()
cfg.Scheduler = &config.SchedulerConfig{NumWorkers: 3}
boltDriver, err := boltdb.GetBoltDriver(boltdb.DBParameters{RootDir: rootDir})
So(err, ShouldBeNil)
metaDB, err := boltdb.New(boltDriver, logger)
So(err, ShouldBeNil)
imageStore := local.NewImageStore(rootDir, false, false,
logger, monitoring.NewMetricsServer(false, logger), nil, nil)
storeController := storage.StoreController{DefaultStore: imageStore}
image := CreateRandomVulnerableImage()
err = WriteImageToFileSystem(image, "zot-test", "0.0.1", storeController)
So(err, ShouldBeNil)
err = meta.ParseStorage(metaDB, storeController, logger)
So(err, ShouldBeNil)
scanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", logger)
err = scanner.UpdateDB()
So(err, ShouldBeNil)
So(scanner.IsResultCached(image.DigestStr()), ShouldBeFalse)
sch := scheduler.NewScheduler(cfg, logger)
generator := cveinfo.NewScanTaskGenerator(metaDB, scanner, logger)
// Start the generator
sch.SubmitGenerator(generator, 120*time.Second, scheduler.MediumPriority)
ctx, cancel := context.WithCancel(context.Background())
sch.RunScheduler(ctx)
defer cancel()
// Make sure the scanner generator has completed
found, err := test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan: finished for available images", 120*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
found, err = test.ReadLogFileAndSearchString(logPath,
image.ManifestDescriptor.Digest.String(), 120*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
found, err = test.ReadLogFileAndSearchString(logPath,
"Scheduled CVE scan completed successfully for image", 120*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
So(scanner.IsResultCached(image.DigestStr()), ShouldBeTrue)
cveMap, err := scanner.ScanImage("zot-test:0.0.1")
So(err, ShouldBeNil)
t.Logf("cveMap: %v", cveMap)
// As of September 22 2023 there are 5 CVEs:
// CVE-2023-1255, CVE-2023-2650, CVE-2023-2975, CVE-2023-3817, CVE-2023-3446
// There may be more discovered in the future
So(len(cveMap), ShouldBeGreaterThanOrEqualTo, 5)
So(cveMap, ShouldContainKey, "CVE-2023-1255")
So(cveMap, ShouldContainKey, "CVE-2023-2650")
So(cveMap, ShouldContainKey, "CVE-2023-2975")
So(cveMap, ShouldContainKey, "CVE-2023-3817")
So(cveMap, ShouldContainKey, "CVE-2023-3446")
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, logger)
// Based on cache population only, no extra scanning
cveSummary, err := cveInfo.GetCVESummaryForImageMedia("zot-test", image.DigestStr(),
image.ManifestDescriptor.MediaType)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldBeGreaterThanOrEqualTo, 5)
// As of September 22 the max severity is MEDIUM, but new CVEs could appear in the future
So([]string{"MEDIUM", "HIGH", "CRITICAL"}, ShouldContain, cveSummary.MaxSeverity)
})
}