From a9085021adea99f08cace34aac2ccae0c83336b9 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 14:37:59 +0100 Subject: [PATCH 01/25] AST-11602 - CLI | Add SSH key to scan create command - Added --ssh-key flag to scan create - Added unit tests and integration tests - Code refactoring --- internal/commands/data/id_rsa | 38 +++++ internal/commands/project.go | 2 +- internal/commands/scan.go | 237 ++++++++++++++++++++------------ internal/commands/scan_test.go | 45 +++++- internal/commands/util/utils.go | 18 +++ internal/params/flags.go | 1 + internal/wrappers/scans.go | 6 +- test/integration/auth_test.go | 34 ----- test/integration/root_test.go | 1 + test/integration/scan_test.go | 23 +++- 10 files changed, 272 insertions(+), 133 deletions(-) create mode 100644 internal/commands/data/id_rsa diff --git a/internal/commands/data/id_rsa b/internal/commands/data/id_rsa new file mode 100644 index 000000000..44f9baa6d --- /dev/null +++ b/internal/commands/data/id_rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY----- diff --git a/internal/commands/project.go b/internal/commands/project.go index af79de6dd..e3cfbfbed 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -283,7 +283,7 @@ func runCreateProjectCommand( if err != nil { return err } - updateTagValues(&input, cmd) + setupScanTags(&input, cmd) var projModel = wrappers.Project{} var projResponseModel *wrappers.ProjectResponseModel var errorModel *wrappers.ErrorModel diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 7ccf33807..d4c9819ce 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/google/shlex" "github.com/pkg/errors" @@ -39,6 +40,8 @@ const ( mbBytes = 1024.0 * 1024.0 scaType = "sca" notExploitable = "NOT_EXPLOITABLE" + git = "git" + invalidSSHSource = "provided source does not need a key. Make sure you are defining the right source or remove the flag --ssh-key" ) var ( @@ -383,6 +386,9 @@ func scanCreateSubCommand( if err != nil { log.Fatal(err) } + + createScanCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") + return createScanCmd } @@ -437,7 +443,7 @@ func createProject( return projectID, err } -func updateTagValues(input *[]byte, cmd *cobra.Command) { +func setupScanTags(input *[]byte, cmd *cobra.Command) { tagListStr, _ := cmd.Flags().GetString(commonParams.TagList) tags := strings.Split(tagListStr, ",") var info map[string]interface{} @@ -476,17 +482,16 @@ func createTagMap(tagListStr string) map[string]string { return tags } -func updateScanRequestValues( +func setupScanTypeProjectAndConfig( input *[]byte, cmd *cobra.Command, - sourceType string, projectsWrapper wrappers.ProjectsWrapper, groupsWrapper wrappers.GroupsWrapper, ) error { var info map[string]interface{} newProjectName, _ := cmd.Flags().GetString(commonParams.ProjectName) _ = json.Unmarshal(*input, &info) - info["type"] = sourceType + info["type"] = getUploadType(cmd) // Handle the project settings if _, ok := info["project"]; !ok { var projectMap map[string]interface{} @@ -534,14 +539,12 @@ func updateScanRequestValues( return err } -func determineScanTypes(cmd *cobra.Command) { +func validateScanTypes(cmd *cobra.Command) { userScanTypes, _ := cmd.Flags().GetString(commonParams.ScanTypes) if len(userScanTypes) > 0 { actualScanTypes = userScanTypes } -} -func validateScanTypes() { scanTypes := strings.Split(actualScanTypes, ",") for _, scanType := range scanTypes { isValid := false @@ -848,29 +851,49 @@ func addScaResults(zipWriter *zip.Writer) error { return nil } -func determineSourceFile( +func getUploadURLFromSource( + cmd *cobra.Command, uploadsWrapper wrappers.UploadsWrapper, - sourcesFile, sourceDir, sourceDirFilter, userIncludeFilter, scaResolver, scaResolverParams string, ) (string, error) { var err error var preSignedURL string - if sourceDir != "" { + + sourceDirFilter, _ := cmd.Flags().GetString(commonParams.SourceDirFilterFlag) + userIncludeFilter, _ := cmd.Flags().GetString(commonParams.IncludeFilterFlag) + + zipFilePath, directoryPath, err := definePathForZipFileOrDirectory(cmd) + if err != nil { + return "", errors.Wrapf(err, "%s: Input in bad format", failedCreating) + } + + if directoryPath != "" { + // Get sca resolver flags + scaResolverParams, err := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) + if err != nil { + scaResolverParams = "" + } + scaResolver, err := cmd.Flags().GetString(commonParams.ScaResolverFlag) + if err != nil { + scaResolver = "" + scaResolverParams = "" + } + // Make sure scaResolver only runs in sca type of scans if strings.Contains(actualScanTypes, scaType) { - err = runScaResolver(sourceDir, scaResolver, scaResolverParams) + err = runScaResolver(directoryPath, scaResolver, scaResolverParams) if err != nil { return "", errors.Wrapf(err, "ScaResolver error") } } - sourcesFile, err = compressFolder(sourceDir, sourceDirFilter, userIncludeFilter, scaResolver) + zipFilePath, err = compressFolder(directoryPath, sourceDirFilter, userIncludeFilter, scaResolver) if err != nil { return "", err } } - if sourcesFile != "" { + if zipFilePath != "" { // Send a request to uploads service var preSignedURL *string - preSignedURL, err = uploadsWrapper.UploadFile(sourcesFile) + preSignedURL, err = uploadsWrapper.UploadFile(zipFilePath) if err != nil { return "", errors.Wrapf(err, "%s: Failed to upload sources file\n", failedCreating) } @@ -880,32 +903,29 @@ func determineSourceFile( return preSignedURL, err } -func determineSourceType(sourcesFile string) (zipFile, sourceDir, scanRepoURL string, err error) { - if strings.HasPrefix(sourcesFile, "https://") || - strings.HasPrefix(sourcesFile, "http://") { - scanRepoURL = sourcesFile - - log.Printf("\n\nScanning branch %s...\n", viper.GetString(commonParams.BranchKey)) - } else { - info, statErr := os.Stat(sourcesFile) - if !os.IsNotExist(statErr) { - if filepath.Ext(sourcesFile) == ".zip" { - zipFile = sourcesFile - } else if info != nil && info.IsDir() { - sourceDir = filepath.ToSlash(sourcesFile) - if !strings.HasSuffix(sourceDir, "/") { - sourceDir += "/" - } - } else { - msg := fmt.Sprintf("Sources input has bad format: %v", sourcesFile) - err = errors.New(msg) +func definePathForZipFileOrDirectory(cmd *cobra.Command) (zipFile, sourceDir string, err error) { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + info, statErr := os.Stat(sourceTrimmed) + if !os.IsNotExist(statErr) { + if filepath.Ext(sourceTrimmed) == ".zip" { + zipFile = sourceTrimmed + } else if info != nil && info.IsDir() { + sourceDir = filepath.ToSlash(sourceTrimmed) + if !strings.HasSuffix(sourceDir, "/") { + sourceDir += "/" } } else { - msg := fmt.Sprintf("Sources input has bad format: %v", sourcesFile) + msg := fmt.Sprintf("Sources input has bad format: %v", sourceTrimmed) err = errors.New(msg) } + } else { + msg := fmt.Sprintf("Sources input has bad format: %v", sourceTrimmed) + err = errors.New(msg) } - return zipFile, sourceDir, scanRepoURL, err + + return zipFile, sourceDir, err } func runCreateScanCommand( @@ -966,81 +986,120 @@ func createScanModel( projectsWrapper wrappers.ProjectsWrapper, groupsWrapper wrappers.GroupsWrapper, ) (*wrappers.Scan, error) { - determineScanTypes(cmd) - validateScanTypes() - sourceDirFilter, _ := cmd.Flags().GetString(commonParams.SourceDirFilterFlag) - userIncludeFilter, _ := cmd.Flags().GetString(commonParams.IncludeFilterFlag) - sourcesFile, _ := cmd.Flags().GetString(commonParams.SourcesFlag) - sourcesFile, sourceDir, scanRepoURL, err := determineSourceType(strings.TrimSpace(sourcesFile)) - if err != nil { - return nil, errors.Wrapf(err, "%s: Input in bad format", failedCreating) - } - uploadType := getUploadType(sourceDir, sourcesFile) + validateScanTypes(cmd) + var input = []byte("{}") - err = updateScanRequestValues(&input, cmd, uploadType, projectsWrapper, groupsWrapper) + + // Define type, project and config in scan model + err := setupScanTypeProjectAndConfig(&input, cmd, projectsWrapper, groupsWrapper) if err != nil { return nil, err } - updateTagValues(&input, cmd) + + // set tags in scan model + setupScanTags(&input, cmd) + scanModel := wrappers.Scan{} // Try to parse to a scan model in order to manipulate the request payload err = json.Unmarshal(input, &scanModel) if err != nil { return nil, errors.Wrapf(err, "%s: Input in bad format", failedCreating) } - // Get sca resolver flags - scaResolverParams, err := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) - if err != nil { - scaResolverParams = "" - } - scaResolver, err := cmd.Flags().GetString(commonParams.ScaResolverFlag) - if err != nil { - scaResolver = "" - scaResolverParams = "" - } - // Set up the project handler (either git or upload) - pHandler, err := setupProjectHandler( - uploadsWrapper, - sourcesFile, - sourceDir, - sourceDirFilter, - userIncludeFilter, - scanRepoURL, - scaResolver, - scaResolverParams, - ) - scanModel.Handler, _ = json.Marshal(pHandler) + + // Set up the scan handler (either git or upload) + scanHandler, err := setupScanHandler(cmd, uploadsWrapper) if err != nil { return nil, err } + + scanModel.Handler, _ = json.Marshal(scanHandler) + + uploadType := getUploadType(cmd) + + if uploadType == "git" { + log.Printf("\n\nScanning branch %s...\n", viper.GetString(commonParams.BranchKey)) + } + return &scanModel, nil } -func getUploadType(sourceDir, sourcesFile string) string { - if sourceDir != "" || sourcesFile != "" { - return "upload" +func getUploadType(cmd *cobra.Command) string { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + if util.IsGitURL(sourceTrimmed) { + return git } - return "git" + + return "upload" } -func setupProjectHandler( +func setupScanHandler( + cmd *cobra.Command, uploadsWrapper wrappers.UploadsWrapper, - sourcesFile, sourceDir, sourceDirFilter, userIncludeFilter, scanRepoURL, scaResolver, scaResolverParams string, -) (wrappers.UploadProjectHandler, error) { - pHandler := wrappers.UploadProjectHandler{} - pHandler.Branch = viper.GetString(commonParams.BranchKey) +) (wrappers.ScanHandler, error) { + scanHandler := wrappers.ScanHandler{} + scanHandler.Branch = viper.GetString(commonParams.BranchKey) + + uploadType := getUploadType(cmd) + + if uploadType == git { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + + scanHandler.RepoURL = strings.TrimSpace(source) + } else { + uploadURL, err := getUploadURLFromSource(cmd, uploadsWrapper) + if err != nil { + return scanHandler, err + } + + scanHandler.UploadURL = uploadURL + } + var err error - pHandler.UploadURL, err = determineSourceFile( - uploadsWrapper, - sourcesFile, - sourceDir, - sourceDirFilter, - userIncludeFilter, - scaResolver, - scaResolverParams, - ) - pHandler.RepoURL = scanRepoURL - return pHandler, err + + // Define SSH credentials if flag --ssh-key is provided + if cmd.Flags().Changed(commonParams.SSHKeyFlag) { + sshKeyPath, _ := cmd.Flags().GetString(commonParams.SSHKeyFlag) + + if strings.TrimSpace(sshKeyPath) == "" { + return scanHandler, errors.New("flag needs an argument: --ssh-key") + } + + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + if !util.IsSSHURL(sourceTrimmed) { + return scanHandler, errors.New(invalidSSHSource) + } + + err = defineSSHCredentials(strings.TrimSpace(sshKeyPath), &scanHandler) + } + + return scanHandler, err +} + +func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) error { + sshKey, err := getSSHKeyValue(sshKeyPath) + + credentials := wrappers.GitCredentials{} + + credentials.Type = "ssh" + credentials.Value = sshKey + + handler.Credentials = credentials + + return err +} + +func getSSHKeyValue(sshKeyPath string) (string, error) { + sshKey, err := os.ReadFile(sshKeyPath) + + if err != nil { + return "", err + } + + return string(sshKey), nil } func handleWait( diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index e7e6c9131..caae5c793 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -15,7 +15,8 @@ const ( unknownFlag = "unknown flag: --chibutero" blankSpace = " " errorMissingBranch = "Failed creating a scan: Please provide a branch" - dummyRepo = "https://www.dummy-repo.com" + dummyRepo = "https://github.com/dummyuser/dummy_project.git" + dummySSHRepo = "git@github.com:dummyRepo/dummyProject.git" errorSourceBadFormat = "Failed creating a scan: Input in bad format: Sources input has bad format: " scaPathError = "ScaResolver error: exec: \"resolver\": executable file not found in " ) @@ -228,3 +229,45 @@ func TestScanWorkflowMissingID(t *testing.T) { err := execCmdNotNilAssertion(t, "scan", "workflow") assert.Error(t, err, "Please provide a scan ID", err.Error()) } + +func TestCreateScanMissingSSHValue(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", "../..", "-b", "dummy_branch"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", " ")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) +} + +func TestCreateScanInvalidSSHSource(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + // zip file with ssh + err := execCmdNotNilAssertion(t, append(baseArgs, "-s", "data/sources.zip", "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) + + // directory with ssh + err = execCmdNotNilAssertion(t, append(baseArgs, "-s", "../..", "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) + + // http url with ssh + err = execCmdNotNilAssertion(t, append(baseArgs, "-s", dummyRepo, "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) +} + +func TestCreateScanWrongSSHKeyPath(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "dummy_key")...) + assert.Error(t, err, "open dummy_key: The system cannot find the file specified.", err.Error()) +} + +func TestCreateScanWithSSHKey(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + execCmdNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "data/id_rsa")...) +} diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index bb62ab2f0..5e012ba62 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "regexp" "github.com/MakeNowJust/heredoc" "github.com/checkmarx/ast-cli/internal/commands/util/usercount" @@ -9,6 +10,9 @@ import ( "github.com/spf13/cobra" ) +const gitURLRegex = "(?:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(.*?)(\\.git)?(\\/?|\\#[-\\d\\w._]+?)$" +const sshURLRegex = "^(?P.*?)@(?P.*?):(?:(?P.*?)/)?(?P.*?/.*?)$" + func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, azureWrapper wrappers.AzureWrapper, bitBucketWrapper wrappers.BitBucketWrapper, @@ -57,3 +61,17 @@ func executeTestCommand(cmd *cobra.Command, args ...string) error { cmd.SilenceUsage = false return cmd.Execute() } + +// IsGitURL Check if provided URL is a valid git URL (http or ssh) +func IsGitURL(url string) bool { + isGitURL, _ := regexp.MatchString(gitURLRegex, url) + + return isGitURL +} + +// IsSSHURL Check if provided URL is a valid ssh URL +func IsSSHURL(url string) bool { + isGitURL, _ := regexp.MatchString(sshURLRegex, url) + + return isGitURL +} diff --git a/internal/params/flags.go b/internal/params/flags.go index bc03b782a..131127679 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -98,6 +98,7 @@ const ( GitLabURLFlag = "url-gitlab" URLFlagUsage = "API base URL" QueryIDFlag = "query-id" + SSHKeyFlag = "ssh-key" ) // Parameter values diff --git a/internal/wrappers/scans.go b/internal/wrappers/scans.go index 537ff036d..1bfcf0b1c 100644 --- a/internal/wrappers/scans.go +++ b/internal/wrappers/scans.go @@ -31,12 +31,14 @@ type Config struct { Value map[string]string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } -type UploadProjectHandler struct { +type ScanHandler struct { // representative branch Branch string `json:"branch,omitempty"` // representative repository url RepoURL string `json:"repoUrl"` UploadURL string `json:"uploadUrl"` + // Credentials + Credentials GitCredentials `json:"credentials"` } type GitProjectHandler struct { @@ -96,7 +98,7 @@ type ScanProject struct { type Scan struct { Type string `json:"type"` // [git|upload] - Handler json.RawMessage `json:"handler"` // One of [GitProjectHandler|UploadProjectHandler] + Handler json.RawMessage `json:"handler"` // One of [GitProjectHandler|ScanHandler] Project ScanProject `json:"project,omitempty"` Config []Config `json:"config,omitempty"` Tags map[string]string `json:"tags,omitempty"` diff --git a/test/integration/auth_test.go b/test/integration/auth_test.go index e18c2c63f..d0c4c9dd6 100644 --- a/test/integration/auth_test.go +++ b/test/integration/auth_test.go @@ -116,40 +116,6 @@ func TestAuthRegister(t *testing.T) { flag(params.ClientRolesFlag), strings.Join(commands.RoleSlice, ","), ) assert.Error(t, err, "User does not have permission for roles [ast-admin ast-scanner]") - //assert.NilError(t, err, "Register should pass") - // - //result, err := io.ReadAll(buffer) - //assert.NilError(t, err, "Reading result should pass") - // - //lines := strings.Split(string(result), "\n") - // - //assert.Assert(t, strings.Contains(lines[0], "CX_CLIENT_ID="+clientIDPrefix)) - //assert.Assert(t, strings.Contains(lines[1], "CX_CLIENT_SECRET=")) - // - //clientID := strings.Split(lines[0], "=")[1] - //secret := strings.Split(lines[1], "=")[1] - //uuidLen := len(uuid.New().String()) - // - //assert.Assert(t, strings.Contains(clientID, clientIDPrefix)) - //assert.Assert(t, len(clientID) == len(clientIDPrefix)+uuidLen) - //assert.Assert(t, len(secret) == uuidLen) - // - //_, err = uuid.Parse(secret) - //assert.NilError(t, err, "Parsing UUID should pass") - // - //validateCommand, buffer := createRedirectedTestCommand(t) - // - //err = execute( - // validateCommand, - // "auth", - // "validate", - // flag(params.AccessKeyIDFlag), - // clientID, - // flag(params.AccessKeySecretFlag), - // secret, - //) - // - //assertSuccessAuthentication(t, err, buffer, defaultSuccessValidationMessage) } func TestFailProxyAuth(t *testing.T) { diff --git a/test/integration/root_test.go b/test/integration/root_test.go index 8fadcb495..526566c03 100644 --- a/test/integration/root_test.go +++ b/test/integration/root_test.go @@ -16,6 +16,7 @@ const ( Dir = "./data" Zip = "data/sources.zip" SlowRepo = "https://github.com/WebGoat/WebGoat" + SSHRepo = "git@github.com:hmmachadocx/hmmachado_dummy_project.git" SlowRepoBranch = "develop" resolverEnvVar = "SCA_RESOLVER" resolverEnvVarDefault = "./ScaResolver" diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 189f7893d..5b42ee739 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -31,7 +31,6 @@ type ScanWorkflowResponse struct { // Create a scan with an empty project name // Assert the scan fails with correct message func TestScanCreateEmptyProjectName(t *testing.T) { - args := []string{ "scan", "create", flag(params.ProjectName), "", @@ -46,7 +45,6 @@ func TestScanCreateEmptyProjectName(t *testing.T) { // Create scans from current dir, zip and url and perform assertions in executeScanAssertions func TestScansE2E(t *testing.T) { - scanID, projectID := createScan(t, Zip, Tags) defer deleteProject(t, projectID) @@ -134,7 +132,7 @@ func TestCancelScan(t *testing.T) { defer deleteProject(t, projectID) defer deleteScan(t, scanID) - // cancelling too quickly after creating fails the scan... + // canceling too quickly after creating fails the scan... time.Sleep(30 * time.Second) executeCmdNilAssertion(t, "Cancel should pass", "scan", "cancel", flag(params.ScanIDFlag), scanID) @@ -273,7 +271,7 @@ func TestBrokenLinkScan(t *testing.T) { // - Get scan with 'scan show' and assert the ID // - Assert all tags exist and are assigned to the scan // - Delete the scan and assert it is deleted -func executeScanAssertions(t *testing.T, projectID string, scanID string, tags map[string]string) { +func executeScanAssertions(t *testing.T, projectID, scanID string, tags map[string]string) { response := listScanByID(t, scanID) assert.Equal(t, len(response), 1, "Total scans should be 1") @@ -347,7 +345,7 @@ func getCreateArgs(source string, tags map[string]string, scanTypes string) []st return getCreateArgsWithName(source, tags, projectName, scanTypes) } -func getCreateArgsWithName(source string, tags map[string]string, projectName string, scanTypes string) []string { +func getCreateArgsWithName(source string, tags map[string]string, projectName, scanTypes string) []string { args := []string{ "scan", "create", flag(params.ProjectName), projectName, @@ -361,7 +359,6 @@ func getCreateArgsWithName(source string, tags map[string]string, projectName st } func executeCreateScan(t *testing.T, args []string) (string, string) { - buffer := executeScanGetBuffer(t, args) createdScan := wrappers.ScanResponseModel{} @@ -509,3 +506,17 @@ func TestFailedScanWithWrongPreset(t *testing.T) { err, _ := executeCommand(t, args...) assertError(t, err, "scan did not complete successfully") } + +func TestScanCreateWithSSHKey(t *testing.T) { + _, projectName := getRootProject(t) + + args := []string{ + "scan", "create", + flag(params.ProjectName), projectName, + flag(params.SourcesFlag), SSHRepo, + flag(params.BranchFlag), "main", + flag(params.SSHKeyFlag), "data/id_rsa", + } + + executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 3*time.Minute, args...) +} From 6908ff8449a05582a12e2d0990d4fe064816cea9 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 14:38:45 +0100 Subject: [PATCH 02/25] AST-11602 - CLI | Add SSH key to scan create command - Added missing private key in integration tests --- test/integration/data/id_rsa | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/integration/data/id_rsa diff --git a/test/integration/data/id_rsa b/test/integration/data/id_rsa new file mode 100644 index 000000000..44f9baa6d --- /dev/null +++ b/test/integration/data/id_rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY----- From b28d35ffe775a0ecb3c9f850d3274a3369b83a88 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 15:07:51 +0100 Subject: [PATCH 03/25] AST-11602 - CLI | Add SSH key to scan create command - Fixed unit tests --- internal/commands/scan_test.go | 9 ++++++++- internal/commands/util/completion.go | 2 +- internal/commands/util/utils.go | 6 ++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index caae5c793..da4d42109 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -8,6 +8,7 @@ import ( "gotest.tools/assert" + "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/spf13/viper" ) @@ -263,7 +264,13 @@ func TestCreateScanWrongSSHKeyPath(t *testing.T) { baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} err := execCmdNotNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "dummy_key")...) - assert.Error(t, err, "open dummy_key: The system cannot find the file specified.", err.Error()) + + expectedMessages := []string{ + "open dummy_key: The system cannot find the file specified.", + "open dummy_key: no such file or directory", + } + + assert.Assert(t, util.Contains(expectedMessages, err.Error())) } func TestCreateScanWithSSHKey(t *testing.T) { diff --git a/internal/commands/util/completion.go b/internal/commands/util/completion.go index ce969b48a..13baf95bf 100644 --- a/internal/commands/util/completion.go +++ b/internal/commands/util/completion.go @@ -62,7 +62,7 @@ func NewCompletionCommand() *cobra.Command { Args: func(cmd *cobra.Command, args []string) error { shellType, _ := cmd.Flags().GetString(shellFlag) - if shellType == "" || contains(cmd.ValidArgs, shellType) { + if shellType == "" || Contains(cmd.ValidArgs, shellType) { return nil } diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 5e012ba62..7f9ce2819 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -43,10 +43,8 @@ func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, return utilsCmd } -/** -Tests if a string exists in the provided array -*/ -func contains(array []string, val string) bool { +// Contains Tests if a string exists in the provided array/** +func Contains(array []string, val string) bool { for _, e := range array { if e == val { return true From 905aa5764ff26268059c932678d6cd3558df6c4a Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 14:37:59 +0100 Subject: [PATCH 04/25] AST-11602 - CLI | Add SSH key to scan create command - Added --ssh-key flag to scan create - Added unit tests and integration tests - Code refactoring --- internal/commands/data/id_rsa | 38 +++++ internal/commands/project.go | 2 +- internal/commands/scan.go | 237 ++++++++++++++++++++------------ internal/commands/scan_test.go | 45 +++++- internal/commands/util/utils.go | 18 +++ internal/params/flags.go | 1 + internal/wrappers/scans.go | 6 +- test/integration/auth_test.go | 34 ----- test/integration/root_test.go | 1 + test/integration/scan_test.go | 23 +++- 10 files changed, 272 insertions(+), 133 deletions(-) create mode 100644 internal/commands/data/id_rsa diff --git a/internal/commands/data/id_rsa b/internal/commands/data/id_rsa new file mode 100644 index 000000000..44f9baa6d --- /dev/null +++ b/internal/commands/data/id_rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY----- diff --git a/internal/commands/project.go b/internal/commands/project.go index af79de6dd..e3cfbfbed 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -283,7 +283,7 @@ func runCreateProjectCommand( if err != nil { return err } - updateTagValues(&input, cmd) + setupScanTags(&input, cmd) var projModel = wrappers.Project{} var projResponseModel *wrappers.ProjectResponseModel var errorModel *wrappers.ErrorModel diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 7ccf33807..d4c9819ce 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/google/shlex" "github.com/pkg/errors" @@ -39,6 +40,8 @@ const ( mbBytes = 1024.0 * 1024.0 scaType = "sca" notExploitable = "NOT_EXPLOITABLE" + git = "git" + invalidSSHSource = "provided source does not need a key. Make sure you are defining the right source or remove the flag --ssh-key" ) var ( @@ -383,6 +386,9 @@ func scanCreateSubCommand( if err != nil { log.Fatal(err) } + + createScanCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") + return createScanCmd } @@ -437,7 +443,7 @@ func createProject( return projectID, err } -func updateTagValues(input *[]byte, cmd *cobra.Command) { +func setupScanTags(input *[]byte, cmd *cobra.Command) { tagListStr, _ := cmd.Flags().GetString(commonParams.TagList) tags := strings.Split(tagListStr, ",") var info map[string]interface{} @@ -476,17 +482,16 @@ func createTagMap(tagListStr string) map[string]string { return tags } -func updateScanRequestValues( +func setupScanTypeProjectAndConfig( input *[]byte, cmd *cobra.Command, - sourceType string, projectsWrapper wrappers.ProjectsWrapper, groupsWrapper wrappers.GroupsWrapper, ) error { var info map[string]interface{} newProjectName, _ := cmd.Flags().GetString(commonParams.ProjectName) _ = json.Unmarshal(*input, &info) - info["type"] = sourceType + info["type"] = getUploadType(cmd) // Handle the project settings if _, ok := info["project"]; !ok { var projectMap map[string]interface{} @@ -534,14 +539,12 @@ func updateScanRequestValues( return err } -func determineScanTypes(cmd *cobra.Command) { +func validateScanTypes(cmd *cobra.Command) { userScanTypes, _ := cmd.Flags().GetString(commonParams.ScanTypes) if len(userScanTypes) > 0 { actualScanTypes = userScanTypes } -} -func validateScanTypes() { scanTypes := strings.Split(actualScanTypes, ",") for _, scanType := range scanTypes { isValid := false @@ -848,29 +851,49 @@ func addScaResults(zipWriter *zip.Writer) error { return nil } -func determineSourceFile( +func getUploadURLFromSource( + cmd *cobra.Command, uploadsWrapper wrappers.UploadsWrapper, - sourcesFile, sourceDir, sourceDirFilter, userIncludeFilter, scaResolver, scaResolverParams string, ) (string, error) { var err error var preSignedURL string - if sourceDir != "" { + + sourceDirFilter, _ := cmd.Flags().GetString(commonParams.SourceDirFilterFlag) + userIncludeFilter, _ := cmd.Flags().GetString(commonParams.IncludeFilterFlag) + + zipFilePath, directoryPath, err := definePathForZipFileOrDirectory(cmd) + if err != nil { + return "", errors.Wrapf(err, "%s: Input in bad format", failedCreating) + } + + if directoryPath != "" { + // Get sca resolver flags + scaResolverParams, err := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) + if err != nil { + scaResolverParams = "" + } + scaResolver, err := cmd.Flags().GetString(commonParams.ScaResolverFlag) + if err != nil { + scaResolver = "" + scaResolverParams = "" + } + // Make sure scaResolver only runs in sca type of scans if strings.Contains(actualScanTypes, scaType) { - err = runScaResolver(sourceDir, scaResolver, scaResolverParams) + err = runScaResolver(directoryPath, scaResolver, scaResolverParams) if err != nil { return "", errors.Wrapf(err, "ScaResolver error") } } - sourcesFile, err = compressFolder(sourceDir, sourceDirFilter, userIncludeFilter, scaResolver) + zipFilePath, err = compressFolder(directoryPath, sourceDirFilter, userIncludeFilter, scaResolver) if err != nil { return "", err } } - if sourcesFile != "" { + if zipFilePath != "" { // Send a request to uploads service var preSignedURL *string - preSignedURL, err = uploadsWrapper.UploadFile(sourcesFile) + preSignedURL, err = uploadsWrapper.UploadFile(zipFilePath) if err != nil { return "", errors.Wrapf(err, "%s: Failed to upload sources file\n", failedCreating) } @@ -880,32 +903,29 @@ func determineSourceFile( return preSignedURL, err } -func determineSourceType(sourcesFile string) (zipFile, sourceDir, scanRepoURL string, err error) { - if strings.HasPrefix(sourcesFile, "https://") || - strings.HasPrefix(sourcesFile, "http://") { - scanRepoURL = sourcesFile - - log.Printf("\n\nScanning branch %s...\n", viper.GetString(commonParams.BranchKey)) - } else { - info, statErr := os.Stat(sourcesFile) - if !os.IsNotExist(statErr) { - if filepath.Ext(sourcesFile) == ".zip" { - zipFile = sourcesFile - } else if info != nil && info.IsDir() { - sourceDir = filepath.ToSlash(sourcesFile) - if !strings.HasSuffix(sourceDir, "/") { - sourceDir += "/" - } - } else { - msg := fmt.Sprintf("Sources input has bad format: %v", sourcesFile) - err = errors.New(msg) +func definePathForZipFileOrDirectory(cmd *cobra.Command) (zipFile, sourceDir string, err error) { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + info, statErr := os.Stat(sourceTrimmed) + if !os.IsNotExist(statErr) { + if filepath.Ext(sourceTrimmed) == ".zip" { + zipFile = sourceTrimmed + } else if info != nil && info.IsDir() { + sourceDir = filepath.ToSlash(sourceTrimmed) + if !strings.HasSuffix(sourceDir, "/") { + sourceDir += "/" } } else { - msg := fmt.Sprintf("Sources input has bad format: %v", sourcesFile) + msg := fmt.Sprintf("Sources input has bad format: %v", sourceTrimmed) err = errors.New(msg) } + } else { + msg := fmt.Sprintf("Sources input has bad format: %v", sourceTrimmed) + err = errors.New(msg) } - return zipFile, sourceDir, scanRepoURL, err + + return zipFile, sourceDir, err } func runCreateScanCommand( @@ -966,81 +986,120 @@ func createScanModel( projectsWrapper wrappers.ProjectsWrapper, groupsWrapper wrappers.GroupsWrapper, ) (*wrappers.Scan, error) { - determineScanTypes(cmd) - validateScanTypes() - sourceDirFilter, _ := cmd.Flags().GetString(commonParams.SourceDirFilterFlag) - userIncludeFilter, _ := cmd.Flags().GetString(commonParams.IncludeFilterFlag) - sourcesFile, _ := cmd.Flags().GetString(commonParams.SourcesFlag) - sourcesFile, sourceDir, scanRepoURL, err := determineSourceType(strings.TrimSpace(sourcesFile)) - if err != nil { - return nil, errors.Wrapf(err, "%s: Input in bad format", failedCreating) - } - uploadType := getUploadType(sourceDir, sourcesFile) + validateScanTypes(cmd) + var input = []byte("{}") - err = updateScanRequestValues(&input, cmd, uploadType, projectsWrapper, groupsWrapper) + + // Define type, project and config in scan model + err := setupScanTypeProjectAndConfig(&input, cmd, projectsWrapper, groupsWrapper) if err != nil { return nil, err } - updateTagValues(&input, cmd) + + // set tags in scan model + setupScanTags(&input, cmd) + scanModel := wrappers.Scan{} // Try to parse to a scan model in order to manipulate the request payload err = json.Unmarshal(input, &scanModel) if err != nil { return nil, errors.Wrapf(err, "%s: Input in bad format", failedCreating) } - // Get sca resolver flags - scaResolverParams, err := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) - if err != nil { - scaResolverParams = "" - } - scaResolver, err := cmd.Flags().GetString(commonParams.ScaResolverFlag) - if err != nil { - scaResolver = "" - scaResolverParams = "" - } - // Set up the project handler (either git or upload) - pHandler, err := setupProjectHandler( - uploadsWrapper, - sourcesFile, - sourceDir, - sourceDirFilter, - userIncludeFilter, - scanRepoURL, - scaResolver, - scaResolverParams, - ) - scanModel.Handler, _ = json.Marshal(pHandler) + + // Set up the scan handler (either git or upload) + scanHandler, err := setupScanHandler(cmd, uploadsWrapper) if err != nil { return nil, err } + + scanModel.Handler, _ = json.Marshal(scanHandler) + + uploadType := getUploadType(cmd) + + if uploadType == "git" { + log.Printf("\n\nScanning branch %s...\n", viper.GetString(commonParams.BranchKey)) + } + return &scanModel, nil } -func getUploadType(sourceDir, sourcesFile string) string { - if sourceDir != "" || sourcesFile != "" { - return "upload" +func getUploadType(cmd *cobra.Command) string { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + if util.IsGitURL(sourceTrimmed) { + return git } - return "git" + + return "upload" } -func setupProjectHandler( +func setupScanHandler( + cmd *cobra.Command, uploadsWrapper wrappers.UploadsWrapper, - sourcesFile, sourceDir, sourceDirFilter, userIncludeFilter, scanRepoURL, scaResolver, scaResolverParams string, -) (wrappers.UploadProjectHandler, error) { - pHandler := wrappers.UploadProjectHandler{} - pHandler.Branch = viper.GetString(commonParams.BranchKey) +) (wrappers.ScanHandler, error) { + scanHandler := wrappers.ScanHandler{} + scanHandler.Branch = viper.GetString(commonParams.BranchKey) + + uploadType := getUploadType(cmd) + + if uploadType == git { + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + + scanHandler.RepoURL = strings.TrimSpace(source) + } else { + uploadURL, err := getUploadURLFromSource(cmd, uploadsWrapper) + if err != nil { + return scanHandler, err + } + + scanHandler.UploadURL = uploadURL + } + var err error - pHandler.UploadURL, err = determineSourceFile( - uploadsWrapper, - sourcesFile, - sourceDir, - sourceDirFilter, - userIncludeFilter, - scaResolver, - scaResolverParams, - ) - pHandler.RepoURL = scanRepoURL - return pHandler, err + + // Define SSH credentials if flag --ssh-key is provided + if cmd.Flags().Changed(commonParams.SSHKeyFlag) { + sshKeyPath, _ := cmd.Flags().GetString(commonParams.SSHKeyFlag) + + if strings.TrimSpace(sshKeyPath) == "" { + return scanHandler, errors.New("flag needs an argument: --ssh-key") + } + + source, _ := cmd.Flags().GetString(commonParams.SourcesFlag) + sourceTrimmed := strings.TrimSpace(source) + + if !util.IsSSHURL(sourceTrimmed) { + return scanHandler, errors.New(invalidSSHSource) + } + + err = defineSSHCredentials(strings.TrimSpace(sshKeyPath), &scanHandler) + } + + return scanHandler, err +} + +func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) error { + sshKey, err := getSSHKeyValue(sshKeyPath) + + credentials := wrappers.GitCredentials{} + + credentials.Type = "ssh" + credentials.Value = sshKey + + handler.Credentials = credentials + + return err +} + +func getSSHKeyValue(sshKeyPath string) (string, error) { + sshKey, err := os.ReadFile(sshKeyPath) + + if err != nil { + return "", err + } + + return string(sshKey), nil } func handleWait( diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index e7e6c9131..caae5c793 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -15,7 +15,8 @@ const ( unknownFlag = "unknown flag: --chibutero" blankSpace = " " errorMissingBranch = "Failed creating a scan: Please provide a branch" - dummyRepo = "https://www.dummy-repo.com" + dummyRepo = "https://github.com/dummyuser/dummy_project.git" + dummySSHRepo = "git@github.com:dummyRepo/dummyProject.git" errorSourceBadFormat = "Failed creating a scan: Input in bad format: Sources input has bad format: " scaPathError = "ScaResolver error: exec: \"resolver\": executable file not found in " ) @@ -228,3 +229,45 @@ func TestScanWorkflowMissingID(t *testing.T) { err := execCmdNotNilAssertion(t, "scan", "workflow") assert.Error(t, err, "Please provide a scan ID", err.Error()) } + +func TestCreateScanMissingSSHValue(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", "../..", "-b", "dummy_branch"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", " ")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) +} + +func TestCreateScanInvalidSSHSource(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + // zip file with ssh + err := execCmdNotNilAssertion(t, append(baseArgs, "-s", "data/sources.zip", "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) + + // directory with ssh + err = execCmdNotNilAssertion(t, append(baseArgs, "-s", "../..", "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) + + // http url with ssh + err = execCmdNotNilAssertion(t, append(baseArgs, "-s", dummyRepo, "--ssh-key", "dummy_key")...) + assert.Error(t, err, invalidSSHSource, err.Error()) +} + +func TestCreateScanWrongSSHKeyPath(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "dummy_key")...) + assert.Error(t, err, "open dummy_key: The system cannot find the file specified.", err.Error()) +} + +func TestCreateScanWithSSHKey(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} + + execCmdNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "data/id_rsa")...) +} diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index bb62ab2f0..5e012ba62 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "regexp" "github.com/MakeNowJust/heredoc" "github.com/checkmarx/ast-cli/internal/commands/util/usercount" @@ -9,6 +10,9 @@ import ( "github.com/spf13/cobra" ) +const gitURLRegex = "(?:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(.*?)(\\.git)?(\\/?|\\#[-\\d\\w._]+?)$" +const sshURLRegex = "^(?P.*?)@(?P.*?):(?:(?P.*?)/)?(?P.*?/.*?)$" + func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, azureWrapper wrappers.AzureWrapper, bitBucketWrapper wrappers.BitBucketWrapper, @@ -57,3 +61,17 @@ func executeTestCommand(cmd *cobra.Command, args ...string) error { cmd.SilenceUsage = false return cmd.Execute() } + +// IsGitURL Check if provided URL is a valid git URL (http or ssh) +func IsGitURL(url string) bool { + isGitURL, _ := regexp.MatchString(gitURLRegex, url) + + return isGitURL +} + +// IsSSHURL Check if provided URL is a valid ssh URL +func IsSSHURL(url string) bool { + isGitURL, _ := regexp.MatchString(sshURLRegex, url) + + return isGitURL +} diff --git a/internal/params/flags.go b/internal/params/flags.go index bc03b782a..131127679 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -98,6 +98,7 @@ const ( GitLabURLFlag = "url-gitlab" URLFlagUsage = "API base URL" QueryIDFlag = "query-id" + SSHKeyFlag = "ssh-key" ) // Parameter values diff --git a/internal/wrappers/scans.go b/internal/wrappers/scans.go index 537ff036d..1bfcf0b1c 100644 --- a/internal/wrappers/scans.go +++ b/internal/wrappers/scans.go @@ -31,12 +31,14 @@ type Config struct { Value map[string]string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } -type UploadProjectHandler struct { +type ScanHandler struct { // representative branch Branch string `json:"branch,omitempty"` // representative repository url RepoURL string `json:"repoUrl"` UploadURL string `json:"uploadUrl"` + // Credentials + Credentials GitCredentials `json:"credentials"` } type GitProjectHandler struct { @@ -96,7 +98,7 @@ type ScanProject struct { type Scan struct { Type string `json:"type"` // [git|upload] - Handler json.RawMessage `json:"handler"` // One of [GitProjectHandler|UploadProjectHandler] + Handler json.RawMessage `json:"handler"` // One of [GitProjectHandler|ScanHandler] Project ScanProject `json:"project,omitempty"` Config []Config `json:"config,omitempty"` Tags map[string]string `json:"tags,omitempty"` diff --git a/test/integration/auth_test.go b/test/integration/auth_test.go index e18c2c63f..d0c4c9dd6 100644 --- a/test/integration/auth_test.go +++ b/test/integration/auth_test.go @@ -116,40 +116,6 @@ func TestAuthRegister(t *testing.T) { flag(params.ClientRolesFlag), strings.Join(commands.RoleSlice, ","), ) assert.Error(t, err, "User does not have permission for roles [ast-admin ast-scanner]") - //assert.NilError(t, err, "Register should pass") - // - //result, err := io.ReadAll(buffer) - //assert.NilError(t, err, "Reading result should pass") - // - //lines := strings.Split(string(result), "\n") - // - //assert.Assert(t, strings.Contains(lines[0], "CX_CLIENT_ID="+clientIDPrefix)) - //assert.Assert(t, strings.Contains(lines[1], "CX_CLIENT_SECRET=")) - // - //clientID := strings.Split(lines[0], "=")[1] - //secret := strings.Split(lines[1], "=")[1] - //uuidLen := len(uuid.New().String()) - // - //assert.Assert(t, strings.Contains(clientID, clientIDPrefix)) - //assert.Assert(t, len(clientID) == len(clientIDPrefix)+uuidLen) - //assert.Assert(t, len(secret) == uuidLen) - // - //_, err = uuid.Parse(secret) - //assert.NilError(t, err, "Parsing UUID should pass") - // - //validateCommand, buffer := createRedirectedTestCommand(t) - // - //err = execute( - // validateCommand, - // "auth", - // "validate", - // flag(params.AccessKeyIDFlag), - // clientID, - // flag(params.AccessKeySecretFlag), - // secret, - //) - // - //assertSuccessAuthentication(t, err, buffer, defaultSuccessValidationMessage) } func TestFailProxyAuth(t *testing.T) { diff --git a/test/integration/root_test.go b/test/integration/root_test.go index 8fadcb495..526566c03 100644 --- a/test/integration/root_test.go +++ b/test/integration/root_test.go @@ -16,6 +16,7 @@ const ( Dir = "./data" Zip = "data/sources.zip" SlowRepo = "https://github.com/WebGoat/WebGoat" + SSHRepo = "git@github.com:hmmachadocx/hmmachado_dummy_project.git" SlowRepoBranch = "develop" resolverEnvVar = "SCA_RESOLVER" resolverEnvVarDefault = "./ScaResolver" diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 189f7893d..5b42ee739 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -31,7 +31,6 @@ type ScanWorkflowResponse struct { // Create a scan with an empty project name // Assert the scan fails with correct message func TestScanCreateEmptyProjectName(t *testing.T) { - args := []string{ "scan", "create", flag(params.ProjectName), "", @@ -46,7 +45,6 @@ func TestScanCreateEmptyProjectName(t *testing.T) { // Create scans from current dir, zip and url and perform assertions in executeScanAssertions func TestScansE2E(t *testing.T) { - scanID, projectID := createScan(t, Zip, Tags) defer deleteProject(t, projectID) @@ -134,7 +132,7 @@ func TestCancelScan(t *testing.T) { defer deleteProject(t, projectID) defer deleteScan(t, scanID) - // cancelling too quickly after creating fails the scan... + // canceling too quickly after creating fails the scan... time.Sleep(30 * time.Second) executeCmdNilAssertion(t, "Cancel should pass", "scan", "cancel", flag(params.ScanIDFlag), scanID) @@ -273,7 +271,7 @@ func TestBrokenLinkScan(t *testing.T) { // - Get scan with 'scan show' and assert the ID // - Assert all tags exist and are assigned to the scan // - Delete the scan and assert it is deleted -func executeScanAssertions(t *testing.T, projectID string, scanID string, tags map[string]string) { +func executeScanAssertions(t *testing.T, projectID, scanID string, tags map[string]string) { response := listScanByID(t, scanID) assert.Equal(t, len(response), 1, "Total scans should be 1") @@ -347,7 +345,7 @@ func getCreateArgs(source string, tags map[string]string, scanTypes string) []st return getCreateArgsWithName(source, tags, projectName, scanTypes) } -func getCreateArgsWithName(source string, tags map[string]string, projectName string, scanTypes string) []string { +func getCreateArgsWithName(source string, tags map[string]string, projectName, scanTypes string) []string { args := []string{ "scan", "create", flag(params.ProjectName), projectName, @@ -361,7 +359,6 @@ func getCreateArgsWithName(source string, tags map[string]string, projectName st } func executeCreateScan(t *testing.T, args []string) (string, string) { - buffer := executeScanGetBuffer(t, args) createdScan := wrappers.ScanResponseModel{} @@ -509,3 +506,17 @@ func TestFailedScanWithWrongPreset(t *testing.T) { err, _ := executeCommand(t, args...) assertError(t, err, "scan did not complete successfully") } + +func TestScanCreateWithSSHKey(t *testing.T) { + _, projectName := getRootProject(t) + + args := []string{ + "scan", "create", + flag(params.ProjectName), projectName, + flag(params.SourcesFlag), SSHRepo, + flag(params.BranchFlag), "main", + flag(params.SSHKeyFlag), "data/id_rsa", + } + + executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 3*time.Minute, args...) +} From 457f57efd4e15cd16abe0feadfcc758c0bcd5839 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 14:38:45 +0100 Subject: [PATCH 05/25] AST-11602 - CLI | Add SSH key to scan create command - Added missing private key in integration tests --- test/integration/data/id_rsa | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/integration/data/id_rsa diff --git a/test/integration/data/id_rsa b/test/integration/data/id_rsa new file mode 100644 index 000000000..44f9baa6d --- /dev/null +++ b/test/integration/data/id_rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY----- From 4be4f1475ec54445e7aa5c99e88d386d57308648 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 12 Apr 2022 15:07:51 +0100 Subject: [PATCH 06/25] AST-11602 - CLI | Add SSH key to scan create command - Fixed unit tests --- internal/commands/scan_test.go | 9 ++++++++- internal/commands/util/completion.go | 2 +- internal/commands/util/utils.go | 6 ++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index caae5c793..da4d42109 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -8,6 +8,7 @@ import ( "gotest.tools/assert" + "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/spf13/viper" ) @@ -263,7 +264,13 @@ func TestCreateScanWrongSSHKeyPath(t *testing.T) { baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} err := execCmdNotNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "dummy_key")...) - assert.Error(t, err, "open dummy_key: The system cannot find the file specified.", err.Error()) + + expectedMessages := []string{ + "open dummy_key: The system cannot find the file specified.", + "open dummy_key: no such file or directory", + } + + assert.Assert(t, util.Contains(expectedMessages, err.Error())) } func TestCreateScanWithSSHKey(t *testing.T) { diff --git a/internal/commands/util/completion.go b/internal/commands/util/completion.go index ce969b48a..13baf95bf 100644 --- a/internal/commands/util/completion.go +++ b/internal/commands/util/completion.go @@ -62,7 +62,7 @@ func NewCompletionCommand() *cobra.Command { Args: func(cmd *cobra.Command, args []string) error { shellType, _ := cmd.Flags().GetString(shellFlag) - if shellType == "" || contains(cmd.ValidArgs, shellType) { + if shellType == "" || Contains(cmd.ValidArgs, shellType) { return nil } diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 5e012ba62..7f9ce2819 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -43,10 +43,8 @@ func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, return utilsCmd } -/** -Tests if a string exists in the provided array -*/ -func contains(array []string, val string) bool { +// Contains Tests if a string exists in the provided array/** +func Contains(array []string, val string) bool { for _, e := range array { if e == val { return true From 32d3d5f3612e719154fce68dc39f517327813297 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 12:31:40 +0100 Subject: [PATCH 07/25] AST-11602 - CLI | Add SSH key to scan create command - Fixed unit tests and lint --- internal/commands/scan.go | 33 +++++++++++++++++---------------- internal/commands/util/utils.go | 11 ++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/internal/commands/scan.go b/internal/commands/scan.go index d4c9819ce..840960046 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -855,7 +855,6 @@ func getUploadURLFromSource( cmd *cobra.Command, uploadsWrapper wrappers.UploadsWrapper, ) (string, error) { - var err error var preSignedURL string sourceDirFilter, _ := cmd.Flags().GetString(commonParams.SourceDirFilterFlag) @@ -867,40 +866,42 @@ func getUploadURLFromSource( } if directoryPath != "" { + var dirPathErr error // Get sca resolver flags - scaResolverParams, err := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) - if err != nil { + scaResolverParams, dirPathErr := cmd.Flags().GetString(commonParams.ScaResolverParamsFlag) + if dirPathErr != nil { scaResolverParams = "" } - scaResolver, err := cmd.Flags().GetString(commonParams.ScaResolverFlag) - if err != nil { + scaResolver, dirPathErr := cmd.Flags().GetString(commonParams.ScaResolverFlag) + if dirPathErr != nil { scaResolver = "" scaResolverParams = "" } // Make sure scaResolver only runs in sca type of scans if strings.Contains(actualScanTypes, scaType) { - err = runScaResolver(directoryPath, scaResolver, scaResolverParams) - if err != nil { - return "", errors.Wrapf(err, "ScaResolver error") + dirPathErr = runScaResolver(directoryPath, scaResolver, scaResolverParams) + if dirPathErr != nil { + return "", errors.Wrapf(dirPathErr, "ScaResolver error") } } - zipFilePath, err = compressFolder(directoryPath, sourceDirFilter, userIncludeFilter, scaResolver) - if err != nil { - return "", err + zipFilePath, dirPathErr = compressFolder(directoryPath, sourceDirFilter, userIncludeFilter, scaResolver) + if dirPathErr != nil { + return "", dirPathErr } } if zipFilePath != "" { + var zipFilePathErr error // Send a request to uploads service var preSignedURL *string - preSignedURL, err = uploadsWrapper.UploadFile(zipFilePath) - if err != nil { - return "", errors.Wrapf(err, "%s: Failed to upload sources file\n", failedCreating) + preSignedURL, zipFilePathErr = uploadsWrapper.UploadFile(zipFilePath) + if zipFilePathErr != nil { + return "", errors.Wrapf(zipFilePathErr, "%s: Failed to upload sources file\n", failedCreating) } PrintIfVerbose(fmt.Sprintf("Uploading file to %s\n", *preSignedURL)) - return *preSignedURL, err + return *preSignedURL, zipFilePathErr } - return preSignedURL, err + return preSignedURL, nil } func definePathForZipFileOrDirectory(cmd *cobra.Command) (zipFile, sourceDir string, err error) { diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 7f9ce2819..8b0b07a6f 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -const gitURLRegex = "(?:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(.*?)(\\.git)?(\\/?|\\#[-\\d\\w._]+?)$" +const gitURLRegex = "(?P:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(?P.*?)(\\.git)?(\\/?|\\#[-\\d\\w._]+?)$" const sshURLRegex = "^(?P.*?)@(?P.*?):(?:(?P.*?)/)?(?P.*?/.*?)$" func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, @@ -62,9 +62,14 @@ func executeTestCommand(cmd *cobra.Command, args ...string) error { // IsGitURL Check if provided URL is a valid git URL (http or ssh) func IsGitURL(url string) bool { - isGitURL, _ := regexp.MatchString(gitURLRegex, url) + compiledRegex := regexp.MustCompile(gitURLRegex) + urlParts := compiledRegex.FindStringSubmatch(url) - return isGitURL + if urlParts == nil || len(urlParts) < 4 { + return false + } + + return len(urlParts[1]) > 0 && len(urlParts[3]) > 0 } // IsSSHURL Check if provided URL is a valid ssh URL From e8d8f146899465965c8b24daa3d2b208dd3445dc Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 12:49:38 +0100 Subject: [PATCH 08/25] AST-11602 - CLI | Add SSH key to scan create command - Fixed unit tests --- internal/commands/util/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 8b0b07a6f..1fc138f15 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -const gitURLRegex = "(?P:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(?P.*?)(\\.git)?(\\/?|\\#[-\\d\\w._]+?)$" +const gitURLRegex = "(?P:git|ssh|https?|git@[-\\w.]+):(\\/\\/)?(?P.*?)(\\.git)?$" const sshURLRegex = "^(?P.*?)@(?P.*?):(?:(?P.*?)/)?(?P.*?/.*?)$" func NewUtilsCommand(gitHubWrapper wrappers.GitHubWrapper, From ad45dbcc32c937fdaa7813a37c6dddb67bddfa1b Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 14:11:55 +0100 Subject: [PATCH 09/25] AST-11602 - CLI | Add SSH key to scan create command - Added debug flag to check error in cicd --- test/integration/scan_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 5b42ee739..2e52df94e 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -516,6 +516,7 @@ func TestScanCreateWithSSHKey(t *testing.T) { flag(params.SourcesFlag), SSHRepo, flag(params.BranchFlag), "main", flag(params.SSHKeyFlag), "data/id_rsa", + flag(params.DebugFlag), } executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 3*time.Minute, args...) From 461e2d0957242ec75ea4aa5be79bf0bf42fa2749 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 14:46:56 +0100 Subject: [PATCH 10/25] AST-11602 - CLI | Add SSH key to scan create command - print error cicd --- test/integration/util_command.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/integration/util_command.go b/test/integration/util_command.go index 4c6905a2d..bedba592f 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -135,6 +135,10 @@ func executeCmdWithTimeOutNilAssertion( ) *bytes.Buffer { cmd, outputBuffer := createRedirectedTestCommand(t) err := executeWithTimeout(cmd, timeout, args...) + + if err != nil { + fmt.Println(err) + } assert.NilError(t, err, infoMsg) return outputBuffer From 3608abe68bcdba593a6d3209986cf9bb6135092d Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 16:13:16 +0100 Subject: [PATCH 11/25] AST-11602 - CLI | Add SSH key to scan create command - Fixed ssh test to create temp file to read ssh key --- test/integration/scan_test.go | 14 +++++++++++--- test/integration/util_command.go | 4 ---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index 2e52df94e..e88504005 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -8,6 +8,7 @@ import ( "context" "fmt" "io" + "io/ioutil" "log" "os" "strings" @@ -508,6 +509,12 @@ func TestFailedScanWithWrongPreset(t *testing.T) { } func TestScanCreateWithSSHKey(t *testing.T) { + _ = viper.BindEnv("CX_SCAN_SSH_KEY") + sshKey := viper.GetString("CX_SCAN_SSH_KEY") + + filename := "ssh-key-file.txt" + _ = ioutil.WriteFile(filename, []byte(sshKey), 0644) + _, projectName := getRootProject(t) args := []string{ @@ -515,9 +522,10 @@ func TestScanCreateWithSSHKey(t *testing.T) { flag(params.ProjectName), projectName, flag(params.SourcesFlag), SSHRepo, flag(params.BranchFlag), "main", - flag(params.SSHKeyFlag), "data/id_rsa", - flag(params.DebugFlag), + flag(params.SSHKeyFlag), filename, } - executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 3*time.Minute, args...) + executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 4*time.Minute, args...) + + _ = os.Remove(filename) } diff --git a/test/integration/util_command.go b/test/integration/util_command.go index bedba592f..4c6905a2d 100644 --- a/test/integration/util_command.go +++ b/test/integration/util_command.go @@ -135,10 +135,6 @@ func executeCmdWithTimeOutNilAssertion( ) *bytes.Buffer { cmd, outputBuffer := createRedirectedTestCommand(t) err := executeWithTimeout(cmd, timeout, args...) - - if err != nil { - fmt.Println(err) - } assert.NilError(t, err, infoMsg) return outputBuffer From 19b1a4ec8874a20d9227994bb50768dcb51948c3 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 13 Apr 2022 17:16:03 +0100 Subject: [PATCH 12/25] AST-11602 - CLI | Add SSH key to scan create command - Fix cicd integration tests --- .github/workflows/ci.yml | 1 + internal/commands/scan.go | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dba7dc9fd..37ef322e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,7 @@ jobs: CX_AST_PASSWORD: ${{ secrets.CX_AST_PASSWORD }} CX_APIKEY: ${{ secrets.CX_APIKEY }} CX_TENANT: ${{ secrets.CX_TENANT }} + CX_SCAN_SSH_KEY: ${{ secrets.CX_SCAN_SSH_KEY }} PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} PROXY_HOST: localhost PROXY_PORT: 3128 diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 840960046..17c29e713 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -1086,6 +1086,14 @@ func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) erro credentials := wrappers.GitCredentials{} credentials.Type = "ssh" + +_: + fmt.Fprintln(os.Stdout, "================== SSH KEY ====================== A") //nolint:gofmt +_: + fmt.Fprintln(os.Stdout, sshKey) +_: + fmt.Fprintln(os.Stdout, "================================================= ") + credentials.Value = sshKey handler.Credentials = credentials From a80ad7a2aa73648078592087b47408100fc76398 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Thu, 14 Apr 2022 10:00:33 +0100 Subject: [PATCH 13/25] AST-11602 - CLI | Add SSH key to scan create command - Remove helping printed messages --- internal/commands/scan.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 17c29e713..840960046 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -1086,14 +1086,6 @@ func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) erro credentials := wrappers.GitCredentials{} credentials.Type = "ssh" - -_: - fmt.Fprintln(os.Stdout, "================== SSH KEY ====================== A") //nolint:gofmt -_: - fmt.Fprintln(os.Stdout, sshKey) -_: - fmt.Fprintln(os.Stdout, "================================================= ") - credentials.Value = sshKey handler.Credentials = credentials From fbf8f8206de7a54c92ef0444844b17ad75ad3e63 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Mon, 18 Apr 2022 10:28:12 +0100 Subject: [PATCH 14/25] AST-11603 - CLI | Add SSH key to project create command - Add --ssh-key flag to project create and update project configuration with the ssh-key after project create - Unit tests and integration tests added --- internal/commands/project.go | 35 +++++++++++++++++++++++++ internal/commands/project_test.go | 34 ++++++++++++++++++++++++ internal/commands/scan.go | 12 +-------- internal/commands/util/utils.go | 12 +++++++++ internal/wrappers/mock/projects-mock.go | 5 ++++ internal/wrappers/projects-http.go | 19 ++++++++++++++ internal/wrappers/projects.go | 11 ++++++++ 7 files changed, 117 insertions(+), 11 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index e3cfbfbed..52f1c9424 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -3,6 +3,7 @@ package commands import ( "encoding/json" "fmt" + "github.com/checkmarx/ast-cli/internal/commands/util" "strings" "time" @@ -88,6 +89,7 @@ func NewProjectCommand(projectsWrapper wrappers.ProjectsWrapper, groupsWrapper w createProjCmd.PersistentFlags().String(commonParams.GroupList, "", "List of groups, ex: (PowerUsers,etc)") createProjCmd.PersistentFlags().StringP(commonParams.ProjectName, "", "", "Name of project") createProjCmd.PersistentFlags().StringP(commonParams.MainBranchFlag, "", "", "Main branch") + createProjCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") listProjectsCmd := &cobra.Command{ Use: "list", @@ -299,6 +301,39 @@ func runCreateProjectCommand( if err != nil { return errors.Wrapf(err, "%s", failedCreatingProj) } + + // add ssh key to project when it is provided + if cmd.Flags().Changed(commonParams.SSHKeyFlag) { + sshKeyPath, _ := cmd.Flags().GetString(commonParams.SSHKeyFlag) + + if strings.TrimSpace(sshKeyPath) == "" { + return errors.New("flag needs an argument: --ssh-key") + } + + sshKey, sshErr := util.ReadFileAsString(sshKeyPath) + if sshErr != nil { + return sshErr + } + + projectSSHKeyConfiguration := wrappers.ProjectConfiguration{} + projectSSHKeyConfiguration.Key = "scan.handler.git.sshKey" + projectSSHKeyConfiguration.Name = "sshKey" + projectSSHKeyConfiguration.Category = "git" + projectSSHKeyConfiguration.OriginLevel = "Project" + projectSSHKeyConfiguration.Value = sshKey + projectSSHKeyConfiguration.ValueType = "Secret" + projectSSHKeyConfiguration.AllowOverride = true + + projectConfigurations := []wrappers.ProjectConfiguration{ + projectSSHKeyConfiguration, + } + + _, sshErr = projectsWrapper.UpdateConfiguration(projResponseModel.ID, projectConfigurations) + if sshErr != nil { + return sshErr + } + } + // Checking the response if errorModel != nil { return errors.Errorf(ErrorCodeFormat, failedCreatingProj, errorModel.Code, errorModel.Message) diff --git a/internal/commands/project_test.go b/internal/commands/project_test.go index 3115cc8e8..7df1c7db2 100644 --- a/internal/commands/project_test.go +++ b/internal/commands/project_test.go @@ -6,6 +6,8 @@ import ( "testing" "gotest.tools/assert" + + "github.com/checkmarx/ast-cli/internal/commands/util" ) func TestProjectHelp(t *testing.T) { @@ -101,3 +103,35 @@ func TestRunProjectCreateInvalidGroup(t *testing.T) { "project", "create", "--project-name", "invalidprj", "--groups", "invalidgroup") assert.Assert(t, err.Error() == "Failed finding groups: [invalidgroup]") } + +func TestCreateProjectMissingSSHValue(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", " ")...) + assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) +} + +func TestCreateProjectWrongSSHKeyPath(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key")...) + + expectedMessages := []string{ + "open dummy_key: The system cannot find the file specified.", + "open dummy_key: no such file or directory", + } + + assert.Assert(t, util.Contains(expectedMessages, err.Error())) +} + +func TestCreateProjectWithSSHKey(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + execCmdNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa")...) +} diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 840960046..ec7334fba 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -1081,7 +1081,7 @@ func setupScanHandler( } func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) error { - sshKey, err := getSSHKeyValue(sshKeyPath) + sshKey, err := util.ReadFileAsString(sshKeyPath) credentials := wrappers.GitCredentials{} @@ -1093,16 +1093,6 @@ func defineSSHCredentials(sshKeyPath string, handler *wrappers.ScanHandler) erro return err } -func getSSHKeyValue(sshKeyPath string) (string, error) { - sshKey, err := os.ReadFile(sshKeyPath) - - if err != nil { - return "", err - } - - return string(sshKey), nil -} - func handleWait( cmd *cobra.Command, scanResponseModel *wrappers.ScanResponseModel, diff --git a/internal/commands/util/utils.go b/internal/commands/util/utils.go index 1fc138f15..8aed19a75 100644 --- a/internal/commands/util/utils.go +++ b/internal/commands/util/utils.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "os" "regexp" "github.com/MakeNowJust/heredoc" @@ -78,3 +79,14 @@ func IsSSHURL(url string) bool { return isGitURL } + +// ReadFileAsString Read a file and return its content as string +func ReadFileAsString(path string) (string, error) { + content, err := os.ReadFile(path) + + if err != nil { + return "", err + } + + return string(content), nil +} diff --git a/internal/wrappers/mock/projects-mock.go b/internal/wrappers/mock/projects-mock.go index 6a453b5de..411ad0156 100644 --- a/internal/wrappers/mock/projects-mock.go +++ b/internal/wrappers/mock/projects-mock.go @@ -18,6 +18,11 @@ func (p *ProjectsMockWrapper) Create(model *wrappers.Project) ( }, nil, nil } +func (p *ProjectsMockWrapper) UpdateConfiguration(projectID string, configuration []wrappers.ProjectConfiguration) (*wrappers.ErrorModel, error) { + fmt.Println("Called Update Configuration for project", projectID, " in ProjectsMockWrapper with the configuration ", configuration) + return nil, nil +} + func (p *ProjectsMockWrapper) Get(params map[string]string) ( *wrappers.ProjectsCollectionResponseModel, *wrappers.ErrorModel, diff --git a/internal/wrappers/projects-http.go b/internal/wrappers/projects-http.go index 490ed8252..dc1cc0457 100644 --- a/internal/wrappers/projects-http.go +++ b/internal/wrappers/projects-http.go @@ -37,6 +37,25 @@ func (p *ProjectsHTTPWrapper) Create(model *Project) ( return handleProjectResponseWithBody(resp, err, http.StatusCreated) } +func (p *ProjectsHTTPWrapper) UpdateConfiguration(projectID string, configuration []ProjectConfiguration) (*ErrorModel, error) { + clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey) + jsonBytes, err := json.Marshal(configuration) + if err != nil { + return nil, err + } + + params := map[string]string{ + commonParams.ProjectIDFlag: projectID, + } + + resp, err := SendHTTPRequestWithQueryParams(http.MethodPatch, "api/configuration/project", params, bytes.NewBuffer(jsonBytes), clientTimeout) + if err != nil { + return nil, err + } + + return handleProjectResponseWithNoBody(resp, err, http.StatusNoContent) +} + func (p *ProjectsHTTPWrapper) Get(params map[string]string) ( *ProjectsCollectionResponseModel, *ErrorModel, error) { diff --git a/internal/wrappers/projects.go b/internal/wrappers/projects.go index 223ad3c3a..43b09689f 100644 --- a/internal/wrappers/projects.go +++ b/internal/wrappers/projects.go @@ -33,6 +33,16 @@ type ProjectResponseModel struct { ScmRepoID string `json:"scmRepoId,omitempty"` } +type ProjectConfiguration struct { + Key string `json:"key"` + Name string `json:"name"` + Category string `json:"category"` + OriginLevel string `json:"originLevel"` + Value string `json:"value"` + ValueType string `json:"valuetype"` + AllowOverride bool `json:"allowOverride"` +} + type ProjectsWrapper interface { Create(model *Project) (*ProjectResponseModel, *ErrorModel, error) Get(params map[string]string) (*ProjectsCollectionResponseModel, *ErrorModel, error) @@ -40,4 +50,5 @@ type ProjectsWrapper interface { GetBranchesByID(projectID string, params map[string]string) ([]string, *ErrorModel, error) Delete(projectID string) (*ErrorModel, error) Tags() (map[string][]string, *ErrorModel, error) + UpdateConfiguration(projectID string, configuration []ProjectConfiguration) (*ErrorModel, error) } From d24b65133f99a941d5e61bcce95c133621dd597a Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Mon, 18 Apr 2022 10:35:08 +0100 Subject: [PATCH 15/25] AST-11603 - CLI | Add SSH key to project create command - Fixed lint errors --- internal/commands/project.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index 52f1c9424..ac9404e14 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -3,11 +3,11 @@ package commands import ( "encoding/json" "fmt" - "github.com/checkmarx/ast-cli/internal/commands/util" "strings" "time" "github.com/MakeNowJust/heredoc" + "github.com/checkmarx/ast-cli/internal/commands/util" "github.com/checkmarx/ast-cli/internal/commands/util/printer" commonParams "github.com/checkmarx/ast-cli/internal/params" @@ -318,7 +318,7 @@ func runCreateProjectCommand( projectSSHKeyConfiguration := wrappers.ProjectConfiguration{} projectSSHKeyConfiguration.Key = "scan.handler.git.sshKey" projectSSHKeyConfiguration.Name = "sshKey" - projectSSHKeyConfiguration.Category = "git" + projectSSHKeyConfiguration.Category = git projectSSHKeyConfiguration.OriginLevel = "Project" projectSSHKeyConfiguration.Value = sshKey projectSSHKeyConfiguration.ValueType = "Secret" From 9ed062967bfe0e9cd887347ee28275c97a31997c Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 19 Apr 2022 12:06:52 +0100 Subject: [PATCH 16/25] AST-11621 - CLI | Handle file filters when source is zip file - Added logs to check tests in CICD --- test/integration/project_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration/project_test.go b/test/integration/project_test.go index aa959efe0..dad405ecc 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -135,6 +135,7 @@ func createProject(t *testing.T, tags map[string]string) (string, string) { func deleteProject(t *testing.T, projectID string) { log.Println("Deleting the project with id ", projectID) + fmt.Println("Deleting the project with id ", projectID) executeCmdNilAssertion( t, "Deleting a project should pass", @@ -147,14 +148,14 @@ func deleteProject(t *testing.T, projectID string) { func listProjectByID(t *testing.T, projectID string) []wrappers.ProjectResponseModel { idFilter := fmt.Sprintf("ids=%s", projectID) - + fmt.Println("Listing project for id ", projectID) outputBuffer := executeCmdNilAssertion( t, "Getting the project should pass", "project", "list", flag(params.FormatFlag), printer.FormatJSON, flag(params.FilterFlag), idFilter, ) - + fmt.Println("Listing project for id output buffer", outputBuffer) var projects []wrappers.ProjectResponseModel _ = unmarshall(t, outputBuffer, &projects, "Reading all projects response JSON should pass") From 78008542ee55e1779dc9b24baf19b1b9c45d2f6f Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 19 Apr 2022 14:08:53 +0100 Subject: [PATCH 17/25] AST-11621 - CLI | Handle file filters when source is zip file - Added logs to check tests in CICD --- test/integration/project_test.go | 3 ++- test/integration/root_test.go | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/integration/project_test.go b/test/integration/project_test.go index dad405ecc..88e5aa8be 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -72,7 +72,6 @@ func TestCreateEmptyProjectName(t *testing.T) { // Create the same project twice and assert that it fails func TestCreateAlreadyExistingProject(t *testing.T) { - assertRequiredParameter(t, "Project name is required", "project", "create") _, projectName := getRootProject(t) @@ -115,6 +114,7 @@ func createProject(t *testing.T, tags map[string]string) (string, string) { projectName := getProjectNameForTest() + "_for_project" tagsStr := formatTags(tags) + fmt.Printf("Creating project : %s \n", projectName) outBuffer := executeCmdNilAssertion( t, "Creating a project should pass", "project", "create", @@ -158,6 +158,7 @@ func listProjectByID(t *testing.T, projectID string) []wrappers.ProjectResponseM fmt.Println("Listing project for id output buffer", outputBuffer) var projects []wrappers.ProjectResponseModel _ = unmarshall(t, outputBuffer, &projects, "Reading all projects response JSON should pass") + fmt.Println("Listing project for id projects length: ", len(projects)) return projects } diff --git a/test/integration/root_test.go b/test/integration/root_test.go index 526566c03..8fc39e4c3 100644 --- a/test/integration/root_test.go +++ b/test/integration/root_test.go @@ -3,6 +3,7 @@ package integration import ( + "fmt" "log" "os" "testing" @@ -78,6 +79,7 @@ func getRootProject(t *testing.T) (string, string) { testInstance = t if len(rootProjectId) > 0 { + fmt.Printf("Using the projectID: " + rootProjectId) log.Println("Using the projectID: ", rootProjectId) log.Println("Using the projectName: ", rootProjectName) return rootProjectId, rootProjectName From c1ba9d22297e962b619d9631d0b9fafa6cc1e263 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Tue, 19 Apr 2022 14:56:14 +0100 Subject: [PATCH 18/25] AST-11602 - CLI | Add SSH key to scan create command - Removed private keys from project; - defer remove file --- internal/commands/data/id_rsa | 38 ---------------------------------- internal/commands/scan_test.go | 2 +- test/integration/data/id_rsa | 38 ---------------------------------- test/integration/scan_test.go | 3 +-- 4 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 internal/commands/data/id_rsa delete mode 100644 test/integration/data/id_rsa diff --git a/internal/commands/data/id_rsa b/internal/commands/data/id_rsa deleted file mode 100644 index 44f9baa6d..000000000 --- a/internal/commands/data/id_rsa +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -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 ------END OPENSSH PRIVATE KEY----- diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index da4d42109..0a99c9d40 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -276,5 +276,5 @@ func TestCreateScanWrongSSHKeyPath(t *testing.T) { func TestCreateScanWithSSHKey(t *testing.T) { baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-b", "dummy_branch"} - execCmdNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "data/id_rsa")...) + execCmdNilAssertion(t, append(baseArgs, "-s", dummySSHRepo, "--ssh-key", "data/sources.zip")...) } diff --git a/test/integration/data/id_rsa b/test/integration/data/id_rsa deleted file mode 100644 index 44f9baa6d..000000000 --- a/test/integration/data/id_rsa +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -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 ------END OPENSSH PRIVATE KEY----- diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index e88504005..74656a41c 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -514,6 +514,7 @@ func TestScanCreateWithSSHKey(t *testing.T) { filename := "ssh-key-file.txt" _ = ioutil.WriteFile(filename, []byte(sshKey), 0644) + defer func() { _ = os.Remove(filename) }() _, projectName := getRootProject(t) @@ -526,6 +527,4 @@ func TestScanCreateWithSSHKey(t *testing.T) { } executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 4*time.Minute, args...) - - _ = os.Remove(filename) } From fec2c87fcbd5fd0f2ef1f15f4f29a2b472dac95c Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 20 Apr 2022 15:07:19 +0100 Subject: [PATCH 19/25] AST-11603 - CLI | Add SSH key to project create command - added repository url to create project command; --- internal/commands/project.go | 139 +++++++++++++++++++++++++++-------- internal/params/flags.go | 1 + 2 files changed, 110 insertions(+), 30 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index ac9404e14..b4593f5a3 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -24,6 +24,9 @@ const ( failedDeletingProj = "Failed deleting a project" failedGettingBranches = "Failed getting branches for project" failedFindingGroup = "Failed finding groups" + projOriginLevel = "Project" + repoConfKey = "scan.handler.git.repository" + sshConfKey = "scan.handler.git.sshKey" ) var ( @@ -90,6 +93,7 @@ func NewProjectCommand(projectsWrapper wrappers.ProjectsWrapper, groupsWrapper w createProjCmd.PersistentFlags().StringP(commonParams.ProjectName, "", "", "Name of project") createProjCmd.PersistentFlags().StringP(commonParams.MainBranchFlag, "", "", "Main branch") createProjCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") + createProjCmd.PersistentFlags().String(commonParams.RepoURLFlag, "", "Repository URL") listProjectsCmd := &cobra.Command{ Use: "list", @@ -286,6 +290,10 @@ func runCreateProjectCommand( return err } setupScanTags(&input, cmd) + err = validateConfiguration(cmd) + if err != nil { + return err + } var projModel = wrappers.Project{} var projResponseModel *wrappers.ProjectResponseModel var errorModel *wrappers.ErrorModel @@ -302,49 +310,120 @@ func runCreateProjectCommand( return errors.Wrapf(err, "%s", failedCreatingProj) } - // add ssh key to project when it is provided + // Checking the response + if errorModel != nil { + return errors.Errorf(ErrorCodeFormat, failedCreatingProj, errorModel.Code, errorModel.Message) + } else if projResponseModel != nil { + err = printByFormat(cmd, toProjectView(*projResponseModel)) + if err != nil { + return errors.Wrapf(err, "%s", failedCreatingProj) + } + } + + err = updateProjectConfigurationIfNeeded(cmd, projectsWrapper, projResponseModel.ID) + if err != nil { + return err + } + + return nil + } +} + +func updateProjectConfigurationIfNeeded(cmd *cobra.Command, projectsWrapper wrappers.ProjectsWrapper, projectID string) error { + // Just update project configuration id a repository url is defined + if cmd.Flags().Changed(commonParams.RepoURLFlag) { + var projectConfigurations []wrappers.ProjectConfiguration + + repoURL, _ := cmd.Flags().GetString(commonParams.RepoURLFlag) + + urlConf := getProjectConfiguration(repoConfKey, "repository", git, projOriginLevel, repoURL, "String", true) + + projectConfigurations = append(projectConfigurations, urlConf) + if cmd.Flags().Changed(commonParams.SSHKeyFlag) { sshKeyPath, _ := cmd.Flags().GetString(commonParams.SSHKeyFlag) - if strings.TrimSpace(sshKeyPath) == "" { - return errors.New("flag needs an argument: --ssh-key") - } - sshKey, sshErr := util.ReadFileAsString(sshKeyPath) if sshErr != nil { return sshErr } - projectSSHKeyConfiguration := wrappers.ProjectConfiguration{} - projectSSHKeyConfiguration.Key = "scan.handler.git.sshKey" - projectSSHKeyConfiguration.Name = "sshKey" - projectSSHKeyConfiguration.Category = git - projectSSHKeyConfiguration.OriginLevel = "Project" - projectSSHKeyConfiguration.Value = sshKey - projectSSHKeyConfiguration.ValueType = "Secret" - projectSSHKeyConfiguration.AllowOverride = true - - projectConfigurations := []wrappers.ProjectConfiguration{ - projectSSHKeyConfiguration, - } + sshKeyConf := getProjectConfiguration(sshConfKey, "sshKey", git, projOriginLevel, sshKey, "Secret", true) - _, sshErr = projectsWrapper.UpdateConfiguration(projResponseModel.ID, projectConfigurations) - if sshErr != nil { - return sshErr - } + projectConfigurations = append(projectConfigurations, sshKeyConf) } - // Checking the response - if errorModel != nil { - return errors.Errorf(ErrorCodeFormat, failedCreatingProj, errorModel.Code, errorModel.Message) - } else if projResponseModel != nil { - err = printByFormat(cmd, toProjectView(*projResponseModel)) - if err != nil { - return errors.Wrapf(err, "%s", failedCreatingProj) - } + _, configErr := projectsWrapper.UpdateConfiguration(projectID, projectConfigurations) + if configErr != nil { + return configErr } - return nil } + + return nil +} + +func getProjectConfiguration( + key string, + name string, + category string, + level string, + value string, + valueType string, + allowOverride bool) wrappers.ProjectConfiguration { + config := wrappers.ProjectConfiguration{} + config.Key = key + config.Name = name + config.Category = category + config.OriginLevel = level + config.Value = value + config.ValueType = valueType + config.AllowOverride = allowOverride + + return config +} + +func validateConfiguration(cmd *cobra.Command) error { + var sshKeyDefined bool + var repoURLDefined bool + + // Validate if ssh key is empty when provided + if cmd.Flags().Changed(commonParams.SSHKeyFlag) { + sshKey, _ := cmd.Flags().GetString(commonParams.SSHKeyFlag) + + if strings.TrimSpace(sshKey) == "" { + return errors.New("flag needs an argument: --ssh-key") + } + + sshKeyDefined = true + } + + // Validate if repo url is empty when provided + if cmd.Flags().Changed(commonParams.RepoURLFlag) { + repoURL, _ := cmd.Flags().GetString(commonParams.RepoURLFlag) + + if strings.TrimSpace(repoURL) == "" { + return errors.New("flag needs an argument: --repo-url") + } + + repoURLDefined = true + } + + // If ssh key is defined we have two checks to validate: + // 1. repo url needs to be provided + // 2. provided repo url needs to be a ssh url + if sshKeyDefined { + if !repoURLDefined { + return errors.New("flag --repo-url is mandatory when --ssh-key is provided") + } + + repoURL, _ := cmd.Flags().GetString(commonParams.RepoURLFlag) + + if !util.IsSSHURL(repoURL) { + return errors.New("provided repository url doesn't need a key. Make sure you are defining the right repository or remove the flag --ssh-key") + } + } + + return nil } func runListProjectsCommand(projectsWrapper wrappers.ProjectsWrapper) func(cmd *cobra.Command, args []string) error { diff --git a/internal/params/flags.go b/internal/params/flags.go index 131127679..fc85449ca 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -99,6 +99,7 @@ const ( URLFlagUsage = "API base URL" QueryIDFlag = "query-id" SSHKeyFlag = "ssh-key" + RepoURLFlag = "repo-url" ) // Parameter values From 58117145677c81f8a07d18239565b655433b36b4 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 20 Apr 2022 15:58:48 +0100 Subject: [PATCH 20/25] AST-11603 - CLI | Add SSH key to project create command - added unit tests and integration tests for project creation with ssh key --- internal/commands/project.go | 6 +++-- internal/commands/project_test.go | 33 +++++++++++++++++++++++-- test/integration/project_test.go | 40 +++++++++++++++++++++++++++++-- test/integration/scan_test.go | 7 +++--- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index b4593f5a3..12aeaf949 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -27,6 +27,8 @@ const ( projOriginLevel = "Project" repoConfKey = "scan.handler.git.repository" sshConfKey = "scan.handler.git.sshKey" + mandatoryRepoURLError = "flag --repo-url is mandatory when --ssh-key is provided" + invalidRepoURL = "provided repository url doesn't need a key. Make sure you are defining the right repository or remove the flag --ssh-key" ) var ( @@ -413,13 +415,13 @@ func validateConfiguration(cmd *cobra.Command) error { // 2. provided repo url needs to be a ssh url if sshKeyDefined { if !repoURLDefined { - return errors.New("flag --repo-url is mandatory when --ssh-key is provided") + return errors.New(mandatoryRepoURLError) } repoURL, _ := cmd.Flags().GetString(commonParams.RepoURLFlag) if !util.IsSSHURL(repoURL) { - return errors.New("provided repository url doesn't need a key. Make sure you are defining the right repository or remove the flag --ssh-key") + return errors.New(invalidRepoURL) } } diff --git a/internal/commands/project_test.go b/internal/commands/project_test.go index 7df1c7db2..c7c9f9ddf 100644 --- a/internal/commands/project_test.go +++ b/internal/commands/project_test.go @@ -117,11 +117,40 @@ func TestCreateProjectMissingSSHValue(t *testing.T) { assert.Error(t, err, "flag needs an argument: --ssh-key", err.Error()) } -func TestCreateProjectWrongSSHKeyPath(t *testing.T) { +func TestCreateProjectMissingRepoURLWithSSHValue(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url")...) + assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", "")...) + assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) + + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", " ")...) + assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) +} + +func TestCreateProjectMandatoryRepoURLWhenSSHKeyProvided(t *testing.T) { baseArgs := []string{"project", "create", "--project-name", "MOCK"} err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key")...) + assert.Error(t, err, mandatoryRepoURLError) +} + +func TestCreateProjectInvalidRepoURLWithSSHKey(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key", "--repo-url", "https://github.com/dummyuser/dummy_project.git")...) + + assert.Error(t, err, invalidRepoURL) +} + +func TestCreateProjectWrongSSHKeyPath(t *testing.T) { + baseArgs := []string{"project", "create", "--project-name", "MOCK"} + + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key", "--repo-url", "git@github.com:dummyRepo/dummyProject.git")...) + expectedMessages := []string{ "open dummy_key: The system cannot find the file specified.", "open dummy_key: no such file or directory", @@ -133,5 +162,5 @@ func TestCreateProjectWrongSSHKeyPath(t *testing.T) { func TestCreateProjectWithSSHKey(t *testing.T) { baseArgs := []string{"project", "create", "--project-name", "MOCK"} - execCmdNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa")...) + execCmdNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", "git@github.com:dummyRepo/dummyProject.git")...) } diff --git a/test/integration/project_test.go b/test/integration/project_test.go index 88e5aa8be..6c9daa446 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -5,17 +5,22 @@ package integration import ( "fmt" "io" + "io/ioutil" "log" + "os" "strings" "testing" "github.com/checkmarx/ast-cli/internal/commands/util/printer" "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/wrappers" + "github.com/spf13/viper" "gotest.tools/assert" ) +const SSHKeyFilePath = "ssh-key-file.txt" + // End-to-end test of project handling. // - Create a project // - Get and assert the project exists @@ -101,9 +106,9 @@ func TestProjectBranches(t *testing.T) { "branches", ) - projectId, _ := getRootProject(t) + projectID, _ := getRootProject(t) - buffer := executeCmdNilAssertion(t, "Branches should be listed", "project", "branches", "--project-id", projectId) + buffer := executeCmdNilAssertion(t, "Branches should be listed", "project", "branches", "--project-id", projectID) result, readingError := io.ReadAll(buffer) assert.NilError(t, readingError, "Reading result should pass") @@ -177,3 +182,34 @@ func showProject(t *testing.T, projectID string) wrappers.ProjectResponseModel { return project } + +func TestCreateProjectWithSSHKey(t *testing.T) { + projectName := getProjectNameForTest() + "_for_project" + tagsStr := formatTags(Tags) + + _ = viper.BindEnv("CX_SCAN_SSH_KEY") + sshKey := viper.GetString("CX_SCAN_SSH_KEY") + + _ = ioutil.WriteFile(SSHKeyFilePath, []byte(sshKey), 0644) + defer func() { _ = os.Remove(SSHKeyFilePath) }() + + fmt.Printf("Creating project : %s \n", projectName) + outBuffer := executeCmdNilAssertion( + t, "Creating a project with ssh key should pass", + "project", "create", + flag(params.FormatFlag), printer.FormatJSON, + flag(params.ProjectName), projectName, + flag(params.BranchFlag), "master", + flag(params.TagList), tagsStr, + flag(params.RepoURLFlag), SSHRepo, + flag(params.SSHKeyFlag), SSHKeyFilePath, + ) + + createdProject := wrappers.ProjectResponseModel{} + createdProjectJSON := unmarshall(t, outBuffer, &createdProject, "Reading project create response JSON should pass") + + fmt.Println("Response after project is created : ", string(createdProjectJSON)) + fmt.Printf("New project created with id: %s \n", createdProject.ID) + + deleteProject(t, createdProject.ID) +} diff --git a/test/integration/scan_test.go b/test/integration/scan_test.go index e88504005..2372b7eb5 100644 --- a/test/integration/scan_test.go +++ b/test/integration/scan_test.go @@ -512,8 +512,7 @@ func TestScanCreateWithSSHKey(t *testing.T) { _ = viper.BindEnv("CX_SCAN_SSH_KEY") sshKey := viper.GetString("CX_SCAN_SSH_KEY") - filename := "ssh-key-file.txt" - _ = ioutil.WriteFile(filename, []byte(sshKey), 0644) + _ = ioutil.WriteFile(SSHKeyFilePath, []byte(sshKey), 0644) _, projectName := getRootProject(t) @@ -522,10 +521,10 @@ func TestScanCreateWithSSHKey(t *testing.T) { flag(params.ProjectName), projectName, flag(params.SourcesFlag), SSHRepo, flag(params.BranchFlag), "main", - flag(params.SSHKeyFlag), filename, + flag(params.SSHKeyFlag), SSHKeyFilePath, } executeCmdWithTimeOutNilAssertion(t, "Create a scan with ssh-key should pass", 4*time.Minute, args...) - _ = os.Remove(filename) + _ = os.Remove(SSHKeyFilePath) } From 90877cbee7e25c0166c78b25462b2cef6b4c847d Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 20 Apr 2022 16:18:06 +0100 Subject: [PATCH 21/25] AST-11603 - CLI | Add SSH key to project create command - Fix lint errors --- internal/commands/project.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index 12aeaf949..97015cdd5 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -364,14 +364,7 @@ func updateProjectConfigurationIfNeeded(cmd *cobra.Command, projectsWrapper wrap return nil } -func getProjectConfiguration( - key string, - name string, - category string, - level string, - value string, - valueType string, - allowOverride bool) wrappers.ProjectConfiguration { +func getProjectConfiguration(key string, name string, category string, level string, value string, valueType string, allowOverride bool) wrappers.ProjectConfiguration { config := wrappers.ProjectConfiguration{} config.Key = key config.Name = name From 2e55b2a5ebbb0b049d0c94ce44e2d409bd602f66 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 20 Apr 2022 16:19:25 +0100 Subject: [PATCH 22/25] AST-11603 - CLI | Add SSH key to project create command - Fix lint errors --- internal/commands/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index 97015cdd5..1a9e3ab4c 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -364,7 +364,7 @@ func updateProjectConfigurationIfNeeded(cmd *cobra.Command, projectsWrapper wrap return nil } -func getProjectConfiguration(key string, name string, category string, level string, value string, valueType string, allowOverride bool) wrappers.ProjectConfiguration { +func getProjectConfiguration(key, name, category, level, value, valueType string, allowOverride bool) wrappers.ProjectConfiguration { config := wrappers.ProjectConfiguration{} config.Key = key config.Name = name From acafc8fee47f375f332e25cfa9d436219601cdac Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 20 Apr 2022 16:31:40 +0100 Subject: [PATCH 23/25] AST-11603 - CLI | Add SSH key to project create command - Fix unit tests --- internal/commands/project_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/commands/project_test.go b/internal/commands/project_test.go index c7c9f9ddf..b40af41a9 100644 --- a/internal/commands/project_test.go +++ b/internal/commands/project_test.go @@ -120,13 +120,13 @@ func TestCreateProjectMissingSSHValue(t *testing.T) { func TestCreateProjectMissingRepoURLWithSSHValue(t *testing.T) { baseArgs := []string{"project", "create", "--project-name", "MOCK"} - err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url")...) + err := execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key", "--repo-url")...) assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) - err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", "")...) + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key", "--repo-url", "")...) assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) - err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", " ")...) + err = execCmdNotNilAssertion(t, append(baseArgs, "--ssh-key", "dummy_key", "--repo-url", " ")...) assert.Error(t, err, "flag needs an argument: --repo-url", err.Error()) } @@ -162,5 +162,5 @@ func TestCreateProjectWrongSSHKeyPath(t *testing.T) { func TestCreateProjectWithSSHKey(t *testing.T) { baseArgs := []string{"project", "create", "--project-name", "MOCK"} - execCmdNilAssertion(t, append(baseArgs, "--ssh-key", "data/id_rsa", "--repo-url", "git@github.com:dummyRepo/dummyProject.git")...) + execCmdNilAssertion(t, append(baseArgs, "--ssh-key", "data/sources.zip", "--repo-url", "git@github.com:dummyRepo/dummyProject.git")...) } From b46aa951ceb6d5a6ad309d3c8edc61fc129b12d9 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Wed, 27 Apr 2022 12:23:11 +0100 Subject: [PATCH 24/25] AST-11603 - CLI | Add SSH key to project create command - Fixed integration tests --- test/integration/project_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/project_test.go b/test/integration/project_test.go index 6c9daa446..de282e231 100644 --- a/test/integration/project_test.go +++ b/test/integration/project_test.go @@ -4,6 +4,7 @@ package integration import ( "fmt" + "github.com/google/uuid" "io" "io/ioutil" "log" @@ -184,7 +185,7 @@ func showProject(t *testing.T, projectID string) wrappers.ProjectResponseModel { } func TestCreateProjectWithSSHKey(t *testing.T) { - projectName := getProjectNameForTest() + "_for_project" + projectName := fmt.Sprintf("ast-cli-tests_%s", uuid.New().String()) + "_for_project" tagsStr := formatTags(Tags) _ = viper.BindEnv("CX_SCAN_SSH_KEY") From a2a3e6e78341952f081850161f60a2aaf5515dc2 Mon Sep 17 00:00:00 2001 From: hmmachadocx Date: Thu, 28 Apr 2022 14:02:09 +0100 Subject: [PATCH 25/25] AST-11603 - CLI | Add SSH key to project create command - Clarify it is a private key required --- internal/commands/project.go | 2 +- internal/commands/scan.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/commands/project.go b/internal/commands/project.go index 1a9e3ab4c..31b78cfeb 100644 --- a/internal/commands/project.go +++ b/internal/commands/project.go @@ -94,7 +94,7 @@ func NewProjectCommand(projectsWrapper wrappers.ProjectsWrapper, groupsWrapper w createProjCmd.PersistentFlags().String(commonParams.GroupList, "", "List of groups, ex: (PowerUsers,etc)") createProjCmd.PersistentFlags().StringP(commonParams.ProjectName, "", "", "Name of project") createProjCmd.PersistentFlags().StringP(commonParams.MainBranchFlag, "", "", "Main branch") - createProjCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") + createProjCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh private key") createProjCmd.PersistentFlags().String(commonParams.RepoURLFlag, "", "Repository URL") listProjectsCmd := &cobra.Command{ diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 2fc1ce3e0..235b1f6da 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -390,7 +390,7 @@ func scanCreateSubCommand( log.Fatal(err) } - createScanCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh key") + createScanCmd.PersistentFlags().String(commonParams.SSHKeyFlag, "", "Path to ssh private key") return createScanCmd }