Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve audit data handling #936

Merged
merged 43 commits into from
Sep 10, 2023
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ccb5c4f
Improve audit data handling
attiasas Sep 6, 2023
ccc3379
Merge remote-tracking branch 'upstream/dev' into refactor_handle_scan…
attiasas Sep 6, 2023
c0cb84f
resolve conflicts
attiasas Sep 6, 2023
ff11b5d
fix tests
attiasas Sep 6, 2023
ffce12b
fix static tests
attiasas Sep 6, 2023
bace6ff
finish convert xray results to sarif
attiasas Sep 6, 2023
7ee9b55
Merge remote-tracking branch 'upstream/dev' into refactor_handle_scan…
attiasas Sep 6, 2023
633b93c
more sarif utils
attiasas Sep 7, 2023
852a378
fix static tests
attiasas Sep 7, 2023
e80a2e7
Merge remote-tracking branch 'upstream/dev' into refactor_handle_scan…
attiasas Sep 7, 2023
18e4c3f
format
attiasas Sep 7, 2023
60a9327
fix tests
attiasas Sep 7, 2023
73de66f
fix tests
attiasas Sep 7, 2023
a08da44
fix tests
attiasas Sep 7, 2023
c7c68d2
cleanup
attiasas Sep 8, 2023
d88a09c
fix tests
attiasas Sep 8, 2023
b62cbe7
review changes
attiasas Sep 8, 2023
1fafae7
fix tests
attiasas Sep 8, 2023
8fd9fa4
review changes, add more sarif utils
attiasas Sep 9, 2023
a3141fa
format
attiasas Sep 9, 2023
7d1ac5c
fix invocation to sast
attiasas Sep 9, 2023
d49a657
more Sarif utils
attiasas Sep 9, 2023
54a7fa3
more Sarif utils
attiasas Sep 9, 2023
d8a90af
more sarif utils
attiasas Sep 10, 2023
75fa7b2
fix generate applic map
attiasas Sep 10, 2023
84789ef
review changes
attiasas Sep 10, 2023
3374ca8
set results not append
attiasas Sep 10, 2023
9848b7e
review changes
attiasas Sep 10, 2023
4e6fca9
Merge remote-tracking branch 'upstream/dev' into refactor_handle_scan…
attiasas Sep 10, 2023
56b8322
fix static
attiasas Sep 10, 2023
3ca4db4
create properties if not exists
attiasas Sep 10, 2023
78ec95b
clean up
attiasas Sep 10, 2023
cd1fb68
fix bugs
attiasas Sep 10, 2023
fad0c0a
format
attiasas Sep 10, 2023
4de5e01
fix tests
attiasas Sep 10, 2023
0f31707
fix diff
attiasas Sep 10, 2023
71e275e
fix diff
attiasas Sep 10, 2023
749d07b
fix diff
attiasas Sep 10, 2023
72a1f09
fix tests
attiasas Sep 10, 2023
92d75dd
format
attiasas Sep 10, 2023
5894b1f
change count text
attiasas Sep 10, 2023
3f3b8ee
review changes
attiasas Sep 10, 2023
6e32436
move filter to frogbot
attiasas Sep 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions xray/commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ func RunAudit(auditParams *AuditParams) (results *Results, err error) {
if err = clientutils.ValidateMinimumVersion(clientutils.Xray, auditParams.xrayVersion, scangraph.GraphScanMinXrayVersion); err != nil {
return
}
results.ExtendedScanResults.XrayVersion = auditParams.xrayVersion
sverdlov93 marked this conversation as resolved.
Show resolved Hide resolved
results.ExtendedScanResults.EntitledForJas, err = isEntitledForJas(xrayManager, auditParams.xrayVersion)
if err != nil {
return
Expand Down
53 changes: 8 additions & 45 deletions xray/commands/audit/jas/applicability/applicabilitymanager.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package applicability

import (
"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas"
"path/filepath"
"strings"

"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas"

"github.com/jfrog/gofrog/datastructures"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/owenrumney/go-sarif/v2/sarif"
Expand All @@ -22,7 +21,7 @@ const (
)

type ApplicabilityScanManager struct {
applicabilityScanResults map[string]utils.ApplicabilityStatus
applicabilityScanResults []*sarif.Run
directDependenciesCves []string
xrayResults []services.ScanResponse
scanner *jas.JasScanner
Expand All @@ -38,7 +37,7 @@ type ApplicabilityScanManager struct {
// bool: true if the user is entitled to the applicability scan, false otherwise.
// error: An error object (if any).
func RunApplicabilityScan(xrayResults []services.ScanResponse, directDependencies []string,
scannedTechnologies []coreutils.Technology, scanner *jas.JasScanner) (results map[string]utils.ApplicabilityStatus, err error) {
scannedTechnologies []coreutils.Technology, scanner *jas.JasScanner) (results []*sarif.Run, err error) {
applicabilityScanManager := newApplicabilityScanManager(xrayResults, directDependencies, scanner)
if !applicabilityScanManager.shouldRunApplicabilityScan(scannedTechnologies) {
log.Debug("The technologies that have been scanned are currently not supported for contextual analysis scanning, or we couldn't find any vulnerable direct dependencies. Skipping....")
Expand All @@ -55,7 +54,7 @@ func RunApplicabilityScan(xrayResults []services.ScanResponse, directDependencie
func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, directDependencies []string, scanner *jas.JasScanner) (manager *ApplicabilityScanManager) {
directDependenciesCves := extractDirectDependenciesCvesFromScan(xrayScanResults, directDependencies)
return &ApplicabilityScanManager{
applicabilityScanResults: map[string]utils.ApplicabilityStatus{},
applicabilityScanResults: []*sarif.Run{},
directDependenciesCves: directDependenciesCves,
xrayResults: xrayScanResults,
scanner: scanner,
Expand Down Expand Up @@ -111,13 +110,11 @@ func (asm *ApplicabilityScanManager) Run(wd string) (err error) {
if err = asm.runAnalyzerManager(); err != nil {
return
}
var workingDirResults map[string]utils.ApplicabilityStatus
if workingDirResults, err = asm.getScanResults(); err != nil {
workingDirResults, err := jas.ReadJasScanRunsFromFile(asm.scanner.ResultsFileName, wd)
if err != nil {
return
}
for cve, result := range workingDirResults {
asm.applicabilityScanResults[cve] = result
}
asm.applicabilityScanResults = append(asm.applicabilityScanResults, workingDirResults...)
return
}

Expand Down Expand Up @@ -163,37 +160,3 @@ func (asm *ApplicabilityScanManager) createConfigFile(workingDir string) error {
func (asm *ApplicabilityScanManager) runAnalyzerManager() error {
return asm.scanner.AnalyzerManager.Exec(asm.scanner.ConfigFileName, applicabilityScanCommand, filepath.Dir(asm.scanner.AnalyzerManager.AnalyzerManagerFullPath), asm.scanner.ServerDetails)
}

func (asm *ApplicabilityScanManager) getScanResults() (applicabilityResults map[string]utils.ApplicabilityStatus, err error) {
applicabilityResults = make(map[string]utils.ApplicabilityStatus, len(asm.directDependenciesCves))
for _, cve := range asm.directDependenciesCves {
applicabilityResults[cve] = utils.ApplicabilityUndetermined
}

report, err := sarif.Open(asm.scanner.ResultsFileName)
if errorutils.CheckError(err) != nil || len(report.Runs) == 0 {
return
}
// Applicability results contains one run only
for _, sarifResult := range report.Runs[0].Results {
cve := getCveFromRuleId(*sarifResult.RuleID)
if _, exists := applicabilityResults[cve]; !exists {
err = errorutils.CheckErrorf("received unexpected CVE: '%s' from RuleID: '%s' that does not exists on the requested CVEs list", cve, *sarifResult.RuleID)
return
}
applicabilityResults[cve] = resultKindToApplicabilityStatus(sarifResult.Kind)
}
return
}

// Gets a result of one CVE from the scanner, and returns true if the CVE is applicable, false otherwise
func resultKindToApplicabilityStatus(kind *string) utils.ApplicabilityStatus {
if !(kind != nil && *kind == "pass") {
return utils.Applicable
}
return utils.NotApplicable
}

func getCveFromRuleId(sarifRuleId string) string {
return strings.TrimPrefix(sarifRuleId, "applic_")
}
35 changes: 16 additions & 19 deletions xray/commands/audit/jas/applicability/applicabilitymanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package applicability
import (
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas"
"github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/stretchr/testify/assert"
"os"
Expand Down Expand Up @@ -276,13 +275,12 @@ func TestParseResults_EmptyResults_AllCvesShouldGetUnknown(t *testing.T) {
applicabilityManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "applicability-scan", "empty-results.sarif")

// Act
results, err := applicabilityManager.getScanResults()
var err error
applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0])

// Assert
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.ApplicabilityUndetermined, cveResult)
if assert.NoError(t, err) {
assert.Len(t, applicabilityManager.applicabilityScanResults, 1)
assert.Empty(t, applicabilityManager.applicabilityScanResults[0].Results)
}
}

Expand All @@ -294,13 +292,13 @@ func TestParseResults_ApplicableCveExist(t *testing.T) {
applicabilityManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "applicability-scan", "applicable-cve-results.sarif")

// Act
results, err := applicabilityManager.getScanResults()
var err error
applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0])

// Assert
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
assert.Equal(t, utils.Applicable, results["testCve1"])
assert.Equal(t, utils.NotApplicable, results["testCve3"])
if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) {
assert.Len(t, applicabilityManager.applicabilityScanResults, 1)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults[0].Results)
}
}

func TestParseResults_AllCvesNotApplicable(t *testing.T) {
Expand All @@ -311,12 +309,11 @@ func TestParseResults_AllCvesNotApplicable(t *testing.T) {
applicabilityManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "applicability-scan", "no-applicable-cves-results.sarif")

// Act
results, err := applicabilityManager.getScanResults()
var err error
applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0])

// Assert
assert.NoError(t, err)
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.NotApplicable, cveResult)
if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) {
assert.Len(t, applicabilityManager.applicabilityScanResults, 1)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults[0].Results)
}
}
93 changes: 52 additions & 41 deletions xray/commands/audit/jas/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ package jas

