Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI | Add sca-hide-dev-test-dependencies Flag (AST-68368) #898

Merged
merged 9 commits into from
Sep 29, 2024
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.9.0
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/crypto v0.26.0
golang.org/x/sync v0.8.0
golang.org/x/text v0.17.0
Expand Down Expand Up @@ -235,7 +236,6 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
Expand All @@ -254,7 +254,6 @@ require (
golang.org/x/term v0.23.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
Expand Down
81 changes: 8 additions & 73 deletions go.sum

Large diffs are not rendered by default.

39 changes: 26 additions & 13 deletions internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const (
scaLastScanTimeFlagDescription = "SCA last scan time. Available options: integer above 1"
projectPrivatePackageFlagDescription = "Enable or disable project private package. Available options: true,false"
scaPrivatePackageVersionFlagDescription = "SCA project private package version. Example: 0.1.1"
scaHideDevAndTestDepFlagDescription = "Filter SCA results to exclude dev and test dependencies"
policeManagementNoneStatus = "none"
apiDocumentationFlagDescription = "Swagger folder/file filter for API-Security scan. Example: ./swagger.json"
summaryCreatedAtLayout = "2006-01-02, 15:04:05"
Expand All @@ -107,8 +108,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{
Expand Down Expand Up @@ -272,6 +273,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, scaHideDevAndTestDepFlagDescription)

return resultShowCmd
}

Expand Down Expand Up @@ -941,15 +944,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)

resultsParams, err := getFilters(cmd)
if err != nil {
return errors.Wrapf(err, "%s", failedListingResults)
}

if scaHideDevAndTestDep {
resultsParams[ScaExcludeResultTypesParam] = ScaDevAndTestExclusionParam
}

scan, errorModel, scanErr := scanWrapper.GetByID(scanID)
if scanErr != nil {
return errors.Wrapf(scanErr, "%s", failedGetting)
Expand All @@ -974,7 +984,7 @@ func runGetResultCommand(
logger.PrintIfVerbose("Skipping policy evaluation")
}
if sastRedundancy {
params[commonParams.SastRedundancyFlag] = ""
resultsParams[commonParams.SastRedundancyFlag] = ""
}

return CreateScanReport(
Expand All @@ -992,7 +1002,7 @@ func runGetResultCommand(
targetFile,
targetPath,
agent,
params,
resultsParams,
featureFlagsWrapper)
}
}
Expand Down Expand Up @@ -1099,7 +1109,7 @@ func CreateScanReport(
targetFile,
targetPath string,
agent string,
params map[string]string,
resultsParams map[string]string,
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
) error {
reportList := strings.Split(reportTypes, ",")
Expand All @@ -1118,7 +1128,7 @@ func CreateScanReport(
return err
}
if !scanPending {
results, err = ReadResults(resultsWrapper, exportWrapper, scan, params)
results, err = ReadResults(resultsWrapper, exportWrapper, scan, resultsParams)
if err != nil {
return err
}
Expand Down Expand Up @@ -1362,15 +1372,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)
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved

if err != nil {
return nil, errors.Wrapf(err, "%s", failedListingResults)
Expand All @@ -1384,7 +1396,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
}
Expand All @@ -1399,9 +1411,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)
}
Expand Down
15 changes: 11 additions & 4 deletions internal/commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, scaHideDevAndTestDepFlagDescription)

return createScanCmd
}
Expand Down Expand Up @@ -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)
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved

params, err := getFilters(cmd)
resultsParams, err := getFilters(cmd)
if err != nil {
return err
}

if scaHideDevAndTestDep {
resultsParams[ScaExcludeResultTypesParam] = ScaDevAndTestExclusionParam
}

if !strings.Contains(reportFormats, printer.FormatSummaryConsole) {
reportFormats += "," + printer.FormatSummaryConsole
}
Expand All @@ -1931,7 +1938,7 @@ func createReportsAfterScan(
targetFile,
targetPath,
agent,
params,
resultsParams,
featureFlagsWrapper,
)
}
Expand Down Expand Up @@ -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
Expand Down
80 changes: 40 additions & 40 deletions internal/params/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,47 +106,47 @@ const (
Threshold = "threshold"
ThresholdFlagUsage = "Local build threshold. Format <engine>-<severity>=<limit>. " +
"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"
Expand Down
5 changes: 4 additions & 1 deletion internal/services/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ 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{},
}
payload := &wrappers.ExportRequestPayload{
ScanID: scanID,
FileFormat: "ScanReportJson",
ExportParameters: wrappers.ExportParameters{
HideDevAndTestDependencies: scaHideDevAndTestDep,
},
}

exportID, err := exportWrapper.InitiateExportRequest(payload)
Expand Down
42 changes: 34 additions & 8 deletions test/integration/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ const (
fileName = "result-test"
resultsDirectory = "output-results-folder/"
fileExtention = "report.json"

//----------------------------------------------------------------------------------------------------------------------
// This ScanIDWithDevAndTestDep is associated with the CXOne project: ASTCLI/HideDevAndTestsVulnerabilities/Test (DEU, Galactica tenant).
// All vulnerable packages in this project have been snoozed or muted, so no vulnerabilities should appear in this scan.
// If the test fails, verify the scan exists in this project. If it doesn't, create a new scan for the project using
// DevAndTestsVulnerabilitiesProject.zip, mute and snooze all packages, and update the scanID accordingly.
ScanIDWithDevAndTestDep = "28d29a61-bc5e-4f5a-9fdd-e18c5a10c05b"
//----------------------------------------------------------------------------------------------------------------------
)

func TestResultsExitCode_OnSendingFakeScanId_ShouldReturnNotFoundError(t *testing.T) {
Expand Down Expand Up @@ -544,19 +552,12 @@ func TestResultsGeneratingReportWithExcludeNotExploitableStateAndSeverityAndStat
}

func TestResultsShow_ScanIDWithSnoozedAndMutedAllVulnerabilities_NoVulnerabilitiesInScan(t *testing.T) {
//----------------------------------------------------------------------------------------------------------------------
// This scanID is associated with the CXOne project: ASTCLI/HideDevAndTestsVulnerabilities/Test (DEU, Galactica tenant).
// All vulnerable packages in this project have been snoozed or muted, so no vulnerabilities should appear in this scan.
// If the test fails, verify the scan exists in this project. If it doesn't, create a new scan for the project using
// DevAndTestsVulnerabilitiesProject.zip, mute and snooze all packages, and update the scanID accordingly.
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.ScanIDFlag), ScanIDWithDevAndTestDep,
flag(params.TargetFormatFlag), printer.FormatJSON,
flag(params.TargetPathFlag), resultsDirectory,
flag(params.TargetFlag), fileName,
Expand All @@ -576,6 +577,31 @@ func TestResultsShow_ScanIDWithSnoozedAndMutedAllVulnerabilities_NoVulnerabiliti
}
}

func TestResultsShow_WithScaHideDevAndTestDependencies_NoVulnerabilitiesInScan(t *testing.T) {
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), ScanIDWithDevAndTestDep,
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")
OrShamirCM marked this conversation as resolved.
Show resolved Hide resolved
}

func assertFileExists(t *testing.T, path string) {
_, err := os.Stat(path)
assert.NilError(t, err, "Report file should exist at path "+path)
Expand Down
2 changes: 1 addition & 1 deletion test/integration/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Loading