Skip to content

Commit

Permalink
CR
Browse files Browse the repository at this point in the history
  • Loading branch information
EyalDelarea committed Sep 13, 2023
1 parent 8488830 commit 81a34ed
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ type scanConfiguration struct {
func (asm *ApplicabilityScanManager) createConfigFile(workingDir string) error {
skipDirs := jas.SkippedDirs
if asm.thirdPartyScan {
log.Debug("Including node modules folder in applicability scan")
log.Info("Including node modules folder in applicability scan")
skipDirs = removeElementFromSlice(skipDirs, jas.NodeModulesPattern)
}
configFileContent := applicabilityScanConfig{
Expand All @@ -170,5 +170,8 @@ func (asm *ApplicabilityScanManager) runAnalyzerManager() error {

func removeElementFromSlice(skipDirs []string, element string) []string {
deleteIndex := slices.Index(skipDirs, element)
if deleteIndex == -1 {
return skipDirs
}
return slices.Delete(skipDirs, deleteIndex, deleteIndex+1)
}
10 changes: 5 additions & 5 deletions xray/commands/audit/sca/npm/npm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/sca"
"github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"golang.org/x/exp/slices"
)

const (
npmPackageTypeIdentifier = "npm://"
ignoreScriptsFlag = "--ignore-scripts"
ignoreScriptsFlag = "--ignore-scripts"
)

func BuildDependencyTree(npmArgs []string) (dependencyTrees []*xrayUtils.GraphNode, uniqueDeps []string, err error) {
Expand Down Expand Up @@ -58,17 +58,17 @@ func addIgnoreScriptsFlag(npmArgs []string) []string {
func parseNpmDependenciesList(dependencies []buildinfo.Dependency, packageInfo *biutils.PackageInfo) (*xrayUtils.GraphNode, []string) {
treeMap := make(map[string][]string)
for _, dependency := range dependencies {
dependencyId := npmPackageTypeIdentifier + dependency.Id
dependencyId := utils.NpmPackageTypeIdentifier + dependency.Id
for _, requestedByNode := range dependency.RequestedBy {
parent := npmPackageTypeIdentifier + requestedByNode[0]
parent := utils.NpmPackageTypeIdentifier + requestedByNode[0]
if children, ok := treeMap[parent]; ok {
treeMap[parent] = appendUniqueChild(children, dependencyId)
} else {
treeMap[parent] = []string{dependencyId}
}
}
}
return sca.BuildXrayDependencyTree(treeMap, npmPackageTypeIdentifier+packageInfo.BuildInfoModuleId())
return sca.BuildXrayDependencyTree(treeMap, utils.NpmPackageTypeIdentifier+packageInfo.BuildInfoModuleId())
}

func appendUniqueChild(children []string, candidateDependency string) []string {
Expand Down
3 changes: 2 additions & 1 deletion xray/commands/audit/sca/npm/npm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package npm
import (
"encoding/json"
"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/sca"
"github.com/jfrog/jfrog-cli-core/v2/xray/utils"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"os"
"testing"
Expand Down Expand Up @@ -102,7 +103,7 @@ func TestParseNpmDependenciesList(t *testing.T) {
}
expectedUniqueDeps := []string{xrayDependenciesTree.Id}
for _, dep := range dependencies {
expectedUniqueDeps = append(expectedUniqueDeps, npmPackageTypeIdentifier+dep.Id)
expectedUniqueDeps = append(expectedUniqueDeps, utils.NpmPackageTypeIdentifier+dep.Id)
}
assert.ElementsMatch(t, uniqueDeps, expectedUniqueDeps, "First is actual, Second is Expected")

Expand Down
24 changes: 14 additions & 10 deletions xray/commands/audit/scarunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,7 @@ func runScaScanOnWorkingDir(params *AuditParams, results *Results, workingDir, r
continue
}
techResults = sca.BuildImpactPathsForScanResponse(techResults, fullDependencyTrees)
var directDependencies []string
if tech == coreutils.Pip || (params.thirdPartyApplicabilityScan && tech == coreutils.Npm) {
// When building pip dependency tree using pipdeptree, some of the direct dependencies are recognized as transitive and missed by the CA scanner.
// Our solution for this case is to send all dependencies to the CA scanner.
// When thirdPartyApplicabilityScan is true, use flatten graph to include all the dependencies in applicability scanning.
// Only npm is supported for this flag.
directDependencies = getDirectDependenciesFromTree([]*xrayCmdUtils.GraphNode{flattenTree})
} else {
directDependencies = getDirectDependenciesFromTree(fullDependencyTrees)
}
directDependencies := getDirectDependencies(params, tech, flattenTree, fullDependencyTrees)
params.AppendDirectDependencies(directDependencies)

results.ExtendedScanResults.XrayResults = append(results.ExtendedScanResults.XrayResults, techResults...)
Expand All @@ -117,6 +108,19 @@ func runScaScanOnWorkingDir(params *AuditParams, results *Results, workingDir, r
return
}

// When building pip dependency tree using pipdeptree, some of the direct dependencies are recognized as transitive and missed by the CA scanner.
// Our solution for this case is to send all dependencies to the CA scanner.
// When thirdPartyApplicabilityScan is true, use flatten graph to include all the dependencies in applicability scanning.
// Only npm is supported for this flag.
func getDirectDependencies(params *AuditParams, tech coreutils.Technology, flattenTree *xrayCmdUtils.GraphNode, fullDependencyTrees []*xrayCmdUtils.GraphNode) (directDependencies []string) {
if tech == coreutils.Pip || (params.thirdPartyApplicabilityScan && tech == coreutils.Npm) {
directDependencies = getDirectDependenciesFromTree([]*xrayCmdUtils.GraphNode{flattenTree})
} else {
directDependencies = getDirectDependenciesFromTree(fullDependencyTrees)
}
return directDependencies
}

// This function retrieves the dependency trees of the scanned project and extracts a set that contains only the direct dependencies.
func getDirectDependenciesFromTree(dependencyTrees []*xrayCmdUtils.GraphNode) []string {
directDependencies := datastructures.MakeSet[string]()
Expand Down
45 changes: 25 additions & 20 deletions xray/utils/resultstable.go
Original file line number Diff line number Diff line change
Expand Up @@ -959,21 +959,25 @@ func getApplicableCveValue(extendedResults *ExtendedScanResults, xrayCves []form
return ApplicabilityUndetermined
}

func getCveApplicability(cve formats.CveRow, applicabilityScanResults []*sarif.Run, components map[string]services.Component) *formats.Applicability {
applicability := &formats.Applicability{Status: string(ApplicabilityUndetermined)}
func getCveApplicability(cve formats.CveRow, applicabilityScanResults []*sarif.Run, components map[string]services.Component) (applicability *formats.Applicability) {
applicability = &formats.Applicability{}
if len(applicabilityScanResults) == 0 {
return
}
resultFound := false
for _, applicabilityRun := range applicabilityScanResults {
foundResult, _ := applicabilityRun.GetResultByRuleId(CveToApplicabilityRuleId(cve.Id))
if foundResult == nil {
result, _ := applicabilityRun.GetResultByRuleId(CveToApplicabilityRuleId(cve.Id))
if result == nil {
continue
}
applicability = &formats.Applicability{}
foundRule, _ := applicabilityRun.GetRuleById(CveToApplicabilityRuleId(cve.Id))
if foundRule != nil {
applicability.ScannerDescription = GetRuleFullDescription(foundRule)
resultFound = true
rule, _ := applicabilityRun.GetRuleById(CveToApplicabilityRuleId(cve.Id))
if rule != nil {
applicability.ScannerDescription = GetRuleFullDescription(rule)
}

// Add new evidences from locations
for _, location := range foundResult.Locations {
for _, location := range result.Locations {
fileName := GetRelativeLocationFileName(location, applicabilityRun.Invocations)
if shouldDisqualifyEvidence(components, fileName) {
continue
Expand All @@ -987,16 +991,20 @@ func getCveApplicability(cve formats.CveRow, applicabilityScanResults []*sarif.R
EndColumn: GetLocationEndColumn(location),
Snippet: GetLocationSnippet(location),
},
Reason: GetResultMsgText(foundResult),
Reason: GetResultMsgText(result),
})
}
}
if len(applicability.Evidence) == 0 {

switch {
case !resultFound:
applicability.Status = string(ApplicabilityUndetermined)
case len(applicability.Evidence) == 0:
applicability.Status = string(NotApplicable)
} else {
default:
applicability.Status = string(Applicable)
}
return applicability
return
}

func printApplicableCveValue(applicableValue ApplicabilityStatus, isTable bool) string {
Expand Down Expand Up @@ -1024,10 +1032,10 @@ func printApplicableCveValue(applicableValue ApplicabilityStatus, isTable bool)
// Found use of a badCode inside the node_modules from a different package, report applicable.
func shouldDisqualifyEvidence(components map[string]services.Component, evidenceFilePath string) (disqualify bool) {
for key := range components {
dependencyName := extractNpmDependencyNameFromComponent(key)
if dependencyName == "" {
if !strings.HasPrefix(key, NpmPackageTypeIdentifier) {
return
}
dependencyName := extractDependencyNameFromComponent(key, NpmPackageTypeIdentifier)
// Check both Unix & Windows paths.
if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) {
return true
Expand All @@ -1036,11 +1044,8 @@ func shouldDisqualifyEvidence(components map[string]services.Component, evidence
return
}

func extractNpmDependencyNameFromComponent(key string) (dependencyName string) {
if !strings.HasPrefix(key, NpmPackageTypeIdentifier) {
return
}
packageAndVersion := strings.TrimPrefix(key, NpmPackageTypeIdentifier)
func extractDependencyNameFromComponent(key string, techIdentifier string) (dependencyName string) {
packageAndVersion := strings.TrimPrefix(key, techIdentifier)
split := strings.Split(packageAndVersion, ":")
if len(split) < 2 {
return
Expand Down

0 comments on commit 81a34ed

Please sign in to comment.