diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 70074233..248e4907 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -218,13 +218,78 @@ func TestDetectScansToPreform(t *testing.T) { // Note: Currently, if a config profile is provided, the scan will use the profile's settings, IGNORING jfrog-apps-config if exists. func TestAuditWithConfigProfile(t *testing.T) { testcases := []struct { - name string - configProfile services.ConfigProfile - expectedSastIssues int - expectedSecretsIssues int + name string + testDirPath string + configProfile services.ConfigProfile + expectedScaIssues int + expectedCaApplicable int + expectedCaUndetermined int + expectedCaNotCovered int + expectedCaNotApplicable int + expectedSastIssues int + expectedSecretsIssues int + expectedIacIssues int }{ { - name: "Enable only secrets scanner", + name: "Enable Sca scanner", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), + configProfile: services.ConfigProfile{ + ProfileName: "Sca only", + Modules: []services.Module{{ + ModuleId: 1, + ModuleName: "only-sca-module", + PathFromRoot: ".", + ScanConfig: services.ScanConfig{ + EnableScaScan: true, + EnableContextualAnalysisScan: false, + SastScannerConfig: services.SastScannerConfig{ + EnableSastScan: false, + }, + SecretsScannerConfig: services.SecretsScannerConfig{ + EnableSecretsScan: false, + }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: false, + }, + }, + }}, + IsDefault: false, + }, + expectedScaIssues: 15, + }, + { + name: "Enable Sca and Applicability scanners", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), + configProfile: services.ConfigProfile{ + ProfileName: "Sca&Applicability", + Modules: []services.Module{{ + ModuleId: 1, + ModuleName: "sca-and-applicability", + PathFromRoot: ".", + ScanConfig: services.ScanConfig{ + EnableScaScan: true, + EnableContextualAnalysisScan: true, + SastScannerConfig: services.SastScannerConfig{ + EnableSastScan: false, + }, + SecretsScannerConfig: services.SecretsScannerConfig{ + EnableSecretsScan: false, + }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: false, + }, + }, + }}, + IsDefault: false, + }, + expectedCaApplicable: 3, + expectedCaUndetermined: 6, + expectedCaNotCovered: 4, + expectedCaNotApplicable: 2, + }, + { + name: "Enable only secrets scanner", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), configProfile: services.ConfigProfile{ ProfileName: "only-secrets", Modules: []services.Module{{ @@ -232,21 +297,26 @@ func TestAuditWithConfigProfile(t *testing.T) { ModuleName: "only-secrets-module", PathFromRoot: ".", ScanConfig: services.ScanConfig{ + EnableScaScan: false, + EnableContextualAnalysisScan: false, SastScannerConfig: services.SastScannerConfig{ EnableSastScan: false, }, SecretsScannerConfig: services.SecretsScannerConfig{ EnableSecretsScan: true, }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: false, + }, }, }}, IsDefault: false, }, - expectedSastIssues: 0, expectedSecretsIssues: 16, }, { - name: "Enable only sast scanner", + name: "Enable only sast scanner", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), configProfile: services.ConfigProfile{ ProfileName: "only-sast", Modules: []services.Module{{ @@ -254,40 +324,82 @@ func TestAuditWithConfigProfile(t *testing.T) { ModuleName: "only-sast-module", PathFromRoot: ".", ScanConfig: services.ScanConfig{ + EnableScaScan: false, + EnableContextualAnalysisScan: false, SastScannerConfig: services.SastScannerConfig{ EnableSastScan: true, }, SecretsScannerConfig: services.SecretsScannerConfig{ EnableSecretsScan: false, }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: false, + }, }, }}, IsDefault: false, }, - expectedSastIssues: 1, - expectedSecretsIssues: 0, + expectedSastIssues: 1, }, { - name: "Enable secrets and sast", + name: "Enable only IaC scanner", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), configProfile: services.ConfigProfile{ - ProfileName: "secrets&sast", + ProfileName: "only-sast", Modules: []services.Module{{ ModuleId: 1, - ModuleName: "secrets&sast-module", + ModuleName: "only-iac-module", PathFromRoot: ".", ScanConfig: services.ScanConfig{ + EnableScaScan: false, + EnableContextualAnalysisScan: false, + SastScannerConfig: services.SastScannerConfig{ + EnableSastScan: false, + }, + SecretsScannerConfig: services.SecretsScannerConfig{ + EnableSecretsScan: false, + }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: true, + }, + }, + }}, + IsDefault: false, + }, + expectedIacIssues: 9, + }, + { + name: "Enable All Scanners", + testDirPath: filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas"), + configProfile: services.ConfigProfile{ + ProfileName: "all-jas-scanners", + Modules: []services.Module{{ + ModuleId: 1, + ModuleName: "all-jas-module", + PathFromRoot: ".", + ScanConfig: services.ScanConfig{ + EnableScaScan: true, + EnableContextualAnalysisScan: true, SastScannerConfig: services.SastScannerConfig{ EnableSastScan: true, }, SecretsScannerConfig: services.SecretsScannerConfig{ EnableSecretsScan: true, }, + IacScannerConfig: services.IacScannerConfig{ + EnableIacScan: true, + }, }, }}, IsDefault: false, }, - expectedSastIssues: 1, - expectedSecretsIssues: 16, + expectedSastIssues: 1, + expectedSecretsIssues: 16, + expectedIacIssues: 9, + expectedCaApplicable: 3, + expectedCaUndetermined: 6, + expectedCaNotCovered: 4, + expectedCaNotApplicable: 2, }, } @@ -298,8 +410,7 @@ func TestAuditWithConfigProfile(t *testing.T) { tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) defer createTempDirCallback() - testDirPath := filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas") - assert.NoError(t, biutils.CopyDir(testDirPath, tempDirPath, true, nil)) + assert.NoError(t, biutils.CopyDir(testcase.testDirPath, tempDirPath, true, nil)) auditBasicParams := (&utils.AuditBasicParams{}). SetServerDetails(serverDetails). @@ -316,18 +427,35 @@ func TestAuditWithConfigProfile(t *testing.T) { ScanType: scanservices.Dependency, IncludeVulnerabilities: true, XscVersion: services.ConfigProfileMinXscVersion, - MultiScanId: "random-msi", + MultiScanId: validations.TestMsi, }) auditParams.SetWorkingDirs([]string{tempDirPath}).SetIsRecursiveScan(true) auditResults := RunAudit(auditParams) assert.NoError(t, auditResults.GetErrors()) - // Currently, the only supported scanners are Secrets and Sast, therefore if a config profile is utilized - all other scanners are disabled. summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{IncludeVulnerabilities: true, HasViolationContext: true}).ConvertToSummary(auditResults) assert.NoError(t, err) - // Validate Sast and Secrets have the expected number of issues and that Iac and Sca did not run - validations.ValidateCommandSummaryOutput(t, validations.ValidationParams{Actual: summary, ExactResultsMatch: true, Sast: testcase.expectedSastIssues, Secrets: testcase.expectedSecretsIssues, Vulnerabilities: testcase.expectedSastIssues + testcase.expectedSecretsIssues}) + + var ScaResultsCount int + // When checking Applicability results with ExactResultsMatch = true, the sum of all statuses should equal total Sca results amount. Else, we check the provided Sca issues amount + if testcase.expectedCaApplicable > 0 || testcase.expectedCaNotApplicable > 0 || testcase.expectedCaNotCovered > 0 || testcase.expectedCaUndetermined > 0 { + ScaResultsCount = testcase.expectedCaApplicable + testcase.expectedCaNotApplicable + testcase.expectedCaNotCovered + testcase.expectedCaUndetermined + } else { + ScaResultsCount = testcase.expectedScaIssues + } + validations.ValidateCommandSummaryOutput(t, validations.ValidationParams{ + Actual: summary, + ExactResultsMatch: true, + Vulnerabilities: testcase.expectedSastIssues + testcase.expectedSecretsIssues + testcase.expectedIacIssues + ScaResultsCount, + Sast: testcase.expectedSastIssues, + Secrets: testcase.expectedSecretsIssues, + Iac: testcase.expectedIacIssues, + Applicable: testcase.expectedCaApplicable, + NotApplicable: testcase.expectedCaNotApplicable, + NotCovered: testcase.expectedCaNotCovered, + Undetermined: testcase.expectedCaUndetermined, + }) }) } } diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index cd925ad0..c3f816c6 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -59,8 +59,14 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner return } if auditParams.configProfile != nil { - log.Debug("Skipping SCA scan as a configuration profile is being utilized and currently only Secrets and Sast scanners are supported when utilizing a configuration profile") - return + if len(auditParams.configProfile.Modules) < 1 { + // Verify Modules are not nil and contain at least one modules + return fmt.Errorf("config profile %s has no modules. A config profile must contain at least one modules", auditParams.configProfile.ProfileName) + } + if !auditParams.configProfile.Modules[0].ScanConfig.EnableScaScan { + log.Debug(fmt.Sprintf("Skipping SCA scan as requested by '%s' config profile...", auditParams.configProfile.ProfileName)) + return + } } // Prepare currentWorkingDir, generalError := os.Getwd() diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index 6e0755d3..cf36a70e 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -87,6 +87,10 @@ func addJasScanTaskForModuleIfNeeded(params JasRunnerParams, subScan utils.SubSc if params.ConfigProfile != nil { // This code section is related to CentralizedConfig integration in CI Next. log.Debug(fmt.Sprintf("Using config profile '%s' to determine whether to run %s scan...", params.ConfigProfile.ProfileName, jasType)) + if len(params.ConfigProfile.Modules) < 1 { + // Verify Modules are not nil and contain at least one modules + return fmt.Errorf("config profile %s has no modules. A config profile must contain at least one modules", params.ConfigProfile.ProfileName) + } // Currently, if config profile exists, the only possible scanners to run are: Secrets, Sast enabled := false switch jasType { @@ -95,11 +99,9 @@ func addJasScanTaskForModuleIfNeeded(params JasRunnerParams, subScan utils.SubSc case jasutils.Sast: enabled = params.ConfigProfile.Modules[0].ScanConfig.SastScannerConfig.EnableSastScan case jasutils.IaC: - log.Debug("Skipping Iac scan as it is not currently supported with a config profile...") - return + enabled = params.ConfigProfile.Modules[0].ScanConfig.IacScannerConfig.EnableIacScan case jasutils.Applicability: - log.Debug("Skipping Contextual Analysis scan as it is not currently supported with a config profile...") - return + enabled = params.ConfigProfile.Modules[0].ScanConfig.EnableContextualAnalysisScan } if enabled { generalError = addModuleJasScanTask(jasType, params.Runner, task, params.ScanResults, params.AllowPartialResults) diff --git a/utils/validations/test_mocks.go b/utils/validations/test_mocks.go index 04b66ad4..3b835a36 100644 --- a/utils/validations/test_mocks.go +++ b/utils/validations/test_mocks.go @@ -101,7 +101,8 @@ func XrayServer(t *testing.T, xrayVersion string) (*httptest.Server, *config.Ser } } } - if strings.HasPrefix(r.RequestURI, "/xray/api/v1/scan/graph") { + // Scan graph with Xray or Xsc + if strings.Contains(r.RequestURI, "/scan/graph") { if r.Method == http.MethodPost { w.WriteHeader(http.StatusCreated) _, err := w.Write([]byte(fmt.Sprintf(`{"scan_id" : "%s"}`, TestScaScanId)))