feat: Add TrivyConfig.VulnSeveritySources (Trivy's --vuln-severity-source) (#3943)

And default it to ["auto"] when unset, with an info log from applyDefaultValues.

Refactor CVE NewScanner to take *CVEConfig instead of separate DB repository
strings so the full Trivy block is available to the scanner.

Extend CLI and search tests for the new field and logged config; document
CVE/Trivy in examples/README and add examples/config-cve-trivy.json.

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2026-04-08 09:39:26 +03:00
committed by GitHub
parent c6289ec5ba
commit 451e7b8e47
15 changed files with 285 additions and 37 deletions
+16
View File
@@ -32,6 +32,7 @@ Examples of working configurations for various use cases are available [here](..
- [Storage Drivers](#storage-drivers)
- [Specifying S3 credentials](#specifying-s3-credentials)
- [Sync](#sync)
- [Search and CVE scanning (Trivy)](#search-and-cve-scanning-trivy)
## Network
@@ -1164,3 +1165,18 @@ sync can also read the certificates directly under certDir:
### Sync's credentials
Besides sync-auth.json file, zot also reads and uses docker credentials by default: https://docs.docker.com/reference/cli/docker/login/#description
## Search and CVE scanning (Trivy)
The `search` extension can include a `cve` section so zot downloads the [Trivy](https://github.com/aquasecurity/trivy) vulnerability database and exposes CVE data via the search API (for example GraphQL).
A minimal configuration only sets how often the DB is refreshed; zot applies defaults for Trivy DB locations and severity selection:
- [config-cve.json](config-cve.json) — `updateInterval` only; defaults are applied for the Trivy DB, Java DB (for language packages), and `vulnSeveritySources`.
To set those options explicitly (for example to mirror standalone Trivys `--vuln-severity-source` behavior), use a `trivy` object under `cve`:
- [config-cve-trivy.json](config-cve-trivy.json) — shows optional `dbRepository`, `javaDBRepository`, and `vulnSeveritySources`.
`vulnSeveritySources` is a list of source names in priority order (for example `auto`, `nvd`, or vendor IDs such as `redhat`, `alpine`). If omitted, zot defaults it to `["auto"]`, consistent with the Trivy CLI. See [Trivy: severity selection](https://trivy.dev/docs/latest/scanner/vulnerability/#severity-selection).
+26
View File
@@ -0,0 +1,26 @@
{
"distSpecVersion": "1.1.1",
"storage": {
"rootDirectory": "/tmp/zot"
},
"http": {
"address": "127.0.0.1",
"port": "8080"
},
"log": {
"level": "debug"
},
"extensions": {
"search": {
"enable": true,
"cve": {
"updateInterval": "24h",
"trivy": {
"dbRepository": "ghcr.io/aquasecurity/trivy-db",
"javaDBRepository": "ghcr.io/aquasecurity/trivy-java-db",
"vulnSeveritySources": ["auto"]
}
}
}
}
}
+72 -1
View File
@@ -967,7 +967,8 @@ func TestServeSearchEnabledDefaultCVEDB(t *testing.T) {
// The default config handling logic will convert the 1h interval to a 2h interval
substring := "\"Search\":{\"Enable\":true,\"CVE\":{\"UpdateInterval\":7200000000000,\"Trivy\":" +
"{\"DBRepository\":\"ghcr.io/aquasecurity/trivy-db\",\"JavaDBRepository\":\"ghcr.io/aquasecurity/trivy-java-db\"}}}"
"{\"DBRepository\":\"ghcr.io/aquasecurity/trivy-db\",\"JavaDBRepository\":\"ghcr.io/aquasecurity/trivy-java-db\"," +
"\"VulnSeveritySources\":[\"auto\"]}}}"
found, err := ReadLogFileAndSearchString(logPath, substring, readLogFileTimeout)
@@ -986,6 +987,76 @@ func TestServeSearchEnabledDefaultCVEDB(t *testing.T) {
So(found, ShouldBeTrue)
So(err, ShouldBeNil)
})
Convey("VulnSeveritySources defaults to [auto] when trivy block is empty", t, func(c C) {
cfg := config.New()
// mapstructure omits an all-empty CVE; at least updateInterval (or any non-zero cve/trivy
// field) must be present for CVE to unmarshal non-nil before defaults run.
content := `{
"storage": { "rootDirectory": "/tmp/zot" },
"http": { "address": "127.0.0.1", "port": "8080" },
"extensions": {
"search": {
"enable": true,
"cve": { "updateInterval": "24h", "trivy": { } }
}
}
}`
configPath := MakeTempFileWithContent(t, "zot-test.json", content)
err := cli.LoadConfiguration(cfg, configPath)
So(err, ShouldBeNil)
So(cfg.Extensions, ShouldNotBeNil)
So(cfg.Extensions.Search, ShouldNotBeNil)
So(cfg.Extensions.Search.CVE, ShouldNotBeNil)
So(cfg.Extensions.Search.CVE.Trivy, ShouldNotBeNil)
So(cfg.Extensions.Search.CVE.Trivy.VulnSeveritySources, ShouldResemble, []string{"auto"})
})
Convey("VulnSeveritySources respects explicit list", t, func(c C) {
cfg := config.New()
content := `{
"storage": { "rootDirectory": "/tmp/zot" },
"http": { "address": "127.0.0.1", "port": "8080" },
"extensions": {
"search": {
"enable": true,
"cve": { "trivy": { "vulnSeveritySources": ["nvd", "ghsa"] } }
}
}
}`
configPath := MakeTempFileWithContent(t, "zot-test.json", content)
err := cli.LoadConfiguration(cfg, configPath)
So(err, ShouldBeNil)
So(cfg.Extensions.Search.CVE.Trivy.VulnSeveritySources, ShouldResemble, []string{"nvd", "ghsa"})
})
Convey("CVE with only updateInterval (no trivy key) gets VulnSeveritySources [auto]", t, func(c C) {
cfg := config.New()
content := `{
"storage": { "rootDirectory": "/tmp/zot" },
"http": { "address": "127.0.0.1", "port": "8080" },
"extensions": {
"search": {
"enable": true,
"cve": { "updateInterval": "24h" }
}
}
}`
configPath := MakeTempFileWithContent(t, "zot-test.json", content)
err := cli.LoadConfiguration(cfg, configPath)
So(err, ShouldBeNil)
So(cfg.Extensions.Search.CVE.Trivy, ShouldNotBeNil)
So(cfg.Extensions.Search.CVE.Trivy.VulnSeveritySources, ShouldResemble, []string{"auto"})
})
}
func TestServeSearchEnabledNoCVE(t *testing.T) {
+8
View File
@@ -891,6 +891,14 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper, logge
config.Extensions.Search.CVE.Trivy.JavaDBRepository = defaultJavaDBDownloadURL
}
if len(config.Extensions.Search.CVE.Trivy.VulnSeveritySources) == 0 {
defaultVulnSeveritySources := []string{"auto"}
logger.Info().Strs("vulnSeveritySources", defaultVulnSeveritySources).Str("component", "config").
Msg("using default trivy vulnerability severity sources.")
config.Extensions.Search.CVE.Trivy.VulnSeveritySources = defaultVulnSeveritySources
}
}
}
+3
View File
@@ -60,6 +60,9 @@ type CVEConfig struct {
type TrivyConfig struct {
DBRepository string // default is "ghcr.io/aquasecurity/trivy-db"
JavaDBRepository string // default is "ghcr.io/aquasecurity/trivy-java-db"
// VulnSeveritySources controls Trivy's severity source selection (same as Trivy's --vuln-severity-source).
// If empty, zot will default it to ["auto"].
VulnSeveritySources []string
}
type MetricsConfig struct {
+1 -3
View File
@@ -39,10 +39,8 @@ func GetCveScanner(conf *config.Config, storeController storage.StoreController,
}
cveConfig := extensionsConfig.GetSearchCVEConfig()
dbRepository := cveConfig.Trivy.DBRepository
javaDBRepository := cveConfig.Trivy.JavaDBRepository
return cveinfo.NewScanner(storeController, metaDB, dbRepository, javaDBRepository, log)
return cveinfo.NewScanner(storeController, metaDB, cveConfig, log)
}
func EnableSearchExtension(conf *config.Config, storeController storage.StoreController,
+3 -2
View File
@@ -12,6 +12,7 @@ import (
zerr "zotregistry.dev/zot/v2/errors"
zcommon "zotregistry.dev/zot/v2/pkg/common"
"zotregistry.dev/zot/v2/pkg/compat"
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
cvemodel "zotregistry.dev/zot/v2/pkg/extensions/search/cve/model"
"zotregistry.dev/zot/v2/pkg/extensions/search/cve/trivy"
"zotregistry.dev/zot/v2/pkg/log"
@@ -45,9 +46,9 @@ type BaseCveInfo struct {
}
func NewScanner(storeController storage.StoreController, metaDB mTypes.MetaDB,
dbRepository, javaDBRepository string, log log.Logger,
cveConfig *extconf.CVEConfig, log log.Logger,
) Scanner {
return trivy.NewScanner(storeController, metaDB, dbRepository, javaDBRepository, log)
return trivy.NewScanner(storeController, metaDB, cveConfig, log)
}
func NewCVEInfo(scanner Scanner, metaDB mTypes.MetaDB, log log.Logger) *BaseCveInfo {
+10 -2
View File
@@ -334,7 +334,11 @@ func TestImageFormat(t *testing.T) {
err = meta.ParseStorage(metaDB, storeController, log)
So(err, ShouldBeNil)
scanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := cveinfo.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
isValidImage, err := scanner.IsImageFormatScannable("zot-test", "")
So(err, ShouldNotBeNil)
@@ -407,7 +411,11 @@ func TestImageFormat(t *testing.T) {
DefaultStore: mocks.MockedImageStore{},
}
scanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := cveinfo.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
isScanable, err := scanner.IsImageFormatScannable("repo", "tag")
So(err, ShouldBeNil)
+6 -1
View File
@@ -19,6 +19,7 @@ import (
zerr "zotregistry.dev/zot/v2/errors"
"zotregistry.dev/zot/v2/pkg/api/config"
zcommon "zotregistry.dev/zot/v2/pkg/common"
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
cveinfo "zotregistry.dev/zot/v2/pkg/extensions/search/cve"
cvecache "zotregistry.dev/zot/v2/pkg/extensions/search/cve/cache"
@@ -513,7 +514,11 @@ func TestScanGeneratorWithRealData(t *testing.T) {
err = meta.ParseStorage(metaDB, storeController, logger)
So(err, ShouldBeNil)
scanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", logger)
scanner := cveinfo.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, logger)
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
+31 -4
View File
@@ -20,6 +20,7 @@ import (
"github.com/aquasecurity/trivy/pkg/javadb"
"github.com/aquasecurity/trivy/pkg/types"
xos "github.com/aquasecurity/trivy/pkg/x/os"
xstrings "github.com/aquasecurity/trivy/pkg/x/strings"
"github.com/google/go-containerregistry/pkg/name"
regTypes "github.com/google/go-containerregistry/pkg/v1/types"
godigest "github.com/opencontainers/go-digest"
@@ -29,6 +30,7 @@ import (
zerr "zotregistry.dev/zot/v2/errors"
zcommon "zotregistry.dev/zot/v2/pkg/common"
"zotregistry.dev/zot/v2/pkg/compat"
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
cvecache "zotregistry.dev/zot/v2/pkg/extensions/search/cve/cache"
cvemodel "zotregistry.dev/zot/v2/pkg/extensions/search/cve/model"
"zotregistry.dev/zot/v2/pkg/log"
@@ -40,7 +42,9 @@ const cacheSize = 1000000
// getNewScanOptions sets trivy configuration values for our scans and returns them as
// a trivy Options structure.
func getNewScanOptions(dir string, dbRepositoryRef, javaDBRepositoryRef name.Reference) *flag.Options {
func getNewScanOptions(dir string, dbRepositoryRef, javaDBRepositoryRef name.Reference,
vulnSeveritySources []dbTypes.SourceID,
) *flag.Options {
scanOptions := flag.Options{
GlobalOptions: flag.GlobalOptions{
CacheDir: dir,
@@ -61,6 +65,9 @@ func getNewScanOptions(dir string, dbRepositoryRef, javaDBRepositoryRef name.Ref
SkipDBUpdate: true,
SkipJavaDBUpdate: true,
},
VulnerabilityOptions: flag.VulnerabilityOptions{
VulnSeveritySources: vulnSeveritySources,
},
ReportOptions: flag.ReportOptions{
Format: "table",
Severities: []dbTypes.Severity{
@@ -90,11 +97,25 @@ type Scanner struct {
cache *cvecache.CveCache
dbRepositoryRef name.Reference
javaDBRepositoryRef name.Reference
vulnSeveritySources []dbTypes.SourceID
}
func NewScanner(storeController storage.StoreController,
metaDB mTypes.MetaDB, dbRepository, javaDBRepository string, log log.Logger,
metaDB mTypes.MetaDB, cveConfig *extconf.CVEConfig, log log.Logger,
) *Scanner {
var trivyCfg *extconf.TrivyConfig
if cveConfig != nil && cveConfig.Trivy != nil {
trivyCfg = cveConfig.Trivy
}
if trivyCfg == nil {
trivyCfg = &extconf.TrivyConfig{}
}
dbRepository := trivyCfg.DBRepository
javaDBRepository := trivyCfg.JavaDBRepository
vulnSeveritySources := trivyCfg.VulnSeveritySources
// The logic to set defaults is similar to what trivy itself uses:
// https://github.com/aquasecurity/trivy/blob/v0.51.4/pkg/flag/db_flags.go#L152
var dbRepositoryRef name.Reference
@@ -126,13 +147,18 @@ func NewScanner(storeController storage.StoreController,
subCveConfig := make(map[string]*flag.Options)
sevSources := xstrings.ToTSlice[dbTypes.SourceID](vulnSeveritySources)
if len(sevSources) == 0 {
sevSources = []dbTypes.SourceID{"auto"}
}
if storeController.DefaultStore != nil {
imageStore := storeController.DefaultStore
rootDir := imageStore.RootDir()
cacheDir := path.Join(rootDir, "_trivy")
opts := getNewScanOptions(cacheDir, dbRepositoryRef, javaDBRepositoryRef)
opts := getNewScanOptions(cacheDir, dbRepositoryRef, javaDBRepositoryRef, sevSources)
cveController.DefaultCveConfig = opts
}
@@ -142,7 +168,7 @@ func NewScanner(storeController storage.StoreController,
rootDir := storage.RootDir()
cacheDir := path.Join(rootDir, "_trivy")
opts := getNewScanOptions(cacheDir, dbRepositoryRef, javaDBRepositoryRef)
opts := getNewScanOptions(cacheDir, dbRepositoryRef, javaDBRepositoryRef, sevSources)
subCveConfig[route] = opts
}
@@ -159,6 +185,7 @@ func NewScanner(storeController storage.StoreController,
cache: cvecache.NewCveCache(cacheSize, log),
dbRepositoryRef: dbRepositoryRef,
javaDBRepositoryRef: javaDBRepositoryRef,
vulnSeveritySources: sevSources,
}
}
@@ -9,12 +9,14 @@ import (
"testing"
"time"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.dev/zot/v2/errors"
"zotregistry.dev/zot/v2/pkg/common"
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
cvecache "zotregistry.dev/zot/v2/pkg/extensions/search/cve/cache"
"zotregistry.dev/zot/v2/pkg/extensions/search/cve/model"
@@ -79,7 +81,11 @@ func TestMultipleStoragePath(t *testing.T) {
metaDB, err := boltdb.New(boltDriver, log)
So(err, ShouldBeNil)
scanner := NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
So(scanner.storeController.DefaultStore, ShouldNotBeNil)
So(scanner.storeController.SubStore, ShouldNotBeNil)
@@ -195,7 +201,11 @@ func TestTrivyLibraryErrors(t *testing.T) {
img := "zot-test:0.0.1" //nolint:goconst
// Download DB fails for invalid DB url
scanner := NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-not-db", "", log)
scanner := NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-not-db",
},
}, log)
ctx := context.Background()
@@ -209,15 +219,23 @@ func TestTrivyLibraryErrors(t *testing.T) {
So(err, ShouldWrap, zerr.ErrCVEDBNotFound)
// Download DB fails for invalid Java DB
scanner = NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db",
"ghcr.io/project-zot/trivy-not-db", log)
scanner = NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
JavaDBRepository: "ghcr.io/project-zot/trivy-not-db",
},
}, log)
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)
scanner = NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
// UpdateDB with good ctx
err = scanner.UpdateDB(ctx)
@@ -317,8 +335,12 @@ func TestImageScannable(t *testing.T) {
storeController := storage.StoreController{}
storeController.DefaultStore = store
scanner := NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db",
"ghcr.io/project-zot/trivy-java-db", log)
scanner := NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
JavaDBRepository: "ghcr.io/project-zot/trivy-java-db",
},
}, log)
Convey("Valid image should be scannable", t, func() {
result, err := scanner.IsImageFormatScannable("repo1", "valid")
@@ -387,8 +409,12 @@ func TestTrivyDBUrl(t *testing.T) {
// Ideally we would want to also test the default urls
// But we are getting `response status code 429: toomanyrequests` from
// `ghcr.io/aquasecurity/trivy-db` and `ghcr.io/aquasecurity/trivy-java-db`
scanner := NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db",
"ghcr.io/project-zot/trivy-java-db", log)
scanner := NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
JavaDBRepository: "ghcr.io/project-zot/trivy-java-db",
},
}, log)
ctx := context.Background()
@@ -480,6 +506,29 @@ func TestIsIndexScannableErrors(t *testing.T) {
})
}
func TestVulnSeveritySourcesDefaulting(t *testing.T) {
Convey("NewScanner defaults VulnSeveritySources to auto when empty", t, func() {
scanner := NewScanner(storage.StoreController{}, nil, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log.NewTestLogger())
So(scanner, ShouldNotBeNil)
So(scanner.vulnSeveritySources, ShouldResemble, []dbTypes.SourceID{"auto"})
})
Convey("NewScanner preserves provided VulnSeveritySources", t, func() {
scanner := NewScanner(storage.StoreController{}, nil, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
VulnSeveritySources: []string{"nvd", "ghsa"},
},
}, log.NewTestLogger())
So(scanner, ShouldNotBeNil)
So(scanner.vulnSeveritySources, ShouldResemble, []dbTypes.SourceID{"nvd", "ghsa"})
})
}
func TestGetCVEReference(t *testing.T) {
Convey("getCVEReference", t, func() {
ref := getCVEReference("primary", []string{})
+39 -11
View File
@@ -61,7 +61,11 @@ func TestScanBigTestFile(t *testing.T) {
cm.StartAndWait(port)
defer cm.StopServer()
// scan
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, "ghcr.io/project-zot/trivy-db", "", ctlr.Log)
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, ctlr.Log)
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
@@ -105,7 +109,11 @@ func TestScanningByDigest(t *testing.T) {
So(err, ShouldBeNil)
// scan
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, "ghcr.io/project-zot/trivy-db", "", ctlr.Log)
scanner := trivy.NewScanner(ctlr.StoreController, ctlr.MetaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, ctlr.Log)
ctx := context.Background()
@@ -191,7 +199,11 @@ func TestVulnerableLayer(t *testing.T) {
err = meta.ParseStorage(metaDB, storeController, log)
So(err, ShouldBeNil)
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
@@ -262,8 +274,12 @@ func TestVulnerableLayer(t *testing.T) {
err = meta.ParseStorage(metaDB, storeController, log)
So(err, ShouldBeNil)
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db",
"ghcr.io/project-zot/trivy-java-db", log)
scanner := trivy.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
JavaDBRepository: "ghcr.io/project-zot/trivy-java-db",
},
}, log)
err = scanner.UpdateDB(context.Background())
So(err, ShouldBeNil)
@@ -343,7 +359,11 @@ func TestWithTempDirErrorHandling(t *testing.T) {
err = meta.ParseStorage(metaDB, storeController, log)
So(err, ShouldBeNil)
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, log)
// Clean up any existing temp directory first
_ = xos.Cleanup()
@@ -420,12 +440,20 @@ func TestScannerErrors(t *testing.T) {
metaDB := mocks.MetaDBMock{}
log := log.NewTestLogger()
testTrivyCVEConfig := func() *extconf.CVEConfig {
return &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}
}
Convey("IsImageFormatScannable", func() {
storeController.DefaultStore = mocks.MockedImageStore{}
metaDB.GetImageMetaFn = func(digest godigest.Digest) (types.ImageMeta, error) {
return types.ImageMeta{}, ErrTestError
}
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, testTrivyCVEConfig(), log)
_, err := scanner.IsImageFormatScannable("repo", godigest.FromString("dig").String())
So(err, ShouldNotBeNil)
@@ -435,7 +463,7 @@ func TestScannerErrors(t *testing.T) {
metaDB.GetImageMetaFn = func(digest godigest.Digest) (types.ImageMeta, error) {
return types.ImageMeta{}, ErrTestError
}
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, testTrivyCVEConfig(), log)
Convey("Manifest", func() {
_, err := scanner.IsImageMediaScannable("repo", godigest.FromString("dig").String(), ispec.MediaTypeImageManifest)
@@ -449,7 +477,7 @@ func TestScannerErrors(t *testing.T) {
metaDB.GetImageMetaFn = func(digest godigest.Digest) (types.ImageMeta, error) {
return types.ImageMeta{}, nil
}
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, testTrivyCVEConfig(), log)
_, err := scanner.IsImageMediaScannable("repo", godigest.FromString("dig").String(), ispec.MediaTypeImageIndex)
So(err, ShouldNotBeNil)
@@ -465,7 +493,7 @@ func TestScannerErrors(t *testing.T) {
}}},
}, nil
}
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, testTrivyCVEConfig(), log)
_, err := scanner.IsImageMediaScannable("repo", godigest.FromString("dig").String(), ispec.MediaTypeImageIndex)
So(err, ShouldBeNil)
@@ -477,7 +505,7 @@ func TestScannerErrors(t *testing.T) {
return types.ImageMeta{}, ErrTestError
}
scanner := trivy.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", log)
scanner := trivy.NewScanner(storeController, metaDB, testTrivyCVEConfig(), log)
_, err := scanner.ScanImage(context.Background(), "image@"+godigest.FromString("digest").String())
So(err, ShouldNotBeNil)
+6 -1
View File
@@ -13,6 +13,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
"zotregistry.dev/zot/v2/pkg/api/config"
extconf "zotregistry.dev/zot/v2/pkg/extensions/config"
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
cveinfo "zotregistry.dev/zot/v2/pkg/extensions/search/cve"
"zotregistry.dev/zot/v2/pkg/log"
@@ -55,7 +56,11 @@ func TestCVEDBGenerator(t *testing.T) {
},
}
cveScanner := cveinfo.NewScanner(storeController, metaDB, "ghcr.io/project-zot/trivy-db", "", logger)
cveScanner := cveinfo.NewScanner(storeController, metaDB, &extconf.CVEConfig{
Trivy: &extconf.TrivyConfig{
DBRepository: "ghcr.io/project-zot/trivy-db",
},
}, logger)
generator := cveinfo.NewDBUpdateTaskGenerator(time.Minute, cveScanner, logger)
sch.SubmitGenerator(generator, 12000*time.Millisecond, scheduler.HighPriority)
+4 -2
View File
@@ -702,8 +702,9 @@ func TestRepoListWithNewestImage(t *testing.T) {
defer ctlr.Shutdown()
// Match a stable prefix; config logging may include additional Trivy fields (e.g. severity sources).
substring := "{\"Search\":{\"Enable\":true,\"CVE\":{\"UpdateInterval\":3600000000000," +
"\"Trivy\":{\"DBRepository\":\"ghcr.io/project-zot/trivy-db\",\"JavaDBRepository\":\"\"}}}"
"\"Trivy\":{\"DBRepository\":\"ghcr.io/project-zot/trivy-db\",\"JavaDBRepository\":\"\""
found, err := readFileAndSearchString(logPath, substring, 2*time.Minute)
So(found, ShouldBeTrue)
So(err, ShouldBeNil)
@@ -3667,8 +3668,9 @@ func TestGlobalSearch(t *testing.T) { //nolint: gocyclo
defer ctlr.Shutdown()
// Wait for trivy db to download
// Match a stable prefix; config logging may include additional Trivy fields (e.g. severity sources).
substring := "{\"Search\":{\"Enable\":true,\"CVE\":{\"UpdateInterval\":3600000000000," +
"\"Trivy\":{\"DBRepository\":\"ghcr.io/project-zot/trivy-db\",\"JavaDBRepository\":\"\"}}}"
"\"Trivy\":{\"DBRepository\":\"ghcr.io/project-zot/trivy-db\",\"JavaDBRepository\":\"\""
found, err := readFileAndSearchString(logPath, substring, 2*time.Minute)
So(found, ShouldBeTrue)
So(err, ShouldBeNil)
+2 -1
View File
@@ -419,7 +419,8 @@ JSON
found=0
for i in "${lines[@]}"
do
if [[ "$i" = *"CVE-2025-26519 UNKNOWN musl libc 0.9.13 through 1.2.5 before 1.2.6 h..."* ]]; then
# Severity can change with Trivy DB / vulnSeveritySources (e.g. auto); match CVE id + title only.
if [[ "$i" = *"CVE-2025-26519"* && "$i" = *"musl libc 0.9.13 through 1.2.5 before 1.2.6 h"* ]]; then
found=1
fi
done