@@ -4,10 +4,9 @@ import (
44 "encoding/json"
55 "errors"
66 "fmt"
7- "github.com/jfrog/jfrog-cli-security/commands/audit/sca/swift"
8-
97 biutils "github.com/jfrog/build-info-go/utils"
108 "github.com/jfrog/jfrog-cli-security/commands/audit/sca/conan"
9+ "github.com/jfrog/jfrog-cli-security/commands/audit/sca/swift"
1110 "github.com/jfrog/jfrog-client-go/utils/io/fileutils"
1211 "golang.org/x/exp/slices"
1312
@@ -99,9 +98,26 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner
9998 _ = targetResult .AddTargetError (fmt .Errorf ("failed to build dependency tree: %s" , bdtErr .Error ()), auditParams .AllowPartialResults ())
10099 continue
101100 }
101+ if auditParams .diffMode {
102+ if auditParams .resultsToCompare == nil {
103+ // First scan, no diff to compare
104+ log .Debug (fmt .Sprintf ("Diff scan - calculated dependencies tree for target %s, skipping scan part" , targetResult .Target ))
105+ continue
106+ } else if treeResult , bdtErr = getDiffDependencyTree (targetResult , results .SearchTargetResultsByPath (utils .GetRelativePath (targetResult .Target , cmdResults .GetCommonParentPath ()), auditParams .resultsToCompare ), treeResult .FullDepTrees ... ); bdtErr != nil {
107+ _ = targetResult .AddTargetError (fmt .Errorf ("failed to build diff dependency tree in source branch: %s" , bdtErr .Error ()), auditParams .AllowPartialResults ())
108+ continue
109+ }
110+ }
111+ if treeResult .FlatTree == nil || len (treeResult .FlatTree .Nodes ) == 0 {
112+ // No dependencies were found. We don't want to run the scan in this case.
113+ log .Debug (fmt .Sprintf ("No dependencies were found in target %s. Skipping SCA" , targetResult .Target ))
114+ continue
115+ }
116+ if err := logDeps (treeResult .FlatTree ); err != nil {
117+ log .Warn ("Failed to log dependencies tree: " + err .Error ())
118+ }
102119 // Create sca scan task
103120 auditParallelRunner .ScaScansWg .Add (1 )
104- // defer auditParallelRunner.ScaScansWg.Done()
105121 _ , taskErr := auditParallelRunner .Runner .AddTaskWithError (executeScaScanTask (auditParallelRunner , serverDetails , auditParams , targetResult , treeResult ), func (err error ) {
106122 _ = targetResult .AddTargetError (fmt .Errorf ("failed to execute SCA scan: %s" , err .Error ()), auditParams .AllowPartialResults ())
107123 })
@@ -133,7 +149,7 @@ func executeScaScanTask(auditParallelRunner *utils.SecurityParallelRunner, serve
133149 auditParallelRunner .ResultsMu .Lock ()
134150 defer auditParallelRunner .ResultsMu .Unlock ()
135151 // We add the results before checking for errors, so we can display the results even if an error occurred.
136- scan .NewScaScanResults (sca .GetScaScansStatusCode (xrayErr , scanResults ... ), results . DepTreeToSbom ( treeResult . FullDepTrees ), scanResults ... ).IsMultipleRootProject = clientutils .Pointer (len (treeResult .FullDepTrees ) > 1 )
152+ scan .NewScaScanResults (sca .GetScaScansStatusCode (xrayErr , scanResults ... ), scanResults ... ).IsMultipleRootProject = clientutils .Pointer (len (treeResult .FullDepTrees ) > 1 )
137153 addThirdPartyDependenciesToParams (auditParams , scan .Technology , treeResult .FlatTree , treeResult .FullDepTrees )
138154
139155 if xrayErr != nil {
@@ -277,10 +293,10 @@ func GetTechDependencyTree(params xrayutils.AuditParams, artifactoryServerDetail
277293 }
278294 log .Debug (fmt .Sprintf ("Created '%s' dependency tree with %d nodes. Elapsed time: %.1f seconds." , tech .ToFormal (), len (uniqueDeps ), time .Since (startTime ).Seconds ()))
279295 if len (uniqDepsWithTypes ) > 0 {
280- depTreeResult .FlatTree , err = createFlatTreeWithTypes (uniqDepsWithTypes )
296+ depTreeResult .FlatTree = createFlatTreeWithTypes (uniqDepsWithTypes )
281297 return
282298 }
283- depTreeResult .FlatTree , err = createFlatTree (uniqueDeps )
299+ depTreeResult .FlatTree = createFlatTree (uniqueDeps )
284300 return
285301}
286302
@@ -331,10 +347,7 @@ func SetResolutionRepoInAuditParamsIfExists(params utils.AuditParams, tech techu
331347 return
332348}
333349
334- func createFlatTreeWithTypes (uniqueDeps map [string ]* xray.DepTreeNode ) (* xrayCmdUtils.GraphNode , error ) {
335- if err := logDeps (uniqueDeps ); err != nil {
336- return nil , err
337- }
350+ func createFlatTreeWithTypes (uniqueDeps map [string ]* xray.DepTreeNode ) * xrayCmdUtils.GraphNode {
338351 var uniqueNodes []* xrayCmdUtils.GraphNode
339352 for uniqueDep , nodeAttr := range uniqueDeps {
340353 node := & xrayCmdUtils.GraphNode {Id : uniqueDep }
@@ -344,26 +357,31 @@ func createFlatTreeWithTypes(uniqueDeps map[string]*xray.DepTreeNode) (*xrayCmdU
344357 }
345358 uniqueNodes = append (uniqueNodes , node )
346359 }
347- return & xrayCmdUtils.GraphNode {Id : "root" , Nodes : uniqueNodes }, nil
360+ return & xrayCmdUtils.GraphNode {Id : "root" , Nodes : uniqueNodes }
348361}
349362
350- func createFlatTree (uniqueDeps []string ) (* xrayCmdUtils.GraphNode , error ) {
351- if err := logDeps (uniqueDeps ); err != nil {
352- return nil , err
353- }
363+ func createFlatTree (uniqueDeps []string ) * xrayCmdUtils.GraphNode {
354364 uniqueNodes := []* xrayCmdUtils.GraphNode {}
355365 for _ , uniqueDep := range uniqueDeps {
356366 uniqueNodes = append (uniqueNodes , & xrayCmdUtils.GraphNode {Id : uniqueDep })
357367 }
358- return & xrayCmdUtils.GraphNode {Id : "root" , Nodes : uniqueNodes }, nil
368+ return & xrayCmdUtils.GraphNode {Id : "root" , Nodes : uniqueNodes }
369+ }
370+
371+ func flatTreeToStringList (flatTree * xrayCmdUtils.GraphNode ) []string {
372+ var uniqueNodes []string
373+ for _ , node := range flatTree .Nodes {
374+ uniqueNodes = append (uniqueNodes , node .Id )
375+ }
376+ return uniqueNodes
359377}
360378
361- func logDeps (uniqueDeps any ) (err error ) {
379+ func logDeps (flatTree * xrayCmdUtils. GraphNode ) (err error ) {
362380 if log .GetLogger ().GetLogLevel () != log .DEBUG {
363381 // Avoid printing and marshaling if not on DEBUG mode.
364382 return
365383 }
366- jsonList , err := json .Marshal (uniqueDeps )
384+ jsonList , err := json .Marshal (flatTreeToStringList ( flatTree ) )
367385 if errorutils .CheckError (err ) != nil {
368386 return err
369387 }
@@ -388,6 +406,7 @@ func buildDependencyTree(scan *results.TargetResults, params *AuditParams) (*Dep
388406 if treeResult .FlatTree == nil || len (treeResult .FlatTree .Nodes ) == 0 {
389407 return nil , errorutils .CheckErrorf ("no dependencies were found. Please try to build your project and re-run the audit command" )
390408 }
409+ scan .SetSbom (results .DepTreeToSbom (treeResult .FullDepTrees ))
391410 return & treeResult , nil
392411}
393412
@@ -402,3 +421,29 @@ func dumpScanResponseToFileIfNeeded(results []services.ScanResponse, scanResults
402421 }
403422 return utils .DumpContentToFile (fileContent , scanResultsOutputDir , scanType .String ())
404423}
424+
425+ // Collect dependencies exists in target and not in resultsToCompare
426+ func getDiffDependencyTree (scanResults * results.TargetResults , resultsToCompare * results.TargetResults , fullDepTrees ... * xrayCmdUtils.GraphNode ) (* DependencyTreeResult , error ) {
427+ if resultsToCompare == nil {
428+ return nil , fmt .Errorf ("failed to get diff dependency tree: no results to compare" )
429+ }
430+ log .Debug (fmt .Sprintf ("Comparing %s SBOM with %s to get diff" , scanResults .Target , resultsToCompare .Target ))
431+ // Compare the dependency trees
432+ filterDepsMap := datastructures .MakeSet [string ]()
433+ for _ , component := range resultsToCompare .Sbom .Components {
434+ filterDepsMap .Add (techutils .ToXrayComponentId (component .XrayType , component .Component , component .Version ))
435+ }
436+ addedDepsMap := datastructures .MakeSet [string ]()
437+ for _ , component := range scanResults .Sbom .Components {
438+ componentId := techutils .ToXrayComponentId (component .XrayType , component .Component , component .Version )
439+ if exists := filterDepsMap .Exists (componentId ); ! exists {
440+ // Dependency in scan results but not in results to compare
441+ addedDepsMap .Add (componentId )
442+ }
443+ }
444+ diffDepTree := DependencyTreeResult {
445+ FlatTree : createFlatTree (addedDepsMap .ToSlice ()),
446+ FullDepTrees : fullDepTrees ,
447+ }
448+ return & diffDepTree , nil
449+ }
0 commit comments