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

Audit - accept working dirs for IaC/Secrets scanners #884

Merged
merged 16 commits into from
Aug 14, 2023
Merged
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)
omerzi marked this conversation as resolved.
Show resolved Hide resolved
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