Skip to content

Commit bae7cad

Browse files
committed
fix error handling
1 parent 6cbbb0d commit bae7cad

File tree

19 files changed

+327
-402
lines changed

19 files changed

+327
-402
lines changed

audit_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func testAuditConan(t *testing.T, format string, withVuln bool) string {
9393
defer cleanUp()
9494
// Run conan install before executing jfrog audit
9595
assert.NoError(t, exec.Command("conan").Run())
96-
watchName, deleteWatch := securityTestUtils.CreateTestWatch(t, "audit-policy", "audit-watch", xrayUtils.High)
96+
watchName, deleteWatch := securityTestUtils.CreateTestWatch(t, "audit-curation-policy", "audit-curation-watch", xrayUtils.High)
9797
defer deleteWatch()
9898
args := []string{"audit", "--licenses", "--format=" + format, "--watches=" + watchName, "--fail=false"}
9999
if withVuln {
@@ -374,12 +374,12 @@ func TestXrayAuditNoTech(t *testing.T) {
374374

375375
func TestXrayAuditMultiProjects(t *testing.T) {
376376
integration.InitAuditGeneralTests(t, scangraph.GraphScanMinXrayVersion)
377-
tempDirPath, cleanUp := securityTestUtils.CreateTestProjectEnvAndChdir(t, filepath.Join(filepath.FromSlash(securityTests.GetTestResourcesPath()), "projects"))
377+
_, cleanUp := securityTestUtils.CreateTestProjectEnvAndChdir(t, filepath.Join(filepath.FromSlash(securityTests.GetTestResourcesPath()), "projects"))
378378
defer cleanUp()
379379
// Set working-dirs flag with multiple projects
380380
workingDirsFlag := fmt.Sprintf("--working-dirs=%s, %s ,%s, %s, %s",
381-
filepath.Join(tempDirPath, "package-managers", "maven", "maven"), filepath.Join(tempDirPath, "package-managers", "nuget", "single4.0"),
382-
filepath.Join(tempDirPath, "package-managers", "python", "pip", "pip-project"), filepath.Join(tempDirPath, "jas", "jas"), filepath.Join(tempDirPath, "package-managers", "go", "missing-context"))
381+
filepath.Join("package-managers", "maven", "maven"), filepath.Join("package-managers", "nuget", "single4.0"),
382+
filepath.Join("package-managers", "python", "pip", "pip-project"), filepath.Join("jas", "jas"), filepath.Join("package-managers", "go", "missing-context"))
383383
// Configure a new server named "default"
384384
securityIntegrationTestUtils.CreateJfrogHomeConfig(t, true)
385385
defer securityTestUtils.CleanTestsHomeEnv()

commands/audit/audit.go

Lines changed: 86 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package audit
33
import (
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\nSince 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

Comments
 (0)