import (
"errors"
"os"
"path/filepath"
"strings"
"testing"

rtutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
Expand All @@ -12,14 +17,19 @@ import (
"github.com/owenrumney/go-sarif/v2/sarif"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"os"
"path/filepath"
"strings"
"testing"
)

var (
SkippedDirs = []string{"**/*test*/**", "**/*venv*/**", "**/*node_modules*/**", "**/*target*/**"}

mapSeverityToScore = map[string]string{
"": "0.0",
"unknown": "0.0",
"low": "3.9",
"medium": "6.9",
"high": "8.9",
"critical": "10",
}
)

type JasScanner struct {
Expand Down Expand Up @@ -88,46 +98,54 @@ func deleteJasProcessFiles(configFile string, resultFile string) error {
return errorutils.CheckError(err)
}

func GetSourceCodeScanResults(resultsFileName, workingDir string, scanType utils.JasScanType) (results []utils.SourceCodeScanResult, err error) {
// Read Sarif format results generated from the Jas scanner
report, err := sarif.Open(resultsFileName)
if errorutils.CheckError(err) != nil {
return nil, err
}
var sarifResults []*sarif.Result
if len(report.Runs) > 0 {
// Jas scanners returns results in a single run entry
sarifResults = report.Runs[0].Results
func ReadJasScanRunsFromFile(fileName, wd string) (sarifRuns []*sarif.Run, err error) {
if sarifRuns, err = utils.ReadScanRunsFromFile(fileName); err != nil {
return
}
resultPointers := convertSarifResultsToSourceCodeScanResults(sarifResults, workingDir, scanType)
for _, res := range resultPointers {
results = append(results, *res)
for _, sarifRun := range sarifRuns {
// Jas reports has only one invocation
// Set the actual working directory to the invocation, not the analyzerManager directory
// Also used to calculate relative paths if needed with it
sarifRun.Invocations[0].WorkingDirectory.WithUri(wd)
// Process runs values
excludeSuppressResults(sarifRun)
attiasas marked this conversation as resolved.
Show resolved Hide resolved
addPropertiesToRunRules(sarifRun)
attiasas marked this conversation as resolved.
Show resolved Hide resolved
}
return results, nil
return
}

func convertSarifResultsToSourceCodeScanResults(sarifResults []*sarif.Result, workingDir string, scanType utils.JasScanType) []*utils.SourceCodeScanResult {
var sourceCodeScanResults []*utils.SourceCodeScanResult
for _, sarifResult := range sarifResults {
// Describes a request to “suppress” a result (to exclude it from result lists)
func excludeSuppressResults(sarifRun *sarif.Run) {
results := []*sarif.Result{}
for _, sarifResult := range sarifRun.Results {
if len(sarifResult.Suppressions) > 0 {
// Describes a request to “suppress” a result (to exclude it from result lists)
continue
}
// Convert
currentResult := utils.GetResultIfExists(sarifResult, workingDir, sourceCodeScanResults)
if currentResult == nil {
currentResult = utils.ConvertSarifResultToSourceCodeScanResult(sarifResult, workingDir)
// Set specific Jas scan attributes
if scanType == utils.Secrets {
currentResult.Text = hideSecret(utils.GetResultLocationSnippet(sarifResult.Locations[0]))
results = append(results, sarifResult)
}
sarifRun.Results = results
}

func addPropertiesToRunRules(sarifRun *sarif.Run) {
for _, sarifResult := range sarifRun.Results {
if rule, err := sarifRun.GetRuleById(*sarifResult.RuleID); err == nil {
// Add to the rule security-severity score based on results severity
score := convertToScore(utils.GetResultSeverity(sarifResult))
if score != utils.MissingCveScore {
if rule.Properties == nil {
rule.WithProperties(sarif.NewPropertyBag().Properties)
}
rule.Properties["security-severity"] = score
}
sourceCodeScanResults = append(sourceCodeScanResults, currentResult)
}
if scanType == utils.Sast {
currentResult.CodeFlow = append(currentResult.CodeFlow, utils.GetResultCodeFlows(sarifResult, workingDir)...)
}
}
return sourceCodeScanResults
}

func convertToScore(severity string) string {
if level, ok := mapSeverityToScore[strings.ToLower(severity)]; ok {
return level
}
return ""
}

func CreateScannersConfigFile(fileName string, fileContent interface{}) error {
Expand All @@ -139,13 +157,6 @@ func CreateScannersConfigFile(fileName string, fileContent interface{}) error {
return errorutils.CheckError(err)
}

func hideSecret(secret string) string {
if len(secret) <= 3 {
return "***"
}
return secret[:3] + strings.Repeat("*", 12)
}

var FakeServerDetails = config.ServerDetails{
Url: "platformUrl",
Password: "password",
Expand Down
23 changes: 0 additions & 23 deletions xray/commands/audit/jas/common_test.go

This file was deleted.

11 changes: 6 additions & 5 deletions xray/commands/audit/jas/iac/iacscanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/owenrumney/go-sarif/v2/sarif"
)

const (
Expand All @@ -14,7 +15,7 @@ const (
)

type IacScanManager struct {
iacScannerResults []utils.SourceCodeScanResult
iacScannerResults []*sarif.Run
scanner *jas.JasScanner
}

Expand All @@ -26,7 +27,7 @@ type IacScanManager struct {
// []utils.SourceCodeScanResult: a list of the iac violations that were found.
// bool: true if the user is entitled to iac scan, false otherwise.
// error: An error object (if any).
func RunIacScan(scanner *jas.JasScanner) (results []utils.SourceCodeScanResult, err error) {
func RunIacScan(scanner *jas.JasScanner) (results []*sarif.Run, err error) {
iacScanManager := newIacScanManager(scanner)
log.Info("Running IaC scanning...")
if err = iacScanManager.scanner.Run(iacScanManager); err != nil {
Expand All @@ -42,7 +43,7 @@ func RunIacScan(scanner *jas.JasScanner) (results []utils.SourceCodeScanResult,

func newIacScanManager(scanner *jas.JasScanner) (manager *IacScanManager) {
return &IacScanManager{
iacScannerResults: []utils.SourceCodeScanResult{},
iacScannerResults: []*sarif.Run{},
scanner: scanner,
}
}
Expand All @@ -55,8 +56,8 @@ func (iac *IacScanManager) Run(wd string) (err error) {
if err = iac.runAnalyzerManager(); err != nil {
return
}
var workingDirResults []utils.SourceCodeScanResult
if workingDirResults, err = jas.GetSourceCodeScanResults(scanner.ResultsFileName, wd, utils.IaC); err != nil {
workingDirResults, err := jas.ReadJasScanRunsFromFile(scanner.ResultsFileName, wd)
if err != nil {
return
}
iac.iacScannerResults = append(iac.iacScannerResults, workingDirResults...)
Expand Down
Loading
Loading