@@ -10,12 +10,19 @@ import (
1010 "regexp"
1111 "strings"
1212
13+ "golang.org/x/exp/maps"
14+ "golang.org/x/exp/slices"
15+
16+ "github.com/jfrog/jfrog-cli-security/jas"
17+ "github.com/jfrog/jfrog-cli-security/jas/applicability"
18+ "github.com/jfrog/jfrog-cli-security/jas/runner"
19+ "github.com/jfrog/jfrog-cli-security/jas/secrets"
1320 "github.com/jfrog/jfrog-cli-security/scangraph"
1421 xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
22+ "golang.org/x/sync/errgroup"
1523
1624 "github.com/jfrog/gofrog/parallel"
1725 "github.com/jfrog/jfrog-cli-core/v2/common/format"
18- outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format"
1926 "github.com/jfrog/jfrog-cli-core/v2/common/spec"
2027 "github.com/jfrog/jfrog-cli-core/v2/utils/config"
2128 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
@@ -35,8 +42,9 @@ type FileContext func(string) parallel.TaskFunc
3542type indexFileHandlerFunc func (file string )
3643
3744type ScanInfo struct {
38- Target string
39- Result * services.ScanResponse
45+ Target string
46+ Result * services.ScanResponse
47+ ExtendedScanResults * utils.ExtendedScanResults
4048}
4149
4250const (
@@ -52,7 +60,7 @@ type ScanCommand struct {
5260 // The location of the downloaded Xray indexer binary on the local file system.
5361 indexerPath string
5462 indexerTempDir string
55- outputFormat outputFormat .OutputFormat
63+ outputFormat format .OutputFormat
5664 projectKey string
5765 minSeverityFilter string
5866 watches []string
@@ -63,6 +71,7 @@ type ScanCommand struct {
6371 bypassArchiveLimits bool
6472 fixableOnly bool
6573 progress ioUtils.ProgressMgr
74+ commandSupportsJAS bool
6675}
6776
6877func (scanCmd * ScanCommand ) SetMinSeverityFilter (minSeverityFilter string ) * ScanCommand {
@@ -75,6 +84,11 @@ func (scanCmd *ScanCommand) SetFixableOnly(fixable bool) *ScanCommand {
7584 return scanCmd
7685}
7786
87+ func (scanCmd * ScanCommand ) SetRunJasScans (run bool ) * ScanCommand {
88+ scanCmd .commandSupportsJAS = run
89+ return scanCmd
90+ }
91+
7892func (scanCmd * ScanCommand ) SetProgress (progress ioUtils.ProgressMgr ) {
7993 scanCmd .progress = progress
8094}
@@ -84,7 +98,7 @@ func (scanCmd *ScanCommand) SetThreads(threads int) *ScanCommand {
8498 return scanCmd
8599}
86100
87- func (scanCmd * ScanCommand ) SetOutputFormat (format outputFormat .OutputFormat ) * ScanCommand {
101+ func (scanCmd * ScanCommand ) SetOutputFormat (format format .OutputFormat ) * ScanCommand {
88102 scanCmd .outputFormat = format
89103 return scanCmd
90104}
@@ -182,6 +196,16 @@ func (scanCmd *ScanCommand) Run() (err error) {
182196 return err
183197 }
184198
199+ scanResults := xrutils .NewAuditResults ()
200+ scanResults .XrayVersion = xrayVersion
201+
202+ scanResults .ExtendedScanResults .EntitledForJas , err = jas .IsEntitledForJas (xrayManager , xrayVersion )
203+ errGroup := new (errgroup.Group )
204+ if scanResults .ExtendedScanResults .EntitledForJas {
205+ // Download (if needed) the analyzer manager in a background routine.
206+ errGroup .Go (xrutils .DownloadAnalyzerManagerIfNeeded )
207+ }
208+
185209 // Validate Xray minimum version for graph scan command
186210 err = clientutils .ValidateMinimumVersion (clientutils .Xray , xrayVersion , scangraph .GraphScanMinXrayVersion )
187211 if err != nil {
@@ -226,16 +250,20 @@ func (scanCmd *ScanCommand) Run() (err error) {
226250 fileCollectingErrorsQueue := clientutils .NewErrorsQueue (1 )
227251 // Start walking on the filesystem to "produce" files that match the given pattern
228252 // while the consumer uses the indexer to index those files.
229- scanCmd .prepareScanTasks (fileProducerConsumer , indexedFileProducerConsumer , resultsArr , fileProducerErrors , indexedFileProducerErrors , fileCollectingErrorsQueue , xrayVersion )
253+ scanCmd .prepareScanTasks (fileProducerConsumer , indexedFileProducerConsumer , scanResults . ExtendedScanResults . EntitledForJas , resultsArr , fileProducerErrors , indexedFileProducerErrors , fileCollectingErrorsQueue , xrayVersion )
230254 scanCmd .performScanTasks (fileProducerConsumer , indexedFileProducerConsumer )
231255
232256 // Handle results
233257 flatResults := []xrutils.ScaScanResult {}
258+
234259 for _ , arr := range resultsArr {
235260 for _ , res := range arr {
236261 flatResults = append (flatResults , xrutils.ScaScanResult {Target : res .Target , XrayResults : []services.ScanResponse {* res .Result }})
262+ scanResults .ExtendedScanResults .ApplicabilityScanResults = append (scanResults .ExtendedScanResults .ApplicabilityScanResults , res .ExtendedScanResults .ApplicabilityScanResults ... )
263+ scanResults .ExtendedScanResults .SecretsScanResults = append (scanResults .ExtendedScanResults .SecretsScanResults , res .ExtendedScanResults .SecretsScanResults ... )
237264 }
238265 }
266+
239267 if scanCmd .progress != nil {
240268 if err = scanCmd .progress .Quit (); err != nil {
241269 return err
@@ -251,10 +279,13 @@ func (scanCmd *ScanCommand) Run() (err error) {
251279 scanErrors = appendErrorSlice (scanErrors , fileProducerErrors )
252280 scanErrors = appendErrorSlice (scanErrors , indexedFileProducerErrors )
253281
254- scanResults := xrutils .NewAuditResults ()
255- scanResults .XrayVersion = xrayVersion
256282 scanResults .ScaResults = flatResults
257283
284+ // Wait for the Download of the AnalyzerManager to complete.
285+ if err = errGroup .Wait (); err != nil {
286+ err = errors .New ("failed while trying to get Analyzer Manager: " + err .Error ())
287+ }
288+
258289 if err = xrutils .NewResultsWriter (scanResults ).
259290 SetOutputFormat (scanCmd .outputFormat ).
260291 SetIncludeVulnerabilities (scanCmd .includeVulnerabilities ).
@@ -296,14 +327,14 @@ func (scanCmd *ScanCommand) CommandName() string {
296327 return "xr_scan"
297328}
298329
299- func (scanCmd * ScanCommand ) prepareScanTasks (fileProducer , indexedFileProducer parallel.Runner , resultsArr [][]* ScanInfo , fileErrors , indexedFileErrors [][]formats.SimpleJsonError , fileCollectingErrorsQueue * clientutils.ErrorsQueue , xrayVersion string ) {
330+ func (scanCmd * ScanCommand ) prepareScanTasks (fileProducer , indexedFileProducer parallel.Runner , entitledForJas bool , resultsArr [][]* ScanInfo , fileErrors , indexedFileErrors [][]formats.SimpleJsonError , fileCollectingErrorsQueue * clientutils.ErrorsQueue , xrayVersion string ) {
300331 go func () {
301332 defer fileProducer .Done ()
302333 // Iterate over file-spec groups and produce indexing tasks.
303334 // When encountering an error, log and move to next group.
304335 specFiles := scanCmd .spec .Files
305336 for i := range specFiles {
306- artifactHandlerFunc := scanCmd .createIndexerHandlerFunc (& specFiles [i ], indexedFileProducer , resultsArr , fileErrors , indexedFileErrors , xrayVersion )
337+ artifactHandlerFunc := scanCmd .createIndexerHandlerFunc (& specFiles [i ], entitledForJas , indexedFileProducer , resultsArr , fileErrors , indexedFileErrors , xrayVersion )
307338 taskHandler := getAddTaskToProducerFunc (fileProducer , artifactHandlerFunc )
308339
309340 err := collectFilesForIndexing (specFiles [i ], taskHandler )
@@ -315,7 +346,7 @@ func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer p
315346 }()
316347}
317348
318- func (scanCmd * ScanCommand ) createIndexerHandlerFunc (file * spec.File , indexedFileProducer parallel.Runner , resultsArr [][]* ScanInfo , fileErrors , indexedFileErrors [][]formats.SimpleJsonError , xrayVersion string ) FileContext {
349+ func (scanCmd * ScanCommand ) createIndexerHandlerFunc (file * spec.File , entitledForJas bool , indexedFileProducer parallel.Runner , resultsArr [][]* ScanInfo , fileErrors , indexedFileErrors [][]formats.SimpleJsonError , xrayVersion string ) FileContext {
319350 return func (filePath string ) parallel.TaskFunc {
320351 return func (threadId int ) (err error ) {
321352 logMsgPrefix := clientutils .GetLogMsgPrefix (threadId , false )
@@ -360,12 +391,26 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, indexedFil
360391 return err
361392 }
362393 scanResults , err := scangraph .RunScanGraphAndGetResults (scanGraphParams , xrayManager )
394+
363395 if err != nil {
364396 log .Error (fmt .Sprintf ("scanning '%s' failed with error: %s" , graph .Id , err .Error ()))
365397 indexedFileErrors [threadId ] = append (indexedFileErrors [threadId ], formats.SimpleJsonError {FilePath : filePath , ErrorMessage : err .Error ()})
366398 return
367399 }
368- resultsArr [threadId ] = append (resultsArr [threadId ], & ScanInfo {Target : filePath , Result : scanResults })
400+
401+ extendedScanResults := utils.ExtendedScanResults {}
402+ if entitledForJas && scanCmd .commandSupportsJAS {
403+ // Run Jas scans
404+ workingDirs := []string {filePath }
405+ err = runner .RunJasScannersAndSetResults (& extendedScanResults , []coreutils.Technology {coreutils .Technology (scanResults .ScannedPackageType )}, []services.ScanResponse {* scanResults }, depsListFromVulnerabilities (* scanResults ), scanCmd .serverDetails , workingDirs , nil , false , "" , applicability .ApplicabilityDockerScanScanType , secrets .SecretsScannerDockerScanType )
406+
407+ if err != nil {
408+ log .Error (fmt .Sprintf ("scanning '%s' failed with error: %s" , graph .Id , err .Error ()))
409+ indexedFileErrors [threadId ] = append (indexedFileErrors [threadId ], formats.SimpleJsonError {FilePath : filePath , ErrorMessage : err .Error ()})
410+ return
411+ }
412+ }
413+ resultsArr [threadId ] = append (resultsArr [threadId ], & ScanInfo {Target : filePath , Result : scanResults , ExtendedScanResults : & extendedScanResults })
369414 return
370415 }
371416
@@ -469,6 +514,20 @@ func appendErrorSlice(scanErrors []formats.SimpleJsonError, errorsToAdd [][]form
469514 return scanErrors
470515}
471516
517+ func depsListFromVulnerabilities (scanResult ... services.ScanResponse ) (depsList []string ) {
518+ for _ , result := range scanResult {
519+ for _ , vulnerability := range result .Vulnerabilities {
520+ dependencies := maps .Keys (vulnerability .Components )
521+ for _ , dependency := range dependencies {
522+ if ! slices .Contains (depsList , dependency ) {
523+ depsList = append (depsList , dependency )
524+ }
525+ }
526+ }
527+ }
528+ return
529+ }
530+
472531func ConditionalUploadDefaultScanFunc (serverDetails * config.ServerDetails , fileSpec * spec.SpecFiles , threads int , scanOutputFormat format.OutputFormat ) error {
473532 return NewScanCommand ().SetServerDetails (serverDetails ).SetSpec (fileSpec ).SetThreads (threads ).SetOutputFormat (scanOutputFormat ).SetFail (true ).SetPrintExtendedTable (false ).Run ()
474533}
0 commit comments