Skip to content

Commit

Permalink
Audit - accept working dirs for IaC/Secrets scanners (#884)
Browse files Browse the repository at this point in the history
  • Loading branch information
omerzi authored Aug 14, 2023
1 parent d3c2f3c commit 542dc7a
Show file tree
Hide file tree
Showing 18 changed files with 1,068 additions and 227 deletions.
2 changes: 1 addition & 1 deletion artifactory/commands/utils/configfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/urfave/cli"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

const BuildConfVersion = 1
Expand Down
2 changes: 1 addition & 1 deletion general/cisetup/pipelinesyaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
"strconv"
)

Expand Down
2 changes: 1 addition & 1 deletion general/project/projectinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

const (
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
golang.org/x/sync v0.2.0
golang.org/x/term v0.10.0
golang.org/x/text v0.11.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
)

require github.com/c-bata/go-prompt v0.2.5 // Should not be updated to 0.2.6 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372)
Expand Down Expand Up @@ -91,7 +91,6 @@ require (
golang.org/x/tools v0.7.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230803140217-0a5f43783ae8
Expand Down
1 change: 0 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
75 changes: 39 additions & 36 deletions xray/audit/jas/applicabilitymanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"github.com/owenrumney/go-sarif/v2/sarif"
"golang.org/x/exp/maps"
"gopkg.in/yaml.v2"
"os"
"path/filepath"
"strings"
)
Expand All @@ -35,8 +33,8 @@ const (
// bool: true if the user is entitled to the applicability scan, false otherwise.
// error: An error object (if any).
func getApplicabilityScanResults(results []services.ScanResponse, dependencyTrees []*xrayUtils.GraphNode,
serverDetails *config.ServerDetails, scannedTechnologies []coreutils.Technology, analyzerManager utils.AnalyzerManagerInterface) (map[string]string, bool, error) {
applicabilityScanManager, cleanupFunc, err := newApplicabilityScanManager(results, dependencyTrees, serverDetails, analyzerManager)
serverDetails *config.ServerDetails, scannedTechnologies []coreutils.Technology, workingDirs []string, analyzerManager utils.AnalyzerManagerInterface) (map[string]string, bool, error) {
applicabilityScanManager, cleanupFunc, err := newApplicabilityScanManager(results, dependencyTrees, serverDetails, workingDirs, analyzerManager)
if err != nil {
return nil, false, utils.Applicability.FormattedError(err)
}
Expand All @@ -63,10 +61,11 @@ type ApplicabilityScanManager struct {
resultsFileName string
analyzerManager utils.AnalyzerManagerInterface
serverDetails *config.ServerDetails
workingDirs []string
}

func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, dependencyTrees []*xrayUtils.GraphNode,
serverDetails *config.ServerDetails, analyzerManager utils.AnalyzerManagerInterface) (manager *ApplicabilityScanManager, cleanup func() error, err error) {
serverDetails *config.ServerDetails, workingDirs []string, analyzerManager utils.AnalyzerManagerInterface) (manager *ApplicabilityScanManager, cleanup func() error, err error) {
directDependencies := getDirectDependenciesSet(dependencyTrees)
tempDir, err := fileutils.CreateTempDir()
if err != nil {
Expand All @@ -75,6 +74,10 @@ func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, depend
cleanup = func() error {
return fileutils.RemoveTempDir(tempDir)
}
fullPathWorkingDirs, err := utils.GetFullPathsWorkingDirs(workingDirs)
if err != nil {
return nil, cleanup, err
}
directDependenciesCves := extractDirectDependenciesCvesFromScan(xrayScanResults, directDependencies)
return &ApplicabilityScanManager{
applicabilityScanResults: map[string]string{},
Expand All @@ -84,6 +87,7 @@ func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, depend
xrayResults: xrayScanResults,
analyzerManager: analyzerManager,
serverDetails: serverDetails,
workingDirs: fullPathWorkingDirs,
}, cleanup, nil
}

Expand Down Expand Up @@ -132,20 +136,31 @@ func getDirectDependenciesSet(dependencyTrees []*xrayUtils.GraphNode) *datastruc
}

func (a *ApplicabilityScanManager) run() (err error) {
defer func() {
if deleteJasProcessFiles(a.configFileName, a.resultsFileName) != nil {
deleteFilesError := deleteJasProcessFiles(a.configFileName, a.resultsFileName)
err = errors.Join(err, deleteFilesError)
log.Info("Running applicability scanning for the identified vulnerable direct dependencies...")
for _, workingDir := range a.workingDirs {
var workingDirResults map[string]string
if workingDirResults, err = a.runApplicabilityScan(workingDir); err != nil {
return
}
for cve, result := range workingDirResults {
a.applicabilityScanResults[cve] = result
}
}
return
}

func (a *ApplicabilityScanManager) runApplicabilityScan(workingDir string) (results map[string]string, err error) {
defer func() {
err = errors.Join(err, deleteJasProcessFiles(a.configFileName, a.resultsFileName))
}()
log.Info("Running applicability scanning for the identified vulnerable dependencies...")
if err = a.createConfigFile(); err != nil {
if err = a.createConfigFile(workingDir); err != nil {
return
}
if err = a.runAnalyzerManager(); err != nil {
return
}
return a.setScanResults()
results, err = a.getScanResults()
return
}

func (a *ApplicabilityScanManager) directDependenciesExist() bool {
Expand All @@ -169,15 +184,11 @@ type scanConfiguration struct {
SkippedDirs []string `yaml:"skipped-folders"`
}

func (a *ApplicabilityScanManager) createConfigFile() error {
currentDir, err := coreutils.GetWorkingDirectory()
if err != nil {
return err
}
func (a *ApplicabilityScanManager) createConfigFile(workingDir string) error {
configFileContent := applicabilityScanConfig{
Scans: []scanConfiguration{
{
Roots: []string{currentDir},
Roots: []string{workingDir},
Output: a.resultsFileName,
Type: applicabilityScanType,
GrepDisable: false,
Expand All @@ -186,47 +197,39 @@ func (a *ApplicabilityScanManager) createConfigFile() error {
},
},
}
yamlData, err := yaml.Marshal(&configFileContent)
if errorutils.CheckError(err) != nil {
return err
}
err = os.WriteFile(a.configFileName, yamlData, 0644)
return errorutils.CheckError(err)
return createScannersConfigFile(a.configFileName, configFileContent)
}

// Runs the analyzerManager app and returns a boolean to indicate whether the user is entitled for
// advance security feature
func (a *ApplicabilityScanManager) runAnalyzerManager() error {
if err := utils.SetAnalyzerManagerEnvVariables(a.serverDetails); err != nil {
return err
}
return a.analyzerManager.Exec(a.configFileName, applicabilityScanCommand)
return a.analyzerManager.Exec(a.configFileName, applicabilityScanCommand, a.serverDetails)
}

func (a *ApplicabilityScanManager) setScanResults() error {
func (a *ApplicabilityScanManager) getScanResults() (map[string]string, error) {
report, err := sarif.Open(a.resultsFileName)
if errorutils.CheckError(err) != nil {
return err
return nil, err
}
var fullVulnerabilitiesList []*sarif.Result
if len(report.Runs) > 0 {
fullVulnerabilitiesList = report.Runs[0].Results
}

xrayCves := a.directDependenciesCves.ToSlice()
for _, xrayCve := range xrayCves {
a.applicabilityScanResults[xrayCve] = utils.ApplicabilityUndeterminedStringValue
applicabilityScanResults := make(map[string]string)
for _, cve := range a.directDependenciesCves.ToSlice() {
applicabilityScanResults[cve] = utils.ApplicabilityUndeterminedStringValue
}

for _, vulnerability := range fullVulnerabilitiesList {
applicableVulnerabilityName := getVulnerabilityName(*vulnerability.RuleID)
if isVulnerabilityApplicable(vulnerability) {
a.applicabilityScanResults[applicableVulnerabilityName] = utils.ApplicableStringValue
applicabilityScanResults[applicableVulnerabilityName] = utils.ApplicableStringValue
} else {
a.applicabilityScanResults[applicableVulnerabilityName] = utils.NotApplicableStringValue
applicabilityScanResults[applicableVulnerabilityName] = utils.NotApplicableStringValue
}
}
return nil
return applicabilityScanResults, nil
}

// Gets a result of one CVE from the scanner, and returns true if the CVE is applicable, false otherwise
Expand Down
59 changes: 28 additions & 31 deletions xray/audit/jas/applicabilitymanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

func TestNewApplicabilityScanManager_InputIsValid(t *testing.T) {
// Act
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand All @@ -27,7 +27,7 @@ func TestNewApplicabilityScanManager_InputIsValid(t *testing.T) {

func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) {
// Act
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, nil, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, nil, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestNewApplicabilityScanManager_NoDirectDependenciesInScan(t *testing.T) {
fakeBasicXrayResults[0].Violations[0].Components["issueId_2_non_direct_dependency"] = services.Component{}

// Act
applicabilityManager, _, err := newApplicabilityScanManager(noDirectDependenciesResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(noDirectDependenciesResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand All @@ -76,7 +76,7 @@ func TestNewApplicabilityScanManager_MultipleDependencyTrees(t *testing.T) {
multipleDependencyTrees := []*xrayUtils.GraphNode{multipleFakeBasicDependencyGraph[0], multipleFakeBasicDependencyGraph[1]}

// Act
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, multipleDependencyTrees, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(fakeBasicXrayResults, multipleDependencyTrees, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand All @@ -100,7 +100,7 @@ func TestNewApplicabilityScanManager_ViolationsDontExistInResults(t *testing.T)
}

// Act
applicabilityManager, _, err := newApplicabilityScanManager(noViolationScanResponse, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(noViolationScanResponse, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand All @@ -124,7 +124,7 @@ func TestNewApplicabilityScanManager_VulnerabilitiesDontExist(t *testing.T) {
}

// Act
applicabilityManager, _, err := newApplicabilityScanManager(noVulnerabilitiesScanResponse, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(noVulnerabilitiesScanResponse, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})

// Assert
assert.NoError(t, err)
Expand All @@ -137,7 +137,7 @@ func TestNewApplicabilityScanManager_VulnerabilitiesDontExist(t *testing.T) {
func TestApplicabilityScanManager_ShouldRun_TechnologiesNotEligibleForScan(t *testing.T) {
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, eligible, err := getApplicabilityScanResults(fakeBasicXrayResults, fakeBasicDependencyGraph,
&fakeServerDetails, []coreutils.Technology{coreutils.Nuget, coreutils.Go}, &analyzerManagerMock{})
&fakeServerDetails, []coreutils.Technology{coreutils.Nuget, coreutils.Go}, nil, &analyzerManagerMock{})

// Assert
assert.Nil(t, applicabilityManager)
Expand All @@ -148,7 +148,7 @@ func TestApplicabilityScanManager_ShouldRun_TechnologiesNotEligibleForScan(t *te
func TestApplicabilityScanManager_ShouldRun_ScanResultsAreEmpty(t *testing.T) {
// Arrange
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, _, err := newApplicabilityScanManager(nil, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, err := newApplicabilityScanManager(nil, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})
assert.NoError(t, err)
// Assert
eligible := applicabilityManager.shouldRunApplicabilityScan([]coreutils.Technology{coreutils.Npm})
Expand Down Expand Up @@ -275,19 +275,19 @@ func TestGetDirectDependenciesList(t *testing.T) {
func TestCreateConfigFile_VerifyFileWasCreated(t *testing.T) {
// Arrange
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})
assert.NoError(t, applicabilityManagerError)

// Act
err := applicabilityManager.createConfigFile()
currWd, err := coreutils.GetWorkingDirectory()
assert.NoError(t, err)
err = applicabilityManager.createConfigFile(currWd)
assert.NoError(t, err)

defer func() {
err = os.Remove(applicabilityManager.configFileName)
assert.NoError(t, err)
}()

// Assert
assert.NoError(t, applicabilityManagerError)
assert.NoError(t, err)
_, fileNotExistError := os.Stat(applicabilityManager.configFileName)
assert.NoError(t, fileNotExistError)
fileContent, err := os.ReadFile(applicabilityManager.configFileName)
Expand All @@ -298,55 +298,52 @@ func TestCreateConfigFile_VerifyFileWasCreated(t *testing.T) {
func TestParseResults_EmptyResults_AllCvesShouldGetUnknown(t *testing.T) {
// Arrange
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})
applicabilityManager.resultsFileName = filepath.Join("..", "..", "commands", "testdata", "applicability-scan", "empty-results.sarif")

// Act
err := applicabilityManager.setScanResults()
results, err := applicabilityManager.getScanResults()

// Assert
assert.NoError(t, applicabilityManagerError)
assert.NoError(t, err)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults)
assert.Equal(t, 5, len(applicabilityManager.applicabilityScanResults))
for _, cveResult := range applicabilityManager.applicabilityScanResults {
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.ApplicabilityUndeterminedStringValue, cveResult)
}
}

func TestParseResults_ApplicableCveExist(t *testing.T) {
// Arrange
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})
applicabilityManager.resultsFileName = filepath.Join("..", "..", "commands", "testdata", "applicability-scan", "applicable-cve-results.sarif")

// Act
err := applicabilityManager.setScanResults()
results, err := applicabilityManager.getScanResults()

// Assert
assert.NoError(t, applicabilityManagerError)
assert.NoError(t, err)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults)
assert.Equal(t, 5, len(applicabilityManager.applicabilityScanResults))
assert.Equal(t, utils.ApplicableStringValue, applicabilityManager.applicabilityScanResults["testCve1"])
assert.Equal(t, utils.NotApplicableStringValue, applicabilityManager.applicabilityScanResults["testCve3"])
assert.Equal(t, 5, len(results))
assert.Equal(t, utils.ApplicableStringValue, results["testCve1"])
assert.Equal(t, utils.NotApplicableStringValue, results["testCve3"])
}

func TestParseResults_AllCvesNotApplicable(t *testing.T) {
// Arrange
analyzerManagerExecuter = &analyzerManagerMock{}
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, &analyzerManagerMock{})
applicabilityManager, _, applicabilityManagerError := newApplicabilityScanManager(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, nil, &analyzerManagerMock{})
applicabilityManager.resultsFileName = filepath.Join("..", "..", "commands", "testdata", "applicability-scan", "no-applicable-cves-results.sarif")

// Act
err := applicabilityManager.setScanResults()
results, err := applicabilityManager.getScanResults()

// Assert
assert.NoError(t, applicabilityManagerError)
assert.NoError(t, err)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults)
assert.Equal(t, 5, len(applicabilityManager.applicabilityScanResults))
for _, cveResult := range applicabilityManager.applicabilityScanResults {
assert.Equal(t, 5, len(results))
for _, cveResult := range results {
assert.Equal(t, utils.NotApplicableStringValue, cveResult)
}
}
Expand All @@ -361,7 +358,7 @@ func TestGetExtendedScanResults_AnalyzerManagerReturnsError(t *testing.T) {
analyzerManagerExecuter = &analyzerManagerMock{}

// Act
extendedResults, err := GetExtendedScanResults(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, []coreutils.Technology{coreutils.Npm})
extendedResults, err := GetExtendedScanResults(fakeBasicXrayResults, fakeBasicDependencyGraph, &fakeServerDetails, []coreutils.Technology{coreutils.Npm}, nil)

// Assert
assert.Error(t, err)
Expand Down
Loading

0 comments on commit 542dc7a

Please sign in to comment.