diff --git a/formats/sarifutils/sarifutils.go b/formats/sarifutils/sarifutils.go index 6b183cb5..42f47895 100644 --- a/formats/sarifutils/sarifutils.go +++ b/formats/sarifutils/sarifutils.go @@ -395,6 +395,17 @@ func GetRuleShortDescriptionText(rule *sarif.ReportingDescriptor) string { return "" } +func GetRuleProperty(key string, rule *sarif.ReportingDescriptor) string { + if rule != nil && rule.Properties != nil && rule.Properties[key] != nil { + prop, ok := rule.Properties[key].(string) + if !ok { + return "" + } + return prop + } + return "" +} + func GetRunRules(run *sarif.Run) []*sarif.ReportingDescriptor { if run != nil && run.Tool.Driver != nil { return run.Tool.Driver.Rules diff --git a/formats/sarifutils/test_sarifutils.go b/formats/sarifutils/test_sarifutils.go index 6848849a..4d557fb8 100644 --- a/formats/sarifutils/test_sarifutils.go +++ b/formats/sarifutils/test_sarifutils.go @@ -1,6 +1,8 @@ package sarifutils -import "github.com/owenrumney/go-sarif/v2/sarif" +import ( + "github.com/owenrumney/go-sarif/v2/sarif" +) func CreateRunWithDummyResultsInWd(wd string, results ...*sarif.Result) *sarif.Run { return createRunWithDummyResults("", results...).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}) @@ -33,14 +35,19 @@ func createRunWithDummyResults(toolName string, results ...*sarif.Result) *sarif return run } -func CreateRunWithDummyResultAndRuleProperties(property, value string, result *sarif.Result) *sarif.Run { +func CreateRunWithDummyResultAndRuleProperties(result *sarif.Result, properties, values []string) *sarif.Run { + if len(properties) != len(values) { + return nil + } run := sarif.NewRunWithInformationURI("", "") if result.RuleID != nil { run.AddRule(*result.RuleID) } run.AddResult(result) - run.Tool.Driver.Rules[0].Properties = make(sarif.Properties) - run.Tool.Driver.Rules[0].Properties[property] = value + run.Tool.Driver.Rules[0].Properties = make(sarif.Properties, len(properties)) + for index := range properties { + run.Tool.Driver.Rules[0].Properties[properties[index]] = values[index] + } return run } diff --git a/formats/simplejsonapi.go b/formats/simplejsonapi.go index 26ec121b..31d2bbfe 100644 --- a/formats/simplejsonapi.go +++ b/formats/simplejsonapi.go @@ -96,6 +96,7 @@ type CveRow struct { type Applicability struct { Status string `json:"status"` ScannerDescription string `json:"scannerDescription,omitempty"` + UndeterminedReason string `json:"undeterminedReason,omitempty"` Evidence []Evidence `json:"evidence,omitempty"` } diff --git a/utils/resultstable.go b/utils/resultstable.go index 06623eac..9594140f 100644 --- a/utils/resultstable.go +++ b/utils/resultstable.go @@ -937,6 +937,7 @@ func getCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cveId)); rule != nil { applicability.ScannerDescription = sarifutils.GetRuleFullDescriptionText(rule) status := getApplicabilityStatusFromRule(rule) + applicability.UndeterminedReason = GetRuleUndeterminedReason(rule) if status != "" { applicabilityStatuses = append(applicabilityStatuses, status) } @@ -1025,6 +1026,10 @@ func extractDependencyNameFromComponent(key string, techIdentifier string) (depe return } +func GetRuleUndeterminedReason(rule *sarif.ReportingDescriptor) string { + return sarifutils.GetRuleProperty("undetermined_reason", rule) +} + func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { if rule.Properties["applicability"] != nil { status, ok := rule.Properties["applicability"].(string) diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go index d0e25ba2..cad2e0e3 100644 --- a/utils/resultstable_test.go +++ b/utils/resultstable_test.go @@ -682,9 +682,9 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - applicable wins all statuses", scanResults: &ExtendedScanResults{ ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"applicable"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_applicable"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve3"), []string{"applicability"}, []string{"not_covered"}), }, EntitledForJas: true}, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, @@ -698,8 +698,8 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - not covered wins not applicable", scanResults: &ExtendedScanResults{ ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"not_covered"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_applicable"}), }, EntitledForJas: true}, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, @@ -712,8 +712,8 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - undetermined wins not covered", scanResults: &ExtendedScanResults{ ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"not_covered"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"undetermined"}), }, EntitledForJas: true}, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, @@ -722,6 +722,19 @@ func TestGetApplicableCveValue(t *testing.T) { {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.ApplicabilityUndetermined.String()}}, }, }, + { + name: "undetermined with undetermined reason", + scanResults: &ExtendedScanResults{ + ApplicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability", "undetermined_reason"}, []string{"undetermined", "however"}), + }, + EntitledForJas: true}, + cves: []services.Cve{{Id: "testCve2"}}, + expectedResult: jasutils.ApplicabilityUndetermined, + expectedCves: []formats.CveRow{ + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.ApplicabilityUndetermined.String(), UndeterminedReason: "however"}}, + }, + }, } for _, testCase := range testCases { diff --git a/utils/resultwriter_test.go b/utils/resultwriter_test.go index d009c777..a06c6ad9 100644 --- a/utils/resultwriter_test.go +++ b/utils/resultwriter_test.go @@ -674,7 +674,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, subScan: ScaScan, input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), []string{"applicability"}, []string{"applicable"}). WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), }, @@ -684,10 +684,9 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { ), }, expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", - sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), - ), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), + ), []string{"applicability"}, []string{"applicable"}, ).WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), }),