You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	
							
								
								
									
										231
									
								
								cmd/codeqlExecuteScan.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								cmd/codeqlExecuteScan.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,231 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/orchestrator" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type codeqlExecuteScanUtils interface { | ||||
| 	command.ExecRunner | ||||
|  | ||||
| 	FileExists(filename string) (bool, error) | ||||
| } | ||||
|  | ||||
| type RepoInfo struct { | ||||
| 	serverUrl string | ||||
| 	repo      string | ||||
| 	commitId  string | ||||
| 	ref       string | ||||
| } | ||||
|  | ||||
| type codeqlExecuteScanUtilsBundle struct { | ||||
| 	*command.Command | ||||
| 	*piperutils.Files | ||||
| } | ||||
|  | ||||
| func newCodeqlExecuteScanUtils() codeqlExecuteScanUtils { | ||||
| 	utils := codeqlExecuteScanUtilsBundle{ | ||||
| 		Command: &command.Command{}, | ||||
| 		Files:   &piperutils.Files{}, | ||||
| 	} | ||||
|  | ||||
| 	utils.Stdout(log.Writer()) | ||||
| 	utils.Stderr(log.Writer()) | ||||
| 	return &utils | ||||
| } | ||||
|  | ||||
| func codeqlExecuteScan(config codeqlExecuteScanOptions, telemetryData *telemetry.CustomData) { | ||||
|  | ||||
| 	utils := newCodeqlExecuteScanUtils() | ||||
|  | ||||
| 	err := runCodeqlExecuteScan(&config, telemetryData, utils) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Codeql scan failed") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func codeqlQuery(cmd []string, codeqlQuery string) []string { | ||||
| 	if len(codeqlQuery) > 0 { | ||||
| 		cmd = append(cmd, codeqlQuery) | ||||
| 	} | ||||
|  | ||||
| 	return cmd | ||||
| } | ||||
|  | ||||
| func execute(utils codeqlExecuteScanUtils, cmd []string, isVerbose bool) error { | ||||
| 	if isVerbose { | ||||
| 		cmd = append(cmd, "-v") | ||||
| 	} | ||||
| 	return utils.RunExecutable("codeql", cmd...) | ||||
| } | ||||
|  | ||||
| func getLangFromBuildTool(buildTool string) string { | ||||
| 	switch buildTool { | ||||
| 	case "maven": | ||||
| 		return "java" | ||||
| 	case "pip": | ||||
| 		return "python" | ||||
| 	case "npm": | ||||
| 		return "javascript" | ||||
| 	case "yarn": | ||||
| 		return "javascript" | ||||
| 	case "golang": | ||||
| 		return "go" | ||||
| 	default: | ||||
| 		return "" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getGitRepoInfo(repoUri string, repoInfo *RepoInfo) error { | ||||
| 	if repoUri == "" { | ||||
| 		return errors.New("repository param is not set or it cannot be auto populated") | ||||
| 	} | ||||
|  | ||||
| 	pat := regexp.MustCompile(`^(https|git)(:\/\/|@)([^\/:]+)[\/:]([^\/:]+\/[^.]+)(.git)*$`) | ||||
| 	matches := pat.FindAllStringSubmatch(repoUri, -1) | ||||
| 	if len(matches) > 0 { | ||||
| 		match := matches[0] | ||||
| 		repoInfo.serverUrl = "https://" + match[3] | ||||
| 		repoInfo.repo = match[4] | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Errorf("Invalid repository %s", repoUri) | ||||
| } | ||||
|  | ||||
| func uploadResults(config *codeqlExecuteScanOptions, utils codeqlExecuteScanUtils) error { | ||||
| 	if config.UploadResults { | ||||
| 		if len(config.GithubToken) == 0 { | ||||
| 			return errors.New("failed running upload-results as github token was not specified") | ||||
| 		} | ||||
|  | ||||
| 		var repoInfo RepoInfo | ||||
| 		err := getGitRepoInfo(config.Repository, &repoInfo) | ||||
| 		if err != nil { | ||||
| 			log.Entry().Error(err) | ||||
| 		} | ||||
| 		repoInfo.ref = config.AnalyzedRef | ||||
| 		repoInfo.commitId = config.CommitID | ||||
|  | ||||
| 		provider, err := orchestrator.NewOrchestratorSpecificConfigProvider() | ||||
| 		if err != nil { | ||||
| 			log.Entry().Error(err) | ||||
| 		} else { | ||||
| 			if repoInfo.ref == "" { | ||||
| 				repoInfo.ref = provider.GetReference() | ||||
| 			} | ||||
|  | ||||
| 			if repoInfo.commitId == "" { | ||||
| 				repoInfo.commitId = provider.GetCommit() | ||||
| 			} | ||||
|  | ||||
| 			if repoInfo.serverUrl == "" { | ||||
| 				err = getGitRepoInfo(provider.GetRepoURL(), &repoInfo) | ||||
| 				if err != nil { | ||||
| 					log.Entry().Error(err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		cmd := []string{"github", "upload-results", "--sarif=" + fmt.Sprintf("%vtarget/codeqlReport.sarif", config.ModulePath), "-a=" + config.GithubToken} | ||||
|  | ||||
| 		if repoInfo.commitId != "" { | ||||
| 			cmd = append(cmd, "--commit="+repoInfo.commitId) | ||||
| 		} | ||||
|  | ||||
| 		if repoInfo.serverUrl != "" { | ||||
| 			cmd = append(cmd, "--github-url="+repoInfo.serverUrl) | ||||
| 		} | ||||
|  | ||||
| 		if repoInfo.repo != "" { | ||||
| 			cmd = append(cmd, "--repository="+repoInfo.repo) | ||||
| 		} | ||||
|  | ||||
| 		if repoInfo.ref != "" { | ||||
| 			cmd = append(cmd, "--ref="+repoInfo.ref) | ||||
| 		} | ||||
|  | ||||
| 		//if no git pramas are passed(commitId, reference, serverUrl, repository), then codeql tries to auto populate it based on git information of the checkout repository. | ||||
| 		//It also depends on the orchestrator. Some orchestrator keep git information and some not. | ||||
| 		err = execute(utils, cmd, GeneralConfig.Verbose) | ||||
| 		if err != nil { | ||||
| 			log.Entry().Error("failed to upload sarif results") | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func runCodeqlExecuteScan(config *codeqlExecuteScanOptions, telemetryData *telemetry.CustomData, utils codeqlExecuteScanUtils) error { | ||||
| 	var reports []piperutils.Path | ||||
| 	cmd := []string{"database", "create", "db", "--overwrite", "--source-root", config.ModulePath} | ||||
|  | ||||
| 	language := getLangFromBuildTool(config.BuildTool) | ||||
|  | ||||
| 	if len(language) == 0 && len(config.Language) == 0 { | ||||
| 		if config.BuildTool == "custom" { | ||||
| 			return fmt.Errorf("as the buildTool is custom. please atleast specify the language parameter") | ||||
| 		} else { | ||||
| 			return fmt.Errorf("the step could not recognize the specified buildTool %s. please specify valid buildtool", config.BuildTool) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	cmd = append(cmd, "--language="+language) | ||||
| 	if len(config.Language) > 0 { | ||||
| 		cmd = append(cmd, "--language="+config.Language) | ||||
| 	} | ||||
|  | ||||
| 	//codeql has an autobuilder which tries to build the project based on specified programming language | ||||
| 	if len(config.BuildCommand) > 0 { | ||||
| 		cmd = append(cmd, "--command="+config.BuildCommand) | ||||
| 	} | ||||
|  | ||||
| 	err := execute(utils, cmd, GeneralConfig.Verbose) | ||||
| 	if err != nil { | ||||
| 		log.Entry().Error("failed running command codeql database create") | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	os.MkdirAll(fmt.Sprintf("%vtarget", config.ModulePath), os.ModePerm) | ||||
|  | ||||
| 	cmd = nil | ||||
| 	cmd = append(cmd, "database", "analyze", "--format=sarif-latest", fmt.Sprintf("--output=%vtarget/codeqlReport.sarif", config.ModulePath), "db") | ||||
| 	cmd = codeqlQuery(cmd, config.QuerySuite) | ||||
| 	err = execute(utils, cmd, GeneralConfig.Verbose) | ||||
| 	if err != nil { | ||||
| 		log.Entry().Error("failed running command codeql database analyze for sarif generation") | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/codeqlReport.sarif", config.ModulePath)}) | ||||
|  | ||||
| 	cmd = nil | ||||
| 	cmd = append(cmd, "database", "analyze", "--format=csv", fmt.Sprintf("--output=%vtarget/codeqlReport.csv", config.ModulePath), "db") | ||||
| 	cmd = codeqlQuery(cmd, config.QuerySuite) | ||||
| 	err = execute(utils, cmd, GeneralConfig.Verbose) | ||||
| 	if err != nil { | ||||
| 		log.Entry().Error("failed running command codeql database analyze for csv generation") | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/codeqlReport.csv", config.ModulePath)}) | ||||
|  | ||||
| 	piperutils.PersistReportsAndLinks("codeqlExecuteScan", "./", reports, nil) | ||||
|  | ||||
| 	err = uploadResults(config, utils) | ||||
| 	if err != nil { | ||||
| 		log.Entry().Error("failed to upload results") | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										335
									
								
								cmd/codeqlExecuteScan_generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								cmd/codeqlExecuteScan_generated.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,335 @@ | ||||
| // Code generated by piper's step-generator. DO NOT EDIT. | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/config" | ||||
| 	"github.com/SAP/jenkins-library/pkg/gcs" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/splunk" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/SAP/jenkins-library/pkg/validation" | ||||
| 	"github.com/bmatcuk/doublestar" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type codeqlExecuteScanOptions struct { | ||||
| 	GithubToken   string `json:"githubToken,omitempty"` | ||||
| 	BuildTool     string `json:"buildTool,omitempty" validate:"possible-values=custom maven golang npm pip yarn"` | ||||
| 	BuildCommand  string `json:"buildCommand,omitempty"` | ||||
| 	Language      string `json:"language,omitempty"` | ||||
| 	ModulePath    string `json:"modulePath,omitempty"` | ||||
| 	QuerySuite    string `json:"querySuite,omitempty"` | ||||
| 	UploadResults bool   `json:"uploadResults,omitempty"` | ||||
| 	AnalyzedRef   string `json:"analyzedRef,omitempty"` | ||||
| 	Repository    string `json:"repository,omitempty"` | ||||
| 	CommitID      string `json:"commitId,omitempty"` | ||||
| } | ||||
|  | ||||
| type codeqlExecuteScanReports struct { | ||||
| } | ||||
|  | ||||
| func (p *codeqlExecuteScanReports) persist(stepConfig codeqlExecuteScanOptions, gcpJsonKeyFilePath string, gcsBucketId string, gcsFolderPath string, gcsSubFolder string) { | ||||
| 	if gcsBucketId == "" { | ||||
| 		log.Entry().Info("persisting reports to GCS is disabled, because gcsBucketId is empty") | ||||
| 		return | ||||
| 	} | ||||
| 	log.Entry().Info("Uploading reports to Google Cloud Storage...") | ||||
| 	content := []gcs.ReportOutputParam{ | ||||
| 		{FilePattern: "**/*.csv", ParamRef: "", StepResultType: "codeql"}, | ||||
| 		{FilePattern: "**/*.sarif", ParamRef: "", StepResultType: "codeql"}, | ||||
| 	} | ||||
| 	envVars := []gcs.EnvVar{ | ||||
| 		{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: gcpJsonKeyFilePath, Modified: false}, | ||||
| 	} | ||||
| 	gcsClient, err := gcs.NewClient(gcs.WithEnvVars(envVars)) | ||||
| 	if err != nil { | ||||
| 		log.Entry().Errorf("creation of GCS client failed: %v", err) | ||||
| 		return | ||||
| 	} | ||||
| 	defer gcsClient.Close() | ||||
| 	structVal := reflect.ValueOf(&stepConfig).Elem() | ||||
| 	inputParameters := map[string]string{} | ||||
| 	for i := 0; i < structVal.NumField(); i++ { | ||||
| 		field := structVal.Type().Field(i) | ||||
| 		if field.Type.String() == "string" { | ||||
| 			paramName := strings.Split(field.Tag.Get("json"), ",") | ||||
| 			paramValue, _ := structVal.Field(i).Interface().(string) | ||||
| 			inputParameters[paramName[0]] = paramValue | ||||
| 		} | ||||
| 	} | ||||
| 	if err := gcs.PersistReportsToGCS(gcsClient, content, inputParameters, gcsFolderPath, gcsBucketId, gcsSubFolder, doublestar.Glob, os.Stat); err != nil { | ||||
| 		log.Entry().Errorf("failed to persist reports: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CodeqlExecuteScanCommand This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws. | ||||
| func CodeqlExecuteScanCommand() *cobra.Command { | ||||
| 	const STEP_NAME = "codeqlExecuteScan" | ||||
|  | ||||
| 	metadata := codeqlExecuteScanMetadata() | ||||
| 	var stepConfig codeqlExecuteScanOptions | ||||
| 	var startTime time.Time | ||||
| 	var reports codeqlExecuteScanReports | ||||
| 	var logCollector *log.CollectorHook | ||||
| 	var splunkClient *splunk.Splunk | ||||
| 	telemetryClient := &telemetry.Telemetry{} | ||||
|  | ||||
| 	var createCodeqlExecuteScanCmd = &cobra.Command{ | ||||
| 		Use:   STEP_NAME, | ||||
| 		Short: "This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws.", | ||||
| 		Long: `This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws. | ||||
|  | ||||
| The codeql step triggers a scan locally on your orchestrator (e.g. Jenkins) within a docker container so finally you have to supply a docker image with codeql | ||||
| and Java plus Maven.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName(STEP_NAME) | ||||
| 			log.SetVerbose(GeneralConfig.Verbose) | ||||
|  | ||||
| 			GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens) | ||||
|  | ||||
| 			path, _ := os.Getwd() | ||||
| 			fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path} | ||||
| 			log.RegisterHook(fatalHook) | ||||
|  | ||||
| 			err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile) | ||||
| 			if err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
| 			log.RegisterSecret(stepConfig.GithubToken) | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { | ||||
| 				sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) | ||||
| 				log.RegisterHook(&sentryHook) | ||||
| 			} | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient = &splunk.Splunk{} | ||||
| 				logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID} | ||||
| 				log.RegisterHook(logCollector) | ||||
| 			} | ||||
|  | ||||
| 			if err = log.RegisterANSHookIfConfigured(GeneralConfig.CorrelationID); err != nil { | ||||
| 				log.Entry().WithError(err).Warn("failed to set up SAP Alert Notification Service log hook") | ||||
| 			} | ||||
|  | ||||
| 			validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err = validation.ValidateStruct(stepConfig); err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		}, | ||||
| 		Run: func(_ *cobra.Command, _ []string) { | ||||
| 			stepTelemetryData := telemetry.CustomData{} | ||||
| 			stepTelemetryData.ErrorCode = "1" | ||||
| 			handler := func() { | ||||
| 				reports.persist(stepConfig, GeneralConfig.GCPJsonKeyFilePath, GeneralConfig.GCSBucketId, GeneralConfig.GCSFolderPath, GeneralConfig.GCSSubFolder) | ||||
| 				config.RemoveVaultSecretFiles() | ||||
| 				stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) | ||||
| 				stepTelemetryData.ErrorCategory = log.GetErrorCategory().String() | ||||
| 				stepTelemetryData.PiperCommitHash = GitCommit | ||||
| 				telemetryClient.SetData(&stepTelemetryData) | ||||
| 				telemetryClient.Send() | ||||
| 				if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 					splunkClient.Send(telemetryClient.GetData(), logCollector) | ||||
| 				} | ||||
| 			} | ||||
| 			log.DeferExitHandler(handler) | ||||
| 			defer handler() | ||||
| 			telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME) | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient.Initialize(GeneralConfig.CorrelationID, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Dsn, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Token, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Index, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.SendLogs) | ||||
| 			} | ||||
| 			codeqlExecuteScan(stepConfig, &stepTelemetryData) | ||||
| 			stepTelemetryData.ErrorCode = "0" | ||||
| 			log.Entry().Info("SUCCESS") | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	addCodeqlExecuteScanFlags(createCodeqlExecuteScanCmd, &stepConfig) | ||||
| 	return createCodeqlExecuteScanCmd | ||||
| } | ||||
|  | ||||
| func addCodeqlExecuteScanFlags(cmd *cobra.Command, stepConfig *codeqlExecuteScanOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.GithubToken, "githubToken", os.Getenv("PIPER_githubToken"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line") | ||||
| 	cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", `maven`, "Defines the build tool which is used for building the project.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.BuildCommand, "buildCommand", os.Getenv("PIPER_buildCommand"), "Command to build the project") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Language, "language", os.Getenv("PIPER_language"), "The programming language used to analyze.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ModulePath, "modulePath", `./`, "Allows providing the path for the module to scan") | ||||
| 	cmd.Flags().StringVar(&stepConfig.QuerySuite, "querySuite", os.Getenv("PIPER_querySuite"), "The name of a CodeQL query suite. If omitted, the default query suite for the language of the database being analyzed will be used.") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.UploadResults, "uploadResults", false, "Allows you to upload codeql SARIF results to your github project. You will need to set githubToken for this.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.AnalyzedRef, "analyzedRef", os.Getenv("PIPER_analyzedRef"), "Name of the ref that was analyzed.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "URL of the GitHub instance") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CommitID, "commitId", os.Getenv("PIPER_commitId"), "SHA of commit that was analyzed.") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("buildTool") | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| func codeqlExecuteScanMetadata() config.StepData { | ||||
| 	var theMetaData = config.StepData{ | ||||
| 		Metadata: config.StepMetadata{ | ||||
| 			Name:        "codeqlExecuteScan", | ||||
| 			Aliases:     []config.Alias{}, | ||||
| 			Description: "This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws.", | ||||
| 		}, | ||||
| 		Spec: config.StepSpec{ | ||||
| 			Inputs: config.StepInputs{ | ||||
| 				Secrets: []config.StepSecrets{ | ||||
| 					{Name: "githubTokenCredentialsId", Description: "Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub.", Type: "jenkins"}, | ||||
| 				}, | ||||
| 				Parameters: []config.StepParameters{ | ||||
| 					{ | ||||
| 						Name: "githubToken", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name: "githubTokenCredentialsId", | ||||
| 								Type: "secret", | ||||
| 							}, | ||||
|  | ||||
| 							{ | ||||
| 								Name:    "githubVaultSecretName", | ||||
| 								Type:    "vaultSecret", | ||||
| 								Default: "github", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{{Name: "access_token"}}, | ||||
| 						Default:   os.Getenv("PIPER_githubToken"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "buildTool", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `maven`, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "buildCommand", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_buildCommand"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "language", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_language"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "modulePath", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `./`, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "querySuite", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_querySuite"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "uploadResults", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "analyzedRef", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "git/ref", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_analyzedRef"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "repository", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "git/httpsUrl", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{{Name: "githubRepo"}}, | ||||
| 						Default:   os.Getenv("PIPER_repository"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "commitId", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "git/commitId", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_commitId"), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
| 				{}, | ||||
| 			}, | ||||
| 			Outputs: config.StepOutputs{ | ||||
| 				Resources: []config.StepResources{ | ||||
| 					{ | ||||
| 						Name: "reports", | ||||
| 						Type: "reports", | ||||
| 						Parameters: []map[string]interface{}{ | ||||
| 							{"filePattern": "**/*.csv", "type": "codeql"}, | ||||
| 							{"filePattern": "**/*.sarif", "type": "codeql"}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return theMetaData | ||||
| } | ||||
							
								
								
									
										17
									
								
								cmd/codeqlExecuteScan_generated_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/codeqlExecuteScan_generated_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestCodeqlExecuteScanCommand(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	testCmd := CodeqlExecuteScanCommand() | ||||
|  | ||||
| 	// only high level testing performed - details are tested in step generation procedure | ||||
| 	assert.Equal(t, "codeqlExecuteScan", testCmd.Use, "command name incorrect") | ||||
|  | ||||
| } | ||||
							
								
								
									
										85
									
								
								cmd/codeqlExecuteScan_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								cmd/codeqlExecuteScan_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| type codeqlExecuteScanMockUtils struct { | ||||
| 	*mock.ExecMockRunner | ||||
| 	*mock.FilesMock | ||||
| } | ||||
|  | ||||
| func newCodeqlExecuteScanTestsUtils() codeqlExecuteScanMockUtils { | ||||
| 	utils := codeqlExecuteScanMockUtils{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 		FilesMock:      &mock.FilesMock{}, | ||||
| 	} | ||||
| 	return utils | ||||
| } | ||||
|  | ||||
| func TestRunCodeqlExecuteScan(t *testing.T) { | ||||
|  | ||||
| 	t.Run("Valid CodeqlExecuteScan", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "maven", ModulePath: "./"} | ||||
| 		assert.Equal(t, nil, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("No auth token passed on upload results", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "maven", UploadResults: true, ModulePath: "./"} | ||||
| 		assert.Error(t, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Upload results with token", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "maven", ModulePath: "./", UploadResults: true, GithubToken: "test"} | ||||
| 		assert.Equal(t, nil, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Custom buildtool", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "custom", Language: "javascript", ModulePath: "./", GithubToken: "test"} | ||||
| 		assert.Equal(t, nil, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Custom buildtool but no language specified", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "custom", ModulePath: "./", GithubToken: "test"} | ||||
| 		assert.Error(t, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Invalid buildtool and no language specified", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "test", ModulePath: "./", GithubToken: "test"} | ||||
| 		assert.Error(t, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Invalid buildtool but language specified", func(t *testing.T) { | ||||
| 		config := codeqlExecuteScanOptions{BuildTool: "test", Language: "javascript", ModulePath: "./", GithubToken: "test"} | ||||
| 		assert.Equal(t, nil, runCodeqlExecuteScan(&config, nil, newCodeqlExecuteScanTestsUtils())) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestGetGitRepoInfo(t *testing.T) { | ||||
| 	t.Run("Valid URL1", func(t *testing.T) { | ||||
| 		var repoInfo RepoInfo | ||||
| 		getGitRepoInfo("https://github.hello.test/Testing/fortify.git", &repoInfo) | ||||
| 		assert.Equal(t, "https://github.hello.test", repoInfo.serverUrl) | ||||
| 		assert.Equal(t, "Testing/fortify", repoInfo.repo) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Valid URL2", func(t *testing.T) { | ||||
| 		var repoInfo RepoInfo | ||||
| 		getGitRepoInfo("https://github.hello.test/Testing/fortify", &repoInfo) | ||||
| 		assert.Equal(t, "https://github.hello.test", repoInfo.serverUrl) | ||||
| 		assert.Equal(t, "Testing/fortify", repoInfo.repo) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Invalid URL as no org/owner passed", func(t *testing.T) { | ||||
| 		var repoInfo RepoInfo | ||||
| 		assert.Error(t, getGitRepoInfo("https://github.com/fortify", &repoInfo)) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Invalid URL as no protocol passed", func(t *testing.T) { | ||||
| 		var repoInfo RepoInfo | ||||
| 		assert.Error(t, getGitRepoInfo("github.hello.test/Testing/fortify", &repoInfo)) | ||||
| 	}) | ||||
| } | ||||
| @@ -45,6 +45,7 @@ func GetAllStepMetadata() map[string]config.StepData { | ||||
| 		"cloudFoundryDeleteSpace":                   cloudFoundryDeleteSpaceMetadata(), | ||||
| 		"cloudFoundryDeploy":                        cloudFoundryDeployMetadata(), | ||||
| 		"cnbBuild":                                  cnbBuildMetadata(), | ||||
| 		"codeqlExecuteScan":                         codeqlExecuteScanMetadata(), | ||||
| 		"containerExecuteStructureTests":            containerExecuteStructureTestsMetadata(), | ||||
| 		"containerSaveImage":                        containerSaveImageMetadata(), | ||||
| 		"detectExecuteScan":                         detectExecuteScanMetadata(), | ||||
|   | ||||
| @@ -112,6 +112,7 @@ func Execute() { | ||||
| 	rootCmd.AddCommand(AbapEnvironmentCreateSystemCommand()) | ||||
| 	rootCmd.AddCommand(CheckmarxExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(FortifyExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(CodeqlExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(MtaBuildCommand()) | ||||
| 	rootCmd.AddCommand(ProtecodeExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(MavenExecuteCommand()) | ||||
|   | ||||
							
								
								
									
										7
									
								
								documentation/docs/steps/codeqlExecuteScan.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								documentation/docs/steps/codeqlExecuteScan.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # ${docGenStepName} | ||||
|  | ||||
| ## ${docGenDescription} | ||||
|  | ||||
| ## ${docGenParameters} | ||||
|  | ||||
| ## ${docGenConfiguration} | ||||
| @@ -89,6 +89,7 @@ nav: | ||||
|         - cloudFoundryDeleteService: steps/cloudFoundryDeleteService.md | ||||
|         - cloudFoundryDeploy: steps/cloudFoundryDeploy.md | ||||
|         - cnbBuild: steps/cnbBuild.md | ||||
|         - codeqlExecuteScan: steps/codeqlExecuteScan.md | ||||
|         - commonPipelineEnvironment: steps/commonPipelineEnvironment.md | ||||
|         - containerExecuteStructureTests: steps/containerExecuteStructureTests.md | ||||
|         - containerPushToRegistry: steps/containerPushToRegistry.md | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	piperHttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	piperHttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| type AzureDevOpsConfigProvider struct { | ||||
| @@ -192,6 +193,11 @@ func (a *AzureDevOpsConfigProvider) GetBranch() string { | ||||
| 	return strings.TrimPrefix(tmp, "refs/heads/") | ||||
| } | ||||
|  | ||||
| // GetReference return the git reference | ||||
| func (a *AzureDevOpsConfigProvider) GetReference() string { | ||||
| 	return getEnv("BUILD_SOURCEBRANCH", "n/a") | ||||
| } | ||||
|  | ||||
| // GetBuildURL returns the builds URL e.g. https://dev.azure.com/fabrikamfiber/your-repo-name/_build/results?buildId=1234 | ||||
| func (a *AzureDevOpsConfigProvider) GetBuildURL() string { | ||||
| 	return os.Getenv("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI") + os.Getenv("SYSTEM_TEAMPROJECT") + "/" + os.Getenv("SYSTEM_DEFINITIONNAME") + "/_build/results?buildId=" + a.getAzureBuildID() | ||||
|   | ||||
| @@ -2,14 +2,15 @@ package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/jarcoal/httpmock" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/jarcoal/httpmock" | ||||
| 	"github.com/pkg/errors" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| @@ -18,7 +19,7 @@ func TestAzure(t *testing.T) { | ||||
| 		defer resetEnv(os.Environ()) | ||||
| 		os.Clearenv() | ||||
| 		os.Setenv("AZURE_HTTP_USER_AGENT", "FOO BAR BAZ") | ||||
| 		os.Setenv("BUILD_SOURCEBRANCH", "feat/test-azure") | ||||
| 		os.Setenv("BUILD_SOURCEBRANCH", "refs/heads/feat/test-azure") | ||||
| 		os.Setenv("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://pogo.sap/") | ||||
| 		os.Setenv("SYSTEM_TEAMPROJECT", "foo") | ||||
| 		os.Setenv("BUILD_BUILDID", "42") | ||||
| @@ -30,6 +31,7 @@ func TestAzure(t *testing.T) { | ||||
|  | ||||
| 		assert.False(t, p.IsPullRequest()) | ||||
| 		assert.Equal(t, "feat/test-azure", p.GetBranch()) | ||||
| 		assert.Equal(t, "refs/heads/feat/test-azure", p.GetReference()) | ||||
| 		assert.Equal(t, "https://pogo.sap/foo/bar/_build/results?buildId=42", p.GetBuildURL()) | ||||
| 		assert.Equal(t, "abcdef42713", p.GetCommit()) | ||||
| 		assert.Equal(t, "github.com/foo/bar", p.GetRepoURL()) | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| type GitHubActionsConfigProvider struct{} | ||||
| @@ -53,6 +54,10 @@ func (g *GitHubActionsConfigProvider) GetBranch() string { | ||||
| 	return strings.TrimPrefix(getEnv("GITHUB_REF", "n/a"), "refs/heads/") | ||||
| } | ||||
|  | ||||
| func (g *GitHubActionsConfigProvider) GetReference() string { | ||||
| 	return getEnv("GITHUB_REF", "n/a") | ||||
| } | ||||
|  | ||||
| func (g *GitHubActionsConfigProvider) GetBuildURL() string { | ||||
| 	return g.GetRepoURL() + "/actions/runs/" + getEnv("GITHUB_RUN_ID", "n/a") | ||||
| } | ||||
|   | ||||
| @@ -24,6 +24,7 @@ func TestGitHubActions(t *testing.T) { | ||||
| 		assert.False(t, p.IsPullRequest()) | ||||
| 		assert.Equal(t, "github.com/foo/bar/actions/runs/42", p.GetBuildURL()) | ||||
| 		assert.Equal(t, "feat/test-gh-actions", p.GetBranch()) | ||||
| 		assert.Equal(t, "refs/heads/feat/test-gh-actions", p.GetReference()) | ||||
| 		assert.Equal(t, "abcdef42713", p.GetCommit()) | ||||
| 		assert.Equal(t, "github.com/foo/bar", p.GetRepoURL()) | ||||
| 		assert.Equal(t, "GitHubActions", p.OrchestratorType()) | ||||
|   | ||||
| @@ -2,12 +2,14 @@ package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io/ioutil" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/Jeffail/gabs/v2" | ||||
| 	piperHttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"io/ioutil" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type JenkinsConfigProvider struct { | ||||
| @@ -196,6 +198,18 @@ func (j *JenkinsConfigProvider) GetBranch() string { | ||||
| 	return getEnv("BRANCH_NAME", "n/a") | ||||
| } | ||||
|  | ||||
| // GetReference returns the git reference, only works with the git plugin enabled | ||||
| func (j *JenkinsConfigProvider) GetReference() string { | ||||
| 	ref := getEnv("BRANCH_NAME", "n/a") | ||||
| 	if ref == "n/a" { | ||||
| 		return ref | ||||
| 	} else if strings.Contains(ref, "PR") { | ||||
| 		return "refs/pull/" + strings.Split(ref, "-")[1] + "/head" | ||||
| 	} else { | ||||
| 		return "refs/heads/" + ref | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetBuildURL returns the build url, e.g. https://jaas.url/job/foo/job/bar/job/main/1234/ | ||||
| func (j *JenkinsConfigProvider) GetBuildURL() string { | ||||
| 	return getEnv("BUILD_URL", "n/a") | ||||
|   | ||||
| @@ -3,15 +3,17 @@ package orchestrator | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
|  | ||||
| 	"net/http" | ||||
|  | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/jarcoal/httpmock" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| func TestJenkins(t *testing.T) { | ||||
| @@ -29,6 +31,7 @@ func TestJenkins(t *testing.T) { | ||||
| 		assert.False(t, p.IsPullRequest()) | ||||
| 		assert.Equal(t, "https://jaas.url/job/foo/job/bar/job/main/1234/", p.GetBuildURL()) | ||||
| 		assert.Equal(t, "main", p.GetBranch()) | ||||
| 		assert.Equal(t, "refs/heads/main", p.GetReference()) | ||||
| 		assert.Equal(t, "abcdef42713", p.GetCommit()) | ||||
| 		assert.Equal(t, "github.com/foo/bar", p.GetRepoURL()) | ||||
| 		assert.Equal(t, "Jenkins", p.OrchestratorType()) | ||||
| @@ -46,6 +49,7 @@ func TestJenkins(t *testing.T) { | ||||
| 		c := p.GetPullRequestConfig() | ||||
|  | ||||
| 		assert.True(t, p.IsPullRequest()) | ||||
| 		assert.Equal(t, "refs/pull/42/head", p.GetReference()) | ||||
| 		assert.Equal(t, "feat/test-jenkins", c.Branch) | ||||
| 		assert.Equal(t, "main", c.Base) | ||||
| 		assert.Equal(t, "42", c.Key) | ||||
|   | ||||
| @@ -2,9 +2,10 @@ package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| type Orchestrator int | ||||
| @@ -22,6 +23,7 @@ type OrchestratorSpecificConfigProviding interface { | ||||
| 	OrchestratorVersion() string | ||||
| 	GetStageName() string | ||||
| 	GetBranch() string | ||||
| 	GetReference() string | ||||
| 	GetBuildURL() string | ||||
| 	GetBuildID() string | ||||
| 	GetJobURL() string | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| package orchestrator | ||||
|  | ||||
| import ( | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| type UnknownOrchestratorConfigProvider struct{} | ||||
| @@ -72,6 +73,12 @@ func (u *UnknownOrchestratorConfigProvider) GetBranch() string { | ||||
| 	return "n/a" | ||||
| } | ||||
|  | ||||
| // GetReference returns n/a for the unknownOrchestrator | ||||
| func (u *UnknownOrchestratorConfigProvider) GetReference() string { | ||||
| 	log.Entry().Warning("Unknown orchestrator - returning default values.") | ||||
| 	return "n/a" | ||||
| } | ||||
|  | ||||
| // GetBuildURL returns n/a for the unknownOrchestrator | ||||
| func (u *UnknownOrchestratorConfigProvider) GetBuildURL() string { | ||||
| 	log.Entry().Warning("Unknown orchestrator - returning default values.") | ||||
|   | ||||
							
								
								
									
										125
									
								
								resources/metadata/codeqlExecuteScan.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								resources/metadata/codeqlExecuteScan.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| metadata: | ||||
|   name: codeqlExecuteScan | ||||
|   description: This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws. | ||||
|   longDescription: |- | ||||
|     This step executes a codeql scan on the specified project to perform static code analysis and check the source code for security flaws. | ||||
|  | ||||
|     The codeql step triggers a scan locally on your orchestrator (e.g. Jenkins) within a docker container so finally you have to supply a docker image with codeql | ||||
|     and Java plus Maven. | ||||
|  | ||||
| spec: | ||||
|   inputs: | ||||
|     secrets: | ||||
|       - name: githubTokenCredentialsId | ||||
|         description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub. | ||||
|         type: jenkins | ||||
|     params: | ||||
|       - name: githubToken | ||||
|         description: "GitHub personal access token as per | ||||
|           https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line" | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         type: string | ||||
|         secret: true | ||||
|         aliases: | ||||
|           - name: access_token | ||||
|         resourceRef: | ||||
|           - name: githubTokenCredentialsId | ||||
|             type: secret | ||||
|           - type: vaultSecret | ||||
|             default: github | ||||
|             name: githubVaultSecretName | ||||
|       - name: buildTool | ||||
|         type: string | ||||
|         description: Defines the build tool which is used for building the project. | ||||
|         longDescription: |- | ||||
|           Based on the build tool the step will try to auto build the project. The step will try to auto select | ||||
|           the language and the build command. You can override the language and the build command by specifiying it seperatly. | ||||
|         mandatory: true | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         possibleValues: | ||||
|           - custom | ||||
|           - maven | ||||
|           - golang | ||||
|           - npm | ||||
|           - pip | ||||
|           - yarn | ||||
|         default: "maven" | ||||
|       - name: buildCommand | ||||
|         type: string | ||||
|         description: "Command to build the project" | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: language | ||||
|         type: string | ||||
|         description: "The programming language used to analyze." | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: modulePath | ||||
|         type: string | ||||
|         description: "Allows providing the path for the module to scan" | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         default: "./" | ||||
|       - name: querySuite | ||||
|         type: string | ||||
|         description: "The name of a CodeQL query suite. If omitted, the default query suite for the language of the database being analyzed will be used." | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: uploadResults | ||||
|         type: bool | ||||
|         description: "Allows you to upload codeql SARIF results to your github project. You will need to set githubToken for this." | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         default: false | ||||
|       - name: analyzedRef | ||||
|         type: string | ||||
|         description: "Name of the ref that was analyzed." | ||||
|         longDescription: |- | ||||
|           If this ref is a pull request merge commit, then use refs/pulls/1234/merge or refs/pulls/1234/head (depending on whether or not this commit corresponds to the HEAD or MERGE commit of the PR). | ||||
|           Otherwise, this should be a branch: refs/heads/branch-name. If omitted, the CLI will attempt to automatically populate this from the current branch of the checkout path, if this exists. | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: git/ref | ||||
|       - name: repository | ||||
|         aliases: | ||||
|           - name: githubRepo | ||||
|         description: "URL of the GitHub instance" | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: git/httpsUrl | ||||
|         type: string | ||||
|       - name: commitId | ||||
|         description: "SHA of commit that was analyzed." | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: git/commitId | ||||
|         type: string | ||||
|   containers: | ||||
|     - image: "" | ||||
|   outputs: | ||||
|     resources: | ||||
|       - name: reports | ||||
|         type: reports | ||||
|         params: | ||||
|           - filePattern: "**/*.csv" | ||||
|             type: codeql | ||||
|           - filePattern: "**/*.sarif" | ||||
|             type: codeql | ||||
| @@ -173,6 +173,7 @@ public class CommonStepsTest extends BasePiperTest{ | ||||
|         'gctsExecuteABAPQualityChecks', //implementing new golang pattern without fields | ||||
|         'gctsExecuteABAPUnitTests', //implementing new golang pattern without fields | ||||
|         'gctsCloneRepository', //implementing new golang pattern without fields | ||||
|         'codeqlExecuteScan', //implementing new golang pattern without fields | ||||
|         'fortifyExecuteScan', //implementing new golang pattern without fields | ||||
|         'gctsDeploy', //implementing new golang pattern without fields | ||||
|         'containerSaveImage', //implementing new golang pattern without fields | ||||
|   | ||||
| @@ -307,6 +307,30 @@ class SetupCommonPipelineEnvironmentTest extends BasePiperTest { | ||||
|         assertThat(nullScript.commonPipelineEnvironment.gitCommitId, is('dummy_git_commit_id')) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void "Set scmInfo parameter sets git reference for branch"() { | ||||
|         helper.registerAllowedMethod("fileExists", [String], { String path -> | ||||
|             return path.endsWith('.pipeline/config.yml') | ||||
|         }) | ||||
|  | ||||
|         def dummyScmInfo = [GIT_BRANCH: 'origin/testbranch'] | ||||
|  | ||||
|         stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo) | ||||
|         assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/heads/testbranch')) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void "Set scmInfo parameter sets git reference for pull request"() { | ||||
|         helper.registerAllowedMethod("fileExists", [String], { String path -> | ||||
|             return path.endsWith('.pipeline/config.yml') | ||||
|         }) | ||||
|  | ||||
|         def dummyScmInfo = [GIT_BRANCH: 'PR-42'] | ||||
|  | ||||
|         stepRule.step.setupCommonPipelineEnvironment(script: nullScript, scmInfo: dummyScmInfo) | ||||
|         assertThat(nullScript.commonPipelineEnvironment.gitRef, is('refs/pull/42/head')) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     void "No scmInfo passed as parameter yields empty git info"() { | ||||
|         helper.registerAllowedMethod("fileExists", [String], { String path -> | ||||
| @@ -319,6 +343,7 @@ class SetupCommonPipelineEnvironmentTest extends BasePiperTest { | ||||
|         assertNull(nullScript.commonPipelineEnvironment.getGitHttpsUrl()) | ||||
|         assertNull(nullScript.commonPipelineEnvironment.getGithubOrg()) | ||||
|         assertNull(nullScript.commonPipelineEnvironment.getGithubRepo()) | ||||
|         assertNull(nullScript.commonPipelineEnvironment.getGitRef()) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|   | ||||
							
								
								
									
										9
									
								
								vars/codeqlExecuteScan.groovy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vars/codeqlExecuteScan.groovy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import groovy.transform.Field | ||||
|  | ||||
| @Field String STEP_NAME = getClass().getName() | ||||
| @Field String METADATA_FILE = 'metadata/codeqlExecuteScan.yaml' | ||||
|  | ||||
| void call(Map parameters = [:]) { | ||||
|     List credentials = [[type: 'token', id: 'githubTokenCredentialsId', env: ['PIPER_githubToken']]] | ||||
|     piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials) | ||||
| } | ||||
| @@ -30,6 +30,7 @@ class commonPipelineEnvironment implements Serializable { | ||||
|     String gitSshUrl | ||||
|     String gitHttpsUrl | ||||
|     String gitBranch | ||||
|     String gitRef | ||||
|  | ||||
|     String xsDeploymentId | ||||
|  | ||||
| @@ -88,6 +89,7 @@ class commonPipelineEnvironment implements Serializable { | ||||
|         gitSshUrl = null | ||||
|         gitHttpsUrl = null | ||||
|         gitBranch = null | ||||
|         gitRef = null | ||||
|  | ||||
|         githubOrg = null | ||||
|         githubRepo = null | ||||
| @@ -199,6 +201,7 @@ class commonPipelineEnvironment implements Serializable { | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/git/branch', property: 'gitBranch'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/git/commitId', property: 'gitCommitId'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/git/httpsUrl', property: 'gitHttpsUrl'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/git/ref', property: 'gitRef'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/git/commitMessage', property: 'gitCommitMessage'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/mtarFilePath', property: 'mtarFilePath'], | ||||
|         [filename: '.pipeline/commonPipelineEnvironment/abap/addonDescriptor', property: 'abapAddonDescriptor'], | ||||
|   | ||||
| @@ -118,6 +118,7 @@ void call(Map parameters = [:]) { | ||||
|         if (scmInfo) { | ||||
|             setGitUrlsOnCommonPipelineEnvironment(script, scmInfo.GIT_URL) | ||||
|             script.commonPipelineEnvironment.setGitCommitId(scmInfo.GIT_COMMIT) | ||||
|             setGitRefOnCommonPipelineEnvironment(script, scmInfo.GIT_BRANCH) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -259,3 +260,20 @@ private void setGitUrlsOnCommonPipelineEnvironment(script, String gitUrl) { | ||||
|     script.commonPipelineEnvironment.setGithubOrg(gitFolder) | ||||
|     script.commonPipelineEnvironment.setGithubRepo(gitRepo) | ||||
| } | ||||
|  | ||||
| private void setGitRefOnCommonPipelineEnvironment(script, String gitBranch) { | ||||
|     if(!gitBranch){ | ||||
|         return | ||||
|     } | ||||
|  | ||||
|     if(gitBranch.contains("/")){ | ||||
|         gitBranch = gitBranch.split("/")[1] | ||||
|     } | ||||
|  | ||||
|     //TODO: refs for merge pull requests | ||||
|     if (gitBranch.contains("PR")) { | ||||
| 		script.commonPipelineEnvironment.setGitRef("refs/pull/" + gitBranch.split("-")[1] + "/head") | ||||
| 	} else { | ||||
| 		script.commonPipelineEnvironment.setGitRef("refs/heads/" + gitBranch) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user