@@ -476,41 +476,27 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru
476476 return nil
477477 }
478478 applicability := formats.Applicability {}
479- resultFound := false
480479 var applicabilityStatuses []jasutils.ApplicabilityStatus
481480 for _ , applicabilityRun := range applicabilityScanResults {
481+ // Get applicability information from the rule
482482 if rule := sarifutils .GetRuleById (applicabilityRun , jasutils .CveToApplicabilityRuleId (cveId )); rule != nil {
483483 applicability .ScannerDescription = sarifutils .GetRuleFullDescription (rule )
484484 applicability .UndeterminedReason = sarifutils .GetRuleUndeterminedReason (rule )
485- status := getApplicabilityStatusFromRule (rule )
486- if status != "" {
485+ if status := getApplicabilityStatusFromRule (rule ); status != jasutils .NotScanned {
487486 applicabilityStatuses = append (applicabilityStatuses , status )
488487 }
489488 }
490- cveResults := sarifutils .GetResultsByRuleId (jasutils .CveToApplicabilityRuleId (cveId ), applicabilityRun )
491- if len (cveResults ) == 0 {
492- continue
493- }
494- resultFound = true
495- for _ , result := range cveResults {
496- // Add new evidences from locations
489+ // Get applicability evidence from the results
490+ for _ , result := range sarifutils .GetResultsByRuleId (jasutils .CveToApplicabilityRuleId (cveId ), applicabilityRun ) {
497491 for _ , location := range result .Locations {
498492 if evidence := getEvidence (result , location , applicabilityRun .Invocations ... ); evidence != nil {
499493 applicability .Evidence = append (applicability .Evidence , * evidence )
500494 }
501495 }
502496 }
503497 }
504- switch {
505- case len (applicabilityStatuses ) > 0 :
506- applicability .Status = string (GetFinalApplicabilityStatus (applicabilityStatuses ))
507- case ! resultFound :
508- applicability .Status = string (jasutils .ApplicabilityUndetermined )
509- case len (applicability .Evidence ) == 0 :
510- applicability .Status = string (jasutils .NotApplicable )
511- default :
512- applicability .Status = string (jasutils .Applicable )
513- }
498+ // Calculate final applicability status
499+ applicability .Status = GetFinalApplicabilityStatus (true , applicabilityStatuses ).String ()
514500 return & applicability
515501}
516502
@@ -551,16 +537,13 @@ func GetApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sar
551537 if ! entitledForJas || len (applicabilityScanResults ) == 0 {
552538 return jasutils .NotScanned
553539 }
554- if len (cves ) == 0 {
555- return jasutils .NotCovered
556- }
557540 var applicableStatuses []jasutils.ApplicabilityStatus
558541 for _ , cve := range cves {
559542 if cve .Applicability != nil {
560543 applicableStatuses = append (applicableStatuses , jasutils .ApplicabilityStatus (cve .Applicability .Status ))
561544 }
562545 }
563- return GetFinalApplicabilityStatus (applicableStatuses )
546+ return GetFinalApplicabilityStatus (true , applicableStatuses )
564547}
565548
566549func getApplicabilityStatusFromRule (rule * sarif.ReportingDescriptor ) jasutils.ApplicabilityStatus {
@@ -569,7 +552,7 @@ func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.Ap
569552 if ! ok {
570553 log .Debug (fmt .Sprintf ("Failed to get applicability status from rule properties for rule_id %s" , sarifutils .GetRuleId (rule )))
571554 }
572- switch status {
555+ switch strings . ToLower ( status ) {
573556 case "not_covered" :
574557 return jasutils .NotCovered
575558 case "undetermined" :
@@ -632,45 +615,58 @@ func shouldDisqualifyEvidence(components map[string]services.Component, evidence
632615 return
633616}
634617
635- // If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned
636- // If at least one cve is applicable -> final value is applicable
637- // Else if at least one cve is undetermined -> final value is undetermined
638- // Else if at least one cve is missing context -> final value is missing context
639- // Else if all cves are not covered -> final value is not covered
640- // Else (case when all cves aren't applicable) -> final value is not applicable
641- func GetFinalApplicabilityStatus (applicabilityStatuses []jasutils.ApplicabilityStatus ) jasutils.ApplicabilityStatus {
642- if len (applicabilityStatuses ) == 0 {
618+ // If we don't get any statues (not scanned are ignored) it means the applicability -> scanner didn't run = not scanned, scanner run = not covered
619+ // If only one status -> final value is that status
620+ // Else If at least one status is applicable -> final value is applicable
621+ // Else if at least one status is undetermined -> final value is undetermined
622+ // Else if at least one status is missing context -> final value is missing context
623+ // Else if all statuses are not applicable -> final value is not applicable
624+ // Else (at least one status is not covered) -> final value is not covered
625+ func GetFinalApplicabilityStatus (hasContextualAnalysisRun bool , applicabilityStatuses []jasutils.ApplicabilityStatus ) jasutils.ApplicabilityStatus {
626+ actualStatuses := []jasutils.ApplicabilityStatus {}
627+ for _ , status := range applicabilityStatuses {
628+ if status != jasutils .NotScanned {
629+ actualStatuses = append (actualStatuses , status )
630+ }
631+ }
632+ if len (actualStatuses ) == 0 {
633+ if hasContextualAnalysisRun {
634+ // Run exists but no statuses found
635+ return jasutils .NotCovered
636+ }
637+ // No runs so not scanned
643638 return jasutils .NotScanned
644639 }
640+ if len (actualStatuses ) == 1 {
641+ // Only one status so return it directly
642+ return actualStatuses [0 ]
643+ }
645644 foundUndetermined := false
646645 foundMissingContext := false
647- foundNotCovered := false
648- for _ , status := range applicabilityStatuses {
646+ allNotApplicable := true
647+ for _ , status := range actualStatuses {
649648 if status == jasutils .Applicable {
649+ // Has at least one applicable status
650650 return jasutils .Applicable
651651 }
652- if status == jasutils .ApplicabilityUndetermined {
653- foundUndetermined = true
654- }
655- if status == jasutils .MissingContext {
656- foundMissingContext = true
657- }
658- if status == jasutils .NotCovered {
659- foundNotCovered = true
660- }
661-
652+ foundUndetermined = foundUndetermined || (status == jasutils .ApplicabilityUndetermined )
653+ foundMissingContext = foundMissingContext || (status == jasutils .MissingContext )
654+ allNotApplicable = allNotApplicable && (status == jasutils .NotApplicable )
662655 }
663656 if foundUndetermined {
657+ // Has at least one undetermined status and no applicable status
664658 return jasutils .ApplicabilityUndetermined
665659 }
666660 if foundMissingContext {
661+ // Has at least one missing context status and no applicable or undetermined status
667662 return jasutils .MissingContext
668663 }
669- if foundNotCovered {
670- return jasutils .NotCovered
664+ if allNotApplicable {
665+ // All statuses are not applicable
666+ return jasutils .NotApplicable
671667 }
672-
673- return jasutils .NotApplicable
668+ // At least one status is not covered (and no applicable, undetermined or missing context and not all are not applicable)
669+ return jasutils .NotCovered
674670}
675671
676672func GetJasResultApplicability (result * sarif.Result ) * formats.Applicability {
0 commit comments