Skip to content

Commit

Permalink
Feature: Added exceptions flag in scan image cmd
Browse files Browse the repository at this point in the history
This commit introduces the "exceptions" flag in the scan image command.
Users can pass a list of vulnerabilities they ignore while scanning an
image using this flag.

Fixes: kubescape#1564

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
  • Loading branch information
VaibhavMalik4187 committed Jan 2, 2024
1 parent 06d9c9d commit 87a704c
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 44 deletions.
12 changes: 9 additions & 3 deletions cmd/scan/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ var (
// getImageCmd returns the scan image command
func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
var imgCredentials shared.ImageCredentials
var exceptions []string

cmd := &cobra.Command{
Use: "image <image>:<tag> [flags]",
Short: "Scan an image for vulnerabilities",
Expand All @@ -51,9 +53,10 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
}

imgScanInfo := &metav1.ImageScanInfo{
Image: args[0],
Username: imgCredentials.Username,
Password: imgCredentials.Password,
Image: args[0],
Username: imgCredentials.Username,
Password: imgCredentials.Password,
Exceptions: exceptions,
}

results, err := ks.ScanImage(context.Background(), imgScanInfo, scanInfo)
Expand All @@ -69,6 +72,9 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
},
}

// The exceptions flag
cmd.Flags().StringSliceVarP(&exceptions, "exceptions", "E", []string{}, "List of CVEs to exclude")

cmd.PersistentFlags().StringVarP(&imgCredentials.Username, "username", "u", "", "Username for registry login")
cmd.PersistentFlags().StringVarP(&imgCredentials.Password, "password", "p", "", "Password for registry login")

Expand Down
2 changes: 1 addition & 1 deletion core/core/image_scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
Password: imgScanInfo.Password,
}

scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds)
scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds, imgScanInfo.Exceptions)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to scan image: %s", imgScanInfo.Image))
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions core/core/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
Password: patchInfo.Password,
}
// Scan the image
scanResults, err := svc.Scan(ctx, patchInfo.Image, creds)
scanResults, err := svc.Scan(ctx, patchInfo.Image, creds, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -73,7 +73,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s

logger.L().Start(fmt.Sprintf("Re-scanning image: %s", patchedImageName))

scanResultsPatched, err := svc.Scan(ctx, patchedImageName, creds)
scanResultsPatched, err := svc.Scan(ctx, patchedImageName, creds, nil)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion core/core/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx

func scanSingleImage(ctx context.Context, img string, svc imagescan.Service, resultsHandling *resultshandling.ResultsHandler) error {

scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{})
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{}, nil)
if err != nil {
return err
}
Expand Down
7 changes: 4 additions & 3 deletions core/meta/datastructures/v1/image_scan.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package v1

type ImageScanInfo struct {
Username string
Password string
Image string
Username string
Password string
Image string
Exceptions []string
}
20 changes: 17 additions & 3 deletions pkg/imagescan/imagescan.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/anchore/grype/grype"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/grype/grypeerr"
"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/matcher"
"github.com/anchore/grype/grype/matcher/dotnet"
"github.com/anchore/grype/grype/matcher/golang"
Expand Down Expand Up @@ -117,7 +118,11 @@ type Service struct {
dbCfg db.Config
}

func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials) (*models.PresenterConfig, error) {
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials, exceptions []string) (*models.PresenterConfig, error) {
if exceptions == nil {
exceptions = []string{}
}

var err error

store, status, dbCloser, err := NewVulnerabilityDB(s.dbCfg, true)
Expand All @@ -134,9 +139,18 @@ func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCred
defer dbCloser.Close()
}

var ignoreRules []match.IgnoreRule
for _, exception := range exceptions {
rule := match.IgnoreRule{
Vulnerability: exception,
}
ignoreRules = append(ignoreRules, rule)
}

matcher := grype.VulnerabilityMatcher{
Store: *store,
Matchers: getMatchers(),
Store: *store,
Matchers: getMatchers(),
IgnoreRules: ignoreRules,
}

remainingMatches, ignoredMatches, err := matcher.FindMatches(packages, pkgContext)
Expand Down
65 changes: 34 additions & 31 deletions pkg/imagescan/imagescan_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package imagescan

import (
"context"
"errors"
"testing"
"time"
Expand Down Expand Up @@ -39,40 +40,42 @@ import (
// assert.IsType(t, Service{}, svc)
// }

// func TestScan(t *testing.T) {
// tt := []struct {
// name string
// image string
// creds RegistryCredentials
// }{
// {
// name: "Valid image name produces a non-nil scan result",
// image: "nginx",
// },
// {
// name: "Scanning a valid image with provided credentials should produce a non-nil scan result",
// image: "nginx",
// creds: RegistryCredentials{
// Username: "test",
// Password: "password",
// },
// },
// }
func TestScan(t *testing.T) {
dbCfg, _ := NewDefaultDBConfig()
svc := NewScanService(dbCfg)
ctx := context.Background()
image := "nginx"
creds := RegistryCredentials{}

// for _, tc := range tt {
// t.Run(tc.name, func(t *testing.T) {
// ctx := context.Background()
// dbCfg, _ := NewDefaultDBConfig()
// svc := NewScanService(dbCfg)
// creds := RegistryCredentials{}
tests := []struct {
name string
image string
exceptions []string
err error
}{
{
name: "Without exceptions",
image: image,
exceptions: []string{},
err: nil,
},
{
name: "With exceptions",
image: image,
exceptions: []string{"CVE-2023-6879", "CVE-2023-45853"},
err: nil,
},
}

// scanResults, err := svc.Scan(ctx, tc.image, creds)
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
scanResults, err := svc.Scan(ctx, tc.image, creds, tc.exceptions)

// assert.NoError(t, err)
// assert.IsType(t, &models.PresenterConfig{}, scanResults)
// })
// }
// }
assert.NoError(t, err)
assert.IsType(t, &models.PresenterConfig{}, scanResults)
})
}
}

// fakeMetaProvider is a test double that fakes an actual MetadataProvider
type fakeMetaProvider struct {
Expand Down

0 comments on commit 87a704c

Please sign in to comment.