From 8f30a0a82ddef62ff9cb01f50623dd05460490eb Mon Sep 17 00:00:00 2001 From: Shachar Menashe <92059693+srmish-jfrog@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:08:28 +0200 Subject: [PATCH] `indirect-cve-whitelist` added to the Applicability Scaner YAML configuration (#1049) --- .../jas/applicability/applicabilitymanager.go | 73 ++++++++++--------- .../applicabilitymanager_test.go | 35 ++++++--- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/xray/commands/audit/jas/applicability/applicabilitymanager.go b/xray/commands/audit/jas/applicability/applicabilitymanager.go index 7ecdc5d44..9acf32ef9 100644 --- a/xray/commands/audit/jas/applicability/applicabilitymanager.go +++ b/xray/commands/audit/jas/applicability/applicabilitymanager.go @@ -26,6 +26,7 @@ const ( type ApplicabilityScanManager struct { applicabilityScanResults []*sarif.Run directDependenciesCves []string + indirectDependenciesCves []string xrayResults []services.ScanResponse scanner *jas.JasScanner thirdPartyScan bool @@ -88,10 +89,11 @@ func newApplicabilityScanManagerCves(xrayScanResults []services.ScanResponse, cv } func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, directDependencies []string, scanner *jas.JasScanner, thirdPartyScan bool) (manager *ApplicabilityScanManager) { - directDependenciesCves := extractDirectDependenciesCvesFromScan(xrayScanResults, directDependencies) + directDependenciesCves, indirectDependenciesCves := extractDependenciesCvesFromScan(xrayScanResults, directDependencies) return &ApplicabilityScanManager{ applicabilityScanResults: []*sarif.Run{}, directDependenciesCves: directDependenciesCves, + indirectDependenciesCves: indirectDependenciesCves, xrayResults: xrayScanResults, scanner: scanner, thirdPartyScan: thirdPartyScan, @@ -99,32 +101,37 @@ func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, direct } } -// This function gets a list of xray scan responses that contain direct and indirect vulnerabilities and returns only direct -// vulnerabilities of the scanned project, ignoring indirect vulnerabilities -func extractDirectDependenciesCvesFromScan(xrayScanResults []services.ScanResponse, directDependencies []string) []string { - directsCves := datastructures.MakeSet[string]() +func addCvesToSet(cves []services.Cve, set *datastructures.Set[string]) { + for _, cve := range cves { + if cve.Id != "" { + set.Add(cve.Id) + } + } +} + +// This function gets a list of xray scan responses that contain direct and indirect vulnerabilities and returns separate +// lists of the direct and indirect CVEs +func extractDependenciesCvesFromScan(xrayScanResults []services.ScanResponse, directDependencies []string) (directCves []string, indirectCves []string) { + directCvesSet := datastructures.MakeSet[string]() + indirectCvesSet := datastructures.MakeSet[string]() for _, scanResult := range xrayScanResults { for _, vulnerability := range scanResult.Vulnerabilities { if isDirectComponents(maps.Keys(vulnerability.Components), directDependencies) { - for _, cve := range vulnerability.Cves { - if cve.Id != "" { - directsCves.Add(cve.Id) - } - } + addCvesToSet(vulnerability.Cves, directCvesSet) + } else { + addCvesToSet(vulnerability.Cves, indirectCvesSet) } } for _, violation := range scanResult.Violations { if isDirectComponents(maps.Keys(violation.Components), directDependencies) { - for _, cve := range violation.Cves { - if cve.Id != "" { - directsCves.Add(cve.Id) - } - } + addCvesToSet(violation.Cves, directCvesSet) + } else { + addCvesToSet(violation.Cves, indirectCvesSet) } } } - return directsCves.ToSlice() + return directCvesSet.ToSlice(), indirectCvesSet.ToSlice() } func isDirectComponents(components []string, directDependencies []string) bool { @@ -159,12 +166,8 @@ func (asm *ApplicabilityScanManager) Run(module jfrogappsconfig.Module) (err err return } -func (asm *ApplicabilityScanManager) directDependenciesExist() bool { - return len(asm.directDependenciesCves) > 0 -} - func (asm *ApplicabilityScanManager) shouldRunApplicabilityScan(technologies []coreutils.Technology) bool { - return asm.directDependenciesExist() && coreutils.ContainsApplicabilityScannableTech(technologies) + return coreutils.ContainsApplicabilityScannableTech(technologies) } type applicabilityScanConfig struct { @@ -172,13 +175,14 @@ type applicabilityScanConfig struct { } type scanConfiguration struct { - Roots []string `yaml:"roots"` - Output string `yaml:"output"` - Type string `yaml:"type"` - GrepDisable bool `yaml:"grep-disable"` - CveWhitelist []string `yaml:"cve-whitelist"` - SkippedDirs []string `yaml:"skipped-folders"` - ScanType string `yaml:"scantype"` + Roots []string `yaml:"roots"` + Output string `yaml:"output"` + Type string `yaml:"type"` + GrepDisable bool `yaml:"grep-disable"` + CveWhitelist []string `yaml:"cve-whitelist"` + IndirectCveWhitelist []string `yaml:"indirect-cve-whitelist"` + SkippedDirs []string `yaml:"skipped-folders"` + ScanType string `yaml:"scantype"` } func (asm *ApplicabilityScanManager) createConfigFile(module jfrogappsconfig.Module) error { @@ -194,12 +198,13 @@ func (asm *ApplicabilityScanManager) createConfigFile(module jfrogappsconfig.Mod configFileContent := applicabilityScanConfig{ Scans: []scanConfiguration{ { - Roots: roots, - Output: asm.scanner.ResultsFileName, - Type: asm.commandType, - GrepDisable: false, - CveWhitelist: asm.directDependenciesCves, - SkippedDirs: excludePatterns, + Roots: roots, + Output: asm.scanner.ResultsFileName, + Type: asm.commandType, + GrepDisable: false, + CveWhitelist: asm.directDependenciesCves, + IndirectCveWhitelist: asm.indirectDependenciesCves, + SkippedDirs: excludePatterns, }, }, } diff --git a/xray/commands/audit/jas/applicability/applicabilitymanager_test.go b/xray/commands/audit/jas/applicability/applicabilitymanager_test.go index 554909181..78f2e239d 100644 --- a/xray/commands/audit/jas/applicability/applicabilitymanager_test.go +++ b/xray/commands/audit/jas/applicability/applicabilitymanager_test.go @@ -172,7 +172,7 @@ func TestApplicabilityScanManager_ShouldRun_ScanResultsAreEmpty(t *testing.T) { applicabilityManager := newApplicabilityScanManager(nil, mockDirectDependencies, scanner, false) // Assert - eligible := applicabilityManager.shouldRunApplicabilityScan([]coreutils.Technology{coreutils.Npm}) + eligible := applicabilityManager.shouldRunApplicabilityScan([]coreutils.Technology{coreutils.Nuget}) assert.False(t, eligible) } @@ -188,23 +188,28 @@ func TestExtractXrayDirectViolations(t *testing.T) { } tests := []struct { directDependencies []string - cvesCount int + directCvesCount int + indirectCvesCount int }{ {directDependencies: []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency"}, - cvesCount: 2, + directCvesCount: 2, + indirectCvesCount: 0, }, // Vulnerability dependency, should be ignored by function {directDependencies: []string{"issueId_1_direct_dependency"}, - cvesCount: 0, + directCvesCount: 0, + indirectCvesCount: 2, }, {directDependencies: []string{}, - cvesCount: 0, + directCvesCount: 0, + indirectCvesCount: 2, }, } for _, test := range tests { - cves := extractDirectDependenciesCvesFromScan(xrayResponseForDirectViolationsTest, test.directDependencies) - assert.Len(t, cves, test.cvesCount) + directCves, indirectCves := extractDependenciesCvesFromScan(xrayResponseForDirectViolationsTest, test.directDependencies) + assert.Len(t, directCves, test.directCvesCount) + assert.Len(t, indirectCves, test.indirectCvesCount) } } @@ -228,23 +233,29 @@ func TestExtractXrayDirectVulnerabilities(t *testing.T) { } tests := []struct { directDependencies []string - cvesCount int + directCvesCount int + indirectCvesCount int }{ { directDependencies: []string{"issueId_1_direct_dependency"}, - cvesCount: 3, + directCvesCount: 3, + indirectCvesCount: 2, }, { directDependencies: []string{"issueId_2_direct_dependency"}, - cvesCount: 2, + directCvesCount: 2, + indirectCvesCount: 3, }, {directDependencies: []string{}, - cvesCount: 0, + directCvesCount: 0, + indirectCvesCount: 5, }, } for _, test := range tests { - assert.Len(t, extractDirectDependenciesCvesFromScan(xrayResponseForDirectVulnerabilitiesTest, test.directDependencies), test.cvesCount) + directCves, indirectCves := extractDependenciesCvesFromScan(xrayResponseForDirectVulnerabilitiesTest, test.directDependencies) + assert.Len(t, directCves, test.directCvesCount) + assert.Len(t, indirectCves, test.indirectCvesCount) } }