Skip to content

Use exclude pattern when building dotnet dependency tree #24

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

Merged
merged 11 commits into from
Feb 25, 2024
4 changes: 2 additions & 2 deletions cli/docs/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
"github.com/jfrog/jfrog-cli-security/commands/audit"
"github.com/jfrog/jfrog-cli-security/commands/audit/sca"
"github.com/jfrog/jfrog-cli-security/commands/curation"
"github.com/jfrog/jfrog-cli-security/commands/xray/offlineupdate"
)
Expand Down Expand Up @@ -200,7 +200,7 @@ var flagsMap = map[string]components.Flag{
ExclusionsAudit: components.NewStringFlag(
Exclusions,
"List of exclusions separated by semicolons, utilized to skip sub-projects from undergoing an audit. These exclusions may incorporate the * and ? wildcards.",
components.WithStrDefaultValue(strings.Join(audit.DefaultExcludePatterns, ";")),
components.WithStrDefaultValue(strings.Join(sca.DefaultExcludePatterns, ";")),
),
Mvn: components.NewBoolFlag(Mvn, "Set to true to request audit for a Maven project."),
Gradle: components.NewBoolFlag(Gradle, "Set to true to request audit for a Gradle project."),
Expand Down
6 changes: 3 additions & 3 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,7 @@ func createAuditCmd(c *components.Context) (*audit.AuditCommand, error) {
SetPrintExtendedTable(c.GetBoolFlagValue(flags.ExtendedTable)).
SetMinSeverityFilter(minSeverity).
SetFixableOnly(c.GetBoolFlagValue(flags.FixableOnly)).
SetThirdPartyApplicabilityScan(c.GetBoolFlagValue(flags.ThirdPartyContextualAnalysis)).
SetExclusions(pluginsCommon.GetStringsArrFlagValue(c, flags.Exclusions))
SetThirdPartyApplicabilityScan(c.GetBoolFlagValue(flags.ThirdPartyContextualAnalysis))

if c.GetStringFlagValue(flags.Watches) != "" {
auditCmd.SetWatches(splitByCommaAndTrim(c.GetStringFlagValue(flags.Watches)))
Expand All @@ -373,7 +372,8 @@ func createAuditCmd(c *components.Context) (*audit.AuditCommand, error) {
SetUseWrapper(c.GetBoolFlagValue(flags.UseWrapper)).
SetInsecureTls(c.GetBoolFlagValue(flags.InsecureTls)).
SetNpmScope(c.GetStringFlagValue(flags.DepType)).
SetPipRequirementsFile(c.GetStringFlagValue(flags.RequirementsFile))
SetPipRequirementsFile(c.GetStringFlagValue(flags.RequirementsFile)).
SetExclusions(pluginsCommon.GetStringsArrFlagValue(c, flags.Exclusions))
return auditCmd, err
}

Expand Down
5 changes: 2 additions & 3 deletions commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ func (auditCmd *AuditCommand) Run() (err error) {
SetMinSeverityFilter(auditCmd.minSeverityFilter).
SetFixableOnly(auditCmd.fixableOnly).
SetGraphBasicParams(auditCmd.AuditBasicParams).
SetThirdPartyApplicabilityScan(auditCmd.thirdPartyApplicabilityScan).
SetExclusions(auditCmd.exclusions).
SetIsRecursiveScan(isRecursiveScan)
SetThirdPartyApplicabilityScan(auditCmd.thirdPartyApplicabilityScan)
auditParams.SetIsRecursiveScan(isRecursiveScan).SetExclusions(auditCmd.Exclusions())
auditResults, err := RunAudit(auditParams)
if err != nil {
return
Expand Down
16 changes: 0 additions & 16 deletions commands/audit/auditparams.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ import (
type AuditParams struct {
xrayGraphScanParams *services.XrayGraphScanParams
workingDirs []string
exclusions []string
installFunc func(tech string) error
fixableOnly bool
minSeverityFilter string
*xrayutils.AuditBasicParams
xrayVersion string
// Include third party dependencies source code in the applicability scan.
thirdPartyApplicabilityScan bool
isRecursiveScan bool
}

func NewAuditParams() *AuditParams {
Expand All @@ -42,20 +40,6 @@ func (params *AuditParams) XrayVersion() string {
return params.xrayVersion
}

func (params *AuditParams) Exclusions() []string {
return params.exclusions
}

func (params *AuditParams) SetExclusions(exclusions []string) *AuditParams {
params.exclusions = exclusions
return params
}

func (params *AuditParams) SetIsRecursiveScan(isRecursiveScan bool) *AuditParams {
params.isRecursiveScan = isRecursiveScan
return params
}

func (params *AuditParams) SetXrayGraphScanParams(xrayGraphScanParams *services.XrayGraphScanParams) *AuditParams {
params.xrayGraphScanParams = xrayGraphScanParams
return params
Expand Down
12 changes: 12 additions & 0 deletions commands/audit/sca/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,25 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
"github.com/jfrog/jfrog-cli-security/scangraph"
"github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns"
clientutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
ioUtils "github.com/jfrog/jfrog-client-go/utils/io"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
)

var DefaultExcludePatterns = []string{"*.git*", "*node_modules*", "*target*", "*venv*", "*test*"}

func GetExcludePattern(params utils.AuditParams) string {
exclusions := params.Exclusions()
if len(exclusions) == 0 {
exclusions = append(exclusions, DefaultExcludePatterns...)
}
return fspatterns.PrepareExcludePathPattern(exclusions, clientutils.WildCardPattern, params.IsRecursiveScan())
}

func RunXrayDependenciesTreeScanGraph(dependencyTree *xrayUtils.GraphNode, progress ioUtils.ProgressMgr, technology coreutils.Technology, scanGraphParams *scangraph.ScanGraphParams) (results []services.ScanResponse, err error) {
scanGraphParams.XrayGraphScanParams().DependenciesGraph = dependencyTree
xscGitInfoContext := scanGraphParams.XrayGraphScanParams().XscGitInfoContext
Expand Down
48 changes: 47 additions & 1 deletion commands/audit/sca/common_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,63 @@
package sca

import (
"golang.org/x/exp/maps"
"reflect"
"testing"

"golang.org/x/exp/maps"

"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
coreXray "github.com/jfrog/jfrog-cli-core/v2/utils/xray"
"github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-client-go/xray/services"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"github.com/stretchr/testify/assert"
)

func TestGetExcludePattern(t *testing.T) {
tests := []struct {
name string
params func() *utils.AuditBasicParams
expected string
}{
{
name: "Test exclude pattern recursive",
params: func() *utils.AuditBasicParams {
param := &utils.AuditBasicParams{}
param.SetExclusions([]string{"exclude1", "exclude2"}).SetIsRecursiveScan(true)
return param
},
expected: "(^exclude1$)|(^exclude2$)",
},
{
name: "Test no exclude pattern recursive",
params: func() *utils.AuditBasicParams { return (&utils.AuditBasicParams{}).SetIsRecursiveScan(true) },
expected: "(^.*\\.git.*$)|(^.*node_modules.*$)|(^.*target.*$)|(^.*venv.*$)|(^.*test.*$)",
},
{
name: "Test exclude pattern not recursive",
params: func() *utils.AuditBasicParams {
param := &utils.AuditBasicParams{}
param.SetExclusions([]string{"exclude1", "exclude2"})
return param
},
expected: "(^exclude1$)|(^exclude2$)",
},
{
name: "Test no exclude pattern",
params: func() *utils.AuditBasicParams { return &utils.AuditBasicParams{} },
expected: "(^.*\\.git.*$)|(^.*node_modules.*$)|(^.*target.*$)|(^.*venv.*$)|(^.*test.*$)",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := GetExcludePattern(test.params())
assert.Equal(t, test.expected, result)
})
}
}

func TestBuildXrayDependencyTree(t *testing.T) {
treeHelper := make(map[string]coreXray.DepTreeNode)
rootDep := coreXray.DepTreeNode{Children: []string{"topDep1", "topDep2", "topDep3"}}
Expand Down
21 changes: 12 additions & 9 deletions commands/audit/sca/nuget/nuget.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ package nuget
import (
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"

bidotnet "github.com/jfrog/build-info-go/build/utils/dotnet"
"github.com/jfrog/build-info-go/build/utils/dotnet/solution"
"github.com/jfrog/build-info-go/entities"
Expand All @@ -11,17 +17,13 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/dotnet"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
coreXray "github.com/jfrog/jfrog-cli-core/v2/utils/xray"
"github.com/jfrog/jfrog-cli-security/commands/audit/sca"
"github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/jfrog/jfrog-client-go/utils/log"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"golang.org/x/exp/maps"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
)

const (
Expand All @@ -40,7 +42,8 @@ func BuildDependencyTree(params utils.AuditParams) (dependencyTree []*xrayUtils.
if err != nil {
return
}
sol, err := solution.Load(wd, "", log.Logger)
exclusionPattern := sca.GetExcludePattern(params)
sol, err := solution.Load(wd, "", exclusionPattern, log.Logger)
if err != nil && !strings.Contains(err.Error(), globalPackagesNotFoundErrorMessage) {
// In older NuGet projects that utilize NuGet Cli and package.config, if the project is not installed, the solution.Load function raises an error because it cannot find global package paths.
// This issue is resolved by executing the 'nuget restore' command followed by running solution.Load again. Therefore, in this scenario, we need to proceed with this process.
Expand All @@ -49,7 +52,7 @@ func BuildDependencyTree(params utils.AuditParams) (dependencyTree []*xrayUtils.

if isInstallRequired(params, sol) {
log.Info("Dependencies sources were not detected nor 'install' command provided. Running 'restore' command")
sol, err = runDotnetRestoreAndLoadSolution(params, wd)
sol, err = runDotnetRestoreAndLoadSolution(params, wd, exclusionPattern)
if err != nil {
return
}
Expand All @@ -74,7 +77,7 @@ func isInstallRequired(params utils.AuditParams, sol solution.Solution) bool {

// Generates a temporary duplicate of the project to execute the 'install' command without impacting the original directory and establishing the JFrog configuration file for Artifactory resolution
// Additionally, re-loads the project's Solution so the dependencies sources will be identified
func runDotnetRestoreAndLoadSolution(params utils.AuditParams, originalWd string) (sol solution.Solution, err error) {
func runDotnetRestoreAndLoadSolution(params utils.AuditParams, originalWd, exclusionPattern string) (sol solution.Solution, err error) {
// Creating a temporary copy of the project in order to run 'install' command without effecting the original directory + creating the jfrog config for artifactory resolution
tmpWd, err := fileutils.CreateTempDir()
if err != nil {
Expand Down Expand Up @@ -129,7 +132,7 @@ func runDotnetRestoreAndLoadSolution(params utils.AuditParams, originalWd string
if err != nil {
return
}
sol, err = solution.Load(tmpWd, "", log.Logger)
sol, err = solution.Load(tmpWd, "", exclusionPattern, log.Logger)
return
}

Expand Down
4 changes: 2 additions & 2 deletions commands/audit/sca/nuget/nuget_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ func TestRunDotnetRestoreAndLoadSolution(t *testing.T) {
dotnetProjectPath := filepath.Join(testDataDir, "dotnet", projectName)
assert.NoError(t, utils.CopyDir(dotnetProjectPath, tempDirPath, true, nil))

sol, err := solution.Load(tempDirPath, "", log.Logger)
sol, err := solution.Load(tempDirPath, "", "", log.Logger)
assert.NoError(t, err)
assert.Empty(t, sol.GetProjects())
assert.Empty(t, sol.GetDependenciesSources())

params := &xrayUtils2.AuditBasicParams{}
sol, err = runDotnetRestoreAndLoadSolution(params, tempDirPath)
sol, err = runDotnetRestoreAndLoadSolution(params, tempDirPath, "")
assert.NoError(t, err)
assert.NotEmpty(t, sol.GetProjects())
assert.NotEmpty(t, sol.GetDependenciesSources())
Expand Down
13 changes: 1 addition & 12 deletions commands/audit/scarunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@ import (
"github.com/jfrog/jfrog-cli-security/commands/audit/sca/yarn"
"github.com/jfrog/jfrog-cli-security/scangraph"
xrayutils "github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns"
clientutils "github.com/jfrog/jfrog-client-go/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"
xrayCmdUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
)

var DefaultExcludePatterns = []string{"*.git*", "*node_modules*", "*target*", "*venv*", "*test*"}

func runScaScan(params *AuditParams, results *xrayutils.Results) (err error) {
// Prepare
currentWorkingDir, err := os.Getwd()
Expand Down Expand Up @@ -75,7 +72,7 @@ func runScaScan(params *AuditParams, results *xrayutils.Results) (err error) {
func getScaScansToPreform(params *AuditParams) (scansToPreform []*xrayutils.ScaScanResult) {
for _, requestedDirectory := range params.workingDirs {
// Detect descriptors and technologies in the requested directory.
techToWorkingDirs, err := coreutils.DetectTechnologiesDescriptors(requestedDirectory, params.isRecursiveScan, params.Technologies(), getRequestedDescriptors(params), getExcludePattern(params, params.isRecursiveScan))
techToWorkingDirs, err := coreutils.DetectTechnologiesDescriptors(requestedDirectory, params.IsRecursiveScan(), params.Technologies(), getRequestedDescriptors(params), sca.GetExcludePattern(params.AuditBasicParams))
if err != nil {
log.Warn("Couldn't detect technologies in", requestedDirectory, "directory.", err.Error())
continue
Expand Down Expand Up @@ -108,14 +105,6 @@ func getRequestedDescriptors(params *AuditParams) map[coreutils.Technology][]str
return requestedDescriptors
}

func getExcludePattern(params *AuditParams, recursive bool) string {
exclusions := params.Exclusions()
if len(exclusions) == 0 {
exclusions = append(exclusions, DefaultExcludePatterns...)
}
return fspatterns.PrepareExcludePathPattern(exclusions, clientutils.WildCardPattern, recursive)
}

// Preform the SCA scan for the given scan information.
// This method will change the working directory to the scan's working directory.
func executeScaScan(serverDetails *config.ServerDetails, params *AuditParams, scan *xrayutils.ScaScanResult) (err error) {
Expand Down
57 changes: 5 additions & 52 deletions commands/audit/scarunner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,55 +117,6 @@ func createEmptyFile(t *testing.T, path string) {
assert.NoError(t, file.Close())
}

func TestGetExcludePattern(t *testing.T) {
tests := []struct {
name string
params func() *AuditParams
recursive bool
expected string
}{
{
name: "Test exclude pattern recursive",
params: func() *AuditParams {
param := NewAuditParams()
param.SetExclusions([]string{"exclude1", "exclude2"})
return param
},
recursive: true,
expected: "(^exclude1$)|(^exclude2$)",
},
{
name: "Test no exclude pattern recursive",
params: NewAuditParams,
recursive: true,
expected: "(^.*\\.git.*$)|(^.*node_modules.*$)|(^.*target.*$)|(^.*venv.*$)|(^.*test.*$)",
},
{
name: "Test exclude pattern not recursive",
params: func() *AuditParams {
param := NewAuditParams()
param.SetExclusions([]string{"exclude1", "exclude2"})
return param
},
recursive: false,
expected: "(^exclude1$)|(^exclude2$)",
},
{
name: "Test no exclude pattern",
params: NewAuditParams,
recursive: false,
expected: "(^.*\\.git.*$)|(^.*node_modules.*$)|(^.*target.*$)|(^.*venv.*$)|(^.*test.*$)",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := getExcludePattern(test.params(), test.recursive)
assert.Equal(t, test.expected, result)
})
}
}

func TestGetScaScansToPreform(t *testing.T) {

dir, cleanUp := createTestDir(t)
Expand All @@ -180,8 +131,8 @@ func TestGetScaScansToPreform(t *testing.T) {
name: "Test specific technologies",
wd: dir,
params: func() *AuditParams {
param := NewAuditParams().SetIsRecursiveScan(true).SetWorkingDirs([]string{dir})
param.SetTechnologies([]string{"maven", "npm", "go"})
param := NewAuditParams().SetWorkingDirs([]string{dir})
param.SetTechnologies([]string{"maven", "npm", "go"}).SetIsRecursiveScan(true)
return param
},
expected: []*xrayutils.ScaScanResult{
Expand Down Expand Up @@ -210,7 +161,9 @@ func TestGetScaScansToPreform(t *testing.T) {
name: "Test all",
wd: dir,
params: func() *AuditParams {
return NewAuditParams().SetIsRecursiveScan(true).SetWorkingDirs([]string{dir})
param := NewAuditParams().SetWorkingDirs([]string{dir})
param.SetIsRecursiveScan(true)
return param
},
expected: []*xrayutils.ScaScanResult{
{
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect
)

// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 dev
replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20240225124040-0941c5ce1007

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go dev
replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240222155638-e55c7d7acbee

replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c
Loading