Merge pull request #1949 from Mujib-Ahasan/grype-db-url

feat: new flag `--grype-db-url` added to overload the url in `kubescape scan` command
This commit is contained in:
Matthias Bertschy
2026-03-15 20:46:26 +01:00
committed by GitHub
9 changed files with 52 additions and 8 deletions
+9
View File
@@ -237,6 +237,15 @@ kubescape scan image nginx:1.21 -v
kubescape scan image myregistry/myimage:tag --username user --password pass
```
#### Using an Offline Grype Database
```bash
# Start the offline Grype-DB server (using docker)
docker run --rm -p8080:8080 quay.io/kubescape/grype-offline-db:v6-latest
# Scan an image using the offline database:
kubescape scan image --grype-db-url http://localhost:8080/databases/ nginx:latest
```
### Auto-Fix
Automatically fix misconfigurations in your manifest files:
+1
View File
@@ -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
}
+1
View File
@@ -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.")
+1
View File
@@ -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 {
+5 -1
View File
@@ -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))
+5 -1
View File
@@ -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))
+5 -1
View File
@@ -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))
+24 -4
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"net/url"
"path/filepath"
"strings"
@@ -25,6 +26,7 @@ import (
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/syft"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
)
@@ -42,16 +44,34 @@ 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 != "" {
logger.L().Info(fmt.Sprintf("Using custom Grype database URL: %s", grypeURL))
parsed, err := url.ParseRequestURI(grypeURL)
if err != nil {
return distribution.Config{}, installation.Config{}, false, err
}
if parsed.Host == "" {
return distribution.Config{}, installation.Config{}, false, fmt.Errorf("invalid grype DB URL: missing host")
}
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 {
+1 -1
View File
@@ -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)