Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/commands/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func runCreateProjectCommand(
applicationName, _ := cmd.Flags().GetString(commonParams.ApplicationName)
var applicationID []string
if applicationName != "" {
application, getAppErr := getApplication(applicationName, applicationsWrapper)
application, getAppErr := services.GetApplication(applicationName, applicationsWrapper)
if getAppErr != nil {
return getAppErr
}
Expand Down
45 changes: 1 addition & 44 deletions internal/commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"github.com/checkmarx/ast-cli/internal/commands/util"
"github.com/checkmarx/ast-cli/internal/commands/util/printer"
"github.com/checkmarx/ast-cli/internal/constants"
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/logger"
"github.com/checkmarx/ast-cli/internal/services"
Expand Down Expand Up @@ -709,23 +708,9 @@ func setupScanTypeProjectAndConfig(
return errors.Errorf("Project name is required")
}

applicationName, _ := cmd.Flags().GetString(commonParams.ApplicationName)

var applicationID []string
if applicationName != "" {
application, getAppErr := getApplication(applicationName, applicationsWrapper)
if getAppErr != nil {
return getAppErr
}
if application == nil {
return errors.Errorf(errorConstants.ApplicationDoesntExistOrNoPermission)
}
applicationID = []string{application.ID}
}

// We need to convert the project name into an ID
projectID, findProjectErr := services.FindProject(
applicationID,
/*applicationID,*/
info["project"].(map[string]interface{})["id"].(string),
cmd,
projectsWrapper,
Expand Down Expand Up @@ -799,34 +784,6 @@ func setupScanTypeProjectAndConfig(
return nil
}

func getApplication(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper) (*wrappers.Application, error) {
if applicationName != "" {
params := make(map[string]string)
params["name"] = applicationName
resp, err := applicationsWrapper.Get(params)
if err != nil {
return nil, err
}
if resp.Applications != nil && len(resp.Applications) > 0 {
application := verifyApplicationNameExactMatch(applicationName, resp)

return application, nil
}
}
return nil, nil
}

func verifyApplicationNameExactMatch(applicationName string, resp *wrappers.ApplicationsResponseModel) *wrappers.Application {
var application *wrappers.Application
for i := range resp.Applications {
if resp.Applications[i].Name == applicationName {
application = &resp.Applications[i]
break
}
}
return application
}

func getResubmitConfiguration(scansWrapper wrappers.ScansWrapper, projectID, userScanTypes string) (
[]wrappers.Config,
error,
Expand Down
33 changes: 32 additions & 1 deletion internal/commands/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const (
SCSScoreCardError = "SCS scan failed to start: Scorecard scan is missing required flags, please include in the ast-cli arguments: " +
"--scs-repo-url your_repo_url --scs-repo-token your_repo_token"
outputFileName = "test_output.log"
noUpdatesForExistingProject = "No applicationId or tags to update. Skipping project update."
noUpdatesForExistingProject = "No tags to update. Skipping project update."
)

func TestScanHelp(t *testing.T) {
Expand Down Expand Up @@ -411,6 +411,23 @@ func TestCreateScan_WhenProjectNotExists_ShouldCreateProjectAndAssignGroup(t *te
assert.Equal(t, strings.Contains(stdoutString, "Updating project groups"), true, "Expected output: %s", "Updating project groups")
}

func TestCreateScan_WhenProjectNotExists_ShouldCreateProjectAndAssociateApplication(t *testing.T) {
file := createOutputFile(t, outputFileName)
defer deleteOutputFile(file)
defer logger.SetOutput(os.Stdout)

baseArgs := []string{"scan", "create", "--project-name", "newProject", "-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, "application association done successfully"), true, "Expected output: %s", "application association done successfully")
}

func TestScanWorkflowMissingID(t *testing.T) {
err := execCmdNotNilAssertion(t, "scan", "workflow")
assert.Error(t, err, "Please provide a scan ID", err.Error())
Expand Down Expand Up @@ -624,6 +641,20 @@ 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)
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)
}
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"}
err := execCmdNotNilAssertion(t, baseArgs...)
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/util/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func runImportCommand(
return errors.Errorf(errorConstants.ProjectNameIsRequired)
}

projectID, err := services.FindProject(nil, projectName, cmd, projectsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, featureFlagsWrapper)
projectID, err := services.FindProject(projectName, cmd, projectsWrapper, groupsWrapper, accessManagementWrapper, applicationsWrapper, featureFlagsWrapper)
if err != nil {
return err
}
Expand Down
75 changes: 54 additions & 21 deletions internal/services/projects.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package services

import (
errorConstants "github.com/checkmarx/ast-cli/internal/constants/errors"
"slices"
"strconv"
"time"
Expand All @@ -22,7 +23,6 @@ const (
)

func FindProject(
applicationID []string,
projectName string,
cmd *cobra.Command,
projectsWrapper wrappers.ProjectsWrapper,
Expand All @@ -44,11 +44,8 @@ func FindProject(
resp,
cmd,
projectsWrapper,
groupsWrapper,
accessManagementWrapper,
applicationWrapper,
projectName,
applicationID,
projectTags,
projectPrivatePackage,
featureFlagsWrapper)
Expand All @@ -57,6 +54,13 @@ 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
}

projectID, err := createProject(projectName, cmd, projectsWrapper, groupsWrapper, accessManagementWrapper, applicationWrapper,
applicationID, projectGroups, projectPrivatePackage, featureFlagsWrapper)
if err != nil {
Expand Down Expand Up @@ -89,6 +93,49 @@ func GetProjectsCollectionByProjectName(projectName string, projectsWrapper wrap
return resp, nil
}

func getApplicationId(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper) ([]string, error) {
var applicationID []string
if applicationName != "" {
application, getAppErr := GetApplication(applicationName, applicationsWrapper)
if getAppErr != nil {
return nil, getAppErr
}
if application == nil {
return nil, errors.Errorf(errorConstants.ApplicationDoesntExistOrNoPermission)
}
applicationID = []string{application.ID}
}
return applicationID, nil
}

func GetApplication(applicationName string, applicationsWrapper wrappers.ApplicationsWrapper) (*wrappers.Application, error) {
if applicationName != "" {
params := make(map[string]string)
params["name"] = applicationName
resp, err := applicationsWrapper.Get(params)
if err != nil {
return nil, err
}
if resp.Applications != nil && len(resp.Applications) > 0 {
application := verifyApplicationNameExactMatch(applicationName, resp)

return application, nil
}
}
return nil, nil
}

func verifyApplicationNameExactMatch(applicationName string, resp *wrappers.ApplicationsResponseModel) *wrappers.Application {
var application *wrappers.Application
for i := range resp.Applications {
if resp.Applications[i].Name == applicationName {
application = &resp.Applications[i]
break
}
}
return application
}

func createProject(
projectName string,
cmd *cobra.Command,
Expand Down Expand Up @@ -178,18 +225,14 @@ func updateProject(
resp *wrappers.ProjectsCollectionResponseModel,
cmd *cobra.Command,
projectsWrapper wrappers.ProjectsWrapper,
groupsWrapper wrappers.GroupsWrapper,
accessManagementWrapper wrappers.AccessManagementWrapper,
applicationsWrapper wrappers.ApplicationsWrapper,
projectName string,
applicationID []string,
projectTags string,
projectPrivatePackage string,
featureFlagsWrapper wrappers.FeatureFlagsWrapper,

) (string, error) {
var projectID string
applicationName, _ := cmd.Flags().GetString(commonParams.ApplicationName)
var projModel = wrappers.Project{}
for i := 0; i < len(resp.Projects); i++ {
if resp.Projects[i].Name == projectName {
Expand All @@ -202,8 +245,8 @@ func updateProject(
projModel.RepoURL = resp.Projects[i].RepoURL
}
}
if projectTags == "" && projectPrivatePackage == "" && len(applicationID) == 0 {
logger.PrintIfVerbose("No applicationId or tags to update. Skipping project update.")
if projectTags == "" && projectPrivatePackage == "" {
logger.PrintIfVerbose("No tags to update. Skipping project update.")
return projectID, nil
}
if projectPrivatePackage != "" {
Expand All @@ -226,22 +269,12 @@ func updateProject(
logger.PrintIfVerbose("Updating project tags")
projModel.Tags = createTagMap(projectTags)
}
if len(applicationID) > 0 {
logger.PrintIfVerbose("Updating project applicationIds")
projModel.ApplicationIds = createApplicationIds(applicationID, projModelResp.ApplicationIds)
}

err = projectsWrapper.Update(projectID, &projModel)
if err != nil {
return "", errors.Errorf("%s: %v", failedUpdatingProj, err)
}

if applicationName != "" || len(applicationID) > 0 {
err = verifyApplicationAssociationDone(applicationName, projectID, applicationsWrapper)
if err != nil {
return projectID, err
}
}

return projectID, nil
}

Expand Down
15 changes: 14 additions & 1 deletion internal/wrappers/mock/application-mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,27 @@ func (a ApplicationsMockWrapper) Get(params map[string]string) (*wrappers.Applic
Name: "MOCK",
Description: "This is a mock application",
Criticality: 2,
ProjectIds: []string{"ProjectID1", "ProjectID2", "MOCK", "test_project", "ID-new-project-name"},
ProjectIds: []string{"ProjectID1", "ProjectID2", "MOCK", "test_project", "ID-new-project-name", "ID-newProject"},
CreatedAt: time.Now(),
}
if params["name"] == ExistingApplication {
mockApplication.Name = ExistingApplication
mockApplication.ID = "ID-newProject"
return &wrappers.ApplicationsResponseModel{
TotalCount: 1,
Applications: []wrappers.Application{mockApplication},
}, nil
}

response := &wrappers.ApplicationsResponseModel{
TotalCount: 1,
Applications: []wrappers.Application{mockApplication},
}

if params["name"] == "anyApplication" {
response.TotalCount = 0
response.Applications = []wrappers.Application{}
}

return response, nil
}
1 change: 1 addition & 0 deletions internal/wrappers/mock/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mock

const (
ApplicationDoesntExist = "application-doesnt-exist"
ExistingApplication = "application-exists"
NoPermissionApp = "NoPermissionApp"
FakeBadRequest400 = "fake-http-status-bad-request"
FakeUnauthorized401 = "fake-unauthorized-response"
Expand Down
29 changes: 29 additions & 0 deletions test/integration/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,35 @@ func TestScanCreate_WhenProjectExists_ShouldNotUpdateGroups(t *testing.T) {
t.Errorf("When project exists, groups before and after scan creation should be equal. Got %v, want %v", groupsAfterScanCreate, groupsBeforeScanCreate)
}

}

func TestScanCreate_WhenProjectExists_ShouldNotUpdateApplication(t *testing.T) {
projectID, projectName := getRootProject(t)
project := showProject(t, projectID)
applicationsBeforeScanCreate := project.ApplicationIds

args := []string{
scanCommand, "create",
flag(params.ProjectName), projectName,
flag(params.SourcesFlag), Zip,
flag(params.ScanTypes), "sast",
flag(params.PresetName), "Checkmarx Default",
flag(params.BranchFlag), "dummy_branch",
flag(params.ApplicationName), "wrong_application",
"--async",
}

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)
}

}
func TestScanCreateExploitablePath(t *testing.T) {
_, projectName := getRootProject(t)
Expand Down
Loading