From b5ed56f07d71a63f3b92bdbcc8c567995e09cb0b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 05:37:30 +0000 Subject: [PATCH] feat: allow disabling CVE independently from search Agent-Logs-Url: https://github.com/project-zot/zot/sessions/9b89c154-fd36-4315-9910-9c19f96e2417 Co-authored-by: rchincha <45800463+rchincha@users.noreply.github.com> --- pkg/cli/server/extensions_test.go | 70 ++++++++++++++++++++++++++++ pkg/cli/server/root.go | 60 +++++++++++++----------- pkg/extensions/config/config.go | 12 ++++- pkg/extensions/config/config_test.go | 22 +++++++++ 4 files changed, 135 insertions(+), 29 deletions(-) diff --git a/pkg/cli/server/extensions_test.go b/pkg/cli/server/extensions_test.go index 62dbc2b2..213311d6 100644 --- a/pkg/cli/server/extensions_test.go +++ b/pkg/cli/server/extensions_test.go @@ -100,6 +100,41 @@ func TestVerifyExtensionsConfig(t *testing.T) { So(cli.NewServerRootCmd().Execute(), ShouldNotBeNil) }) + Convey("Test verify CVE can be explicitly disabled for remote storage", t, func(c C) { + content := fmt.Sprintf(`{ + "storage":{ + "rootDirectory":"%s", + "dedupe":true, + "remoteCache":false, + "storageDriver":{ + "name":"s3", + "rootdirectory":"/zot", + "region":"us-east-2", + "bucket":"zot-storage", + "secure":true, + "skipverify":false + } + }, + "http":{ + "address":"127.0.0.1", + "port":"8080" + }, + "extensions":{ + "search": { + "enable": true, + "cve": { + "enable": false + } + } + } + }`, t.TempDir()) + + tmpfile := MakeTempFileWithContent(t, "zot-test.json", content) + os.Args = []string{"cli_test", "verify", tmpfile} + + So(cli.NewServerRootCmd().Execute(), ShouldBeNil) + }) + Convey("Test verify w/ sync and w/o filesystem storage", t, func(c C) { content := fmt.Sprintf(`{"storage":{"rootDirectory":"%s", "storageDriver": {"name": "s3"}}, "http":{"address":"127.0.0.1","port":"8080","realm":"zot", @@ -1099,6 +1134,41 @@ func TestServeSearchEnabledNoCVE(t *testing.T) { So(found, ShouldBeTrue) So(err, ShouldBeNil) }) + + Convey("search explicitly enabled, and CVE explicitly disabled", t, func(c C) { + content := `{ + "storage": { + "rootDirectory": "%s" + }, + "http": { + "address": "127.0.0.1", + "port": "%s" + }, + "log": { + "level": "debug", + "output": "%s" + }, + "extensions": { + "search": { + "enable": true, + "cve": { + "enable": false + } + } + } + }` + + logPath, _, err := runCLIWithConfig(t, content) + So(err, ShouldBeNil) + + found, err := ReadLogFileAndSearchString(logPath, `"CVE":{"Enable":false`, readLogFileTimeout) + So(found, ShouldBeTrue) + So(err, ShouldBeNil) + + found, err = ReadLogFileAndSearchString(logPath, "cve config not provided, skipping cve-db update", readLogFileTimeout) + So(found, ShouldBeTrue) + So(err, ShouldBeNil) + }) } func TestServeSearchDisabled(t *testing.T) { diff --git a/pkg/cli/server/root.go b/pkg/cli/server/root.go index 61f4e4e2..4e1388aa 100644 --- a/pkg/cli/server/root.go +++ b/pkg/cli/server/root.go @@ -874,41 +874,47 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper, logge } if *config.Extensions.Search.Enable && config.Extensions.Search.CVE != nil { - defaultUpdateInterval, _ := time.ParseDuration("2h") - - if config.Extensions.Search.CVE.UpdateInterval < defaultUpdateInterval { - config.Extensions.Search.CVE.UpdateInterval = defaultUpdateInterval - - logger.Warn().Msg("cve update interval set to too-short interval < 2h, " + - "changing update duration to 2 hours and continuing.") + if config.Extensions.Search.CVE.Enable == nil { + config.Extensions.Search.CVE.Enable = &defaultVal } - if config.Extensions.Search.CVE.Trivy == nil { - config.Extensions.Search.CVE.Trivy = &extconf.TrivyConfig{} - } + if *config.Extensions.Search.CVE.Enable { + defaultUpdateInterval, _ := time.ParseDuration("2h") - if config.Extensions.Search.CVE.Trivy.DBRepository == "" { - defaultDBDownloadURL := "ghcr.io/aquasecurity/trivy-db" - logger.Info().Str("url", defaultDBDownloadURL).Str("component", "config"). - Msg("using default trivy-db download URL.") + if config.Extensions.Search.CVE.UpdateInterval < defaultUpdateInterval { + config.Extensions.Search.CVE.UpdateInterval = defaultUpdateInterval - config.Extensions.Search.CVE.Trivy.DBRepository = defaultDBDownloadURL - } + logger.Warn().Msg("cve update interval set to too-short interval < 2h, " + + "changing update duration to 2 hours and continuing.") + } - if config.Extensions.Search.CVE.Trivy.JavaDBRepository == "" { - defaultJavaDBDownloadURL := "ghcr.io/aquasecurity/trivy-java-db" - logger.Info().Str("url", defaultJavaDBDownloadURL).Str("component", "config"). - Msg("using default trivy-java-db download URL.") + if config.Extensions.Search.CVE.Trivy == nil { + config.Extensions.Search.CVE.Trivy = &extconf.TrivyConfig{} + } - config.Extensions.Search.CVE.Trivy.JavaDBRepository = defaultJavaDBDownloadURL - } + if config.Extensions.Search.CVE.Trivy.DBRepository == "" { + defaultDBDownloadURL := "ghcr.io/aquasecurity/trivy-db" + logger.Info().Str("url", defaultDBDownloadURL).Str("component", "config"). + Msg("using default trivy-db download URL.") - 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.DBRepository = defaultDBDownloadURL + } - config.Extensions.Search.CVE.Trivy.VulnSeveritySources = defaultVulnSeveritySources + if config.Extensions.Search.CVE.Trivy.JavaDBRepository == "" { + defaultJavaDBDownloadURL := "ghcr.io/aquasecurity/trivy-java-db" + logger.Info().Str("url", defaultJavaDBDownloadURL).Str("component", "config"). + Msg("using default trivy-java-db download URL.") + + 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 + } } } } diff --git a/pkg/extensions/config/config.go b/pkg/extensions/config/config.go index 94bf291f..02c7597b 100644 --- a/pkg/extensions/config/config.go +++ b/pkg/extensions/config/config.go @@ -53,6 +53,7 @@ type SearchConfig struct { } type CVEConfig struct { + Enable *bool `mapstructure:",omitempty" json:",omitempty"` UpdateInterval time.Duration // should be 2 hours or more, if not specified default be kept as 2 hours Trivy *TrivyConfig } @@ -109,8 +110,15 @@ func (e *ExtensionConfig) IsCveScanningEnabled() bool { return false } - return e.Search != nil && e.Search.Enable != nil && *e.Search.Enable && - e.Search.CVE != nil && e.Search.CVE.Trivy != nil + if e.Search == nil || e.Search.Enable == nil || !*e.Search.Enable || e.Search.CVE == nil { + return false + } + + if e.Search.CVE.Enable != nil && !*e.Search.CVE.Enable { + return false + } + + return e.Search.CVE.Trivy != nil } // IsEventRecorderEnabled checks if event recording is enabled in this extensions config. diff --git a/pkg/extensions/config/config_test.go b/pkg/extensions/config/config_test.go index 93dbd402..23fc7488 100644 --- a/pkg/extensions/config/config_test.go +++ b/pkg/extensions/config/config_test.go @@ -44,6 +44,22 @@ func buildSearchConfigWithCVE(enabled bool) *config.ExtensionConfig { return ext } +func buildSearchConfigWithCVEDisabled(enabled bool) *config.ExtensionConfig { + disabled := false + ext := &config.ExtensionConfig{} + ext.Search = &config.SearchConfig{ + BaseConfig: config.BaseConfig{ + Enable: &enabled, + }, + CVE: &config.CVEConfig{ + Enable: &disabled, + Trivy: &config.TrivyConfig{}, + }, + } + + return ext +} + func buildEventsConfig(enabled bool) *config.ExtensionConfig { ext := &config.ExtensionConfig{} ext.Events = &events.Config{ @@ -302,6 +318,12 @@ func TestExtensionConfig(t *testing.T) { testMethodWithNilEnable("Search", (*config.ExtensionConfig).IsCveScanningEnabled) testMethodWithDisabledEnable("Search", (*config.ExtensionConfig).IsCveScanningEnabled, buildSearchConfig) testMethodWithEnabledEnable("Search", (*config.ExtensionConfig).IsCveScanningEnabled, buildSearchConfigWithCVE) + + Convey("Test with search enabled but cve explicitly disabled", func() { + enabled := true + extensionConfig := buildSearchConfigWithCVEDisabled(enabled) + So(extensionConfig.IsCveScanningEnabled(), ShouldBeFalse) + }) }) Convey("Test IsEventRecorderEnabled()", func() {