From 7931ffaf5dd5af40f39e6d50b03a757128d52fbe Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Mon, 11 Sep 2023 23:02:13 +0300 Subject: [PATCH] Fix sarif relative path (#944) --- xray/formats/conversion.go | 7 +-- xray/formats/simplejsonapi.go | 21 +++++---- xray/utils/resultstable.go | 85 +++++++++++++++++++++++------------ xray/utils/sarifutils.go | 18 +++++--- 4 files changed, 85 insertions(+), 46 deletions(-) diff --git a/xray/formats/conversion.go b/xray/formats/conversion.go index f210ae708..624791dfe 100644 --- a/xray/formats/conversion.go +++ b/xray/formats/conversion.go @@ -1,6 +1,7 @@ package formats import ( + "strconv" "strings" ) @@ -145,7 +146,7 @@ func ConvertToSecretsTableRow(rows []SourceCodeRow) (tableRows []secretsTableRow tableRows = append(tableRows, secretsTableRow{ severity: rows[i].Severity, file: rows[i].File, - lineColumn: rows[i].LineColumn, + lineColumn: (strconv.Itoa(rows[i].StartLine) + ":" + strconv.Itoa(rows[i].StartColumn)), text: rows[i].Snippet, }) } @@ -157,7 +158,7 @@ func ConvertToIacTableRow(rows []SourceCodeRow) (tableRows []iacTableRow) { tableRows = append(tableRows, iacTableRow{ severity: rows[i].Severity, file: rows[i].File, - lineColumn: rows[i].LineColumn, + lineColumn: (strconv.Itoa(rows[i].StartLine) + ":" + strconv.Itoa(rows[i].StartColumn)), text: rows[i].Snippet, }) } @@ -169,7 +170,7 @@ func ConvertToSastTableRow(rows []SourceCodeRow) (tableRows []sastTableRow) { tableRows = append(tableRows, sastTableRow{ severity: rows[i].Severity, file: rows[i].File, - lineColumn: rows[i].LineColumn, + lineColumn: (strconv.Itoa(rows[i].StartLine) + ":" + strconv.Itoa(rows[i].StartColumn)), text: rows[i].Snippet, }) } diff --git a/xray/formats/simplejsonapi.go b/xray/formats/simplejsonapi.go index e547e09c8..be4b7cc1a 100644 --- a/xray/formats/simplejsonapi.go +++ b/xray/formats/simplejsonapi.go @@ -77,15 +77,20 @@ type OperationalRiskViolationRow struct { type SourceCodeRow struct { Severity string `json:"severity"` SeverityNumValue int `json:"-"` // For sorting - SourceCodeLocationRow - Type string `json:"type"` - CodeFlow [][]SourceCodeLocationRow `json:"codeFlow,omitempty"` + Location + Type string `json:"type"` + Finding string `json:"finding,omitempty"` + ScannerDescription string `json:"scannerDescription,omitempty"` + CodeFlow [][]Location `json:"codeFlow,omitempty"` } -type SourceCodeLocationRow struct { - File string `json:"file"` - LineColumn string `json:"lineColumn"` - Snippet string `json:"snippet"` +type Location struct { + File string `json:"file"` + StartLine int `json:"startLine,omitempty"` + StartColumn int `json:"startColumn,omitempty"` + EndLine int `json:"endLine,omitempty"` + EndColumn int `json:"endColumn,omitempty"` + Snippet string `json:"snippet,omitempty"` } type ComponentRow struct { @@ -107,7 +112,7 @@ type Applicability struct { } type Evidence struct { - SourceCodeLocationRow + Location Reason string `json:"reason,omitempty"` } diff --git a/xray/utils/resultstable.go b/xray/utils/resultstable.go index 49b124791..44909fd11 100644 --- a/xray/utils/resultstable.go +++ b/xray/utils/resultstable.go @@ -308,11 +308,15 @@ func prepareSecrets(secrets []*sarif.Run, isTable bool) []formats.SourceCodeRow secretsRows = append(secretsRows, formats.SourceCodeRow{ Severity: currSeverity.printableTitle(isTable), + Finding: GetResultMsgText(secret), SeverityNumValue: currSeverity.numValue, - SourceCodeLocationRow: formats.SourceCodeLocationRow{ - File: GetLocationFileName(location), - LineColumn: GetStartLocationInFile(location), - Snippet: GetLocationSnippet(location), + Location: formats.Location{ + File: GetLocationFileName(location), + StartLine: GetLocationStartLine(location), + StartColumn: GetLocationStartColumn(location), + EndLine: GetLocationEndLine(location), + EndColumn: GetLocationEndColumn(location), + Snippet: GetLocationSnippet(location), }, Type: *secret.RuleID, }, @@ -347,16 +351,25 @@ func prepareIacs(iacs []*sarif.Run, isTable bool) []formats.SourceCodeRow { var iacRows []formats.SourceCodeRow for _, iacRun := range iacs { for _, iac := range iacRun.Results { + scannerDescription := "" + if rule, err := iacRun.GetRuleById(*iac.RuleID); err == nil { + scannerDescription = GetRuleFullDescription(rule) + } currSeverity := GetSeverity(GetResultSeverity(iac), Applicable) for _, location := range iac.Locations { iacRows = append(iacRows, formats.SourceCodeRow{ - Severity: currSeverity.printableTitle(isTable), - SeverityNumValue: currSeverity.numValue, - SourceCodeLocationRow: formats.SourceCodeLocationRow{ - File: GetLocationFileName(location), - LineColumn: GetStartLocationInFile(location), - Snippet: GetResultMsgText(iac), + Severity: currSeverity.printableTitle(isTable), + Finding: GetResultMsgText(iac), + ScannerDescription: scannerDescription, + SeverityNumValue: currSeverity.numValue, + Location: formats.Location{ + File: GetLocationFileName(location), + StartLine: GetLocationStartLine(location), + StartColumn: GetLocationStartColumn(location), + EndLine: GetLocationEndLine(location), + EndColumn: GetLocationEndColumn(location), + Snippet: GetLocationSnippet(location), }, Type: *iac.RuleID, }, @@ -390,18 +403,26 @@ func prepareSast(sasts []*sarif.Run, isTable bool) []formats.SourceCodeRow { var sastRows []formats.SourceCodeRow for _, sastRun := range sasts { for _, sast := range sastRun.Results { + scannerDescription := "" + if rule, err := sastRun.GetRuleById(*sast.RuleID); err == nil { + scannerDescription = GetRuleFullDescription(rule) + } currSeverity := GetSeverity(GetResultSeverity(sast), Applicable) - flows := toSourceCodeCodeFlowRow(sast.CodeFlows, isTable) for _, location := range sast.Locations { sastRows = append(sastRows, formats.SourceCodeRow{ - Severity: currSeverity.printableTitle(isTable), - SeverityNumValue: currSeverity.numValue, - SourceCodeLocationRow: formats.SourceCodeLocationRow{ - File: GetLocationFileName(location), - LineColumn: GetStartLocationInFile(location), - Snippet: GetResultMsgText(sast), + Severity: currSeverity.printableTitle(isTable), + Finding: GetResultMsgText(sast), + ScannerDescription: scannerDescription, + SeverityNumValue: currSeverity.numValue, + Location: formats.Location{ + File: GetLocationFileName(location), + StartLine: GetLocationStartLine(location), + StartColumn: GetLocationStartColumn(location), + EndLine: GetLocationEndLine(location), + EndColumn: GetLocationEndColumn(location), + Snippet: GetLocationSnippet(location), }, Type: *sast.RuleID, CodeFlow: flows, @@ -418,19 +439,22 @@ func prepareSast(sasts []*sarif.Run, isTable bool) []formats.SourceCodeRow { return sastRows } -func toSourceCodeCodeFlowRow(flows []*sarif.CodeFlow, isTable bool) (flowRows [][]formats.SourceCodeLocationRow) { +func toSourceCodeCodeFlowRow(flows []*sarif.CodeFlow, isTable bool) (flowRows [][]formats.Location) { if isTable { // Not displaying in table return } for _, codeFlow := range flows { for _, stackTrace := range codeFlow.ThreadFlows { - rowFlow := []formats.SourceCodeLocationRow{} + rowFlow := []formats.Location{} for _, stackTraceEntry := range stackTrace.Locations { - rowFlow = append(rowFlow, formats.SourceCodeLocationRow{ - File: GetLocationFileName(stackTraceEntry.Location), - LineColumn: GetStartLocationInFile(stackTraceEntry.Location), - Snippet: GetLocationSnippet(stackTraceEntry.Location), + rowFlow = append(rowFlow, formats.Location{ + File: GetLocationFileName(stackTraceEntry.Location), + StartLine: GetLocationStartLine(stackTraceEntry.Location), + StartColumn: GetLocationStartColumn(stackTraceEntry.Location), + EndLine: GetLocationEndLine(stackTraceEntry.Location), + EndColumn: GetLocationEndColumn(stackTraceEntry.Location), + Snippet: GetLocationSnippet(stackTraceEntry.Location), }) } flowRows = append(flowRows, rowFlow) @@ -920,7 +944,7 @@ func getApplicableCveValue(extendedResults *ExtendedScanResults, xrayCves []form } for _, relatedResult := range relatedResults { cveExistsInResult = true - if isApplicableResult(relatedResult) { + if IsApplicableResult(relatedResult) { return Applicable } } @@ -940,7 +964,7 @@ func getCveApplicability(cve formats.CveRow, applicabilityScanResults []*sarif.R continue } applicability = &formats.Applicability{} - if isApplicableResult(foundResult) { + if IsApplicableResult(foundResult) { applicability.Status = string(Applicable) } else { applicability.Status = string(NotApplicable) @@ -954,10 +978,13 @@ func getCveApplicability(cve formats.CveRow, applicabilityScanResults []*sarif.R // Add new evidences from locations for _, location := range foundResult.Locations { applicability.Evidence = append(applicability.Evidence, formats.Evidence{ - SourceCodeLocationRow: formats.SourceCodeLocationRow{ - File: GetLocationFileName(location), - LineColumn: GetStartLocationInFile(location), - Snippet: GetLocationSnippet(location), + Location: formats.Location{ + File: GetLocationFileName(location), + StartLine: GetLocationStartLine(location), + StartColumn: GetLocationStartColumn(location), + EndLine: GetLocationEndLine(location), + EndColumn: GetLocationEndColumn(location), + Snippet: GetLocationSnippet(location), }, Reason: GetResultMsgText(foundResult), }) diff --git a/xray/utils/sarifutils.go b/xray/utils/sarifutils.go index 2864d1335..623c727d6 100644 --- a/xray/utils/sarifutils.go +++ b/xray/utils/sarifutils.go @@ -91,12 +91,15 @@ func getRunInformationUri(run *sarif.Run) string { // Calculate new information that exists at the run and not at the source func GetDiffFromRun(sources []*sarif.Run, targets []*sarif.Run) (runWithNewOnly *sarif.Run) { // Combine - combinedSource := sarif.NewRunWithInformationURI(sources[0].Tool.Driver.Name, getRunInformationUri(sources[0])) + combinedSource := sarif.NewRunWithInformationURI(sources[0].Tool.Driver.Name, getRunInformationUri(sources[0])).WithInvocations([]*sarif.Invocation{}) AggregateMultipleRunsIntoSingle(sources, combinedSource) if combinedSource == nil { return } - combinedTarget := sarif.NewRunWithInformationURI(targets[0].Tool.Driver.Name, getRunInformationUri(targets[0])) + if len(targets) == 0 { + return combinedSource + } + combinedTarget := sarif.NewRunWithInformationURI(targets[0].Tool.Driver.Name, getRunInformationUri(targets[0])).WithInvocations([]*sarif.Invocation{}) AggregateMultipleRunsIntoSingle(targets, combinedTarget) if combinedTarget == nil { return combinedSource @@ -342,9 +345,12 @@ func GetStartLocationInFile(location *sarif.Location) string { } func ExtractRelativePath(resultPath string, projectRoot string) string { - filePrefix := "file://" - relativePath := strings.ReplaceAll(strings.ReplaceAll(resultPath, projectRoot, ""), filePrefix, "") - return relativePath + // Remove OS-specific file prefix + resultPath = strings.TrimPrefix(resultPath, "file:///private") + resultPath = strings.TrimPrefix(resultPath, "file://") + + // Get relative path + return strings.ReplaceAll(resultPath, projectRoot, "") } func GetResultSeverity(result *sarif.Result) string { @@ -363,7 +369,7 @@ func ConvertToSarifLevel(severity string) string { return string(noneLevel) } -func isApplicableResult(result *sarif.Result) bool { +func IsApplicableResult(result *sarif.Result) bool { return !(result.Kind != nil && *result.Kind == "pass") }