diff --git a/internal/commands/result.go b/internal/commands/result.go index 585e8f384..ed2cb4095 100644 --- a/internal/commands/result.go +++ b/internal/commands/result.go @@ -1211,7 +1211,7 @@ func CreateScanReport( return nil, err } if !scanPending { - results, err = ReadResults(resultsWrapper, exportWrapper, scan, resultsParams, agent) + results, err = ReadResults(resultsWrapper, exportWrapper, scan, resultsParams, agent, featureFlagsWrapper) if err != nil { return nil, err } @@ -1498,8 +1498,7 @@ func ReadResults( exportWrapper wrappers.ExportWrapper, scan *wrappers.ScanResponseModel, resultsParams map[string]string, - agent string, -) (results *wrappers.ScanResultsCollection, err error) { + agent string, featureflagsWrappers wrappers.FeatureFlagsWrapper) (results *wrappers.ScanResultsCollection, err error) { var resultsModel *wrappers.ScanResultsCollection var errorModel *wrappers.WebError @@ -1522,7 +1521,7 @@ func ReadResults( // Compute SAST results redundancy resultsModel = ComputeRedundantSastResults(resultsModel) } - resultsModel, err = enrichScaResults(exportWrapper, scan, resultsModel, scaHideDevAndTestDep) + resultsModel, err = enrichScaResults(exportWrapper, scan, resultsModel, scaHideDevAndTestDep, featureflagsWrappers) if err != nil { return nil, err } @@ -1545,10 +1544,9 @@ func enrichScaResults( exportWrapper wrappers.ExportWrapper, scan *wrappers.ScanResponseModel, resultsModel *wrappers.ScanResultsCollection, - scaHideDevAndTestDep bool, -) (*wrappers.ScanResultsCollection, error) { + scaHideDevAndTestDep bool, featureflagWrapper wrappers.FeatureFlagsWrapper) (*wrappers.ScanResultsCollection, error) { if slices.Contains(scan.Engines, commonParams.ScaType) { - scaExportDetails, err := services.GetExportPackage(exportWrapper, scan.ID, scaHideDevAndTestDep) + scaExportDetails, err := services.GetExportPackage(exportWrapper, scan.ID, scaHideDevAndTestDep, featureflagWrapper) if err != nil { return nil, errors.Wrapf(err, "%s", failedListingResults) } diff --git a/internal/services/export.go b/internal/services/export.go index 6d5a0c190..54d7e586a 100644 --- a/internal/services/export.go +++ b/internal/services/export.go @@ -20,7 +20,7 @@ const ( pollingTimeout = 15 // minutes ) -func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string, scaHideDevAndTestDep bool) (*wrappers.ScaPackageCollectionExport, error) { +func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string, scaHideDevAndTestDep bool, featureflagWrappers wrappers.FeatureFlagsWrapper) (*wrappers.ScaPackageCollectionExport, error) { var scaPackageCollection = &wrappers.ScaPackageCollectionExport{ Packages: []wrappers.ScaPackage{}, ScaTypes: []wrappers.ScaType{}, @@ -44,9 +44,16 @@ func GetExportPackage(exportWrapper wrappers.ExportWrapper, scanID string, scaHi if err != nil { return nil, err } + minioEnabled, _ := wrappers.GetSpecificFeatureFlag(featureflagWrappers, wrappers.MinioEnabled) if exportResponse != nil && strings.EqualFold(exportResponse.ExportStatus, completedStatus) && exportResponse.FileURL != "" { - scaPackageCollection, err = exportWrapper.GetScaPackageCollectionExport(exportResponse.FileURL) + filePath := "" + if minioEnabled.Status { + filePath = exportResponse.FileURL + } else { + filePath = exportID.ExportID + } + scaPackageCollection, err = exportWrapper.GetScaPackageCollectionExport(filePath, minioEnabled.Status) if err != nil { return nil, err } diff --git a/internal/wrappers/export-http.go b/internal/wrappers/export-http.go index 2222db158..a82df783d 100644 --- a/internal/wrappers/export-http.go +++ b/internal/wrappers/export-http.go @@ -176,23 +176,27 @@ func (e *ExportHTTPWrapper) DownloadExportReport(reportID, targetFile string) er return nil } -func (e *ExportHTTPWrapper) GetScaPackageCollectionExport(fileURL string) (*ScaPackageCollectionExport, error) { +func (e *ExportHTTPWrapper) GetScaPackageCollectionExport(fileURL string, auth bool) (*ScaPackageCollectionExport, error) { const bomPrefix = "\xef\xbb\xbf" - - accessToken, err := GetAccessToken() - if err != nil { - return nil, errors.Wrap(err, "failed to get access token") - } - start := time.Now() var resp *http.Response + var err error + var accessToken string for { if time.Since(start) > timeout { return nil, errors.New(errorTimeoutMsg) } - - resp, err = SendHTTPRequestByFullURL(http.MethodGet, fileURL, http.NoBody, true, viper.GetUint(commonParams.ClientTimeoutKey), accessToken, true) + if !auth { + customURL := fmt.Sprintf("%s/requests/%s/download", e.path, fileURL) + resp, err = SendHTTPRequest(http.MethodGet, customURL, http.NoBody, true, viper.GetUint(commonParams.ClientTimeoutKey)) + } else { + accessToken, err = GetAccessToken() + if err != nil { + return nil, errors.Wrap(err, "failed to get access token") + } + resp, err = SendHTTPRequestByFullURL(http.MethodGet, fileURL, http.NoBody, true, viper.GetUint(commonParams.ClientTimeoutKey), accessToken, true) + } if err == nil && resp.StatusCode == http.StatusOK { break } diff --git a/internal/wrappers/export.go b/internal/wrappers/export.go index d931e20c8..331a79262 100644 --- a/internal/wrappers/export.go +++ b/internal/wrappers/export.go @@ -4,7 +4,7 @@ type ExportWrapper interface { InitiateExportRequest(payload *ExportRequestPayload) (*ExportResponse, error) GetExportReportStatus(reportID string) (*ExportPollingResponse, error) DownloadExportReport(reportID, targetFile string) error - GetScaPackageCollectionExport(fileURL string) (*ScaPackageCollectionExport, error) + GetScaPackageCollectionExport(fileURL string, auth bool) (*ScaPackageCollectionExport, error) } type ScaPackageCollectionExport struct { diff --git a/internal/wrappers/mock/export-mock.go b/internal/wrappers/mock/export-mock.go index ac08a5b11..c82710b06 100644 --- a/internal/wrappers/mock/export-mock.go +++ b/internal/wrappers/mock/export-mock.go @@ -43,6 +43,6 @@ func (*ExportMockWrapper) DownloadExportReport(_, targetFile string) error { return nil } -func (e *ExportMockWrapper) GetScaPackageCollectionExport(fileURL string) (*wrappers.ScaPackageCollectionExport, error) { +func (e *ExportMockWrapper) GetScaPackageCollectionExport(fileURL string, auth bool) (*wrappers.ScaPackageCollectionExport, error) { return &wrappers.ScaPackageCollectionExport{}, nil } diff --git a/test/integration/logs_test.go b/test/integration/logs_test.go new file mode 100644 index 000000000..2d1cb357c --- /dev/null +++ b/test/integration/logs_test.go @@ -0,0 +1,36 @@ +//go:build integration + +package integration + +import ( + "github.com/checkmarx/ast-cli/internal/commands/util/printer" + commonParams "github.com/checkmarx/ast-cli/internal/params" + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_DownloadScan_Logs_Success(t *testing.T) { + args := []string{ + "scan", "create", + flag(commonParams.ProjectName), GenerateRandomProjectNameForScan(), + flag(commonParams.SourcesFlag), "data/sources.zip", + flag(commonParams.ScanTypes), commonParams.SastType, + flag(commonParams.BranchFlag), "dummy_branch", + flag(commonParams.ScanInfoFormatFlag), printer.FormatJSON, + } + scanID, _ := executeCreateScan(t, args) + args1 := []string{ + "scan", "logs", flag(commonParams.ScanIDFlag), scanID, flag(commonParams.ScanTypeFlag), commonParams.SastType, + } + err, _ := executeCommand(t, args1...) + assert.Nil(t, err) + +} + +func Test_DownloadScan_Logs_Failed(t *testing.T) { + args1 := []string{ + "scan", "logs", flag(commonParams.ScanIDFlag), "fake-scan-id", flag(commonParams.ScanTypeFlag), commonParams.SastType, + } + err, _ := executeCommand(t, args1...) + assert.Error(t, err, "failed to download log") +} diff --git a/test/integration/pre_commit_test.go b/test/integration/pre_commit_test.go index 6307883d2..2df5fae9d 100644 --- a/test/integration/pre_commit_test.go +++ b/test/integration/pre_commit_test.go @@ -39,6 +39,15 @@ func TestHooksPreCommitUpdatePreCommitHook(t *testing.T) { _ = executeCmdNilAssertion(t, "Uninstalling cx-secret-detection hook", "hooks", "pre-commit", "secrets-uninstall-git-hook") } +func TestHooksPreCommitSecretsIgnore(t *testing.T) { + tmpDir, cleanup := setupTempDir(t) + defer cleanup() + // Initialize Git repository + execCmd(t, tmpDir, "git", "init") + // Ignore precommit hook command + _ = executeCmdNilAssertion(t, "precommit secrets Ignore", "hooks", "pre-commit", "secrets-ignore", "--all") +} + // Helper functions func execCmd(t *testing.T, dir string, name string, args ...string) { cmd := exec.Command(name, args...) diff --git a/test/integration/predicate_test.go b/test/integration/predicate_test.go index f51161818..794c74e09 100644 --- a/test/integration/predicate_test.go +++ b/test/integration/predicate_test.go @@ -150,6 +150,69 @@ func TestPredicateWithInvalidValues(t *testing.T) { assert.Assert(t, kicsPredicate.TotalCount == 0, "Predicate with invalid values should have 0 as the result.") } +func TestSastUpdateAndGetPredicatesForNotFoundSimilarityId(t *testing.T) { + scanID, projectID := getRootScan(t) + _ = 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, + ) + + defer func() { + _ = os.RemoveAll(fmt.Sprintf(resultsDirectory)) + }() + + result := wrappers.ScanResultsCollection{} + + _, err := os.Stat(fmt.Sprintf("%s%s.%s", resultsDirectory, fileName, printer.FormatJSON)) + assert.NilError(t, err, "Report file should exist for extension "+printer.FormatJSON) + + file, err := os.ReadFile(fmt.Sprintf("%s%s.%s", resultsDirectory, fileName, printer.FormatJSON)) + assert.NilError(t, err, "error reading file") + + err = json.Unmarshal(file, &result) + assert.NilError(t, err, "error unmarshalling file") + + index := 0 + for i := range result.Results { + if strings.EqualFold(result.Results[i].Type, params.SastType) { + index = i + break + } + } + + similarityID := "1" + + state := "CONFIRMED" + if !strings.EqualFold(result.Results[index].State, "Urgent") { + state = "URGENT" + } + severity := "HIGH" + if !strings.EqualFold(result.Results[index].Severity, "Medium") { + severity = "MEDIUM" + } + comment := "Testing CLI Command for triage." + scanType := result.Results[index].Type + + args := []string{ + "triage", "update", + flag(params.ProjectIDFlag), projectID, + flag(params.SimilarityIDFlag), similarityID, + flag(params.StateFlag), state, + flag(params.SeverityFlag), severity, + flag(params.CommentFlag), comment, + flag(params.ScanTypeFlag), scanType, + } + + err, outputBufferForStep1 := executeCommand(t, args...) + _, readingError := io.ReadAll(outputBufferForStep1) + assert.NilError(t, readingError, "Reading result should pass") + + assert.ErrorContains(t, err, "Predicate not found") +} + func TestTriageShowAndUpdateWithCustomStates(t *testing.T) { t.Skip("Skipping this test temporarily until the API becomes available in the DEU environment.") fmt.Println("Step 1: Testing the command 'triage show' with predefined values.") diff --git a/test/integration/project_test.go b/test/integration/project_test.go index f2e25fddd..ca09be098 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -143,19 +143,18 @@ func TestCreateProjectWhenUserdoes_not_have_groups_permission(t *testing.T) { } groups := []string{ - "it_test_group_1", - "it_test_group_2", + "TT_Group1", } groupsStr := formatGroups(groups) - err, _ := executeCommand( + _, outBuffer := executeCommand( t, "project", "create", flag(params.FormatFlag), printer.FormatJSON, - flag(params.ProjectName), "project-1", flag(params.GroupList), groupsStr, + flag(params.ProjectName), projectNameRandom, flag(params.GroupList), groupsStr, ) - assertError(t, err, "Failed creating a project: CODE: 233, Unauthorized groups") + assert.Assert(t, outBuffer != nil, "Project creation output response should not be nil") } func TestCreateProjectWhenUserdoes_not_have_groups_permission_butonlyAM1_is_On(t *testing.T) { @@ -180,6 +179,7 @@ func TestCreateProjectWhenUserdoes_not_have_groups_permission_butonlyAM1_is_On(t createdProject := wrappers.ProjectResponseModel{} unmarshall(t, outBuffer, &createdProject, "Reading project create response JSON should pass") fmt.Printf("New project created with id: %s \n", createdProject.ID) + assert.Assert(t, createdProject.ID != "", "Project ID should not be empty") defer deleteProject(t, createdProject.ID) } diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index ec27b6aa6..ddcba2e17 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -27,6 +27,7 @@ import ( errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" exitCodes "github.com/checkmarx/ast-cli/internal/constants/exit-codes" "github.com/checkmarx/ast-cli/internal/params" + commonParams "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/services" "github.com/checkmarx/ast-cli/internal/wrappers" "github.com/checkmarx/ast-cli/internal/wrappers/configuration" @@ -2136,7 +2137,8 @@ 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, false) + featureFlagsPath := viper.GetString(commonParams.FeatureFlagsKey) + exportRes, err := services.GetExportPackage(wrappers.NewExportHTTPWrapper("api/sca/export"), scanID, false, wrappers.NewFeatureFlagsHTTPWrapper(featureFlagsPath)) asserts.Nil(t, err) assert.Assert(t, exportRes != nil, "Export response should not be nil") } diff --git a/test/integration/secrets-realtime_test.go b/test/integration/secrets-realtime_test.go new file mode 100644 index 000000000..9a4a99804 --- /dev/null +++ b/test/integration/secrets-realtime_test.go @@ -0,0 +1,25 @@ +//go:build integration + +package integration + +import ( + commonParams "github.com/checkmarx/ast-cli/internal/params" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSecrets_RealtimeScan_TextFile_Success(t *testing.T) { + args := []string{ + "scan", "secrets-realtime", "-s", "data/secret-exposed.txt", flag(commonParams.IgnoredFilePathFlag), "", + } + err, _ := executeCommand(t, args...) + assert.Nil(t, err) +} + +func TestSecrets_RealtimeScan_Empty_filePath_Fail(t *testing.T) { + args := []string{ + "scan", "secrets-realtime", "-s", "", flag(commonParams.IgnoredFilePathFlag), "", + } + err, _ := executeCommand(t, args...) + assert.NotNil(t, err) +}