Skip to content

Commit

Permalink
Improve applicability scan code (#926)
Browse files Browse the repository at this point in the history
  • Loading branch information
sverdlov93 authored Sep 3, 2023
1 parent b9d14a8 commit 49b48ba
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 302 deletions.
61 changes: 30 additions & 31 deletions xray/audit/jas/applicabilitymanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
// bool: true if the user is entitled to the applicability scan, false otherwise.
// error: An error object (if any).
func getApplicabilityScanResults(xrayResults []services.ScanResponse, directDependencies []string,
scannedTechnologies []coreutils.Technology, scanner *AdvancedSecurityScanner) (results map[string]string, err error) {
scannedTechnologies []coreutils.Technology, scanner *AdvancedSecurityScanner) (results map[string]utils.ApplicabilityStatus, err error) {
applicabilityScanManager := newApplicabilityScanManager(xrayResults, directDependencies, scanner)
if !applicabilityScanManager.shouldRunApplicabilityScan(scannedTechnologies) {
log.Debug("The technologies that have been scanned are currently not supported for contextual analysis scanning, or we couldn't find any vulnerable direct dependencies. Skipping....")
Expand All @@ -45,16 +45,16 @@ func getApplicabilityScanResults(xrayResults []services.ScanResponse, directDepe
}

type ApplicabilityScanManager struct {
applicabilityScanResults map[string]string
directDependenciesCves *datastructures.Set[string]
applicabilityScanResults map[string]utils.ApplicabilityStatus
directDependenciesCves []string
xrayResults []services.ScanResponse
scanner *AdvancedSecurityScanner
}

func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, directDependencies []string, scanner *AdvancedSecurityScanner) (manager *ApplicabilityScanManager) {
directDependenciesCves := extractDirectDependenciesCvesFromScan(xrayScanResults, directDependencies)
return &ApplicabilityScanManager{
applicabilityScanResults: map[string]string{},
applicabilityScanResults: map[string]utils.ApplicabilityStatus{},
directDependenciesCves: directDependenciesCves,
xrayResults: xrayScanResults,
scanner: scanner,
Expand All @@ -63,7 +63,7 @@ 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) *datastructures.Set[string] {
func extractDirectDependenciesCvesFromScan(xrayScanResults []services.ScanResponse, directDependencies []string) []string {
directsCves := datastructures.MakeSet[string]()
for _, scanResult := range xrayScanResults {
for _, vulnerability := range scanResult.Vulnerabilities {
Expand All @@ -86,7 +86,7 @@ func extractDirectDependenciesCvesFromScan(xrayScanResults []services.ScanRespon
}
}

return directsCves
return directsCves.ToSlice()
}

func isDirectComponents(components []string, directDependencies []string) bool {
Expand All @@ -110,7 +110,7 @@ func (a *ApplicabilityScanManager) Run(wd string) (err error) {
if err = a.runAnalyzerManager(); err != nil {
return
}
var workingDirResults map[string]string
var workingDirResults map[string]utils.ApplicabilityStatus
if workingDirResults, err = a.getScanResults(); err != nil {
return
}
Expand All @@ -121,7 +121,7 @@ func (a *ApplicabilityScanManager) Run(wd string) (err error) {
}

func (a *ApplicabilityScanManager) directDependenciesExist() bool {
return a.directDependenciesCves.Size() > 0
return len(a.directDependenciesCves) > 0
}

func (a *ApplicabilityScanManager) shouldRunApplicabilityScan(technologies []coreutils.Technology) bool {
Expand Down Expand Up @@ -149,7 +149,7 @@ func (a *ApplicabilityScanManager) createConfigFile(workingDir string) error {
Output: a.scanner.resultsFileName,
Type: applicabilityScanType,
GrepDisable: false,
CveWhitelist: a.directDependenciesCves.ToSlice(),
CveWhitelist: a.directDependenciesCves,
SkippedDirs: skippedDirs,
},
},
Expand All @@ -163,37 +163,36 @@ func (a *ApplicabilityScanManager) runAnalyzerManager() error {
return a.scanner.analyzerManager.Exec(a.scanner.configFileName, applicabilityScanCommand, filepath.Dir(a.scanner.analyzerManager.AnalyzerManagerFullPath), a.scanner.serverDetails)
}

func (a *ApplicabilityScanManager) getScanResults() (map[string]string, error) {
report, err := sarif.Open(a.scanner.resultsFileName)
if errorutils.CheckError(err) != nil {
return nil, err
}
var fullVulnerabilitiesList []*sarif.Result
if len(report.Runs) > 0 {
fullVulnerabilitiesList = report.Runs[0].Results
func (a *ApplicabilityScanManager) getScanResults() (applicabilityResults map[string]utils.ApplicabilityStatus, err error) {
applicabilityResults = make(map[string]utils.ApplicabilityStatus, len(a.directDependenciesCves))
for _, cve := range a.directDependenciesCves {
applicabilityResults[cve] = utils.ApplicabilityUndetermined
}

applicabilityScanResults := make(map[string]string)
for _, cve := range a.directDependenciesCves.ToSlice() {
applicabilityScanResults[cve] = utils.ApplicabilityUndeterminedStringValue
report, err := sarif.Open(a.scanner.resultsFileName)
if errorutils.CheckError(err) != nil || len(report.Runs) == 0 {
return
}

for _, vulnerability := range fullVulnerabilitiesList {
applicableVulnerabilityName := getVulnerabilityName(*vulnerability.RuleID)
if isVulnerabilityApplicable(vulnerability) {
applicabilityScanResults[applicableVulnerabilityName] = utils.ApplicableStringValue
} else {
applicabilityScanResults[applicableVulnerabilityName] = utils.NotApplicableStringValue
// Applicability results contains one run only
for _, sarifResult := range report.Runs[0].Results {
cve := getCveFromRuleId(*sarifResult.RuleID)
if _, exists := applicabilityResults[cve]; !exists {
err = errorutils.CheckErrorf("received unexpected CVE: '%s' from RuleID: '%s' that does not exists on the requested CVEs list", cve, *sarifResult.RuleID)
return
}
applicabilityResults[cve] = resultKindToApplicabilityStatus(sarifResult.Kind)
}
return applicabilityScanResults, nil
return
}

// Gets a result of one CVE from the scanner, and returns true if the CVE is applicable, false otherwise
func isVulnerabilityApplicable(result *sarif.Result) bool {
return !(result.Kind != nil && *result.Kind == "pass")
func resultKindToApplicabilityStatus(kind *string) utils.ApplicabilityStatus {
if !(kind != nil && *kind == "pass") {
return utils.Applicable
}
return utils.NotApplicable
}

func getVulnerabilityName(sarifRuleId string) string {
func getCveFromRuleId(sarifRuleId string) string {
return strings.TrimPrefix(sarifRuleId, "applic_")
}
24 changes: 12 additions & 12 deletions xray/audit/jas/applicabilitymanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestNewApplicabilityScanManager_InputIsValid(t *testing.T) {
if assert.NotNil(t, applicabilityManager) {
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
assert.Equal(t, 5, applicabilityManager.directDependenciesCves.Size())
assert.Len(t, applicabilityManager.directDependenciesCves, 5)
}
}

Expand All @@ -37,7 +37,7 @@ func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) {
assert.Len(t, applicabilityManager.scanner.workingDirs, 1)
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
assert.Equal(t, applicabilityManager.directDependenciesCves.Size(), 0)
assert.Empty(t, applicabilityManager.directDependenciesCves)
}
}

Expand Down Expand Up @@ -73,7 +73,7 @@ func TestNewApplicabilityScanManager_NoDirectDependenciesInScan(t *testing.T) {
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
// Non-direct dependencies should not be added
assert.Equal(t, 0, applicabilityManager.directDependenciesCves.Size())
assert.Empty(t, applicabilityManager.directDependenciesCves)
}
}

Expand All @@ -88,7 +88,7 @@ func TestNewApplicabilityScanManager_MultipleDependencyTrees(t *testing.T) {
if assert.NotNil(t, applicabilityManager) {
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
assert.Equal(t, 5, applicabilityManager.directDependenciesCves.Size())
assert.Len(t, applicabilityManager.directDependenciesCves, 5)
}
}

Expand All @@ -114,7 +114,7 @@ func TestNewApplicabilityScanManager_ViolationsDontExistInResults(t *testing.T)
if assert.NotNil(t, applicabilityManager) {
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
assert.Equal(t, 3, applicabilityManager.directDependenciesCves.Size())
assert.Len(t, applicabilityManager.directDependenciesCves, 3)
}
}

Expand All @@ -140,7 +140,7 @@ func TestNewApplicabilityScanManager_VulnerabilitiesDontExist(t *testing.T) {
if assert.NotNil(t, applicabilityManager) {
assert.NotEmpty(t, applicabilityManager.scanner.configFileName)
assert.NotEmpty(t, applicabilityManager.scanner.resultsFileName)
assert.Equal(t, 2, applicabilityManager.directDependenciesCves.Size())
assert.Len(t, applicabilityManager.directDependenciesCves, 2)
}
}

Expand Down Expand Up @@ -196,7 +196,7 @@ func TestExtractXrayDirectViolations(t *testing.T) {

for _, test := range tests {
cves := extractDirectDependenciesCvesFromScan(xrayResponseForDirectViolationsTest, test.directDependencies)
assert.Equal(t, test.cvesCount, cves.Size())
assert.Len(t, cves, test.cvesCount)
}
}

Expand Down Expand Up @@ -236,7 +236,7 @@ func TestExtractXrayDirectVulnerabilities(t *testing.T) {
}

for _, test := range tests {
assert.Equal(t, test.cvesCount, extractDirectDependenciesCvesFromScan(xrayResponseForDirectVulnerabilitiesTest, test.directDependencies).Size())
assert.Len(t, extractDirectDependenciesCvesFromScan(xrayResponseForDirectVulnerabilitiesTest, test.directDependencies), test.cvesCount)
}
}

Expand Down Expand Up @@ -279,7 +279,7 @@ func TestParseResults_EmptyResults_AllCvesShouldGetUnknown(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.ApplicabilityUndeterminedStringValue, cveResult)
assert.Equal(t, utils.ApplicabilityUndetermined, cveResult)
}
}

Expand All @@ -296,8 +296,8 @@ func TestParseResults_ApplicableCveExist(t *testing.T) {
// Assert
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
assert.Equal(t, utils.ApplicableStringValue, results["testCve1"])
assert.Equal(t, utils.NotApplicableStringValue, results["testCve3"])
assert.Equal(t, utils.Applicable, results["testCve1"])
assert.Equal(t, utils.NotApplicable, results["testCve3"])
}

func TestParseResults_AllCvesNotApplicable(t *testing.T) {
Expand All @@ -314,7 +314,7 @@ func TestParseResults_AllCvesNotApplicable(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.NotApplicableStringValue, cveResult)
assert.Equal(t, utils.NotApplicable, cveResult)
}
}

Expand Down
Loading

0 comments on commit 49b48ba

Please sign in to comment.