diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index ae0c42933..be91f8ed7 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -193,8 +193,9 @@ func TestScanCreate_ApplicationNameIsNotExactMatch_FailedToCreateScan(t *testing assert.Assert(t, err.Error() == errorConstants.ApplicationDoesntExistOrNoPermission) } -func TestScanCreate_ExistingProjectAndApplicationWithNoPermission_ShouldCreateScan(t *testing.T) { - execCmdNilAssertion(t, "scan", "create", "--project-name", "MOCK", "--application-name", mock.ApplicationDoesntExist, "-s", dummyRepo, "-b", "dummy_branch") +func TestScanCreate_ExistingProjectAndApplicationWithNoPermission_ShouldFailScan(t *testing.T) { + err := execCmdNotNilAssertion(t, "scan", "create", "--project-name", "MOCK", "--application-name", mock.NoPermissionApp, "-s", dummyRepo, "-b", "dummy_branch") + assert.Assert(t, strings.Contains(err.Error(), errorConstants.FailedToGetApplication), err.Error()) } func TestScanCreate_ExistingApplicationWithNoPermission_FailedToCreateScan(t *testing.T) { @@ -712,18 +713,13 @@ func TestCreateScan_WhenProjectExists_ShouldIgnoreGroups(t *testing.T) { assert.Equal(t, strings.Contains(stdoutString, noUpdatesForExistingProject), true, "Expected output: %s", noUpdatesForExistingProject) } -func TestCreateScan_WhenProjectExists_ShouldIgnoreApplication(t *testing.T) { - file := createOutputFile(t, outputFileName) - defer deleteOutputFile(file) - defer logger.SetOutput(os.Stdout) +// Now as we give the ability to assign existing projects to applications , there is validation if application exists + +func TestCreateScan_WhenProjectExists_GetApplication_Fails500Err_Failed(t *testing.T) { baseArgs := []string{scanCommand, "create", "--project-name", "MOCK", "-s", dummyRepo, "-b", "dummy_branch", - "--debug", "--application-name", "anyApplication"} - execCmdNilAssertion(t, baseArgs...) - stdoutString, err := util.ReadFileAsString(file.Name()) - if err != nil { - t.Fatalf("Failed to read log file: %v", err) - } - assert.Equal(t, strings.Contains(stdoutString, noUpdatesForExistingProject), true, "Expected output: %s", noUpdatesForExistingProject) + "--debug", "--application-name", mock.FakeInternalServerError500} + err := execCmdNotNilAssertion(t, baseArgs...) + assert.ErrorContains(t, err, errorConstants.FailedToGetApplication, err.Error()) } func TestScanCreateLastSastScanTimeWithInvalidValue(t *testing.T) { baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", dummyRepo, "-b", "dummy_branch", "--sca-exploitable-path", "true", "--sca-last-sast-scan-time", "notaniteger"} @@ -3623,3 +3619,64 @@ func Test_CreateScanWithIgnorePolicyFlag(t *testing.T) { "scan", "create", "--project-name", "MOCK", "-s", "data/sources.zip", "--branch", "dummy_branch", "--ignore-policy", ) } + +func Test_CreateScanWithExistingProjectAndAssign_Application(t *testing.T) { + file := createOutputFile(t, outputFileName) + defer deleteOutputFile(file) + defer logger.SetOutput(os.Stdout) + + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--application-name", mock.ExistingApplication, "--debug"} + execCmdNilAssertion( + t, + baseArgs..., + ) + stdoutString, err := util.ReadFileAsString(file.Name()) + if err != nil { + t.Fatalf("Failed to read log file: %v", err) + } + assert.Equal(t, strings.Contains(stdoutString, "Successfully updated the application"), true, "Expected output: %s", "Successfully updated the application") +} + +func Test_CreateScanWithExistingProjectAndAssign_FailedNoApplication_NameProvided(t *testing.T) { + file := createOutputFile(t, outputFileName) + defer deleteOutputFile(file) + defer logger.SetOutput(os.Stdout) + + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug"} + execCmdNilAssertion( + t, + baseArgs..., + ) + stdoutString, err := util.ReadFileAsString(file.Name()) + if err != nil { + t.Fatalf("Failed to read log file: %v", err) + } + assert.Equal(t, strings.Contains(stdoutString, "No application name provided. Skipping application update"), true, "Expected output: %s", "No application name provided. Skipping application update") +} + +func Test_CreateScanWithExistingProjectAndAssign_FailedApplication_DoesNot_Exist(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug", "--application-name", "NoPermissionApp"} + err := execCmdNotNilAssertion( + t, + baseArgs..., + ) + assert.ErrorContains(t, err, errorConstants.FailedToGetApplication, err.Error()) +} + +func Test_CreateScanWithExistingProjectAssign_to_Application_FF_DirectAssociationEnabledShouldPass(t *testing.T) { + file := createOutputFile(t, outputFileName) + defer deleteOutputFile(file) + defer logger.SetOutput(os.Stdout) + + mock.Flag = wrappers.FeatureFlagResponseModel{Name: wrappers.DirectAssociationEnabled, Status: true} + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", ".", "--branch", "main", "--debug", "--application-name", mock.ExistingApplication} + execCmdNilAssertion( + t, + baseArgs..., + ) + stdoutString, err := util.ReadFileAsString(file.Name()) + if err != nil { + t.Fatalf("Failed to read log file: %v", err) + } + assert.Equal(t, strings.Contains(stdoutString, "Successfully updated the application"), true, "Expected output: %s", "Successfully updated the application") +} diff --git a/internal/constants/errors/errors.go b/internal/constants/errors/errors.go index e565e1cdc..62c207a7a 100644 --- a/internal/constants/errors/errors.go +++ b/internal/constants/errors/errors.go @@ -24,6 +24,9 @@ const ( NoASCALicense = "User doesn't have \"AI Protection\" or \"Checkmarx One Assist\" license" FailedUploadFileMsgWithDomain = "Unable to upload the file to the pre-signed URL. Try adding the domain: %s to your allow list." FailedUploadFileMsgWithURL = "Unable to upload the file to the pre-signed URL. Try adding the URL: %s to your allow list." + NoPermissionToUpdateApplication = "you do not have permission to update the application" + FailedToUpdateApplication = "failed to update application" + ApplicationNotFound = "Application not found" // asca Engine FileExtensionIsRequired = "file must have an extension" diff --git a/internal/services/applications.go b/internal/services/applications.go index 744e89670..ad6298de3 100644 --- a/internal/services/applications.go +++ b/internal/services/applications.go @@ -2,11 +2,16 @@ package services import ( errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" + "github.com/checkmarx/ast-cli/internal/logger" "github.com/checkmarx/ast-cli/internal/wrappers" "github.com/checkmarx/ast-cli/internal/wrappers/utils" "github.com/pkg/errors" ) +const ( + ApplicationRuleType = "project.name.in" +) + func createApplicationIds(applicationID, existingApplicationIds []string) []string { for _, id := range applicationID { if !utils.Contains(existingApplicationIds, id) { @@ -58,3 +63,71 @@ func verifyApplicationNameExactMatch(applicationName string, resp *wrappers.Appl } return application } + +func findApplicationAndUpdate(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper, projectName, projectID string, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error { + if applicationName == "" { + logger.PrintfIfVerbose("No application name provided. Skipping application update") + return nil + } + applicationResp, err := GetApplication(applicationName, applicationsWrapper) + if err != nil { + return errors.Wrapf(err, "%s:%s", errorConstants.FailedToGetApplication, applicationName) + } + if applicationResp == nil { + return errors.Errorf("%s: %s", errorConstants.ApplicationNotFound, applicationName) + } + + directAssociationEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.DirectAssociationEnabled) + if directAssociationEnabled.Status { + err = associateProjectToApplication(applicationResp.ID, projectID, applicationResp.ProjectIds, applicationsWrapper) + if err != nil { + return err + } + return nil + } + var applicationModel wrappers.ApplicationConfiguration + var newApplicationRule wrappers.Rule + var applicationID string + + applicationModel.Name = applicationResp.Name + applicationModel.Description = applicationResp.Description + applicationModel.Criticality = applicationResp.Criticality + applicationModel.Type = applicationResp.Type + applicationModel.Tags = applicationResp.Tags + newApplicationRule.Type = ApplicationRuleType + newApplicationRule.Value = projectName + applicationModel.Rules = append(applicationModel.Rules, applicationResp.Rules...) + applicationModel.Rules = append(applicationModel.Rules, newApplicationRule) + applicationID = applicationResp.ID + + err = updateApplication(&applicationModel, applicationsWrapper, applicationID) + if err != nil { + return err + } + return nil +} + +func updateApplication(applicationModel *wrappers.ApplicationConfiguration, applicationWrapper wrappers.ApplicationsWrapper, applicationID string) error { + errorModel, err := applicationWrapper.Update(applicationID, applicationModel) + return handleApplicationUpdateResponse(errorModel, err) +} + +func associateProjectToApplication(applicationID, projectID string, associatedProjectIds []string, applicationsWrapper wrappers.ApplicationsWrapper) error { + associatedProjectIds = append(associatedProjectIds, projectID) + associateProjectsModel := &wrappers.AssociateProjectModel{ + ProjectIds: associatedProjectIds, + } + errorModel, err := applicationsWrapper.CreateProjectAssociation(applicationID, associateProjectsModel) + return handleApplicationUpdateResponse(errorModel, err) +} + +func handleApplicationUpdateResponse(errorModel *wrappers.ErrorModel, err error) error { + if errorModel != nil { + err = errors.Errorf(ErrorCodeFormat, errorConstants.FailedToUpdateApplication, errorModel.Code, errorModel.Message) + } + if errorModel == nil && err == nil { + logger.PrintIfVerbose("Successfully updated the application") + return nil + } + return err +} diff --git a/internal/services/applications_test.go b/internal/services/applications_test.go index 06ecad984..48e13dc91 100644 --- a/internal/services/applications_test.go +++ b/internal/services/applications_test.go @@ -1,7 +1,12 @@ package services import ( + errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" + "github.com/checkmarx/ast-cli/internal/wrappers" + "github.com/checkmarx/ast-cli/internal/wrappers/mock" + "gotest.tools/assert" "reflect" + "strings" "testing" ) @@ -36,3 +41,49 @@ func Test_createApplicationIds(t *testing.T) { }) } } +func Test_ProjectAssociation_ToApplicationDirectly(t *testing.T) { + applicationWrapper := &mock.ApplicationsMockWrapper{} + + tests := []struct { + description string + applicationName string + projectName string + error string + }{ + {"Project association to Application should fail with 403 forbidden permission error", mock.FakeForbidden403, "random-project", errorConstants.NoPermissionToUpdateApplication}, + {"Project association to Application should fail with 401 unauthorized error", mock.FakeUnauthorized401, "random-project", errorConstants.StatusUnauthorized}, + {"Project association to Application should fail with 400 BadRequest error", mock.FakeBadRequest400, "random-project", errorConstants.FailedToUpdateApplication}, + } + + for _, test := range tests { + tt := test + t.Run(tt.description, func(t *testing.T) { + err := associateProjectToApplication(tt.applicationName, tt.projectName, []string{}, applicationWrapper) + assert.Assert(t, strings.Contains(err.Error(), tt.error), err.Error()) + }) + } +} + +func Test_ProjectAssociation_ToApplicationWithoutDirectAssociation(t *testing.T) { + applicationModel := wrappers.ApplicationConfiguration{} + applicationWrapper := &mock.ApplicationsMockWrapper{} + + tests := []struct { + description string + applicationID string + projectName string + error string + }{ + {"Application update should fail with 403 forbidden permission error", mock.FakeForbidden403, "random-project", errorConstants.NoPermissionToUpdateApplication}, + {"Application update should fail with 401 unauthorized error", mock.FakeUnauthorized401, "random-project", errorConstants.StatusUnauthorized}, + {"Application update should fail with 400 BadRequest error", mock.FakeBadRequest400, "random-project", errorConstants.FailedToUpdateApplication}, + } + + for _, test := range tests { + tt := test + t.Run(tt.description, func(t *testing.T) { + err := updateApplication(&applicationModel, applicationWrapper, tt.applicationID) + assert.Assert(t, strings.Contains(err.Error(), tt.error), err.Error()) + }) + } +} diff --git a/internal/services/projects.go b/internal/services/projects.go index c39a25863..3d34cc110 100644 --- a/internal/services/projects.go +++ b/internal/services/projects.go @@ -40,9 +40,14 @@ func FindProject( } branchName := strings.TrimSpace(viper.GetString(commonParams.BranchKey)) isBranchPrimary, _ = cmd.Flags().GetBool(commonParams.BranchPrimaryFlag) + applicationName, _ := cmd.Flags().GetString(commonParams.ApplicationName) for i := 0; i < len(resp.Projects); i++ { project := resp.Projects[i] if project.Name == projectName { + err = findApplicationAndUpdate(applicationName, applicationWrapper, projectName, project.ID, featureFlagsWrapper) + if err != nil { + return "", err + } projectTags, _ := cmd.Flags().GetString(commonParams.ProjectTagList) projectPrivatePackage, _ := cmd.Flags().GetString(commonParams.ProjecPrivatePackageFlag) return updateProject(&project, projectsWrapper, projectTags, projectPrivatePackage, isBranchPrimary, branchName) @@ -51,8 +56,6 @@ func FindProject( projectGroups, _ := cmd.Flags().GetString(commonParams.ProjectGroupList) projectPrivatePackage, _ := cmd.Flags().GetString(commonParams.ProjecPrivatePackageFlag) - - applicationName, _ := cmd.Flags().GetString(commonParams.ApplicationName) applicationID, appErr := getApplicationID(applicationName, applicationWrapper) if appErr != nil { return "", appErr diff --git a/internal/wrappers/application-http.go b/internal/wrappers/application-http.go index 157cb9258..1921aa2c4 100644 --- a/internal/wrappers/application-http.go +++ b/internal/wrappers/application-http.go @@ -1,7 +1,9 @@ package wrappers import ( + "bytes" "encoding/json" + "fmt" "net/http" errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" @@ -20,6 +22,81 @@ func NewApplicationsHTTPWrapper(path string) ApplicationsWrapper { } } +func (a *ApplicationsHTTPWrapper) CreateProjectAssociation(applicationID string, projectAssociationModel *AssociateProjectModel) (*ErrorModel, error) { + clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) + jsonBytes, err := json.Marshal(*projectAssociationModel) + if err != nil { + return nil, err + } + associationPath := fmt.Sprintf("%s/%s/%s", a.path, applicationID, "projects") + resp, err := SendHTTPRequest(http.MethodPost, associationPath, bytes.NewBuffer(jsonBytes), true, clientTimeout) + if err != nil { + return nil, err + } + decoder := json.NewDecoder(resp.Body) + defer func() { + _ = resp.Body.Close() + }() + switch resp.StatusCode { + case http.StatusBadRequest: + errorModel := ErrorModel{} + err = decoder.Decode(&errorModel) + if err != nil { + return nil, errors.Errorf("failed to parse application response for project updation: %s ", err) + } + return &errorModel, nil + + case http.StatusCreated: + return nil, nil + + case http.StatusForbidden: + return nil, errors.New(errorConstants.NoPermissionToUpdateApplication) + + case http.StatusUnauthorized: + return nil, errors.New(errorConstants.StatusUnauthorized) + default: + return nil, errors.Errorf("response status code %d", resp.StatusCode) + } +} + +func (a *ApplicationsHTTPWrapper) Update(applicationID string, applicationBody *ApplicationConfiguration) (*ErrorModel, error) { + clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) + jsonBytes, err := json.Marshal(applicationBody) + updatePath := fmt.Sprintf("%s/%s", a.path, applicationID) + if err != nil { + return nil, err + } + resp, err := SendHTTPRequest(http.MethodPut, updatePath, bytes.NewBuffer(jsonBytes), true, clientTimeout) + if err != nil { + return nil, err + } + decoder := json.NewDecoder(resp.Body) + defer func() { + _ = resp.Body.Close() + }() + + switch resp.StatusCode { + case http.StatusBadRequest: + errorModel := ErrorModel{} + err = decoder.Decode(&errorModel) + if err != nil { + return nil, errors.Errorf("failed to parse application response: %s ", err) + } + return &errorModel, nil + + case http.StatusNoContent: + return nil, nil + + case http.StatusForbidden: + return nil, errors.New(errorConstants.NoPermissionToUpdateApplication) + + case http.StatusUnauthorized: + return nil, errors.New(errorConstants.StatusUnauthorized) + default: + return nil, errors.Errorf("response status code %d", resp.StatusCode) + } +} + func (a *ApplicationsHTTPWrapper) Get(params map[string]string) (*ApplicationsResponseModel, error) { if _, ok := params[limit]; !ok { params[limit] = limitValue diff --git a/internal/wrappers/application.go b/internal/wrappers/application.go index 6bb30d62a..81f4ba8bc 100644 --- a/internal/wrappers/application.go +++ b/internal/wrappers/application.go @@ -9,15 +9,29 @@ type ApplicationsResponseModel struct { } type Application struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Criticality int `json:"criticality"` - Rules []Rule `json:"rules"` - ProjectIds []string `json:"projectIds"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - Tags Tags `json:"tags"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Criticality int `json:"criticality"` + Rules []Rule `json:"rules"` + ProjectIds []string `json:"projectIds"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + Tags map[string]string `json:"tags"` + Type string `json:"type"` +} + +type ApplicationConfiguration struct { + Name string `json:"name"` + Description string `json:"description"` + Type string `json:"type"` + Criticality int `json:"criticality"` + Rules []Rule `json:"rules"` + Tags map[string]string `json:"tags"` +} + +type AssociateProjectModel struct { + ProjectIds []string `json:"projectIds"` } type Rule struct { @@ -26,11 +40,8 @@ type Rule struct { Value string `json:"value"` } -type Tags struct { - Test string `json:"test"` - Priority string `json:"priority"` -} - type ApplicationsWrapper interface { Get(params map[string]string) (*ApplicationsResponseModel, error) + Update(applicationID string, applicationBody *ApplicationConfiguration) (*ErrorModel, error) + CreateProjectAssociation(applicationID string, requestModel *AssociateProjectModel) (*ErrorModel, error) } diff --git a/internal/wrappers/feature-flags.go b/internal/wrappers/feature-flags.go index a243db0f9..e5b229dc3 100644 --- a/internal/wrappers/feature-flags.go +++ b/internal/wrappers/feature-flags.go @@ -16,6 +16,7 @@ const SCSEngineCLIEnabled = "NEW_2MS_SCORECARD_RESULTS_CLI_ENABLED" const RiskManagementEnabled = "RISK_MANAGEMENT_IDES_PROJECT_RESULTS_SCORES_API_ENABLED" const OssRealtimeEnabled = "OSS_REALTIME_ENABLED" const ScsLicensingV2Enabled = "SSCS_NEW_LICENSING_ENABLED" +const DirectAssociationEnabled = "DIRECT_APP_ASSOCIATION_ENABLED" const maxRetries = 3 var DefaultFFLoad bool = false diff --git a/internal/wrappers/mock/application-mock.go b/internal/wrappers/mock/application-mock.go index fdb9e01a9..9bbdd28ef 100644 --- a/internal/wrappers/mock/application-mock.go +++ b/internal/wrappers/mock/application-mock.go @@ -1,6 +1,7 @@ package mock import ( + "fmt" "time" errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors" @@ -8,6 +9,8 @@ import ( "github.com/pkg/errors" ) +const code = 355 + type ApplicationsMockWrapper struct{} func (a ApplicationsMockWrapper) Get(params map[string]string) (*wrappers.ApplicationsResponseModel, error) { @@ -49,6 +52,44 @@ func (a ApplicationsMockWrapper) Get(params map[string]string) (*wrappers.Applic response.TotalCount = 0 response.Applications = []wrappers.Application{} } - return response, nil } + +func (a ApplicationsMockWrapper) Update(applicationID string, applicationBody *wrappers.ApplicationConfiguration) (*wrappers.ErrorModel, error) { + fmt.Println("called Update application") + + if applicationID == FakeForbidden403 { + return nil, errors.Errorf(errorConstants.NoPermissionToUpdateApplication) + } + if applicationID == FakeUnauthorized401 { + return nil, errors.Errorf(errorConstants.StatusUnauthorized) + } + if applicationID == FakeBadRequest400 { + return &wrappers.ErrorModel{ + Message: "invalid applicationBody", + Code: code, + Type: "validation", + }, nil + } + return nil, nil +} + +func (a ApplicationsMockWrapper) CreateProjectAssociation(applicationID string, requestModel *wrappers.AssociateProjectModel) (*wrappers.ErrorModel, error) { + fmt.Println("called Create project association to application") + if applicationID == FakeForbidden403 { + return nil, errors.Errorf(errorConstants.NoPermissionToUpdateApplication) + } + if applicationID == FakeUnauthorized401 { + return nil, errors.Errorf(errorConstants.StatusUnauthorized) + } + + if applicationID == FakeBadRequest400 { + return &wrappers.ErrorModel{ + Message: "invalid applicationBody", + Code: code, + Type: "validation", + }, nil + } + + return nil, nil +} diff --git a/test/integration/predicate_test.go b/test/integration/predicate_test.go index 794c74e09..5bd27d029 100644 --- a/test/integration/predicate_test.go +++ b/test/integration/predicate_test.go @@ -214,32 +214,49 @@ func TestSastUpdateAndGetPredicatesForNotFoundSimilarityId(t *testing.T) { } 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.") // After the api/custom-states becomes available in the DEU environment, replace the hardcoded value with getRootScan(t) and create "state2" as a custom state in DEU. - projectID := "a2d52ac9-d007-4d95-a65e-bbe61c3451a4" - similarityID := "-1213859962" - scanType := "sast" - - outputBuffer := executeCmdNilAssertion( - t, "Fetching predicates should work.", "triage", "show", - flag(params.FormatFlag), printer.FormatJSON, - flag(params.ProjectIDFlag), projectID, - flag(params.SimilarityIDFlag), similarityID, - flag(params.ScanTypeFlag), scanType, + 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, ) - predicateResult := []wrappers.Predicate{} - fmt.Println(outputBuffer) - _ = unmarshall(t, outputBuffer, &predicateResult, "Reading results should pass") - assert.Assert(t, len(predicateResult) >= 1, "Should have at least 1 predicate as the result.") + 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 := result.Results[index].SimilarityID + scanType := result.Results[index].Type fmt.Println("Step 2: Updating the predicate state.") - newState := "state2" + newState := "Custom1" newSeverity := "HIGH" - comment := "" + comment := "Updating State test" - err, _ := executeCommand( + err, _ = executeCommand( t, "triage", "update", flag(params.ProjectIDFlag), projectID, flag(params.SimilarityIDFlag), similarityID, diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index ddcba2e17..2cd7c2360 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -299,7 +299,7 @@ func TestScanCreate_ExistingApplicationAndExistingProject_CreateScanSuccessfully _, projectName := createNewProject(t, nil, nil, GenerateRandomProjectNameForScan()) args := []string{ "scan", "create", - flag(params.ApplicationName), "my-application", + flag(params.ApplicationName), "test-app", flag(params.ProjectName), projectName, flag(params.SourcesFlag), ".", flag(params.ScanTypes), params.IacType, @@ -1667,10 +1667,8 @@ func TestScanCreate_WhenProjectExists_ShouldNotUpdateGroups(t *testing.T) { } -func TestScanCreate_WhenProjectExists_ShouldNotUpdateApplication(t *testing.T) { - projectID, projectName := getRootProject(t) - project := showProject(t, projectID) - applicationsBeforeScanCreate := project.ApplicationIds +func TestScanCreate_WhenProjectExists_ShouldThrow_Error_ApplicationNotFound(t *testing.T) { + _, projectName := getRootProject(t) args := []string{ scanCommand, "create", @@ -1684,15 +1682,7 @@ func TestScanCreate_WhenProjectExists_ShouldNotUpdateApplication(t *testing.T) { } err, _ := executeCommand(t, args...) - if err != nil { - assertError(t, err, "running a scan should pass") - } - - project = showProject(t, projectID) - applicationsAfterScanCreate := project.ApplicationIds - if !reflect.DeepEqual(applicationsBeforeScanCreate, applicationsAfterScanCreate) { - t.Errorf("When project exists, applications before and after scan creation should be equal. Got %v, want %v", applicationsAfterScanCreate, applicationsBeforeScanCreate) - } + assert.Error(t, err, "Application not found: wrong_application") } func TestScanCreateExploitablePath(t *testing.T) { @@ -2706,3 +2696,32 @@ func TestCreateScanFilterGitIgnoreFile_GitIgnoreExist(t *testing.T) { err, _ := executeCommand(t, args...) assert.NilError(t, err, "Scan creation with gitignore filter should pass without error") } + +func TestCreateScanWithExistingProjectAnd_AssignApplication(t *testing.T) { + _, projectName := createNewProject(t, nil, nil, GenerateRandomProjectNameForScan()) + + args := []string{ + "scan", "create", + flag(params.ProjectName), projectName, + flag(params.BranchFlag), "dummy_branch", + flag(params.SourcesFlag), "data/sources-gitignore.zip", + flag(params.ApplicationName), "cli-application", + } + err, _ := executeCommand(t, args...) + assert.NilError(t, err, "Project should be assigned to application") +} + +func TestCreateScanWithNewProjectName_Assign_Groups(t *testing.T) { + + defer deleteProjectByName(t, getProjectNameForTest()) + args := []string{ + "scan", "create", + flag(params.ProjectName), getProjectNameForScanTests(), + flag(params.BranchFlag), "dummy_branch", + flag(params.SourcesFlag), "data/sources-gitignore.zip", + flag(params.ProjectGroupList), formatGroups(Groups), + } + err, _ := executeCommand(t, args...) + assert.NilError(t, err, "Groups should be assigned to newly created projects") + +}