diff --git a/cmd/patch/patch.go b/cmd/patch/patch.go index 7a43f5a6..a1d58c12 100644 --- a/cmd/patch/patch.go +++ b/cmd/patch/patch.go @@ -80,6 +80,7 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command { patchCmd.PersistentFlags().StringVarP(&scanInfo.FailThresholdSeverity, "severity-threshold", "s", "", "Severity threshold is the severity of a vulnerability at which the command fails and returns exit code 1") patchCmd.PersistentFlags().BoolVarP(&useDefaultMatchers, "use-default-matchers", "", true, "Use default matchers (true) or CPE matchers (false) for image scanning") + patchCmd.PersistentFlags().StringVar(&scanInfo.ListingURL, "grype-db-url", "", "Grype vulnerability database URL") return patchCmd } diff --git a/cmd/scan/scan.go b/cmd/scan/scan.go index 0dc41ff9..0f07a800 100644 --- a/cmd/scan/scan.go +++ b/cmd/scan/scan.go @@ -94,6 +94,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command { scanCmd.PersistentFlags().BoolVarP(&scanInfo.ScanImages, "scan-images", "", false, "Scan resources images") scanCmd.PersistentFlags().BoolVarP(&scanInfo.UseDefaultMatchers, "use-default-matchers", "", true, "Use default matchers (true) or CPE matchers (false) for image scanning") scanCmd.PersistentFlags().StringSliceVar(&scanInfo.LabelsToCopy, "labels-to-copy", nil, "Labels to copy from workloads to scan reports for easy identification. e.g: --labels-to-copy=app,team,environment") + scanCmd.PersistentFlags().StringVar(&scanInfo.ListingURL, "grype-db-url", "", "Grype vulnerability database URL") scanCmd.PersistentFlags().MarkDeprecated("fail-threshold", "use '--compliance-threshold' flag instead. Flag will be removed at 1.Dec.2023") scanCmd.PersistentFlags().MarkDeprecated("create-account", "Create account is no longer supported. In case of a missing Account ID and a configured backend server, a new account id will be generated automatically by Kubescape. Feel free to contact the Kubescape maintainers for more information.") diff --git a/core/cautils/scaninfo.go b/core/cautils/scaninfo.go index 810aac9a..d557051a 100644 --- a/core/cautils/scaninfo.go +++ b/core/cautils/scaninfo.go @@ -143,6 +143,7 @@ type ScanInfo struct { LabelsToCopy []string // Labels to copy from workloads to scan reports scanningContext *ScanningContext cleanups []func() + ListingURL string //Grype vulnerability database URL } type Getters struct { diff --git a/core/core/image_scan.go b/core/core/image_scan.go index 371e4716..046cc9cd 100644 --- a/core/core/image_scan.go +++ b/core/core/image_scan.go @@ -165,7 +165,11 @@ func getUniqueVulnerabilitiesAndSeverities(policies []VulnerabilitiesIgnorePolic func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (bool, error) { logger.L().Start(fmt.Sprintf("Scanning image %s...", imgScanInfo.Image)) - distCfg, installCfg, _ := imagescan.NewDefaultDBConfig() + distCfg, installCfg, _, err := imagescan.NewDefaultDBConfig(scanInfo.ListingURL) + if err != nil { + logger.L().StopError(fmt.Sprintf("Invalid Grype database URL '%s': %v", scanInfo.ListingURL, err)) + return false, err + } svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, imgScanInfo.UseDefaultMatchers) if err != nil { logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err)) diff --git a/core/core/patch.go b/core/core/patch.go index 9b7d1409..d5d3e85f 100644 --- a/core/core/patch.go +++ b/core/core/patch.go @@ -48,7 +48,11 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan logger.L().Start(fmt.Sprintf("Scanning image: %s", patchInfo.Image)) // Setup the scan service - distCfg, installCfg, _ := imagescan.NewDefaultDBConfig() + distCfg, installCfg, _, err := imagescan.NewDefaultDBConfig(scanInfo.ListingURL) + if err != nil { + logger.L().StopError(fmt.Sprintf("Invalid Grype database URL '%s': %v", scanInfo.ListingURL, err)) + return false, err + } svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, scanInfo.UseDefaultMatchers) if err != nil { logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err)) diff --git a/core/core/scan.go b/core/core/scan.go index 572a3de6..fd3213fb 100644 --- a/core/core/scan.go +++ b/core/core/scan.go @@ -249,7 +249,11 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx } } - distCfg, installCfg, _ := imagescan.NewDefaultDBConfig() + distCfg, installCfg, _, err := imagescan.NewDefaultDBConfig(scanInfo.ListingURL) + if err != nil { + logger.L().StopError(fmt.Sprintf("Invalid Grype database URL '%s': %v", scanInfo.ListingURL, err)) + return + } svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, scanInfo.UseDefaultMatchers) if err != nil { logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err)) diff --git a/pkg/imagescan/imagescan.go b/pkg/imagescan/imagescan.go index 38171b94..71cc90fd 100644 --- a/pkg/imagescan/imagescan.go +++ b/pkg/imagescan/imagescan.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net/url" "path/filepath" "strings" @@ -42,16 +43,29 @@ func (c RegistryCredentials) IsEmpty() bool { return c.Username == "" || c.Password == "" } -func NewDefaultDBConfig() (distribution.Config, installation.Config, bool) { +func NewDefaultDBConfig(grypeURL string) (distribution.Config, installation.Config, bool, error) { dir := filepath.Join(xdg.CacheHome, defaultDBDirName) - url := defaultGrypeListingURL + finalURL := defaultGrypeListingURL + if grypeURL != "" { + parsed, err := url.ParseRequestURI(grypeURL) + if err != nil || parsed.Host == "" { + return distribution.Config{}, installation.Config{}, false, err + } + + if parsed.Scheme != "https" && parsed.Scheme != "http" { + return distribution.Config{}, installation.Config{}, false, fmt.Errorf("invalid scheme: %s", parsed.Scheme) + } + + finalURL = grypeURL + } + shouldUpdate := true return distribution.Config{ - LatestURL: url, + LatestURL: finalURL, }, installation.Config{ DBRootDir: dir, - }, shouldUpdate + }, shouldUpdate, nil } func getMatchers(useDefaultMatchers bool) []match.Matcher { diff --git a/pkg/imagescan/imagescan_test.go b/pkg/imagescan/imagescan_test.go index ff7d54e0..abd5a311 100644 --- a/pkg/imagescan/imagescan_test.go +++ b/pkg/imagescan/imagescan_test.go @@ -176,7 +176,7 @@ func TestNewScanServiceWithMatchers(t *testing.T) { func TestNewScanServiceWithMatchersIntegration(t *testing.T) { // Test the actual NewScanServiceWithMatchers function - distCfg, installCfg, _ := NewDefaultDBConfig() + distCfg, installCfg, _, _ := NewDefaultDBConfig("") // Test with default matchers enabled svcWithDefault, err := NewScanServiceWithMatchers(distCfg, installCfg, true)