mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 11:37:56 +08:00
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:
@@ -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 Trivy’s `--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).
|
||||
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user