diff --git a/internal/commands/result.go b/internal/commands/result.go index 378022fe..a8aa5ef7 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -2117,7 +2117,7 @@ func translateReportSectionsForImproved(sections []string) []string { func convertCxResultsToSarif(results *wrappers.ScanResultsCollection) *wrappers.SarifResultsCollection { var sarif = new(wrappers.SarifResultsCollection) - sarif.Schema = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" + sarif.Schema = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json" sarif.Version = "2.1.0" sarif.Runs = []wrappers.SarifRun{} sarif.Runs = append(sarif.Runs, createSarifRun(results)) @@ -2558,6 +2558,21 @@ func getSastStartColumn(column uint) uint { return column - 1 } +func ensureSarifRegionCoordinate(value uint) uint { + if value < 1 { + return 1 + } + return value +} + +func sarifEndColumn(startColumn, length uint) uint { + endColumn := startColumn + length + if endColumn <= startColumn { + return startColumn + 1 + } + return endColumn +} + func findRuleID(result *wrappers.ScanResult) (ruleID, ruleName, shortMessage string) { caser := cases.Title(language.English) @@ -2734,7 +2749,7 @@ func parseSarifResultKics(result *wrappers.ScanResult, scanResults []wrappers.Sa 1, ) scanLocation.PhysicalLocation.Region = &wrappers.SarifRegion{} - scanLocation.PhysicalLocation.Region.StartLine = result.ScanResultData.Line + scanLocation.PhysicalLocation.Region.StartLine = ensureSarifRegionCoordinate(result.ScanResultData.Line) scanLocation.PhysicalLocation.Region.StartColumn = 1 scanLocation.PhysicalLocation.Region.EndColumn = 2 scanResult.Locations = append(scanResult.Locations, scanLocation) @@ -2759,29 +2774,31 @@ func parseSarifResultSast(result *wrappers.ScanResult, scanResults []wrappers.Sa } scanLocation.PhysicalLocation.Region = &wrappers.SarifRegion{} scanLocation.PhysicalLocation.Region.StartLine = node.Line - column := node.Column - length := node.Length + column := ensureSarifRegionCoordinate(node.Column) scanLocation.PhysicalLocation.Region.StartColumn = column - scanLocation.PhysicalLocation.Region.EndColumn = column + length + scanLocation.PhysicalLocation.Region.EndColumn = sarifEndColumn(column, node.Length) allLocations = append(allLocations, scanLocation) } } - if len(allLocations) > 0 { - var threadFlowLocations []wrappers.SarifThreadFlowLocation - for _, loc := range allLocations { - threadFlowLocations = append(threadFlowLocations, wrappers.SarifThreadFlowLocation{Location: loc}) - } - scanResult.CodeFlows = []wrappers.SarifCodeFlow{ - { - ThreadFlows: []wrappers.SarifThreadFlow{ - { - Locations: threadFlowLocations, - }, + if len(allLocations) == 0 { + return scanResults + } + + scanResult.Locations = append(scanResult.Locations, allLocations[0]) + var threadFlowLocations []wrappers.SarifThreadFlowLocation + for _, loc := range allLocations { + threadFlowLocations = append(threadFlowLocations, wrappers.SarifThreadFlowLocation{Location: loc}) + } + scanResult.CodeFlows = []wrappers.SarifCodeFlow{ + { + ThreadFlows: []wrappers.SarifThreadFlow{ + { + Locations: threadFlowLocations, }, }, - } + }, } scanResults = append(scanResults, scanResult) @@ -2804,7 +2821,7 @@ func parseSarifResultsSscs(result *wrappers.ScanResult, scanResults []wrappers.S } scanLocation.PhysicalLocation.Region = &wrappers.SarifRegion{} - scanLocation.PhysicalLocation.Region.StartLine = result.ScanResultData.Line + scanLocation.PhysicalLocation.Region.StartLine = ensureSarifRegionCoordinate(result.ScanResultData.Line) scanLocation.PhysicalLocation.Region.StartColumn = 1 scanLocation.PhysicalLocation.Region.EndColumn = 2 if result.ScanResultData.Snippet != "" { diff --git a/internal/commands/result_test.go b/internal/commands/result_test.go index dff116ed..d504436d 100644 --- a/internal/commands/result_test.go +++ b/internal/commands/result_test.go @@ -369,6 +369,59 @@ func TestParseSarifEmptyResultSast(t *testing.T) { } } +func TestParseSarifResultSastClampsZeroColumns(t *testing.T) { + result := &wrappers.ScanResult{ + ScanResultData: wrappers.ScanResultData{ + Nodes: []*wrappers.ScanResultNode{ + {FileName: "/src/app.go", Line: 10, Column: 0, Length: 0}, + {FileName: "/src/app.go", Line: 12, Column: 0, Length: 5}, + }, + }, + } + + sarifResults := parseSarifResultSast(result, nil) + assert.Assert(t, len(sarifResults) == 1) + assert.Assert(t, len(sarifResults[0].Locations) == 1) + + primary := sarifResults[0].Locations[0].PhysicalLocation.Region + assert.Equal(t, uint(1), primary.StartColumn) + assert.Equal(t, uint(2), primary.EndColumn) + + threadLocations := sarifResults[0].CodeFlows[0].ThreadFlows[0].Locations + assert.Equal(t, uint(1), threadLocations[0].Location.PhysicalLocation.Region.StartColumn) + assert.Equal(t, uint(2), threadLocations[0].Location.PhysicalLocation.Region.EndColumn) + assert.Equal(t, uint(1), threadLocations[1].Location.PhysicalLocation.Region.StartColumn) + assert.Equal(t, uint(6), threadLocations[1].Location.PhysicalLocation.Region.EndColumn) +} + +func TestParseSarifResultKicsClampsZeroStartLine(t *testing.T) { + result := &wrappers.ScanResult{ + ScanResultData: wrappers.ScanResultData{ + Filename: "/Dockerfile", + Line: 0, + }, + } + + sarifResults := parseSarifResultKics(result, nil) + assert.Assert(t, len(sarifResults) == 1) + assert.Equal(t, uint(1), sarifResults[0].Locations[0].PhysicalLocation.Region.StartLine) +} + +func TestParseSarifResultsSscsClampsZeroStartLine(t *testing.T) { + result := &wrappers.ScanResult{ + Type: params.SCSSecretDetectionType, + Description: "secret found", + ScanResultData: wrappers.ScanResultData{ + Filename: "config.yaml", + Line: 0, + }, + } + + sarifResults := parseSarifResultsSscs(result, nil) + assert.Assert(t, len(sarifResults) == 1) + assert.Equal(t, uint(1), sarifResults[0].Locations[0].PhysicalLocation.Region.StartLine) +} + func TestRunGetResultsByScanIdSonarFormat(t *testing.T) { execCmdNilAssertion(t, "results", "show", "--scan-id", "MOCK", "--report-format", "sonar") // Remove generated sonar file