Added support for severity exceptions in imagescan

This commit add relevant functions to support severity exceptions during
image scan.

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
This commit is contained in:
VaibhavMalik4187
2025-02-07 10:26:53 +01:00
committed by Matthias Bertschy
parent 199c57be30
commit a31154897f
5 changed files with 67 additions and 23 deletions
+24 -14
View File
@@ -60,29 +60,38 @@ func GetImageExceptionsFromFile(filePath string) ([]VulnerabilitiesIgnorePolicy,
return policies, nil
}
func getUniqueVulnerabilities(policies []VulnerabilitiesIgnorePolicy) []string {
// Create a map to store unique vulnerabilities (case-insensitive)
uniqueVulns := make(map[string]bool)
func getUniqueVulnerabilitiesAndSeverities(policies []VulnerabilitiesIgnorePolicy) ([]string, []string) {
// Create maps with slices as values to store unique vulnerabilities and severities (case-insensitive)
uniqueVulns := make(map[string][]string)
uniqueSevers := make(map[string][]string)
// Iterate over each policy
// Iterate over each policy and its vulnerabilities/severities
for _, policy := range policies {
// Iterate over each vulnerability in the policy
for _, vuln := range policy.Vulnerabilities {
// Convert to uppercase for case-insensitive comparison
vulnLower := strings.ToUpper(vuln)
for _, vulnerability := range policy.Vulnerabilities {
// Add to slice directly
vulnerabilityUppercase := strings.ToUpper(vulnerability)
uniqueVulns[vulnerabilityUppercase] = append(uniqueVulns[vulnerabilityUppercase], vulnerability)
}
// Add the vulnerability to the map (only if it's not already present)
uniqueVulns[vulnLower] = true
for _, severity := range policy.Severities {
// Add to slice directly
severityUppercase := strings.ToUpper(severity)
uniqueSevers[severityUppercase] = append(uniqueSevers[severityUppercase], severity)
}
}
// Convert the map keys (unique vulnerabilities) to a slice
// Extract unique keys (which are unique vulnerabilities/severities) and their slices
uniqueVulnsList := make([]string, 0, len(uniqueVulns))
for vuln := range uniqueVulns {
uniqueVulnsList = append(uniqueVulnsList, vuln)
}
return uniqueVulnsList
uniqueSeversList := make([]string, 0, len(uniqueSevers))
for sever := range uniqueSevers {
uniqueSeversList = append(uniqueSeversList, sever)
}
return uniqueVulnsList, uniqueSeversList
}
func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
@@ -97,6 +106,7 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
}
var vulnerabilityExceptions []string
var severityExceptions []string
if imgScanInfo.Exceptions != "" {
exceptionPolicies, err := GetImageExceptionsFromFile(imgScanInfo.Exceptions)
if err != nil {
@@ -104,10 +114,10 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
return nil, err
}
vulnerabilityExceptions = getUniqueVulnerabilities(exceptionPolicies)
vulnerabilityExceptions, severityExceptions = getUniqueVulnerabilitiesAndSeverities(exceptionPolicies)
}
scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds, vulnerabilityExceptions)
scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds, vulnerabilityExceptions, severityExceptions)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to scan image: %s", imgScanInfo.Image))
return nil, err
+2 -2
View File
@@ -37,7 +37,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, nil)
scanResults, err := svc.Scan(ctx, patchInfo.Image, creds, nil, nil)
if err != nil {
return nil, err
}
@@ -81,7 +81,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, nil)
scanResultsPatched, err := svc.Scan(ctx, patchedImageName, creds, nil, nil)
if err != nil {
return nil, err
}
+1 -1
View File
@@ -257,7 +257,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{}, nil)
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{}, nil, nil)
if err != nil {
return err
}
+39 -5
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/adrg/xdg"
"github.com/anchore/grype/grype"
@@ -117,9 +118,40 @@ type Service struct {
dbCfg db.Config
}
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials, exceptions []string) (*models.PresenterConfig, error) {
if exceptions == nil {
exceptions = []string{}
// Filter the remaing matches based on severity exceptions.
func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches match.Matches, store *store.Store) match.Matches {
filteredMatches := match.NewMatches()
for m := range remainingMatches.Enumerate() {
metadata, err := store.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
if err != nil {
continue
}
// Skip this match if the severity of this match is present in severityExceptions.
excludeSeverity := false
for _, sever := range severityExceptions {
if strings.ToUpper(metadata.Severity) == sever {
excludeSeverity = true
continue
}
}
if !excludeSeverity {
filteredMatches.Add(m)
}
}
return filteredMatches
}
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials, vulnerabilityExceptions, severityExceptions []string) (*models.PresenterConfig, error) {
if vulnerabilityExceptions == nil {
vulnerabilityExceptions = []string{}
}
if severityExceptions == nil {
severityExceptions = []string{}
}
var err error
@@ -139,7 +171,7 @@ func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCred
}
var ignoreRules []match.IgnoreRule
for _, exception := range exceptions {
for _, exception := range vulnerabilityExceptions {
rule := match.IgnoreRule{
Vulnerability: exception,
}
@@ -159,8 +191,10 @@ func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCred
}
}
filteredMatches := filterMatchesBasedOnSeverity(severityExceptions, *remainingMatches, store)
pb := models.PresenterConfig{
Matches: *remainingMatches,
Matches: filteredMatches,
IgnoredMatches: ignoredMatches,
Packages: packages,
Context: pkgContext,
+1 -1
View File
@@ -72,7 +72,7 @@ func TestScan(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
scanResults, err := svc.Scan(ctx, tc.image, creds, tc.exceptions)
scanResults, err := svc.Scan(ctx, tc.image, creds, tc.exceptions, nil)
assert.NoError(t, err)
assert.IsType(t, &models.PresenterConfig{}, scanResults)