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>
This commit is contained in:
peusebiu
2023-11-24 10:40:10 +02:00
committed by GitHub
parent 92837c2bcb
commit 6222dae1f0
49 changed files with 710 additions and 379 deletions
+5 -1
View File
@@ -256,8 +256,12 @@ func (validityT *validityTask) DoWork(ctx context.Context) error {
validityT.log.Info().Msg("update signatures validity")
for signedManifest, sigs := range validityT.repo.Signatures {
if zcommon.IsContextDone(ctx) {
return ctx.Err()
}
if len(sigs[zcommon.CosignSignature]) != 0 || len(sigs[zcommon.NotationSignature]) != 0 {
err := validityT.metaDB.UpdateSignaturesValidity(validityT.repo.Name, godigest.Digest(signedManifest))
err := validityT.metaDB.UpdateSignaturesValidity(ctx, validityT.repo.Name, godigest.Digest(signedManifest))
if err != nil {
validityT.log.Info().Msg("error while verifying signatures")
@@ -1215,6 +1215,13 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
repo := "repo" //nolint:goconst
tag := "test" //nolint:goconst
Convey("verify running an image trust with context done", func() {
image := CreateRandomImage()
err = UploadImage(image, baseURL, repo, tag)
So(err, ShouldBeNil)
})
Convey("verify cosign signature is trusted", func() {
image := CreateRandomImage()
@@ -1291,6 +1298,18 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
So(err, ShouldBeNil)
So(isTrusted, ShouldBeTrue)
So(author, ShouldNotBeEmpty)
Convey("run imagetrust task with context done", func() {
repoMeta, err := ctlr.MetaDB.GetRepoMeta(context.Background(), repo)
So(err, ShouldBeNil)
cancelCtx, cancel := context.WithCancel(context.Background())
cancel()
task := imagetrust.NewValidityTask(ctlr.MetaDB, repoMeta, ctlr.Log)
err = task.DoWork(cancelCtx)
So(err, ShouldEqual, cancelCtx.Err())
})
})
Convey("verify notation signature is trusted", func() {
@@ -61,7 +61,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{}, ErrTestError
},
@@ -99,7 +99,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{
Count: 1,
@@ -126,7 +126,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{}, ErrTestError
},
@@ -149,7 +149,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{
Count: 1,
@@ -179,7 +179,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{
Count: 1,
@@ -207,7 +207,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{
Count: 1,
@@ -248,7 +248,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{
Count: 1,
@@ -271,7 +271,7 @@ func TestCVEConvert(t *testing.T) {
Vulnerabilities: false,
},
mocks.CveInfoMock{
GetCVESummaryForImageMediaFn: func(repo string, digest, mediaType string,
GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
return cvemodel.ImageCVESummary{}, ErrTestError
},
+2 -2
View File
@@ -47,7 +47,7 @@ func updateImageSummaryVulnerabilities(
return
}
imageCveSummary, err := cveInfo.GetCVESummaryForImageMedia(*imageSummary.RepoName, *imageSummary.Digest,
imageCveSummary, err := cveInfo.GetCVESummaryForImageMedia(ctx, *imageSummary.RepoName, *imageSummary.Digest,
*imageSummary.MediaType)
if err != nil {
// Log the error, but we should still include the image in results
@@ -91,7 +91,7 @@ func updateManifestSummaryVulnerabilities(
return
}
imageCveSummary, err := cveInfo.GetCVESummaryForImageMedia(repoName, *manifestSummary.Digest,
imageCveSummary, err := cveInfo.GetCVESummaryForImageMedia(ctx, repoName, *manifestSummary.Digest,
ispec.MediaTypeImageManifest)
if err != nil {
// Log the error, but we should still include the manifest in results
+31 -21
View File
@@ -19,20 +19,20 @@ import (
)
type CveInfo interface {
GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error)
GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error)
GetCVEListForImage(repo, tag string, searchedCVE string, pageinput cvemodel.PageInput,
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, pageinput cvemodel.PageInput,
) ([]cvemodel.CVE, zcommon.PageInfo, error)
GetCVESummaryForImageMedia(repo, digest, mediaType string) (cvemodel.ImageCVESummary, error)
GetCVESummaryForImageMedia(ctx context.Context, repo, digest, mediaType string) (cvemodel.ImageCVESummary, error)
}
type Scanner interface {
ScanImage(image string) (map[string]cvemodel.CVE, error)
ScanImage(ctx context.Context, image string) (map[string]cvemodel.CVE, error)
IsImageFormatScannable(repo, ref string) (bool, error)
IsImageMediaScannable(repo, digestStr, mediaType string) (bool, error)
IsResultCached(digestStr string) bool
GetCachedResult(digestStr string) map[string]cvemodel.CVE
UpdateDB() error
UpdateDB(ctx context.Context) error
}
type BaseCveInfo struct {
@@ -55,10 +55,10 @@ func NewCVEInfo(scanner Scanner, metaDB mTypes.MetaDB, log log.Logger) *BaseCveI
}
}
func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error) {
func (cveinfo BaseCveInfo) GetImageListForCVE(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) {
imgList := make([]cvemodel.TagInfo, 0)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(ctx, repo)
if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
Msg("unable to get list of tags from repo")
@@ -80,8 +80,12 @@ func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.Ta
continue
}
cveMap, err := cveinfo.Scanner.ScanImage(zcommon.GetFullImageName(repo, tag))
cveMap, err := cveinfo.Scanner.ScanImage(ctx, zcommon.GetFullImageName(repo, tag))
if err != nil {
if zcommon.IsContextDone(ctx) {
return imgList, err
}
cveinfo.Log.Info().Str("image", repo+":"+tag).Err(err).Msg("image scan failed")
continue
@@ -105,8 +109,9 @@ func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.Ta
return imgList, nil
}
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error) {
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(context.Background(), repo)
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(ctx context.Context, repo, cveID string,
) ([]cvemodel.TagInfo, error) {
repoMeta, err := cveinfo.MetaDB.GetRepoMeta(ctx, repo)
if err != nil {
cveinfo.Log.Error().Err(err).Str("repository", repo).Str("cve-id", cveID).
Msg("unable to get list of tags from repo")
@@ -118,6 +123,10 @@ func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemo
allTags := make([]cvemodel.TagInfo, 0)
for tag, descriptor := range repoMeta.Tags {
if zcommon.IsContextDone(ctx) {
return []cvemodel.TagInfo{}, ctx.Err()
}
switch descriptor.MediaType {
case ispec.MediaTypeImageManifest:
manifestDigestStr := descriptor.Digest
@@ -132,7 +141,7 @@ func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemo
allTags = append(allTags, tagInfo)
if cveinfo.isManifestVulnerable(repo, tag, manifestDigestStr, cveID) {
if cveinfo.isManifestVulnerable(ctx, repo, tag, manifestDigestStr, cveID) {
vulnerableTags = append(vulnerableTags, tagInfo)
}
case ispec.MediaTypeImageIndex:
@@ -162,7 +171,7 @@ func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemo
allManifests = append(allManifests, manifestDescriptorInfo)
if cveinfo.isManifestVulnerable(repo, tag, manifest.Digest.String(), cveID) {
if cveinfo.isManifestVulnerable(ctx, repo, tag, manifest.Digest.String(), cveID) {
vulnerableManifests = append(vulnerableManifests, manifestDescriptorInfo)
}
}
@@ -250,7 +259,8 @@ func getTagInfoForManifest(tag, manifestDigestStr string, metaDB mTypes.MetaDB)
}, nil
}
func (cveinfo *BaseCveInfo) isManifestVulnerable(repo, tag, manifestDigestStr, cveID string) bool {
func (cveinfo *BaseCveInfo) isManifestVulnerable(ctx context.Context, repo, tag, manifestDigestStr, cveID string,
) bool {
image := zcommon.GetFullImageName(repo, tag)
isValidImage, err := cveinfo.Scanner.IsImageMediaScannable(repo, manifestDigestStr, ispec.MediaTypeImageManifest)
@@ -261,7 +271,7 @@ func (cveinfo *BaseCveInfo) isManifestVulnerable(repo, tag, manifestDigestStr, c
return true
}
cveMap, err := cveinfo.Scanner.ScanImage(zcommon.GetFullImageName(repo, manifestDigestStr))
cveMap, err := cveinfo.Scanner.ScanImage(ctx, zcommon.GetFullImageName(repo, manifestDigestStr))
if err != nil {
cveinfo.Log.Debug().Str("image", image).Str("cve-id", cveID).
Msg("scanning failed, adding as a vulnerable image")
@@ -330,10 +340,10 @@ func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinde
}
}
func (cveinfo BaseCveInfo) GetCVEListForImage(repo, ref string, searchedCVE string, pageInput cvemodel.PageInput) (
[]cvemodel.CVE,
zcommon.PageInfo,
error,
func (cveinfo BaseCveInfo) GetCVEListForImage(ctx context.Context, repo, ref string, searchedCVE string,
pageInput cvemodel.PageInput,
) (
[]cvemodel.CVE, zcommon.PageInfo, error,
) {
isValidImage, err := cveinfo.Scanner.IsImageFormatScannable(repo, ref)
if !isValidImage {
@@ -344,7 +354,7 @@ func (cveinfo BaseCveInfo) GetCVEListForImage(repo, ref string, searchedCVE stri
image := zcommon.GetFullImageName(repo, ref)
cveMap, err := cveinfo.Scanner.ScanImage(image)
cveMap, err := cveinfo.Scanner.ScanImage(ctx, image)
if err != nil {
return []cvemodel.CVE{}, zcommon.PageInfo{}, err
}
@@ -361,7 +371,7 @@ func (cveinfo BaseCveInfo) GetCVEListForImage(repo, ref string, searchedCVE stri
return cveList, pageInfo, nil
}
func (cveinfo BaseCveInfo) GetCVESummaryForImageMedia(repo, digest, mediaType string,
func (cveinfo BaseCveInfo) GetCVESummaryForImageMedia(ctx context.Context, repo, digest, mediaType string,
) (cvemodel.ImageCVESummary, error) {
// There are several cases, expected returned values below:
// not scanned yet - max severity "" - cve count 0 - no Errors
+46 -44
View File
@@ -913,7 +913,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
// 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) {
ScanImageFn: func(ctx context.Context, 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 {
@@ -1127,15 +1127,17 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
SortBy: cveinfo.SeverityDsc,
}
ctx := context.Background()
// Image is found
cveList, pageInfo, err := cveInfo.GetCVEListForImage(repo1, "0.1.0", "", pageInput)
cveList, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE1")
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 1)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo1, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.0", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 3)
So(cveList[0].ID, ShouldEqual, "CVE2")
@@ -1144,7 +1146,7 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, ShouldEqual, 3)
So(pageInfo.TotalCount, ShouldEqual, 3)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo1, "1.0.1", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.0.1", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 2)
So(cveList[0].ID, ShouldEqual, "CVE1")
@@ -1152,21 +1154,21 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.ItemCount, ShouldEqual, 2)
So(pageInfo.TotalCount, ShouldEqual, 2)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo1, "1.1.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "1.1.0", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE3")
So(pageInfo.ItemCount, ShouldEqual, 1)
So(pageInfo.TotalCount, ShouldEqual, 1)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo6, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo6, "1.0.0", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Image is multiarch
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repoMultiarch, "tagIndex", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repoMultiarch, "tagIndex", "", pageInput)
So(err, ShouldBeNil)
So(len(cveList), ShouldEqual, 1)
So(cveList[0].ID, ShouldEqual, "CVE1")
@@ -1174,35 +1176,35 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(pageInfo.TotalCount, ShouldEqual, 1)
// Image is not scannable
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo2, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo2, "1.0.0", "", pageInput)
So(err, ShouldEqual, zerr.ErrScanNotSupported)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Tag is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo3, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo3, "1.0.0", "", pageInput)
So(err, ShouldEqual, zerr.ErrTagMetaNotFound)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Scan failed
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo7, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo7, "1.0.0", "", pageInput)
So(err, ShouldEqual, ErrFailedScan)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Tag is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage("repo-with-bad-tag-digest", "tag", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo-with-bad-tag-digest", "tag", "", pageInput)
So(err, ShouldEqual, zerr.ErrImageMetaNotFound)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
// Repo is not found
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo100, "1.0.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo100, "1.0.0", "", pageInput)
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
So(len(cveList), ShouldEqual, 0)
So(pageInfo.ItemCount, ShouldEqual, 0)
@@ -1212,51 +1214,51 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
t.Log("\nTest GetCVESummaryForImage\n")
// Image is found
cveSummary, err := cveInfo.GetCVESummaryForImageMedia(repo1, image11Digest, image11Media)
cveSummary, err := cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image11Digest, image11Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo1, image12Digest, image12Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image12Digest, image12Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 3)
So(cveSummary.MaxSeverity, ShouldEqual, "HIGH")
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo1, image14Digest, image14Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image14Digest, image14Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 2)
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo1, image13Digest, image13Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image13Digest, image13Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "LOW")
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo6, image61Digest, image61Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo6, image61Digest, image61Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "NONE")
// Image is multiarch
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repoMultiarch, indexDigest, indexMedia)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repoMultiarch, indexDigest, indexMedia)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 1)
So(cveSummary.MaxSeverity, ShouldEqual, "MEDIUM")
// Image is not scannable
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo2, image21Digest, image21Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo2, image21Digest, image21Media)
So(err, ShouldEqual, zerr.ErrScanNotSupported)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "")
// Scan failed
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo5, image71Digest, image71Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo5, image71Digest, image71Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "")
// Repo is not found
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo100,
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo100,
godigest.FromString("missing_digest").String(), ispec.MediaTypeImageManifest)
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
So(cveSummary.Count, ShouldEqual, 0)
@@ -1265,19 +1267,19 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
t.Log("\nTest GetImageListWithCVEFixed\n")
// Image is found
tagList, err := cveInfo.GetImageListWithCVEFixed(repo1, "CVE1")
tagList, err := cveInfo.GetImageListWithCVEFixed(ctx, repo1, "CVE1")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 1)
So(tagList[0].Tag, ShouldEqual, "1.1.0")
tagList, err = cveInfo.GetImageListWithCVEFixed(repo1, "CVE2")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo1, "CVE2")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 2)
expectedTags := []string{"1.0.1", "1.1.0"}
So(expectedTags, ShouldContain, tagList[0].Tag)
So(expectedTags, ShouldContain, tagList[1].Tag)
tagList, err = cveInfo.GetImageListWithCVEFixed(repo1, "CVE3")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo1, "CVE3")
So(err, ShouldBeNil)
// CVE3 is not present in 0.1.0, but that is older than all other
// images where it is present. The rest of the images explicitly have it.
@@ -1285,13 +1287,13 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(len(tagList), ShouldEqual, 0)
// Image doesn't have any CVEs in the first place
tagList, err = cveInfo.GetImageListWithCVEFixed(repo6, "CVE1")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo6, "CVE1")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 1)
So(tagList[0].Tag, ShouldEqual, "1.0.0")
// Image is not scannable
tagList, err = cveInfo.GetImageListWithCVEFixed(repo2, "CVE100")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo2, "CVE100")
// CVE is not considered fixed as scan is not possible
// but do not return an error
So(err, ShouldBeNil)
@@ -1299,14 +1301,14 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
// Repo is not found, there could potentially be unaffected tags in the repo
// but we can't access their data
tagList, err = cveInfo.GetImageListWithCVEFixed(repo100, "CVE100")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo100, "CVE100")
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
So(len(tagList), ShouldEqual, 0)
t.Log("\nTest GetImageListForCVE\n")
// Image is found
tagList, err = cveInfo.GetImageListForCVE(repo1, "CVE1")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo1, "CVE1")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 3)
expectedTags = []string{"0.1.0", "1.0.0", "1.0.1"}
@@ -1314,12 +1316,12 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(expectedTags, ShouldContain, tagList[1].Tag)
So(expectedTags, ShouldContain, tagList[2].Tag)
tagList, err = cveInfo.GetImageListForCVE(repo1, "CVE2")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo1, "CVE2")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 1)
So(tagList[0].Tag, ShouldEqual, "1.0.0")
tagList, err = cveInfo.GetImageListForCVE(repo1, "CVE3")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo1, "CVE3")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 3)
expectedTags = []string{"1.0.0", "1.0.1", "1.1.0"}
@@ -1328,32 +1330,32 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
So(expectedTags, ShouldContain, tagList[2].Tag)
// Image/repo doesn't have the CVE at all
tagList, err = cveInfo.GetImageListForCVE(repo6, "CVE1")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo6, "CVE1")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
// Image is not scannable
tagList, err = cveInfo.GetImageListForCVE(repo2, "CVE100")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo2, "CVE100")
// Image is not considered affected with CVE as scan is not possible
// but do not return an error
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
// Tag is not found, but we should not error
tagList, err = cveInfo.GetImageListForCVE(repo3, "CVE101")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo3, "CVE101")
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
// Repo is not found, assume it is affected by the CVE
// But we don't have enough of its data to actually return it
tagList, err = cveInfo.GetImageListForCVE(repo100, "CVE100")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo100, "CVE100")
So(err, ShouldEqual, zerr.ErrRepoMetaNotFound)
So(len(tagList), ShouldEqual, 0)
t.Log("\nTest errors while scanning\n")
faultyScanner := mocks.CveScannerMock{
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
// Could be any type of error, let's reuse this one
return nil, zerr.ErrScanNotSupported
},
@@ -1361,24 +1363,24 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
cveInfo = cveinfo.BaseCveInfo{Log: log, Scanner: faultyScanner, MetaDB: metaDB}
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(repo1, image11Digest, image11Media)
cveSummary, err = cveInfo.GetCVESummaryForImageMedia(ctx, repo1, image11Digest, image11Media)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldEqual, 0)
So(cveSummary.MaxSeverity, ShouldEqual, "")
cveList, pageInfo, err = cveInfo.GetCVEListForImage(repo1, "0.1.0", "", pageInput)
cveList, pageInfo, err = cveInfo.GetCVEListForImage(ctx, repo1, "0.1.0", "", pageInput)
So(err, ShouldNotBeNil)
So(cveList, ShouldBeEmpty)
So(pageInfo.ItemCount, ShouldEqual, 0)
So(pageInfo.TotalCount, ShouldEqual, 0)
tagList, err = cveInfo.GetImageListWithCVEFixed(repo1, "CVE1")
tagList, err = cveInfo.GetImageListWithCVEFixed(ctx, repo1, "CVE1")
// CVE is not considered fixed as scan is not possible
// but do not return an error
So(err, ShouldBeNil)
So(len(tagList), ShouldEqual, 0)
tagList, err = cveInfo.GetImageListForCVE(repo1, "CVE1")
tagList, err = cveInfo.GetImageListForCVE(ctx, repo1, "CVE1")
// Image is not considered affected with CVE as scan is not possible
// but do not return an error
So(err, ShouldBeNil)
@@ -1390,19 +1392,19 @@ func TestCVEStruct(t *testing.T) { //nolint:gocyclo
},
}, MetaDB: metaDB}
_, err = cveInfo.GetImageListForCVE(repoMultiarch, "CVE1")
_, 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(image string) (map[string]cvemodel.CVE, error) {
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
return nil, zerr.ErrTypeAssertionFailed
},
}, MetaDB: metaDB}
_, err = cveInfo.GetImageListForCVE(repoMultiarch, "CVE1")
_, err = cveInfo.GetImageListForCVE(ctx, repoMultiarch, "CVE1")
So(err, ShouldBeNil)
})
}
@@ -1545,7 +1547,7 @@ func TestFixedTagsWithIndex(t *testing.T) {
cveInfo := cveinfo.NewCVEInfo(ctlr.CveScanner, ctlr.MetaDB, ctlr.Log)
tagsInfo, err := cveInfo.GetImageListWithCVEFixed("repo", Vulnerability1ID)
tagsInfo, err := cveInfo.GetImageListWithCVEFixed(context.Background(), "repo", Vulnerability1ID)
So(err, ShouldBeNil)
So(len(tagsInfo), ShouldEqual, 1)
So(len(tagsInfo[0].Manifests), ShouldEqual, 1)
@@ -1593,7 +1595,7 @@ func TestGetCVESummaryForImageMediaErrors(t *testing.T) {
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, log)
_, err := cveInfo.GetCVESummaryForImageMedia("repo", "digest", ispec.MediaTypeImageManifest)
_, err := cveInfo.GetCVESummaryForImageMedia(context.Background(), "repo", "digest", ispec.MediaTypeImageManifest)
So(err, ShouldNotBeNil)
})
})
+16 -14
View File
@@ -73,7 +73,7 @@ func TestCVEPagination(t *testing.T) {
// Setup test CVE data in mock scanner
scanner := mocks.CveScannerMock{
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
cveMap := map[string]cvemodel.CVE{}
if image == "repo1:0.1.0" {
@@ -106,6 +106,8 @@ func TestCVEPagination(t *testing.T) {
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)
@@ -138,7 +140,7 @@ func TestCVEPagination(t *testing.T) {
Convey("Page", func() {
Convey("defaults", func() {
// By default expect unlimitted results sorted by severity
cves, pageInfo, err := cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{})
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)
@@ -149,7 +151,7 @@ func TestCVEPagination(t *testing.T) {
previousSeverity = severityToInt[cve.Severity]
}
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "1.0.0", "", cvemodel.PageInput{})
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)
@@ -167,7 +169,7 @@ func TestCVEPagination(t *testing.T) {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
}
cves, pageInfo, err := cveInfo.GetCVEListForImage("repo1", "0.1.0", "",
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 5)
@@ -178,7 +180,7 @@ func TestCVEPagination(t *testing.T) {
}
sort.Strings(cveIds)
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "1.0.0", "",
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticAsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
@@ -189,7 +191,7 @@ func TestCVEPagination(t *testing.T) {
}
sort.Sort(sort.Reverse(sort.StringSlice(cveIds)))
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "1.0.0", "",
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.AlphabeticDsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
@@ -199,7 +201,7 @@ func TestCVEPagination(t *testing.T) {
So(cve.ID, ShouldEqual, cveIds[i])
}
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "1.0.0", "",
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "",
cvemodel.PageInput{SortBy: cveinfo.SeverityDsc})
So(err, ShouldBeNil)
So(len(cves), ShouldEqual, 30)
@@ -218,7 +220,7 @@ func TestCVEPagination(t *testing.T) {
cveIds = append(cveIds, fmt.Sprintf("CVE%d", i))
}
cves, pageInfo, err := cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 3,
Offset: 1,
SortBy: cveinfo.AlphabeticAsc,
@@ -232,7 +234,7 @@ func TestCVEPagination(t *testing.T) {
So(cves[1].ID, ShouldEqual, "CVE2")
So(cves[2].ID, ShouldEqual, "CVE3")
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 2,
Offset: 1,
SortBy: cveinfo.AlphabeticDsc,
@@ -245,7 +247,7 @@ func TestCVEPagination(t *testing.T) {
So(cves[0].ID, ShouldEqual, "CVE3")
So(cves[1].ID, ShouldEqual, "CVE2")
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 3,
Offset: 1,
SortBy: cveinfo.SeverityDsc,
@@ -262,7 +264,7 @@ func TestCVEPagination(t *testing.T) {
}
sort.Strings(cveIds)
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "1.0.0", "", cvemodel.PageInput{
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "1.0.0", "", cvemodel.PageInput{
Limit: 5,
Offset: 20,
SortBy: cveinfo.AlphabeticAsc,
@@ -278,7 +280,7 @@ func TestCVEPagination(t *testing.T) {
})
Convey("limit > len(cves)", func() {
cves, pageInfo, err := cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err := cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.AlphabeticAsc,
@@ -291,7 +293,7 @@ func TestCVEPagination(t *testing.T) {
So(cves[0].ID, ShouldEqual, "CVE3")
So(cves[1].ID, ShouldEqual, "CVE4")
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.AlphabeticDsc,
@@ -304,7 +306,7 @@ func TestCVEPagination(t *testing.T) {
So(cves[0].ID, ShouldEqual, "CVE1")
So(cves[1].ID, ShouldEqual, "CVE0")
cves, pageInfo, err = cveInfo.GetCVEListForImage("repo1", "0.1.0", "", cvemodel.PageInput{
cves, pageInfo, err = cveInfo.GetCVEListForImage(ctx, "repo1", "0.1.0", "", cvemodel.PageInput{
Limit: 6,
Offset: 3,
SortBy: cveinfo.SeverityDsc,
+1 -1
View File
@@ -183,7 +183,7 @@ func (st *scanTask) DoWork(ctx context.Context) error {
// We cache the results internally in the scanner
// so we can discard the actual results for now
if _, err := st.generator.scanner.ScanImage(image); err != nil {
if _, err := st.generator.scanner.ScanImage(ctx, image); err != nil {
st.generator.log.Error().Err(err).Str("image", image).Msg("Scheduled CVE scan errored for image")
st.generator.addError(st.digest, err)
+6 -6
View File
@@ -216,7 +216,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
// 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) {
ScanImageFn: func(ctx context.Context, 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 {
@@ -408,7 +408,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
IsResultCachedFn: func(digest string) bool {
return cache.Contains(digest)
},
UpdateDBFn: func() error {
UpdateDBFn: func(ctx context.Context) error {
cache.Purge()
return nil
@@ -416,7 +416,7 @@ func TestScanGeneratorWithMockedData(t *testing.T) { //nolint: gocyclo
}
// Purge scan, it should not be needed
So(scanner.UpdateDB(), ShouldBeNil)
So(scanner.UpdateDB(context.Background()), ShouldBeNil)
// Verify none of the entries are cached to begin with
t.Log("verify cache is initially empty")
@@ -515,7 +515,7 @@ func TestScanGeneratorWithRealData(t *testing.T) {
So(err, ShouldBeNil)
scanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", logger)
err = scanner.UpdateDB()
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
So(scanner.IsResultCached(image.DigestStr()), ShouldBeFalse)
@@ -551,7 +551,7 @@ func TestScanGeneratorWithRealData(t *testing.T) {
So(scanner.IsResultCached(image.DigestStr()), ShouldBeTrue)
cveMap, err := scanner.ScanImage("zot-test:0.0.1")
cveMap, err := scanner.ScanImage(context.Background(), "zot-test:0.0.1")
So(err, ShouldBeNil)
t.Logf("cveMap: %v", cveMap)
// As of September 22 2023 there are 5 CVEs:
@@ -567,7 +567,7 @@ func TestScanGeneratorWithRealData(t *testing.T) {
cveInfo := cveinfo.NewCVEInfo(scanner, metaDB, logger)
// Based on cache population only, no extra scanning
cveSummary, err := cveInfo.GetCVESummaryForImageMedia("zot-test", image.DigestStr(),
cveSummary, err := cveInfo.GetCVESummaryForImageMedia(context.Background(), "zot-test", image.DigestStr(),
image.ManifestDescriptor.MediaType)
So(err, ShouldBeNil)
So(cveSummary.Count, ShouldBeGreaterThanOrEqualTo, 5)
+16 -20
View File
@@ -157,9 +157,7 @@ func (scanner Scanner) getTrivyOptions(image string) flag.Options {
return opts
}
func (scanner Scanner) runTrivy(opts flag.Options) (types.Report, error) {
ctx := context.Background()
func (scanner Scanner) runTrivy(ctx context.Context, opts flag.Options) (types.Report, error) {
err := scanner.checkDBPresence()
if err != nil {
return types.Report{}, err
@@ -191,7 +189,7 @@ func (scanner Scanner) IsImageFormatScannable(repo, ref string) (bool, error) {
)
if zcommon.IsTag(ref) {
imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
imgDescriptor, err := getImageDescriptor(context.Background(), scanner.metaDB, repo, ref)
if err != nil {
return false, err
}
@@ -316,7 +314,7 @@ func (scanner Scanner) GetCachedResult(digest string) map[string]cvemodel.CVE {
return scanner.cache.Get(digest)
}
func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error) {
func (scanner Scanner) ScanImage(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
var (
originalImageInput = image
digest string
@@ -328,7 +326,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
digest = ref
if isTag {
imgDescriptor, err := getImageDescriptor(scanner.metaDB, repo, ref)
imgDescriptor, err := getImageDescriptor(ctx, scanner.metaDB, repo, ref)
if err != nil {
return map[string]cvemodel.CVE{}, err
}
@@ -351,9 +349,9 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
switch mediaType {
case ispec.MediaTypeImageIndex:
cveIDMap, err = scanner.scanIndex(repo, digest)
cveIDMap, err = scanner.scanIndex(ctx, repo, digest)
default:
cveIDMap, err = scanner.scanManifest(repo, digest)
cveIDMap, err = scanner.scanManifest(ctx, repo, digest)
}
if err != nil {
@@ -365,7 +363,7 @@ func (scanner Scanner) ScanImage(image string) (map[string]cvemodel.CVE, error)
return cveIDMap, nil
}
func (scanner Scanner) scanManifest(repo, digest string) (map[string]cvemodel.CVE, error) {
func (scanner Scanner) scanManifest(ctx context.Context, repo, digest string) (map[string]cvemodel.CVE, error) {
if cachedMap := scanner.cache.Get(digest); cachedMap != nil {
return cachedMap, nil
}
@@ -375,7 +373,7 @@ func (scanner Scanner) scanManifest(repo, digest string) (map[string]cvemodel.CV
scanner.dbLock.Lock()
opts := scanner.getTrivyOptions(image)
report, err := scanner.runTrivy(opts)
report, err := scanner.runTrivy(ctx, opts)
scanner.dbLock.Unlock()
if err != nil { //nolint: wsl
@@ -441,7 +439,7 @@ func (scanner Scanner) scanManifest(repo, digest string) (map[string]cvemodel.CV
return cveidMap, nil
}
func (scanner Scanner) scanIndex(repo, digest string) (map[string]cvemodel.CVE, error) {
func (scanner Scanner) scanIndex(ctx context.Context, repo, digest string) (map[string]cvemodel.CVE, error) {
if cachedMap := scanner.cache.Get(digest); cachedMap != nil {
return cachedMap, nil
}
@@ -459,7 +457,7 @@ func (scanner Scanner) scanIndex(repo, digest string) (map[string]cvemodel.CVE,
for _, manifest := range indexData.Index.Manifests {
if isScannable, err := scanner.isManifestScanable(manifest.Digest.String()); isScannable && err == nil {
manifestCveIDMap, err := scanner.scanManifest(repo, manifest.Digest.String())
manifestCveIDMap, err := scanner.scanManifest(ctx, repo, manifest.Digest.String())
if err != nil {
return nil, err
}
@@ -476,7 +474,7 @@ func (scanner Scanner) scanIndex(repo, digest string) (map[string]cvemodel.CVE,
}
// UpdateDB downloads the Trivy DB / Cache under the store root directory.
func (scanner Scanner) UpdateDB() error {
func (scanner Scanner) UpdateDB(ctx context.Context) error {
// We need a lock as using multiple substores each with its own DB
// can result in a DATARACE because some varibles in trivy-db are global
// https://github.com/project-zot/trivy-db/blob/main/pkg/db/db.go#L23
@@ -486,7 +484,7 @@ func (scanner Scanner) UpdateDB() error {
if scanner.storeController.DefaultStore != nil {
dbDir := path.Join(scanner.storeController.DefaultStore.RootDir(), "_trivy")
err := scanner.updateDB(dbDir)
err := scanner.updateDB(ctx, dbDir)
if err != nil {
return err
}
@@ -496,7 +494,7 @@ func (scanner Scanner) UpdateDB() error {
for _, storage := range scanner.storeController.SubStore {
dbDir := path.Join(storage.RootDir(), "_trivy")
err := scanner.updateDB(dbDir)
err := scanner.updateDB(ctx, dbDir)
if err != nil {
return err
}
@@ -508,11 +506,9 @@ func (scanner Scanner) UpdateDB() error {
return nil
}
func (scanner Scanner) updateDB(dbDir string) error {
func (scanner Scanner) updateDB(ctx context.Context, dbDir string) error {
scanner.log.Debug().Str("dbDir", dbDir).Msg("Download Trivy DB to destination dir")
ctx := context.Background()
registryOpts := fanalTypes.RegistryOptions{Insecure: false}
scanner.log.Debug().Str("dbDir", dbDir).Msg("Started downloading Trivy DB to destination dir")
@@ -569,8 +565,8 @@ func (scanner Scanner) checkDBPresence() error {
return nil
}
func getImageDescriptor(metaDB mTypes.MetaDB, repo, tag string) (mTypes.Descriptor, error) {
repoMeta, err := metaDB.GetRepoMeta(context.Background(), repo)
func getImageDescriptor(ctx context.Context, metaDB mTypes.MetaDB, repo, tag string) (mTypes.Descriptor, error) {
repoMeta, err := metaDB.GetRepoMeta(ctx, repo)
if err != nil {
return mTypes.Descriptor{}, err
}
@@ -128,46 +128,56 @@ func TestMultipleStoragePath(t *testing.T) {
So(err, ShouldBeNil)
// Try to scan without the DB being downloaded
_, err = scanner.ScanImage(img0)
_, err = scanner.ScanImage(context.Background(), img0)
So(err, ShouldNotBeNil)
So(err, ShouldWrap, zerr.ErrCVEDBNotFound)
// Try to scan with a context done
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err = scanner.ScanImage(ctx, img0)
So(err, ShouldNotBeNil)
ctx = context.Background()
// Download DB since DB download on scan is disabled
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldBeNil)
// Scanning image in default store
cveMap, err := scanner.ScanImage(img0)
cveMap, err := scanner.ScanImage(ctx, img0)
So(err, ShouldBeNil)
So(len(cveMap), ShouldEqual, 0)
// Scanning image in substore
cveMap, err = scanner.ScanImage(img1)
cveMap, err = scanner.ScanImage(ctx, img1)
So(err, ShouldBeNil)
So(len(cveMap), ShouldEqual, 0)
// Scanning image which does not exist
cveMap, err = scanner.ScanImage("a/test/image2:tag100")
cveMap, err = scanner.ScanImage(ctx, "a/test/image2:tag100")
So(err, ShouldNotBeNil)
So(len(cveMap), ShouldEqual, 0)
// Download the DB to a default store location without permissions
err = os.Chmod(firstRootDir, 0o000)
So(err, ShouldBeNil)
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldNotBeNil)
// Check the download works correctly when permissions allow
err = os.Chmod(firstRootDir, 0o777)
So(err, ShouldBeNil)
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldBeNil)
// Download the DB to a substore location without permissions
err = os.Chmod(secondRootDir, 0o000)
So(err, ShouldBeNil)
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldNotBeNil)
err = os.Chmod(secondRootDir, 0o777)
@@ -210,12 +220,14 @@ func TestTrivyLibraryErrors(t *testing.T) {
// Download DB fails for missing DB url
scanner := NewScanner(storeController, metaDB, "", "", log)
err = scanner.UpdateDB()
ctx := context.Background()
err = scanner.UpdateDB(ctx)
So(err, ShouldNotBeNil)
// Try to scan without the DB being downloaded
opts := scanner.getTrivyOptions(img)
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldNotBeNil)
So(err, ShouldWrap, zerr.ErrCVEDBNotFound)
@@ -223,37 +235,38 @@ func TestTrivyLibraryErrors(t *testing.T) {
scanner = NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db",
"ghcr.io/project-zot/trivy-not-db", log)
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldNotBeNil)
// Download DB passes for valid Trivy DB url, and missing Trivy Java DB url
// Download DB is necessary since DB download on scan is disabled
scanner = NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
err = scanner.UpdateDB()
// UpdateDB with good ctx
err = scanner.UpdateDB(ctx)
So(err, ShouldBeNil)
// Scanning image with correct options
opts = scanner.getTrivyOptions(img)
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldBeNil)
// Scanning image with incorrect cache options
// to trigger runner initialization errors
opts.CacheOptions.CacheBackend = "redis://asdf!$%&!*)("
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldNotBeNil)
// Scanning image with invalid input to trigger a scanner error
opts = scanner.getTrivyOptions("nilnonexisting_image:0.0.1")
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldNotBeNil)
// Scanning image with incorrect report options
// to trigger report filtering errors
opts = scanner.getTrivyOptions(img)
opts.ReportOptions.IgnorePolicy = "invalid file path"
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldNotBeNil)
})
}
@@ -397,22 +410,31 @@ func TestDefaultTrivyDBUrl(t *testing.T) {
scanner := NewScanner(storeController, metaDB, "ghcr.io/aquasecurity/trivy-db",
"ghcr.io/aquasecurity/trivy-java-db", log)
ctx := context.Background()
cancelCtx, cancel := context.WithCancel(ctx)
cancel()
// Download DB with context done should return ctx error.
err = scanner.UpdateDB(cancelCtx)
So(err, ShouldNotBeNil)
// Download DB since DB download on scan is disabled
err = scanner.UpdateDB()
err = scanner.UpdateDB(ctx)
So(err, ShouldBeNil)
// Scanning image
img := "zot-test:0.0.1" //nolint:goconst
opts := scanner.getTrivyOptions(img)
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldBeNil)
// Scanning image containing a jar file
img = "zot-cve-java-test:0.0.1"
opts = scanner.getTrivyOptions(img)
_, err = scanner.runTrivy(opts)
_, err = scanner.runTrivy(ctx, opts)
So(err, ShouldBeNil)
})
}
+13 -10
View File
@@ -3,6 +3,7 @@
package trivy_test
import (
"context"
"errors"
"path/filepath"
"testing"
@@ -61,10 +62,10 @@ func TestScanBigTestFile(t *testing.T) {
// scan
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, "ghcr.io/project-zot/trivy-db", "", ctlr.Log)
err = scanner.UpdateDB()
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
cveMap, err := scanner.ScanImage("zot-test:0.0.1")
cveMap, err := scanner.ScanImage(context.Background(), "zot-test:0.0.1")
So(err, ShouldBeNil)
So(cveMap, ShouldNotBeNil)
})
@@ -105,26 +106,28 @@ func TestScanningByDigest(t *testing.T) {
// scan
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, "ghcr.io/project-zot/trivy-db", "", ctlr.Log)
err = scanner.UpdateDB()
ctx := context.Background()
err = scanner.UpdateDB(ctx)
So(err, ShouldBeNil)
cveMap, err := scanner.ScanImage("multi-arch@" + vulnImage.DigestStr())
cveMap, err := scanner.ScanImage(ctx, "multi-arch@"+vulnImage.DigestStr())
So(err, ShouldBeNil)
So(cveMap, ShouldContainKey, Vulnerability1ID)
So(cveMap, ShouldContainKey, Vulnerability2ID)
So(cveMap, ShouldContainKey, Vulnerability3ID)
cveMap, err = scanner.ScanImage("multi-arch@" + simpleImage.DigestStr())
cveMap, err = scanner.ScanImage(ctx, "multi-arch@"+simpleImage.DigestStr())
So(err, ShouldBeNil)
So(cveMap, ShouldBeEmpty)
cveMap, err = scanner.ScanImage("multi-arch@" + multiArch.DigestStr())
cveMap, err = scanner.ScanImage(ctx, "multi-arch@"+multiArch.DigestStr())
So(err, ShouldBeNil)
So(cveMap, ShouldContainKey, Vulnerability1ID)
So(cveMap, ShouldContainKey, Vulnerability2ID)
So(cveMap, ShouldContainKey, Vulnerability3ID)
cveMap, err = scanner.ScanImage("multi-arch:multi-arch-tag")
cveMap, err = scanner.ScanImage(ctx, "multi-arch:multi-arch-tag")
So(err, ShouldBeNil)
So(cveMap, ShouldContainKey, Vulnerability1ID)
So(cveMap, ShouldContainKey, Vulnerability2ID)
@@ -188,10 +191,10 @@ func TestVulnerableLayer(t *testing.T) {
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
err = scanner.UpdateDB()
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
cveMap, err := scanner.ScanImage("repo@" + img.DigestStr())
cveMap, err := scanner.ScanImage(context.Background(), "repo@"+img.DigestStr())
So(err, ShouldBeNil)
t.Logf("cveMap: %v", cveMap)
// As of September 17 2023 there are 5 CVEs:
@@ -271,7 +274,7 @@ func TestScannerErrors(t *testing.T) {
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
_, err := scanner.ScanImage("image@" + godigest.FromString("digest").String())
_, err := scanner.ScanImage(context.Background(), "image@"+godigest.FromString("digest").String())
So(err, ShouldNotBeNil)
})
})
+1 -1
View File
@@ -94,7 +94,7 @@ func newDBUpdadeTask(interval time.Duration, scanner Scanner,
func (dbt *dbUpdateTask) DoWork(ctx context.Context) error {
dbt.log.Info().Msg("updating the CVE database")
err := dbt.scanner.UpdateDB()
err := dbt.scanner.UpdateDB(ctx)
if err != nil {
dbt.generator.lock.Lock()
dbt.generator.status = pending
+3 -3
View File
@@ -211,7 +211,7 @@ func getCVEListForImage(
return &gql_generated.CVEResultForImage{}, gqlerror.Errorf("no reference provided")
}
cveList, pageInfo, err := cveInfo.GetCVEListForImage(repo, ref, searchedCVE, pageInput)
cveList, pageInfo, err := cveInfo.GetCVEListForImage(ctx, repo, ref, searchedCVE, pageInput)
if err != nil {
return &gql_generated.CVEResultForImage{}, err
}
@@ -334,7 +334,7 @@ func getImageListForCVE(
log.Info().Str("repository", repo).Str("CVE", cveID).Msg("extracting list of tags affected by CVE")
tagsInfo, err := cveInfo.GetImageListForCVE(repo, cveID)
tagsInfo, err := cveInfo.GetImageListForCVE(ctx, repo, cveID)
if err != nil {
log.Error().Str("repository", repo).Str("CVE", cveID).Err(err).
Msg("error getting image list for CVE from repo")
@@ -407,7 +407,7 @@ func getImageListWithCVEFixed(
log.Info().Str("repository", repo).Str("CVE", cveID).Msg("extracting list of tags where CVE is fixed")
tagsInfo, err := cveInfo.GetImageListWithCVEFixed(repo, cveID)
tagsInfo, err := cveInfo.GetImageListWithCVEFixed(ctx, repo, cveID)
if err != nil {
log.Error().Str("repository", repo).Str("CVE", cveID).Err(err).
Msg("error getting image list with CVE fixed from repo")
+40 -3
View File
@@ -1046,14 +1046,14 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
// 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) {
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
repo, ref, _, _ := common.GetRepoReference(image)
if common.IsDigest(ref) {
return getCveResults(ref), nil
}
repoMeta, _ := metaDB.GetRepoMeta(context.Background(), repo)
repoMeta, _ := metaDB.GetRepoMeta(ctx, repo)
if _, ok := repoMeta.Tags[ref]; !ok {
panic("unexpected tag '" + ref + "', test might be wrong")
@@ -1239,6 +1239,32 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
So(err, ShouldNotBeNil)
})
Convey("context done", func() {
pageInput := getPageInput(1, 0)
ctx, cancel := context.WithCancel(ctx)
cancel()
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover)
canceledScanner := scanner
canceledScanner.ScanImageFn = func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
return nil, ctx.Err()
}
cveInfo.Scanner = canceledScanner
defer func() {
cveInfo.Scanner = scanner
}()
_, err = getImageListForCVE(responseContext, "repo1:1.1.0", cveInfo, &gql_generated.Filter{},
pageInput, metaDB, log)
So(err, ShouldEqual, ctx.Err())
})
Convey("Paginated requests", func() {
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover,
@@ -1506,6 +1532,17 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
So(err, ShouldNotBeNil)
})
Convey("context done", func() {
ctx, cancel := context.WithCancel(ctx)
cancel()
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover)
_, err := getImageListWithCVEFixed(responseContext, "CVE1", "repo1", cveInfo, nil, nil, metaDB, log)
So(err, ShouldNotBeNil)
})
Convey("Paginated requests", func() {
responseContext := graphql.WithResponseContext(ctx, graphql.DefaultErrorPresenter,
graphql.DefaultRecover,
@@ -1685,7 +1722,7 @@ func TestCVEResolvers(t *testing.T) { //nolint:gocyclo
ctx,
"id",
mocks.CveInfoMock{
GetImageListForCVEFn: func(repo, cveID string) ([]cvemodel.TagInfo, error) {
GetImageListForCVEFn: func(ctx context.Context, repo, cveID string) ([]cvemodel.TagInfo, error) {
return []cvemodel.TagInfo{}, ErrTestError
},
},
+1 -1
View File
@@ -292,7 +292,7 @@ func getMockCveScanner(metaDB mTypes.MetaDB) cveinfo.Scanner {
}
scanner := mocks.CveScannerMock{
ScanImageFn: func(image string) (map[string]cvemodel.CVE, error) {
ScanImageFn: func(ctx context.Context, image string) (map[string]cvemodel.CVE, error) {
return getCveResults(image), nil
},
GetCachedResultFn: func(digestStr string) map[string]cvemodel.CVE {
+1 -3
View File
@@ -292,10 +292,8 @@ func (service *BaseService) SyncRepo(ctx context.Context, repo string) error {
localRepo := service.contentManager.GetRepoDestination(repo)
for _, tag := range tags {
select {
case <-ctx.Done():
if common.IsContextDone(ctx) {
return ctx.Err()
default:
}
if references.IsCosignTag(tag) || common.IsReferrersTag(tag) {
+4 -3
View File
@@ -1883,9 +1883,6 @@ func TestConfigReloader(t *testing.T) {
destConfig.Log.Output = logFile.Name()
dctlr := api.NewController(destConfig)
dcm := test.NewControllerManager(dctlr)
defer dcm.StopServer()
//nolint: dupl
Convey("Reload config without sync", func() {
@@ -1927,6 +1924,8 @@ func TestConfigReloader(t *testing.T) {
time.Sleep(100 * time.Millisecond)
}
defer dctlr.Shutdown()
// let it sync
time.Sleep(3 * time.Second)
@@ -2075,6 +2074,8 @@ func TestConfigReloader(t *testing.T) {
time.Sleep(100 * time.Millisecond)
}
defer dctlr.Shutdown()
// let it sync
time.Sleep(3 * time.Second)