@@ -3,7 +3,10 @@ package audit
33import (
44 "errors"
55 "fmt"
6+ "os"
7+ "strings"
68
9+ "github.com/jfrog/gofrog/parallel"
710 jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go"
811 "github.com/jfrog/jfrog-cli-core/v2/utils/config"
912 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
@@ -125,14 +128,12 @@ func (auditCmd *AuditCommand) Run() (err error) {
125128 SetScansResultsOutputDir (auditCmd .scanResultsOutputDir )
126129 auditParams .SetIsRecursiveScan (isRecursiveScan ).SetExclusions (auditCmd .Exclusions ())
127130
128- auditResults , err := RunAudit (auditParams )
129- if err != nil {
130- return
131- }
131+ auditResults := RunAudit (auditParams )
132132 auditCmd .analyticsMetricsService .UpdateGeneralEvent (auditCmd .analyticsMetricsService .CreateXscAnalyticsGeneralEventFinalizeFromAuditResults (auditResults ))
133+
133134 if auditCmd .Progress () != nil {
134135 if err = auditCmd .Progress ().Quit (); err != nil {
135- return
136+ return errors . Join ( err , auditResults . GetErrors ())
136137 }
137138 }
138139 var messages []string
@@ -148,7 +149,7 @@ func (auditCmd *AuditCommand) Run() (err error) {
148149 SetExtraMessages (messages ).
149150 SetSubScansPreformed (auditCmd .ScansToPerform ()).
150151 PrintScanResults (); err != nil {
151- return
152+ return errors . Join ( err , auditResults . GetErrors ())
152153 }
153154
154155 if err = auditResults .GetErrors (); err != nil {
@@ -173,70 +174,41 @@ func (auditCmd *AuditCommand) HasViolationContext() bool {
173174// Runs an audit scan based on the provided auditParams.
174175// Returns an audit Results object containing all the scan results.
175176// If the current server is entitled for JAS, the advanced security results will be included in the scan results.
176- func RunAudit (auditParams * AuditParams ) (cmdResults * results.SecurityCommandResults , err error ) {
177- // Prepare
178- serverDetails , err := auditParams .ServerDetails ()
179- if err != nil {
180- return
181- }
182- var xrayManager * xray.XrayServicesManager
183- if xrayManager , auditParams .xrayVersion , err = xrayutils .CreateXrayServiceManagerAndGetVersion (serverDetails ); err != nil {
184- return
185- }
186- if err = clientutils .ValidateMinimumVersion (clientutils .Xray , auditParams .xrayVersion , scangraph .GraphScanMinXrayVersion ); err != nil {
187- return
188- }
189- entitledForJas , err := isEntitledForJas (xrayManager , auditParams )
190- if err != nil {
177+ func RunAudit (auditParams * AuditParams ) (cmdResults * results.SecurityCommandResults ) {
178+ // Initialize Results struct
179+ if cmdResults = initAuditCmdResults (auditParams ); cmdResults .GeneralError != nil {
191180 return
192181 }
193- // Initialize Results struct
194- cmdResults = initCmdResults (
195- entitledForJas ,
196- jas .CheckForSecretValidation (xrayManager , auditParams .xrayVersion , slices .Contains (auditParams .AuditBasicParams .ScansToPerform (), utils .SecretTokenValidationScan )),
197- auditParams ,
198- )
199182 jfrogAppsConfig , err := jas .CreateJFrogAppsConfig (cmdResults .GetTargetsPaths ())
200183 if err != nil {
201- return cmdResults , fmt .Errorf ("failed to create JFrogAppsConfig: %s" , err .Error ())
184+ return cmdResults . AddGeneralError ( fmt .Errorf ("failed to create JFrogAppsConfig: %s" , err .Error () ))
202185 }
203186 // Initialize the parallel runner
204187 auditParallelRunner := utils .CreateSecurityParallelRunner (auditParams .threads )
205- auditParallelRunner .ErrWg .Add (1 )
206188 // Add the JAS scans to the parallel runner
207189 var jasScanner * jas.JasScanner
208- var jasScanErr error
209- if jasScanner , jasScanErr = RunJasScans (auditParallelRunner , auditParams , cmdResults , jfrogAppsConfig ); jasScanErr != nil {
210- auditParallelRunner . AddErrorToChan ( jasScanErr )
190+ var generalJasScanErr error
191+ if jasScanner , generalJasScanErr = RunJasScans (auditParallelRunner , auditParams , cmdResults , jfrogAppsConfig ); generalJasScanErr != nil {
192+ cmdResults . AddGeneralError ( fmt . Errorf ( "An error has occurred during JAS scan process. JAS scan is skipped for the following directories: %s \n %s" , strings . Join ( cmdResults . GetTargetsPaths (), "," ), generalJasScanErr . Error ()) )
211193 }
212194 if auditParams .Progress () != nil {
213195 auditParams .Progress ().SetHeadlineMsg ("Scanning for issues" )
214196 }
215197 // The sca scan doesn't require the analyzer manager, so it can run separately from the analyzer manager download routine.
216- if scaScanErr := buildDepTreeAndRunScaScan (auditParallelRunner , auditParams , cmdResults ); scaScanErr != nil {
217- // If error to be caught, we add it to the auditParallelRunner error queue and continue. The error need not be returned
218- _ = createErrorIfPartialResultsDisabled (auditParams , auditParallelRunner , fmt .Sprintf ("An error has occurred during SCA scan process. SCA scan is skipped for the following directories: %s." , auditParams .workingDirs ), scaScanErr )
198+ if generalScaScanError := buildDepTreeAndRunScaScan (auditParallelRunner , auditParams , cmdResults ); generalScaScanError != nil {
199+ cmdResults .AddGeneralError (fmt .Errorf ("An error has occurred during SCA scan process. SCA scan is skipped for the following directories: %s\n %s" , strings .Join (cmdResults .GetTargetsPaths (), "," ), generalScaScanError .Error ()))
219200 }
220201 go func () {
221202 auditParallelRunner .ScaScansWg .Wait ()
222203 auditParallelRunner .JasWg .Wait ()
223204 // Wait for all jas scanners to complete before cleaning up scanners temp dir
224205 auditParallelRunner .JasScannersWg .Wait ()
225206 if jasScanner != nil && jasScanner .ScannerDirCleanupFunc != nil {
226- auditParallelRunner . AddErrorToChan (jasScanner .ScannerDirCleanupFunc ())
207+ cmdResults . AddGeneralError (jasScanner .ScannerDirCleanupFunc ())
227208 }
228- close (auditParallelRunner .ErrorsQueue )
229209 auditParallelRunner .Runner .Done ()
230210 }()
231- // a new routine that collects errors from the err channel into results object
232- go func () {
233- defer auditParallelRunner .ErrWg .Done ()
234- for e := range auditParallelRunner .ErrorsQueue {
235- cmdResults .Error = errors .Join (cmdResults .Error , e )
236- }
237- }()
238211 auditParallelRunner .Runner .Run ()
239- auditParallelRunner .ErrWg .Wait ()
240212 return
241213}
242214
@@ -248,73 +220,102 @@ func isEntitledForJas(xrayManager *xray.XrayServicesManager, auditParams *AuditP
248220 return jas .IsEntitledForJas (xrayManager , auditParams .xrayVersion )
249221}
250222
251- func RunJasScans (auditParallelRunner * utils.SecurityParallelRunner , auditParams * AuditParams , scanResults * results.SecurityCommandResults , jfrogAppsConfig * jfrogappsconfig.JFrogAppsConfig ) (jasScanner * jas.JasScanner , err error ) {
223+ func RunJasScans (auditParallelRunner * utils.SecurityParallelRunner , auditParams * AuditParams , scanResults * results.SecurityCommandResults , jfrogAppsConfig * jfrogappsconfig.JFrogAppsConfig ) (jasScanner * jas.JasScanner , generalError error ) {
252224 if ! scanResults .EntitledForJas {
253225 log .Info ("Not entitled for JAS, skipping advance security scans..." )
254226 return
255227 }
256228 serverDetails , err := auditParams .ServerDetails ()
257229 if err != nil {
258- err = fmt .Errorf ("failed to get server details: %s" , err .Error ())
230+ generalError = fmt .Errorf ("failed to get server details: %s" , err .Error ())
259231 return
260232 }
261233 auditParallelRunner .ResultsMu .Lock ()
262234 jasScanner , err = jas .CreateJasScanner (serverDetails , scanResults .SecretValidation , auditParams .minSeverityFilter , jas .GetAnalyzerManagerXscEnvVars (auditParams .commonGraphScanParams .MultiScanId , scanResults .GetTechnologies ()... ), auditParams .Exclusions ()... )
263235 auditParallelRunner .ResultsMu .Unlock ()
264236 if err != nil {
265- err = fmt .Errorf ("failed to create jas scanner: %s" , err .Error ())
237+ generalError = fmt .Errorf ("failed to create jas scanner: %s" , err .Error ())
266238 return
267239 } else if jasScanner == nil {
268240 log .Debug ("Jas scanner was not created, skipping advance security scans..." )
269241 return
270242 }
271243 auditParallelRunner .JasWg .Add (1 )
272- if _ , jasErr := auditParallelRunner .Runner .AddTaskWithError (func ( threadId int ) error {
273- return downloadAnalyzerManagerAndRunScanners ( auditParallelRunner , scanResults , serverDetails , auditParams , jasScanner , jfrogAppsConfig , threadId )
274- }, auditParallelRunner . AddErrorToChan ); jasErr != nil {
275- auditParallelRunner . AddErrorToChan ( fmt .Errorf ("failed to create AM downloading task, skipping JAS scans... : %s" , jasErr .Error () ))
244+ if _ , jasErr := auditParallelRunner .Runner .AddTaskWithError (createJasScansTasks ( auditParallelRunner , scanResults , serverDetails , auditParams , jasScanner , jfrogAppsConfig ), func ( generalError error ) {
245+ generalError = errors . Join ( generalError , fmt . Errorf ( "failed while adding JAS scan tasks: %s" , generalError . Error ()) )
246+ }); jasErr != nil {
247+ generalError = fmt .Errorf ("failed to create JAS task : %s" , jasErr .Error ())
276248 }
277249 return
278250}
279251
280- func downloadAnalyzerManagerAndRunScanners (auditParallelRunner * utils.SecurityParallelRunner , scanResults * results.SecurityCommandResults ,
281- serverDetails * config.ServerDetails , auditParams * AuditParams , scanner * jas.JasScanner , jfrogAppsConfig * jfrogappsconfig.JFrogAppsConfig , threadId int ) (err error ) {
282- defer func () {
283- auditParallelRunner .JasWg .Done ()
284- }()
285- if err = jas .DownloadAnalyzerManagerIfNeeded (threadId ); err != nil {
286- return fmt .Errorf ("%s failed to download analyzer manager: %s" , clientutils .GetLogMsgPrefix (threadId , false ), err .Error ())
287- }
288- // Run JAS scanners for each scan target
289- for _ , scan := range scanResults .Targets {
290- module := jas .GetModule (scan .Target , jfrogAppsConfig )
291- if module == nil {
292- scan .AddError (fmt .Errorf ("can't find module for path %s" , scan .Target ))
293- continue
294- }
295- params := runner.JasRunnerParams {
296- Runner : auditParallelRunner ,
297- ServerDetails : serverDetails ,
298- Scanner : scanner ,
299- Module : * module ,
300- ConfigProfile : auditParams .configProfile ,
301- ScansToPreform : auditParams .ScansToPerform (),
302- SecretsScanType : secrets .SecretsScannerType ,
303- DirectDependencies : auditParams .DirectDependencies (),
304- ThirdPartyApplicabilityScan : auditParams .thirdPartyApplicabilityScan ,
305- ApplicableScanType : applicability .ApplicabilityScannerType ,
306- ScanResults : scan ,
307- TargetOutputDir : auditParams .scanResultsOutputDir ,
252+ func createJasScansTasks (auditParallelRunner * utils.SecurityParallelRunner , scanResults * results.SecurityCommandResults ,
253+ serverDetails * config.ServerDetails , auditParams * AuditParams , scanner * jas.JasScanner , jfrogAppsConfig * jfrogappsconfig.JFrogAppsConfig ) parallel.TaskFunc {
254+ return func (threadId int ) (generalError error ) {
255+ defer func () {
256+ auditParallelRunner .JasWg .Done ()
257+ }()
258+ logPrefix := clientutils .GetLogMsgPrefix (threadId , false )
259+ // First download the analyzer manager if needed
260+ if err := jas .DownloadAnalyzerManagerIfNeeded (threadId ); err != nil {
261+ return fmt .Errorf ("%s failed to download analyzer manager: %s" , logPrefix , err .Error ())
308262 }
309- if err = runner .AddJasScannersTasks (params ); err != nil {
310- return fmt .Errorf ("%s failed to run JAS scanners: %s" , clientutils .GetLogMsgPrefix (threadId , false ), err .Error ())
263+ // Run JAS scanners for each scan target
264+ for _ , targetResult := range scanResults .Targets {
265+ module := jas .GetModule (targetResult .Target , jfrogAppsConfig )
266+ if module == nil {
267+ targetResult .AddError (fmt .Errorf ("can't find module for path %s" , targetResult .Target ), auditParams .AllowPartialResults ())
268+ continue
269+ }
270+ params := runner.JasRunnerParams {
271+ Runner : auditParallelRunner ,
272+ ServerDetails : serverDetails ,
273+ Scanner : scanner ,
274+ Module : * module ,
275+ ConfigProfile : auditParams .configProfile ,
276+ ScansToPreform : auditParams .ScansToPerform (),
277+ SecretsScanType : secrets .SecretsScannerType ,
278+ DirectDependencies : auditParams .DirectDependencies (),
279+ ThirdPartyApplicabilityScan : auditParams .thirdPartyApplicabilityScan ,
280+ ApplicableScanType : applicability .ApplicabilityScannerType ,
281+ ScanResults : targetResult ,
282+ TargetOutputDir : auditParams .scanResultsOutputDir ,
283+ }
284+ if generalError := runner .AddJasScannersTasks (params ); generalError != nil {
285+ targetResult .AddError (fmt .Errorf ("%s failed to add JAS scan tasks: %s" , logPrefix , generalError .Error ()), auditParams .AllowPartialResults ())
286+ }
311287 }
288+ return
312289 }
313- return
314290}
315291
316- func initCmdResults (entitledForJas , secretValidation bool , params * AuditParams ) (cmdResults * results.SecurityCommandResults ) {
317- cmdResults = results .NewCommandResults (utils .SourceCode , params .xrayVersion , entitledForJas , secretValidation ).SetMultiScanId (params .commonGraphScanParams .MultiScanId )
292+ func initAuditCmdResults (params * AuditParams ) (cmdResults * results.SecurityCommandResults ) {
293+ cmdResults = results .NewCommandResults (utils .SourceCode )
294+ // Initialize general information
295+ serverDetails , err := params .ServerDetails ()
296+ if err != nil {
297+ return cmdResults .AddGeneralError (err )
298+ }
299+ var xrayManager * xray.XrayServicesManager
300+ if xrayManager , params .xrayVersion , err = xrayutils .CreateXrayServiceManagerAndGetVersion (serverDetails ); err != nil {
301+ return cmdResults .AddGeneralError (err )
302+ } else {
303+ cmdResults .SetXrayVersion (params .xrayVersion )
304+ }
305+ if err = clientutils .ValidateMinimumVersion (clientutils .Xray , params .xrayVersion , scangraph .GraphScanMinXrayVersion ); err != nil {
306+ return cmdResults .AddGeneralError (err )
307+ }
308+ entitledForJas , err := isEntitledForJas (xrayManager , params )
309+ if err != nil {
310+ return cmdResults .AddGeneralError (err )
311+ } else {
312+ cmdResults .SetEntitledForJas (entitledForJas )
313+ }
314+ if entitledForJas {
315+ cmdResults .SetSecretValidation (jas .CheckForSecretValidation (xrayManager , params .xrayVersion , slices .Contains (params .AuditBasicParams .ScansToPerform (), utils .SecretTokenValidationScan )))
316+ }
317+ cmdResults .SetMultiScanId (params .commonGraphScanParams .MultiScanId )
318+ // Initialize targets
318319 detectScanTargets (cmdResults , params )
319320 if params .IsRecursiveScan () && len (params .workingDirs ) == 1 && len (cmdResults .Targets ) == 0 {
320321 // No SCA targets were detected, add the root directory as a target for JAS scans.
@@ -358,27 +359,3 @@ func detectScanTargets(cmdResults *results.SecurityCommandResults, params *Audit
358359 }
359360 }
360361}
361-
362- // This function checks if partial results are allowed. If so we log the error and continue.
363- // If partial results are not allowed and a SecurityParallelRunner is provided we add the error to its error queue and return without an error, since the errors will be later collected from the queue.
364- // If partial results are not allowed and a SecurityParallelRunner is not provided we return the error.
365- func createErrorIfPartialResultsDisabled (auditParams * AuditParams , auditParallelRunner * utils.SecurityParallelRunner , extraMassageForLog string , err error ) error {
366- if err == nil {
367- return nil
368- }
369-
370- if auditParams .AllowPartialResults () {
371- if extraMassageForLog == "" {
372- extraMassageForLog = "An error has occurred during the audit scans"
373- }
374- log .Warn (fmt .Sprintf ("%s\n Since partial results are allowed, the error is skipped: %s" , extraMassageForLog , err .Error ()))
375- return nil
376- }
377-
378- // When SecurityParallelRunner is provided we add the error to the queue, otherwise we return the error
379- if auditParallelRunner != nil {
380- auditParallelRunner .AddErrorToChan (err )
381- return nil
382- }
383- return err
384- }
0 commit comments