From fe4d4c444709fd8cadd26cf605474aff4a49d626 Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 30 Aug 2023 16:08:28 +0300 Subject: [PATCH] refactor handling sarif, describe better --- xray/audit/jas/jasmanager.go | 27 ++++--- xray/utils/analyzermanager.go | 131 ---------------------------------- xray/utils/sarifutils.go | 130 +++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 140 deletions(-) create mode 100644 xray/utils/sarifutils.go diff --git a/xray/audit/jas/jasmanager.go b/xray/audit/jas/jasmanager.go index 35e62f4c9..f14aba631 100644 --- a/xray/audit/jas/jasmanager.go +++ b/xray/audit/jas/jasmanager.go @@ -128,31 +128,40 @@ func deleteJasProcessFiles(configFile string, resultFile string) error { } func getSourceCodeScanResults(resultsFileName, workingDir string, scanType utils.JasScanType) ([]utils.SourceCodeScanResult, error) { + // Read Sarif format results generated from the Jas scanner report, err := sarif.Open(resultsFileName) if errorutils.CheckError(err) != nil { return nil, err } - var results []*sarif.Result + var sarifResults []*sarif.Result if len(report.Runs) > 0 { - results = report.Runs[0].Results + // Jas scanners returns results in a single run entry + sarifResults = report.Runs[0].Results } + return convertSarifResultsToSourceCodeScanResults(sarifResults, workingDir, scanType), nil +} +func convertSarifResultsToSourceCodeScanResults(sarifResults []*sarif.Result, workingDir string, scanType utils.JasScanType) []utils.SourceCodeScanResult { var sourceCodeScanResults []utils.SourceCodeScanResult - for _, result := range results { + for _, sarifResult := range sarifResults { // Describes a request to “suppress” a result (to exclude it from result lists) - if len(result.Suppressions) > 0 { + if len(sarifResult.Suppressions) > 0 { continue } - index := utils.GetOrCreateCodeScanResult(result, workingDir, &sourceCodeScanResults) + // Convert + sourceCodeScanResult := utils.IsSarifResultExistsInSourceCodeScanResults(sarifResult, workingDir, &sourceCodeScanResults) + if sourceCodeScanResult == nil { + sourceCodeScanResult = utils.ConvertSarifResultToSourceCodeScanResult(sarifResult, workingDir, &sourceCodeScanResults) + } + // Set specific Jas scan attributes if scanType == utils.Secrets { - sourceCodeScanResults[index].Text = hideSecret(utils.GetResultLocationSnippet(result.Locations[0])) + sourceCodeScanResult.Text = hideSecret(utils.GetResultLocationSnippet(sarifResult.Locations[0])) } if scanType == utils.Sast { - flows := utils.GetResultCodeFlows(result, workingDir) - sourceCodeScanResults[index].CodeFlow = append(sourceCodeScanResults[index].CodeFlow, flows...) + sourceCodeScanResult.CodeFlow = append(sourceCodeScanResult.CodeFlow, utils.GetResultCodeFlows(sarifResult, workingDir)...) } } - return sourceCodeScanResults, nil + return sourceCodeScanResults } func createScannersConfigFile(fileName string, fileContent interface{}) error { diff --git a/xray/utils/analyzermanager.go b/xray/utils/analyzermanager.go index 9ca2c457d..2aa2ee1bd 100644 --- a/xray/utils/analyzermanager.go +++ b/xray/utils/analyzermanager.go @@ -7,8 +7,6 @@ import ( "os/exec" "path" "path/filepath" - "strconv" - "strings" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -16,7 +14,6 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" ) var ( @@ -210,134 +207,6 @@ func RemoveDuplicateValues(stringSlice []string) []string { return finalSlice } -func GetResultIndexIfExists(file, lineCol, text string, results []SourceCodeScanResult) int { - for i, result := range results { - if result.File == file && result.LineColumn == lineCol && result.Text == text { - return i - } - } - return -1 -} - -// If a result with the same file, line, column and text exists return it. otherwise create a new result and add it to results -// Used to combine results from similar places instead of reporting multiple duplicate rows -func GetOrCreateCodeScanResult(result *sarif.Result, workingDir string, results *[]SourceCodeScanResult) int { - file := ExtractRelativePath(GetResultFileName(result), workingDir) - lineCol := GetResultLocationInFile(result) - text := *result.Message.Text - // Already exists - if index := GetResultIndexIfExists(file, lineCol, text, *results); index >= 0 { - return index - } - // New result - newResult := SourceCodeScanResult{ - Severity: GetResultSeverity(result), - SourceCodeLocation: SourceCodeLocation{ - File: file, - LineColumn: lineCol, - Text: text, - }, - Type: *result.RuleID, - } - index := len(*results) - *results = append(*results, newResult) - - return index -} - -func GetResultFileName(result *sarif.Result) string { - if len(result.Locations) > 0 { - return getResultFileName(result.Locations[0]) - } - return "" -} - -func getResultFileName(location *sarif.Location) string { - filePath := location.PhysicalLocation.ArtifactLocation.URI - if filePath != nil { - return *filePath - } - return "" -} - -func GetResultLocationInFile(result *sarif.Result) string { - if len(result.Locations) > 0 { - return getResultLocationInFile(result.Locations[0]) - } - return "" -} - -func getResultLocationInFile(location *sarif.Location) string { - startLine := location.PhysicalLocation.Region.StartLine - startColumn := location.PhysicalLocation.Region.StartColumn - if startLine != nil && startColumn != nil { - return strconv.Itoa(*startLine) + ":" + strconv.Itoa(*startColumn) - } - return "" -} - -func GetResultLocationSnippet(location *sarif.Location) string { - if location != nil && location.PhysicalLocation != nil && location.PhysicalLocation.Region != nil && location.PhysicalLocation.Region.Snippet != nil { - return *location.PhysicalLocation.Region.Snippet.Text - } - return "" -} - -func GetResultCodeFlows(result *sarif.Result, workingDir string) (flows [][]SourceCodeLocation) { - if len(result.CodeFlows) == 0 { - return - } - for _, codeFlow := range result.CodeFlows { - if codeFlow == nil || len(codeFlow.ThreadFlows) == 0 { - continue - } - flows = append(flows, extractThreadFlows(codeFlow.ThreadFlows, workingDir)...) - } - return -} - -func extractThreadFlows(threadFlows []*sarif.ThreadFlow, workingDir string) (flows [][]SourceCodeLocation) { - for _, threadFlow := range threadFlows { - if threadFlow == nil || len(threadFlow.Locations) == 0 { - continue - } - flow := extractStackTraceLocations(threadFlow.Locations, workingDir) - if len(flow) > 0 { - flows = append(flows, flow) - } - } - return -} - -func extractStackTraceLocations(locations []*sarif.ThreadFlowLocation, workingDir string) (flow []SourceCodeLocation) { - for _, location := range locations { - if location == nil { - continue - } - flow = append(flow, SourceCodeLocation{ - File: ExtractRelativePath(getResultFileName(location.Location), workingDir), - LineColumn: getResultLocationInFile(location.Location), - Text: GetResultLocationSnippet(location.Location), - }) - } - return -} - -func ExtractRelativePath(resultPath string, projectRoot string) string { - filePrefix := "file://" - relativePath := strings.ReplaceAll(strings.ReplaceAll(resultPath, projectRoot, ""), filePrefix, "") - return relativePath -} - -func GetResultSeverity(result *sarif.Result) string { - if result.Level != nil { - if severity, ok := levelToSeverity[*result.Level]; ok { - return severity - } - } - return SeverityDefaultValue -} - // Receives a list of relative path working dirs, returns a list of full paths working dirs func GetFullPathsWorkingDirs(workingDirs []string) ([]string, error) { if len(workingDirs) == 0 { diff --git a/xray/utils/sarifutils.go b/xray/utils/sarifutils.go new file mode 100644 index 000000000..c5108e916 --- /dev/null +++ b/xray/utils/sarifutils.go @@ -0,0 +1,130 @@ +package utils + +import ( + "strconv" + "strings" + + "github.com/owenrumney/go-sarif/v2/sarif" +) + +// If exists SourceCodeScanResult with the same location as the provided SarifResult, return it +func IsSarifResultExistsInSourceCodeScanResults(result *sarif.Result, workingDir string, results *[]SourceCodeScanResult) *SourceCodeScanResult { + file := ExtractRelativePath(GetResultFileName(result), workingDir) + lineCol := GetResultLocationInFile(result) + text := *result.Message.Text + for _, result := range *results { + if result.File == file && result.LineColumn == lineCol && result.Text == text { + return &result + } + } + return nil +} + +func ConvertSarifResultToSourceCodeScanResult(result *sarif.Result, workingDir string, results *[]SourceCodeScanResult) *SourceCodeScanResult { + file := ExtractRelativePath(GetResultFileName(result), workingDir) + lineCol := GetResultLocationInFile(result) + text := *result.Message.Text + + return &SourceCodeScanResult{ + Severity: GetResultSeverity(result), + SourceCodeLocation: SourceCodeLocation{ + File: file, + LineColumn: lineCol, + Text: text, + }, + Type: *result.RuleID, + } +} + +func GetResultCodeFlows(result *sarif.Result, workingDir string) (flows [][]SourceCodeLocation) { + if len(result.CodeFlows) == 0 { + return + } + for _, codeFlow := range result.CodeFlows { + if codeFlow == nil || len(codeFlow.ThreadFlows) == 0 { + continue + } + flows = append(flows, extractThreadFlows(codeFlow.ThreadFlows, workingDir)...) + } + return +} + +func extractThreadFlows(threadFlows []*sarif.ThreadFlow, workingDir string) (flows [][]SourceCodeLocation) { + for _, threadFlow := range threadFlows { + if threadFlow == nil || len(threadFlow.Locations) == 0 { + continue + } + flow := extractStackTraceLocations(threadFlow.Locations, workingDir) + if len(flow) > 0 { + flows = append(flows, flow) + } + } + return +} + +func extractStackTraceLocations(locations []*sarif.ThreadFlowLocation, workingDir string) (flow []SourceCodeLocation) { + for _, location := range locations { + if location == nil { + continue + } + flow = append(flow, SourceCodeLocation{ + File: ExtractRelativePath(getResultFileName(location.Location), workingDir), + LineColumn: getResultLocationInFile(location.Location), + Text: GetResultLocationSnippet(location.Location), + }) + } + return +} + +func GetResultLocationSnippet(location *sarif.Location) string { + if location != nil && location.PhysicalLocation != nil && location.PhysicalLocation.Region != nil && location.PhysicalLocation.Region.Snippet != nil { + return *location.PhysicalLocation.Region.Snippet.Text + } + return "" +} + +func GetResultFileName(result *sarif.Result) string { + if len(result.Locations) > 0 { + return getResultFileName(result.Locations[0]) + } + return "" +} + +func getResultFileName(location *sarif.Location) string { + filePath := location.PhysicalLocation.ArtifactLocation.URI + if filePath != nil { + return *filePath + } + return "" +} + +func GetResultLocationInFile(result *sarif.Result) string { + if len(result.Locations) > 0 { + return getResultLocationInFile(result.Locations[0]) + } + return "" +} + +func getResultLocationInFile(location *sarif.Location) string { + startLine := location.PhysicalLocation.Region.StartLine + startColumn := location.PhysicalLocation.Region.StartColumn + if startLine != nil && startColumn != nil { + return strconv.Itoa(*startLine) + ":" + strconv.Itoa(*startColumn) + } + return "" +} + +func ExtractRelativePath(resultPath string, projectRoot string) string { + filePrefix := "file://" + relativePath := strings.ReplaceAll(strings.ReplaceAll(resultPath, projectRoot, ""), filePrefix, "") + return relativePath +} + +func GetResultSeverity(result *sarif.Result) string { + if result.Level != nil { + if severity, ok := levelToSeverity[*result.Level]; ok { + return severity + } + } + return SeverityDefaultValue +}