diff --git a/internal/commands/result.go b/internal/commands/result.go index 4f293d876..1435587e3 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -107,8 +107,8 @@ const ( redundantLabel = "redundant" delayValueForReport = 10 fixLinkPrefix = "https://devhub.checkmarx.com/cve-details/" - snoozeLabel = "Snooze" - muteLabel = "Muted" + ScaDevAndTestExclusionParam = "DEV_AND_TEST" + ScaExcludeResultTypesParam = "exclude-result-types" ) var summaryFormats = []string{ @@ -272,6 +272,8 @@ func resultShowSubCommand( resultShowCmd.PersistentFlags().Bool(commonParams.IgnorePolicyFlag, false, "Do not evaluate policies") resultShowCmd.PersistentFlags().Bool(commonParams.SastRedundancyFlag, false, "Populate SAST results 'data.redundancy' with values '"+fixLabel+"' (to fix) or '"+redundantLabel+"' (no need to fix)") + resultShowCmd.PersistentFlags().Bool(commonParams.ScaHideDevAndTestDepFlag, false, "Hide dev and test dependencies in SCA scan results") + return resultShowCmd } @@ -941,15 +943,22 @@ func runGetResultCommand( formatSbomOptions, _ := cmd.Flags().GetString(commonParams.ReportSbomFormatFlag) sastRedundancy, _ := cmd.Flags().GetBool(commonParams.SastRedundancyFlag) agent, _ := cmd.Flags().GetString(commonParams.AgentFlag) + scaHideDevAndTestDep, _ := cmd.Flags().GetBool(commonParams.ScaHideDevAndTestDepFlag) scanID, _ := cmd.Flags().GetString(commonParams.ScanIDFlag) if scanID == "" { return errors.Errorf("%s: Please provide a scan ID", failedListingResults) } + params, err := getFilters(cmd) if err != nil { return errors.Wrapf(err, "%s", failedListingResults) } + + if scaHideDevAndTestDep { + params[ScaExcludeResultTypesParam] = ScaDevAndTestExclusionParam + } + scan, errorModel, scanErr := scanWrapper.GetByID(scanID) if scanErr != nil { return errors.Wrapf(scanErr, "%s", failedGetting) @@ -1099,7 +1108,7 @@ func CreateScanReport( targetFile, targetPath string, agent string, - params map[string]string, + resultsParam map[string]string, featureFlagsWrapper wrappers.FeatureFlagsWrapper, ) error { reportList := strings.Split(reportTypes, ",") @@ -1118,7 +1127,7 @@ func CreateScanReport( return err } if !scanPending { - results, err = ReadResults(resultsWrapper, exportWrapper, scan, params) + results, err = ReadResults(resultsWrapper, exportWrapper, scan, resultsParam) if err != nil { return err } @@ -1362,15 +1371,17 @@ func ReadResults( resultsWrapper wrappers.ResultsWrapper, exportWrapper wrappers.ExportWrapper, scan *wrappers.ScanResponseModel, - params map[string]string, + resultsParams map[string]string, ) (results *wrappers.ScanResultsCollection, err error) { var resultsModel *wrappers.ScanResultsCollection var errorModel *wrappers.WebError - params[commonParams.ScanIDQueryParam] = scan.ID - _, sastRedundancy := params[commonParams.SastRedundancyFlag] + resultsParams[commonParams.ScanIDQueryParam] = scan.ID + _, sastRedundancy := resultsParams[commonParams.SastRedundancyFlag] + + scaHideDevAndTestDep := resultsParams[ScaExcludeResultTypesParam] == ScaDevAndTestExclusionParam - resultsModel, errorModel, err = resultsWrapper.GetAllResultsByScanID(params) + resultsModel, errorModel, err = resultsWrapper.GetAllResultsByScanID(resultsParams) if err != nil { return nil, errors.Wrapf(err, "%s", failedListingResults) @@ -1384,7 +1395,7 @@ func ReadResults( // Compute SAST results redundancy resultsModel = ComputeRedundantSastResults(resultsModel) } - resultsModel, err = enrichScaResults(exportWrapper, scan, resultsModel) + resultsModel, err = enrichScaResults(exportWrapper, scan, resultsModel, scaHideDevAndTestDep) if err != nil { return nil, err } @@ -1399,9 +1410,10 @@ func enrichScaResults( exportWrapper wrappers.ExportWrapper, scan *wrappers.ScanResponseModel, resultsModel *wrappers.ScanResultsCollection, + scaHideDevAndTestDep bool, ) (*wrappers.ScanResultsCollection, error) { if slices.Contains(scan.Engines, commonParams.ScaType) { - scaExportDetails, err := services.GetExportPackage(exportWrapper, scan.ID) + scaExportDetails, err := services.GetExportPackage(exportWrapper, scan.ID, scaHideDevAndTestDep) if err != nil { return nil, errors.Wrapf(err, "%s", failedListingResults) } diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 77611317f..af9e52ab8 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -652,6 +652,7 @@ func scanCreateSubCommand( createScanCmd.PersistentFlags().String(commonParams.SCSRepoTokenFlag, "", "Provide a token with read permission for the repo that you are scanning (for scorecard scans)") createScanCmd.PersistentFlags().String(commonParams.SCSRepoURLFlag, "", "The URL of the repo that you are scanning with scs (for scorecard scans)") createScanCmd.PersistentFlags().String(commonParams.SCSEnginesFlag, "", "Specify which scs engines will run (default: all licensed engines)") + createScanCmd.PersistentFlags().Bool(commonParams.ScaHideDevAndTestDepFlag, false, "Hide dev and test dependencies in SCA scan results") return createScanCmd } @@ -1901,11 +1902,17 @@ func createReportsAfterScan( formatPdfOptions, _ := cmd.Flags().GetString(commonParams.ReportFormatPdfOptionsFlag) formatSbomOptions, _ := cmd.Flags().GetString(commonParams.ReportSbomFormatFlag) agent, _ := cmd.Flags().GetString(commonParams.AgentFlag) + scaHideDevAndTestDep, _ := cmd.Flags().GetBool(commonParams.ScaHideDevAndTestDepFlag) params, err := getFilters(cmd) if err != nil { return err } + + if scaHideDevAndTestDep { + params[ScaExcludeResultTypesParam] = ScaDevAndTestExclusionParam + } + if !strings.Contains(reportFormats, printer.FormatSummaryConsole) { reportFormats += "," + printer.FormatSummaryConsole } @@ -2042,11 +2049,11 @@ func getSummaryThresholdMap( resultsWrapper wrappers.ResultsWrapper, exportWrapper wrappers.ExportWrapper, scan *wrappers.ScanResponseModel, - params map[string]string, + resultsParams map[string]string, risksOverviewWrapper wrappers.RisksOverviewWrapper, ) (map[string]int, error) { summaryMap := make(map[string]int) - results, err := ReadResults(resultsWrapper, exportWrapper, scan, params) + results, err := ReadResults(resultsWrapper, exportWrapper, scan, resultsParams) if err != nil { return nil, err diff --git a/internal/params/flags.go b/internal/params/flags.go index 3770183ee..85b580991 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -106,47 +106,47 @@ const ( Threshold = "threshold" ThresholdFlagUsage = "Local build threshold. Format -=. " + "Example: scan --threshold \"sast-high=10;sca-high=5;iac-security-low=10\"" - KeyValuePairSize = 2 - WaitDelayDefault = 5 - SimilarityIDFlag = "similarity-id" - SeverityFlag = "severity" - StateFlag = "state" - CommentFlag = "comment" - LanguageFlag = "language" - VulnerabilityTypeFlag = "vulnerability-type" - CweIDFlag = "cwe-id" - SCMTokenFlag = "token" - AzureTokenUsage = "Azure DevOps personal access token. Requires “Connected server” and “Code“ scope." - GithubTokenUsage = "GitHub OAuth token. Requires “Repo” scope and organization SSO authorization, if enforced by the organization" - GitLabTokenUsage = "GitLab OAuth token" - BotCount = "Note: dependabot is not counted but other bots might be considered as contributors." - DisabledReposCount = "Note: Disabled repositories are not counted." - URLFlag = "url" - GitLabURLFlag = "url-gitlab" - URLFlagUsage = "API base URL" - QueryIDFlag = "query-id" - SSHKeyFlag = "ssh-key" - RepoURLFlag = "repo-url" - AstToken = "ast-token" - SSHValue = "ssh-value" - KicsContainerNameKey = "kics-container-name" - KicsPlatformsFlag = "kics-platforms" - KicsPlatformsFlagUsage = "KICS Platform Flag. Use ',' as the delimiter for arrays." - IacsPlatformsFlag = "iac-security-platforms" - IacsPlatformsFlagUsage = "IaC Security Platform Flag" - ApikeyOverrideFlag = "apikey-override" - ExploitablePathFlag = "sca-exploitable-path" - LastSastScanTime = "sca-last-sast-scan-time" - ProjecPrivatePackageFlag = "project-private-package" - SastRedundancyFlag = "sast-redundancy" - ContainerImagesFlag = "container-images" - ContainersTypeFlag = "container-security" - VSCodeAgent = "VS Code" - EclipseAgent = "Eclipse" - VisualStudioAgent = "Visual Studio" - JetbrainsAgent = "Jetbrains" - + KeyValuePairSize = 2 + WaitDelayDefault = 5 + SimilarityIDFlag = "similarity-id" + SeverityFlag = "severity" + StateFlag = "state" + CommentFlag = "comment" + LanguageFlag = "language" + VulnerabilityTypeFlag = "vulnerability-type" + CweIDFlag = "cwe-id" + SCMTokenFlag = "token" + AzureTokenUsage = "Azure DevOps personal access token. Requires “Connected server” and “Code“ scope." + GithubTokenUsage = "GitHub OAuth token. Requires “Repo” scope and organization SSO authorization, if enforced by the organization" + GitLabTokenUsage = "GitLab OAuth token" + BotCount = "Note: dependabot is not counted but other bots might be considered as contributors." + DisabledReposCount = "Note: Disabled repositories are not counted." + URLFlag = "url" + GitLabURLFlag = "url-gitlab" + URLFlagUsage = "API base URL" + QueryIDFlag = "query-id" + SSHKeyFlag = "ssh-key" + RepoURLFlag = "repo-url" + AstToken = "ast-token" + SSHValue = "ssh-value" + KicsContainerNameKey = "kics-container-name" + KicsPlatformsFlag = "kics-platforms" + KicsPlatformsFlagUsage = "KICS Platform Flag. Use ',' as the delimiter for arrays." + IacsPlatformsFlag = "iac-security-platforms" + IacsPlatformsFlagUsage = "IaC Security Platform Flag" + ApikeyOverrideFlag = "apikey-override" + ExploitablePathFlag = "sca-exploitable-path" + LastSastScanTime = "sca-last-sast-scan-time" + ProjecPrivatePackageFlag = "project-private-package" + SastRedundancyFlag = "sast-redundancy" + ContainerImagesFlag = "container-images" + ContainersTypeFlag = "container-security" + VSCodeAgent = "VS Code" + EclipseAgent = "Eclipse" + VisualStudioAgent = "Visual Studio" + JetbrainsAgent = "Jetbrains" ScaPrivatePackageVersionFlag = "sca-private-package-version" + ScaHideDevAndTestDepFlag = "sca-hide-dev-test-dependencies" // INDIVIDUAL FILTER FLAGS SastFilterFlag = "sast-filter" diff --git a/internal/services/export.go b/internal/services/export.go index 3c866c74e..e85051a0d 100644 --- a/internal/services/export.go +++ b/internal/services/export.go @@ -20,7 +20,7 @@ const ( pollingTimeout = 5 // minutes ) -func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string) (*wrappers.ScaPackageCollectionExport, error) { +func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string, scaHideDevAndTestDep bool) (*wrappers.ScaPackageCollectionExport, error) { var scaPackageCollection = &wrappers.ScaPackageCollectionExport{ Packages: []wrappers.ScaPackage{}, ScaTypes: []wrappers.ScaType{}, @@ -28,6 +28,9 @@ func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string) (*wra payload := &wrappers.ExportRequestPayload{ ScanID: scanID, FileFormat: "ScanReportJson", + ExportParameters: wrappers.ExportParameters{ + HideDevAndTestDependencies: scaHideDevAndTestDep, + }, } exportID, err := exportWrapper.InitiateExportRequest(payload) diff --git a/test/integration/result_test.go b/test/integration/result_test.go index e85c94653..bc48b5c45 100644 --- a/test/integration/result_test.go +++ b/test/integration/result_test.go @@ -576,6 +576,32 @@ func TestResultsShow_ScanIDWithSnoozedAndMutedAllVulnerabilities_NoVulnerabiliti } } +func TestResultsShow_WithScaHideDevAndTestDependencies_NoVulnerabilitiesInScan(t *testing.T) { + scanID := "28d29a61-bc5e-4f5a-9fdd-e18c5a10c05b" + reportFilePath := fmt.Sprintf("%s%s.%s", resultsDirectory, fileName, printer.FormatJSON) + + _ = executeCmdNilAssertion( + t, "Results show generating JSON report with options should pass", + "results", "show", + flag(params.ScanIDFlag), scanID, + flag(params.TargetFormatFlag), printer.FormatJSON, + flag(params.TargetPathFlag), resultsDirectory, + flag(params.TargetFlag), fileName, + flag(params.ScaHideDevAndTestDepFlag), + ) + + defer func() { + _ = os.RemoveAll(resultsDirectory) + }() + + assertFileExists(t, reportFilePath) + + var result wrappers.ScanResultsCollection + readAndUnmarshalFile(t, reportFilePath, &result) + + assert.Equal(t, len(result.Results), 0, "Should have no results") +} + func assertFileExists(t *testing.T, path string) { _, err := os.Stat(path) assert.NilError(t, err, "Report file should exist at path "+path) diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index fcd20f9df..957064684 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -1945,7 +1945,7 @@ func TestCreateAsyncScan_CallExportServiceBeforeScanFinishWithRetry_Success(t *t flag(params.ScanInfoFormatFlag), printer.FormatJSON, } scanID, _ := executeCreateScan(t, args) - exportRes, err := services.GetExportPackage(wrappers.NewExportHTTPWrapper("api/sca/export"), scanID) + exportRes, err := services.GetExportPackage(wrappers.NewExportHTTPWrapper("api/sca/export"), scanID, false) asserts.Nil(t, err) assert.Assert(t, exportRes != nil, "Export response should not be nil") }