You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-07-13 01:30:24 +02:00
Fortify implementation in golang (#1428)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,6 +25,7 @@ consumer-test/**/workspace
|
|||||||
/piper.exe
|
/piper.exe
|
||||||
.factorypath
|
.factorypath
|
||||||
|
|
||||||
|
debug.test
|
||||||
/cache/protecode
|
/cache/protecode
|
||||||
|
|
||||||
*errorDetails.json
|
*errorDetails.json
|
||||||
|
@ -189,7 +189,7 @@ Define ` + "`" + `buildTool: custom` + "`" + `, ` + "`" + `filePath: <path to yo
|
|||||||
|
|
||||||
func addArtifactPrepareVersionFlags(cmd *cobra.Command, stepConfig *artifactPrepareVersionOptions) {
|
func addArtifactPrepareVersionFlags(cmd *cobra.Command, stepConfig *artifactPrepareVersionOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", os.Getenv("PIPER_buildTool"), "Defines the tool which is used for building the artifact. Supports `custom`, `dub`, `golang`, `maven`, `mta`, `npm`, `pip`, `sbt`.")
|
cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", os.Getenv("PIPER_buildTool"), "Defines the tool which is used for building the artifact. Supports `custom`, `dub`, `golang`, `maven`, `mta`, `npm`, `pip`, `sbt`.")
|
||||||
cmd.Flags().StringVar(&stepConfig.CommitUserName, "commitUserName", "Project Piper", "Defines the user name which appears in version control for the versioning update (in case `versioningType: cloud`).")
|
cmd.Flags().StringVar(&stepConfig.CommitUserName, "commitUserName", `Project Piper`, "Defines the user name which appears in version control for the versioning update (in case `versioningType: cloud`).")
|
||||||
cmd.Flags().StringVar(&stepConfig.CustomVersionField, "customVersionField", os.Getenv("PIPER_customVersionField"), "For `buildTool: custom`: Defines the field which contains the version in the descriptor file.")
|
cmd.Flags().StringVar(&stepConfig.CustomVersionField, "customVersionField", os.Getenv("PIPER_customVersionField"), "For `buildTool: custom`: Defines the field which contains the version in the descriptor file.")
|
||||||
cmd.Flags().StringVar(&stepConfig.CustomVersionSection, "customVersionSection", os.Getenv("PIPER_customVersionSection"), "For `buildTool: custom`: Defines the section for version retrieval in vase a *.ini/*.cfg file is used.")
|
cmd.Flags().StringVar(&stepConfig.CustomVersionSection, "customVersionSection", os.Getenv("PIPER_customVersionSection"), "For `buildTool: custom`: Defines the section for version retrieval in vase a *.ini/*.cfg file is used.")
|
||||||
cmd.Flags().StringVar(&stepConfig.CustomVersioningScheme, "customVersioningScheme", os.Getenv("PIPER_customVersioningScheme"), "For `buildTool: custom`: Defines the versioning scheme to be used (possible options `pep440`, `maven`, `semver2`).")
|
cmd.Flags().StringVar(&stepConfig.CustomVersioningScheme, "customVersioningScheme", os.Getenv("PIPER_customVersioningScheme"), "For `buildTool: custom`: Defines the versioning scheme to be used (possible options `pep440`, `maven`, `semver2`).")
|
||||||
@ -201,11 +201,11 @@ func addArtifactPrepareVersionFlags(cmd *cobra.Command, stepConfig *artifactPrep
|
|||||||
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password/token for git authentication.")
|
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password/token for git authentication.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Maven only - Path to the mvn settings file that should be used as project settings file.")
|
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Maven only - Path to the mvn settings file that should be used as project settings file.")
|
||||||
cmd.Flags().BoolVar(&stepConfig.ShortCommitID, "shortCommitId", false, "Defines if a short version of the commitId should be used. GitHub format is used (first 7 characters).")
|
cmd.Flags().BoolVar(&stepConfig.ShortCommitID, "shortCommitId", false, "Defines if a short version of the commitId should be used. GitHub format is used (first 7 characters).")
|
||||||
cmd.Flags().StringVar(&stepConfig.TagPrefix, "tagPrefix", "build_", "Defines the prefix which is used for the git tag which is written during the versioning run (only `versioningType: cloud`).")
|
cmd.Flags().StringVar(&stepConfig.TagPrefix, "tagPrefix", `build_`, "Defines the prefix which is used for the git tag which is written during the versioning run (only `versioningType: cloud`).")
|
||||||
cmd.Flags().BoolVar(&stepConfig.UnixTimestamp, "unixTimestamp", false, "Defines if the Unix timestamp number should be used as build number instead of the standard date format.")
|
cmd.Flags().BoolVar(&stepConfig.UnixTimestamp, "unixTimestamp", false, "Defines if the Unix timestamp number should be used as build number instead of the standard date format.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User name for git authentication")
|
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User name for git authentication")
|
||||||
cmd.Flags().StringVar(&stepConfig.VersioningTemplate, "versioningTemplate", os.Getenv("PIPER_versioningTemplate"), "DEPRECATED: Defines the template for the automatic version which will be created")
|
cmd.Flags().StringVar(&stepConfig.VersioningTemplate, "versioningTemplate", os.Getenv("PIPER_versioningTemplate"), "DEPRECATED: Defines the template for the automatic version which will be created")
|
||||||
cmd.Flags().StringVar(&stepConfig.VersioningType, "versioningType", "cloud", "Defines the type of versioning (`cloud`: fully automatic, `cloud_noTag`: automatic but no tag created, `library`: manual)")
|
cmd.Flags().StringVar(&stepConfig.VersioningType, "versioningType", `cloud`, "Defines the type of versioning (`cloud`: fully automatic, `cloud_noTag`: automatic but no tag created, `library`: manual)")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("buildTool")
|
cmd.MarkFlagRequired("buildTool")
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -44,6 +45,10 @@ func (a *artifactVersioningMock) SetVersion(version string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *artifactVersioningMock) GetCoordinates() (versioning.Coordinates, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
type gitRepositoryMock struct {
|
type gitRepositoryMock struct {
|
||||||
createRemoteConfigs []*gitConfig.RemoteConfig
|
createRemoteConfigs []*gitConfig.RemoteConfig
|
||||||
createRemoteCalls int
|
createRemoteCalls int
|
||||||
|
@ -226,8 +226,8 @@ thresholds instead of ` + "`" + `percentage` + "`" + ` whereas we strongly recom
|
|||||||
|
|
||||||
func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecuteScanOptions) {
|
func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecuteScanOptions) {
|
||||||
cmd.Flags().BoolVar(&stepConfig.AvoidDuplicateProjectScans, "avoidDuplicateProjectScans", false, "Whether duplicate scans of the same project state shall be avoided or not")
|
cmd.Flags().BoolVar(&stepConfig.AvoidDuplicateProjectScans, "avoidDuplicateProjectScans", false, "Whether duplicate scans of the same project state shall be avoided or not")
|
||||||
cmd.Flags().StringVar(&stepConfig.FilterPattern, "filterPattern", "!**/node_modules/**, !**/.xmake/**, !**/*_test.go, !**/vendor/**/*.go, **/*.html, **/*.xml, **/*.go, **/*.py, **/*.js, **/*.scala, **/*.ts", "The filter pattern used to zip the files relevant for scanning, patterns can be negated by setting an exclamation mark in front i.e. `!test/*.js` would avoid adding any javascript files located in the test directory")
|
cmd.Flags().StringVar(&stepConfig.FilterPattern, "filterPattern", `!**/node_modules/**, !**/.xmake/**, !**/*_test.go, !**/vendor/**/*.go, **/*.html, **/*.xml, **/*.go, **/*.py, **/*.js, **/*.scala, **/*.ts`, "The filter pattern used to zip the files relevant for scanning, patterns can be negated by setting an exclamation mark in front i.e. `!test/*.js` would avoid adding any javascript files located in the test directory")
|
||||||
cmd.Flags().StringVar(&stepConfig.FullScanCycle, "fullScanCycle", "5", "Indicates how often a full scan should happen between the incremental scans when activated")
|
cmd.Flags().StringVar(&stepConfig.FullScanCycle, "fullScanCycle", `5`, "Indicates how often a full scan should happen between the incremental scans when activated")
|
||||||
cmd.Flags().BoolVar(&stepConfig.FullScansScheduled, "fullScansScheduled", true, "Whether full scans are to be scheduled or not. Should be used in relation with `incremental` and `fullScanCycle`")
|
cmd.Flags().BoolVar(&stepConfig.FullScansScheduled, "fullScansScheduled", true, "Whether full scans are to be scheduled or not. Should be used in relation with `incremental` and `fullScanCycle`")
|
||||||
cmd.Flags().BoolVar(&stepConfig.GeneratePdfReport, "generatePdfReport", true, "Whether to generate a PDF report of the analysis results or not")
|
cmd.Flags().BoolVar(&stepConfig.GeneratePdfReport, "generatePdfReport", true, "Whether to generate a PDF report of the analysis results or not")
|
||||||
cmd.Flags().BoolVar(&stepConfig.Incremental, "incremental", true, "Whether incremental scans are to be applied which optimizes the scan time but might reduce detection capabilities. Therefore full scans are still required from time to time and should be scheduled via `fullScansScheduled` and `fullScanCycle`")
|
cmd.Flags().BoolVar(&stepConfig.Incremental, "incremental", true, "Whether incremental scans are to be applied which optimizes the scan time but might reduce detection capabilities. Therefore full scans are still required from time to time and should be scheduled via `fullScansScheduled` and `fullScanCycle`")
|
||||||
@ -236,7 +236,7 @@ func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecu
|
|||||||
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "The name of the Checkmarx project to scan into")
|
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "The name of the Checkmarx project to scan into")
|
||||||
cmd.Flags().StringVar(&stepConfig.PullRequestName, "pullRequestName", os.Getenv("PIPER_pullRequestName"), "Used to supply the name for the newly created PR project branch when being used in pull request scenarios")
|
cmd.Flags().StringVar(&stepConfig.PullRequestName, "pullRequestName", os.Getenv("PIPER_pullRequestName"), "Used to supply the name for the newly created PR project branch when being used in pull request scenarios")
|
||||||
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL pointing to the root of the Checkmarx server to be used")
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL pointing to the root of the Checkmarx server to be used")
|
||||||
cmd.Flags().StringVar(&stepConfig.SourceEncoding, "sourceEncoding", "1", "The source encoding to be used, if not set explicitly the project's default will be used")
|
cmd.Flags().StringVar(&stepConfig.SourceEncoding, "sourceEncoding", `1`, "The source encoding to be used, if not set explicitly the project's default will be used")
|
||||||
cmd.Flags().StringVar(&stepConfig.TeamID, "teamId", os.Getenv("PIPER_teamId"), "The group ID related to your team which can be obtained via the Pipeline Syntax plugin as described in the `Details` section")
|
cmd.Flags().StringVar(&stepConfig.TeamID, "teamId", os.Getenv("PIPER_teamId"), "The group ID related to your team which can be obtained via the Pipeline Syntax plugin as described in the `Details` section")
|
||||||
cmd.Flags().StringVar(&stepConfig.TeamName, "teamName", os.Getenv("PIPER_teamName"), "The full name of the team to assign newly created projects to which is preferred to teamId")
|
cmd.Flags().StringVar(&stepConfig.TeamName, "teamName", os.Getenv("PIPER_teamName"), "The full name of the team to assign newly created projects to which is preferred to teamId")
|
||||||
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "The username to authenticate")
|
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "The username to authenticate")
|
||||||
@ -244,8 +244,8 @@ func addCheckmarxExecuteScanFlags(cmd *cobra.Command, stepConfig *checkmarxExecu
|
|||||||
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdHigh, "vulnerabilityThresholdHigh", 100, "The specific threshold for high severity findings")
|
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdHigh, "vulnerabilityThresholdHigh", 100, "The specific threshold for high severity findings")
|
||||||
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdLow, "vulnerabilityThresholdLow", 10, "The specific threshold for low severity findings")
|
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdLow, "vulnerabilityThresholdLow", 10, "The specific threshold for low severity findings")
|
||||||
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdMedium, "vulnerabilityThresholdMedium", 100, "The specific threshold for medium severity findings")
|
cmd.Flags().IntVar(&stepConfig.VulnerabilityThresholdMedium, "vulnerabilityThresholdMedium", 100, "The specific threshold for medium severity findings")
|
||||||
cmd.Flags().StringVar(&stepConfig.VulnerabilityThresholdResult, "vulnerabilityThresholdResult", "FAILURE", "The result of the build in case thresholds are enabled and exceeded")
|
cmd.Flags().StringVar(&stepConfig.VulnerabilityThresholdResult, "vulnerabilityThresholdResult", `FAILURE`, "The result of the build in case thresholds are enabled and exceeded")
|
||||||
cmd.Flags().StringVar(&stepConfig.VulnerabilityThresholdUnit, "vulnerabilityThresholdUnit", "percentage", "The unit for the threshold to apply.")
|
cmd.Flags().StringVar(&stepConfig.VulnerabilityThresholdUnit, "vulnerabilityThresholdUnit", `percentage`, "The unit for the threshold to apply.")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("password")
|
cmd.MarkFlagRequired("password")
|
||||||
cmd.MarkFlagRequired("projectName")
|
cmd.MarkFlagRequired("projectName")
|
||||||
|
@ -83,9 +83,9 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan
|
|||||||
cmd.Flags().StringVar(&stepConfig.CodeLocation, "codeLocation", os.Getenv("PIPER_codeLocation"), "An override for the name Detect will use for the scan file it creates.")
|
cmd.Flags().StringVar(&stepConfig.CodeLocation, "codeLocation", os.Getenv("PIPER_codeLocation"), "An override for the name Detect will use for the scan file it creates.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "Name of the Synopsis Detect (formerly BlackDuck) project.")
|
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", os.Getenv("PIPER_projectName"), "Name of the Synopsis Detect (formerly BlackDuck) project.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectVersion, "projectVersion", os.Getenv("PIPER_projectVersion"), "Version of the Synopsis Detect (formerly BlackDuck) project.")
|
cmd.Flags().StringVar(&stepConfig.ProjectVersion, "projectVersion", os.Getenv("PIPER_projectVersion"), "Version of the Synopsis Detect (formerly BlackDuck) project.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.Scanners, "scanners", []string{"signature"}, "List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.")
|
cmd.Flags().StringSliceVar(&stepConfig.Scanners, "scanners", []string{`signature`}, "List of scanners to be used for Synopsis Detect (formerly BlackDuck) scan.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.ScanPaths, "scanPaths", []string{"."}, "List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.")
|
cmd.Flags().StringSliceVar(&stepConfig.ScanPaths, "scanPaths", []string{`.`}, "List of paths which should be scanned by the Synopsis Detect (formerly BlackDuck) scan.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.ScanProperties, "scanProperties", []string{"--blackduck.signature.scanner.memory=4096", "--blackduck.timeout=6000", "--blackduck.trust.cert=true", "--detect.policy.check.fail.on.severities=BLOCKER,CRITICAL,MAJOR", "--detect.report.timeout=4800", "--logging.level.com.synopsys.integration=DEBUG"}, "Properties passed to the Synopsis Detect (formerly BlackDuck) scan. You can find details in the [Synopsis Detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/622846/Using+Synopsys+Detect+Properties)")
|
cmd.Flags().StringSliceVar(&stepConfig.ScanProperties, "scanProperties", []string{`--blackduck.signature.scanner.memory=4096`, `--blackduck.timeout=6000`, `--blackduck.trust.cert=true`, `--detect.policy.check.fail.on.severities=BLOCKER,CRITICAL,MAJOR`, `--detect.report.timeout=4800`, `--logging.level.com.synopsys.integration=DEBUG`}, "Properties passed to the Synopsis Detect (formerly BlackDuck) scan. You can find details in the [Synopsis Detect documentation](https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/622846/Using+Synopsys+Detect+Properties)")
|
||||||
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Server url to the Synopsis Detect (formerly BlackDuck) Server.")
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Server url to the Synopsis Detect (formerly BlackDuck) Server.")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("apiToken")
|
cmd.MarkFlagRequired("apiToken")
|
||||||
|
690
cmd/fortifyExecuteScan.go
Normal file
690
cmd/fortifyExecuteScan.go
Normal file
@ -0,0 +1,690 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v28/github"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/piper-validation/fortify-client-go/models"
|
||||||
|
|
||||||
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/fortify"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/maven"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||||
|
|
||||||
|
piperGithub "github.com/SAP/jenkins-library/pkg/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pullRequestService interface {
|
||||||
|
ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkString = "<---CHECK FORTIFY---"
|
||||||
|
const classpathFileName = "cp.txt"
|
||||||
|
|
||||||
|
func fortifyExecuteScan(config fortifyExecuteScanOptions, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux) {
|
||||||
|
auditStatus := map[string]string{}
|
||||||
|
sys := fortify.NewSystemInstance(config.ServerURL, config.APIEndpoint, config.AuthToken, time.Second*30)
|
||||||
|
c := command.Command{}
|
||||||
|
// reroute command output to logging framework
|
||||||
|
c.Stdout(log.Entry().Writer())
|
||||||
|
c.Stderr(log.Entry().Writer())
|
||||||
|
err := runFortifyScan(config, sys, &c, telemetryData, influx, auditStatus)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Fortify scan and check failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, command execRunner, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux, auditStatus map[string]string) error {
|
||||||
|
log.Entry().Debugf("Running Fortify scan against SSC at %v", config.ServerURL)
|
||||||
|
artifact, err := versioning.GetArtifact(config.BuildTool, config.BuildDescriptorFile, &versioning.Options{}, command)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get artifact from descriptor %v: %w", config.BuildDescriptorFile, err)
|
||||||
|
}
|
||||||
|
gav, err := artifact.GetCoordinates()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get project coordinates from descriptor %v: %w", config.BuildDescriptorFile, err)
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("determined project coordinates %v", gav)
|
||||||
|
fortifyProjectName, fortifyProjectVersion := versioning.DetermineProjectCoordinates(config.ProjectName, config.DefaultVersioningModel, gav)
|
||||||
|
project, err := sys.GetProjectByName(fortifyProjectName, config.AutoCreate, fortifyProjectVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to load project %v: %w", fortifyProjectName, err)
|
||||||
|
}
|
||||||
|
projectVersion, err := sys.GetProjectVersionDetailsByProjectIDAndVersionName(project.ID, fortifyProjectVersion, config.AutoCreate, fortifyProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to load project version %v: %w", fortifyProjectVersion, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.PullRequestName) > 0 {
|
||||||
|
fortifyProjectVersion = config.PullRequestName
|
||||||
|
projectVersion, err := sys.LookupOrCreateProjectVersionDetailsForPullRequest(project.ID, projectVersion, fortifyProjectVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to lookup / create project version for pull request %v: %w", fortifyProjectVersion, err)
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("Looked up / created project version with ID %v for PR %v", projectVersion.ID, fortifyProjectVersion)
|
||||||
|
} else {
|
||||||
|
prID := determinePullRequestMerge(config)
|
||||||
|
if len(prID) > 0 {
|
||||||
|
log.Entry().Debugf("Determined PR ID '%v' for merge check", prID)
|
||||||
|
pullRequestProjectName := fmt.Sprintf("PR-%v", prID)
|
||||||
|
err = sys.MergeProjectVersionStateOfPRIntoMaster(config.FprDownloadEndpoint, config.FprUploadEndpoint, project.ID, projectVersion.ID, pullRequestProjectName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to merge project version state for pull request %v into project version %v of project %v: %w", pullRequestProjectName, fortifyProjectVersion, project.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Debugf("Scanning and uploading to project %v with version %v and projectVersionId %v", fortifyProjectName, fortifyProjectVersion, projectVersion.ID)
|
||||||
|
buildLabel := fmt.Sprintf("%v/repos/%v/%v/commits/%v", config.GithubAPIURL, config.Owner, config.Repository, config.CommitID)
|
||||||
|
|
||||||
|
// Create sourceanalyzer command based on configuration
|
||||||
|
buildID := uuid.New().String()
|
||||||
|
command.SetDir(config.ModulePath)
|
||||||
|
os.MkdirAll(fmt.Sprintf("%v/%v", config.ModulePath, "target"), os.ModePerm)
|
||||||
|
|
||||||
|
if config.UpdateRulePack {
|
||||||
|
err := command.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-url", config.ServerURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("serverUrl", config.ServerURL).Fatal("Failed to update rule pack")
|
||||||
|
}
|
||||||
|
err = command.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-showInstalledRules")
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("serverUrl", config.ServerURL).Fatal("Failed to fetch details of installed rule pack")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerFortifyScan(config, command, buildID, buildLabel)
|
||||||
|
|
||||||
|
var reports []piperutils.Path
|
||||||
|
reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/fortify-scan.*", config.ModulePath)})
|
||||||
|
reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/*.fpr", config.ModulePath)})
|
||||||
|
|
||||||
|
var message string
|
||||||
|
if config.UploadResults {
|
||||||
|
log.Entry().Debug("Uploading results")
|
||||||
|
resultFilePath := fmt.Sprintf("%vtarget/result.fpr", config.ModulePath)
|
||||||
|
err = sys.UploadResultFile(config.FprUploadEndpoint, resultFilePath, projectVersion.ID)
|
||||||
|
message = fmt.Sprintf("Failed to upload result file %v to Fortify SSC at %v", resultFilePath, config.ServerURL)
|
||||||
|
} else {
|
||||||
|
log.Entry().Debug("Generating XML report")
|
||||||
|
xmlReportName := "fortify_result.xml"
|
||||||
|
err = command.RunExecutable("ReportGenerator", "-format", "xml", "-f", xmlReportName, "-source", fmt.Sprintf("%vtarget/result.fpr", config.ModulePath))
|
||||||
|
message = fmt.Sprintf("Failed to generate XML report %v", xmlReportName)
|
||||||
|
if err != nil {
|
||||||
|
reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vfortify_result.xml", config.ModulePath)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
piperutils.PersistReportsAndLinks("fortifyExecuteScan", config.ModulePath, reports, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(message+": %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Debugf("Starting audit status check on project %v with version %v and project version ID %v", fortifyProjectName, fortifyProjectVersion, projectVersion.ID)
|
||||||
|
filterSet, err := sys.GetFilterSetOfProjectVersionByTitle(projectVersion.ID, config.FilterSetTitle)
|
||||||
|
if filterSet == nil || err != nil {
|
||||||
|
return fmt.Errorf("Failed to load filter set with title %v", config.FilterSetTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure latest FPR is processed
|
||||||
|
err = verifyScanResultsFinishedUploading(config, sys, projectVersion.ID, buildLabel, filterSet, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate report
|
||||||
|
if config.Reporting {
|
||||||
|
resultURL := []byte(fmt.Sprintf("https://fortify.tools.sap/ssc/html/ssc/version/%v/fix/null/", projectVersion.ID))
|
||||||
|
ioutil.WriteFile(fmt.Sprintf("%vtarget/%v-%v.%v", config.ModulePath, *project.Name, *projectVersion.Name, "txt"), resultURL, 0700)
|
||||||
|
|
||||||
|
data, err := generateAndDownloadQGateReport(config, sys, project, projectVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ioutil.WriteFile(fmt.Sprintf("%vtarget/%v-%v.%v", config.ModulePath, *project.Name, *projectVersion.Name, config.ReportType), data, 0700)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform audit compliance checks
|
||||||
|
issueFilterSelectorSet, err := sys.GetIssueFilterSelectorOfProjectVersionByName(projectVersion.ID, []string{"Analysis", "Folder", "Category"}, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Failed to fetch project version issue filter selector for project version ID %v", projectVersion.ID)
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("initial filter selector set: %v", issueFilterSelectorSet)
|
||||||
|
numberOfViolations := analyseUnauditedIssues(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||||
|
numberOfViolations += analyseSuspiciousExploitable(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||||
|
|
||||||
|
log.Entry().Infof("Counted %v violations, details: %v", numberOfViolations, auditStatus)
|
||||||
|
|
||||||
|
influx.fortify_data.fields.projectName = fortifyProjectName
|
||||||
|
influx.fortify_data.fields.projectVersion = fortifyProjectVersion
|
||||||
|
influx.fortify_data.fields.violations = fmt.Sprintf("%v", numberOfViolations)
|
||||||
|
if numberOfViolations > 0 {
|
||||||
|
return errors.New("fortify scan failed, the project is not compliant. For details check the archived report")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) int {
|
||||||
|
log.Entry().Info("Analyzing unaudited issues")
|
||||||
|
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Folder"}, nil)
|
||||||
|
fetchedIssueGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Failed to fetch project version issue groups with filter set %v and selector %v for project version ID %v", filterSet, issueFilterSelectorSet, projectVersion.ID)
|
||||||
|
}
|
||||||
|
overallViolations := 0
|
||||||
|
for _, issueGroup := range fetchedIssueGroups {
|
||||||
|
overallViolations += getIssueDeltaFor(config, sys, issueGroup, projectVersion.ID, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||||
|
}
|
||||||
|
return overallViolations
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIssueDeltaFor(config fortifyExecuteScanOptions, sys fortify.System, issueGroup *models.ProjectVersionIssueGroup, projectVersionID int64, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) int {
|
||||||
|
totalMinusAuditedDelta := 0
|
||||||
|
group := ""
|
||||||
|
total := 0
|
||||||
|
audited := 0
|
||||||
|
if issueGroup != nil {
|
||||||
|
group = *issueGroup.ID
|
||||||
|
total = int(*issueGroup.TotalCount)
|
||||||
|
audited = int(*issueGroup.AuditedCount)
|
||||||
|
}
|
||||||
|
groupTotalMinusAuditedDelta := total - audited
|
||||||
|
if groupTotalMinusAuditedDelta > 0 {
|
||||||
|
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Folder", "Analysis"}, []string{group})
|
||||||
|
folderSelector := sys.GetFilterSetByDisplayName(reducedFilterSelectorSet, "Folder")
|
||||||
|
if folderSelector == nil {
|
||||||
|
log.Entry().Fatal("folder selector not found")
|
||||||
|
}
|
||||||
|
analysisSelector := sys.GetFilterSetByDisplayName(reducedFilterSelectorSet, "Analysis")
|
||||||
|
|
||||||
|
auditStatus[group] = fmt.Sprintf("%v total : %v audited", total, audited)
|
||||||
|
|
||||||
|
if strings.Contains(config.MustAuditIssueGroups, group) {
|
||||||
|
totalMinusAuditedDelta += groupTotalMinusAuditedDelta
|
||||||
|
if group == "Corporate Security Requirements" {
|
||||||
|
influx.fortify_data.fields.corporateTotal = fmt.Sprintf("%v", total)
|
||||||
|
influx.fortify_data.fields.corporateAudited = fmt.Sprintf("%v", audited)
|
||||||
|
}
|
||||||
|
if group == "Audit All" {
|
||||||
|
influx.fortify_data.fields.auditAllTotal = fmt.Sprintf("%v", total)
|
||||||
|
influx.fortify_data.fields.auditAllAudited = fmt.Sprintf("%v", audited)
|
||||||
|
}
|
||||||
|
log.Entry().Errorf("[projectVersionId %v]: Unaudited %v detected, count %v", projectVersionID, group, totalMinusAuditedDelta)
|
||||||
|
logIssueURL(config, projectVersionID, folderSelector, analysisSelector)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(config.SpotAuditIssueGroups, group) {
|
||||||
|
log.Entry().Infof("Analyzing %v", config.SpotAuditIssueGroups)
|
||||||
|
filter := fmt.Sprintf("%v:%v", folderSelector.EntityType, folderSelector.SelectorOptions[0].Value)
|
||||||
|
fetchedIssueGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersionID, filter, filterSet.GUID, sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Category"}, nil))
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Failed to fetch project version issue groups with filter %v, filter set %v and selector %v for project version ID %v", filter, filterSet, issueFilterSelectorSet, projectVersionID)
|
||||||
|
}
|
||||||
|
totalMinusAuditedDelta += getSpotIssueCount(config, sys, fetchedIssueGroups, projectVersionID, filterSet, reducedFilterSelectorSet, influx, auditStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalMinusAuditedDelta
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spotCheckCategories []*models.ProjectVersionIssueGroup, projectVersionID int64, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) int {
|
||||||
|
overallDelta := 0
|
||||||
|
overallIssues := 0
|
||||||
|
overallIssuesAudited := 0
|
||||||
|
for _, issueGroup := range spotCheckCategories {
|
||||||
|
group := ""
|
||||||
|
total := 0
|
||||||
|
audited := 0
|
||||||
|
if issueGroup != nil {
|
||||||
|
group = *issueGroup.ID
|
||||||
|
total = int(*issueGroup.TotalCount)
|
||||||
|
audited = int(*issueGroup.AuditedCount)
|
||||||
|
}
|
||||||
|
flagOutput := ""
|
||||||
|
|
||||||
|
if ((total <= config.SpotCheckMinimum || config.SpotCheckMinimum < 0) && audited != total) || (total > config.SpotCheckMinimum && audited < config.SpotCheckMinimum) {
|
||||||
|
currentDelta := config.SpotCheckMinimum - audited
|
||||||
|
if config.SpotCheckMinimum < 0 || config.SpotCheckMinimum > total {
|
||||||
|
currentDelta = total - audited
|
||||||
|
}
|
||||||
|
if currentDelta > 0 {
|
||||||
|
filterSelectorFolder := sys.GetFilterSetByDisplayName(issueFilterSelectorSet, "Folder")
|
||||||
|
filterSelectorAnalysis := sys.GetFilterSetByDisplayName(issueFilterSelectorSet, "Analysis")
|
||||||
|
overallDelta += currentDelta
|
||||||
|
log.Entry().Errorf("[projectVersionId %v]: %v unaudited spot check issues detected in group %v", projectVersionID, currentDelta, group)
|
||||||
|
logIssueURL(config, projectVersionID, filterSelectorFolder, filterSelectorAnalysis)
|
||||||
|
flagOutput = checkString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
overallIssues += total
|
||||||
|
overallIssuesAudited += audited
|
||||||
|
|
||||||
|
auditStatus[group] = fmt.Sprintf("%v total : %v audited %v", total, audited, flagOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
influx.fortify_data.fields.spotChecksTotal = fmt.Sprintf("%v", overallIssues)
|
||||||
|
influx.fortify_data.fields.spotChecksAudited = fmt.Sprintf("%v", overallIssuesAudited)
|
||||||
|
influx.fortify_data.fields.spotChecksGap = fmt.Sprintf("%v", overallDelta)
|
||||||
|
|
||||||
|
return overallDelta
|
||||||
|
}
|
||||||
|
|
||||||
|
func analyseSuspiciousExploitable(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) int {
|
||||||
|
log.Entry().Info("Analyzing suspicious and exploitable issues")
|
||||||
|
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Analysis"}, []string{})
|
||||||
|
fetchedGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
|
||||||
|
|
||||||
|
suspiciousCount := 0
|
||||||
|
exploitableCount := 0
|
||||||
|
for _, issueGroup := range fetchedGroups {
|
||||||
|
if *issueGroup.ID == "3" {
|
||||||
|
suspiciousCount = int(*issueGroup.TotalCount)
|
||||||
|
} else if *issueGroup.ID == "4" {
|
||||||
|
exploitableCount = int(*issueGroup.TotalCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := 0
|
||||||
|
if (suspiciousCount > 0 && config.ConsiderSuspicious) || exploitableCount > 0 {
|
||||||
|
result = result + suspiciousCount + exploitableCount
|
||||||
|
log.Entry().Errorf("[projectVersionId %v]: %v suspicious and %v exploitable issues detected", projectVersion.ID, suspiciousCount, exploitableCount)
|
||||||
|
log.Entry().Errorf("%v/html/ssc/index.jsp#!/version/%v/fix?issueGrouping=%v_%v&issueFilters=%v_%v", config.ServerURL, projectVersion.ID, reducedFilterSelectorSet.GroupBySet[0].EntityType, reducedFilterSelectorSet.GroupBySet[0].Value, reducedFilterSelectorSet.FilterBySet[0].EntityType, reducedFilterSelectorSet.FilterBySet[0].Value)
|
||||||
|
}
|
||||||
|
issueStatistics, err := sys.GetIssueStatisticsOfProjectVersion(projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Errorf("Failed to fetch project version statistics for project version ID %v", projectVersion.ID)
|
||||||
|
}
|
||||||
|
auditStatus["Suspicious"] = fmt.Sprintf("%v", suspiciousCount)
|
||||||
|
auditStatus["Exploitable"] = fmt.Sprintf("%v", exploitableCount)
|
||||||
|
suppressedCount := *issueStatistics[0].SuppressedCount
|
||||||
|
if suppressedCount > 0 {
|
||||||
|
auditStatus["Suppressed"] = fmt.Sprintf("WARNING: Detected %v suppressed issues which could violate audit compliance!!!", suppressedCount)
|
||||||
|
}
|
||||||
|
influx.fortify_data.fields.suspicious = fmt.Sprintf("%v", suspiciousCount)
|
||||||
|
influx.fortify_data.fields.exploitable = fmt.Sprintf("%v", exploitableCount)
|
||||||
|
influx.fortify_data.fields.suppressed = fmt.Sprintf("%v", suppressedCount)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func logIssueURL(config fortifyExecuteScanOptions, projectVersionID int64, folderSelector, analysisSelector *models.IssueFilterSelector) {
|
||||||
|
url := fmt.Sprintf("%v/html/ssc/index.jsp#!/version/%v/fix", config.ServerURL, projectVersionID)
|
||||||
|
if len(folderSelector.SelectorOptions) > 0 {
|
||||||
|
url += fmt.Sprintf("?issueFilters=%v_%v:%v",
|
||||||
|
folderSelector.EntityType,
|
||||||
|
folderSelector.Value,
|
||||||
|
folderSelector.SelectorOptions[0].Value)
|
||||||
|
} else {
|
||||||
|
log.Entry().Debugf("no 'filter by set' array entries")
|
||||||
|
}
|
||||||
|
if analysisSelector != nil {
|
||||||
|
url += fmt.Sprintf("&issueFilters=%v_%v:",
|
||||||
|
analysisSelector.EntityType,
|
||||||
|
analysisSelector.Value)
|
||||||
|
} else {
|
||||||
|
log.Entry().Debugf("no second entry in 'filter by set' array")
|
||||||
|
}
|
||||||
|
log.Entry().Error(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAndDownloadQGateReport(config fortifyExecuteScanOptions, sys fortify.System, project *models.Project, projectVersion *models.ProjectVersion) ([]byte, error) {
|
||||||
|
log.Entry().Infof("Generating report with template ID %v", config.ReportTemplateID)
|
||||||
|
report, err := sys.GenerateQGateReport(project.ID, projectVersion.ID, int64(config.ReportTemplateID), *project.Name, *projectVersion.Name, config.ReportType)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatal("Failed to generate Q-Gate report")
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("Triggered report generation of report ID %v", report.ID)
|
||||||
|
status := report.Status
|
||||||
|
for status != "Complete" && status != "Error Processing" {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
report, err = sys.GetReportDetails(report.ID)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("Failed to fetch Q-Gate report generation status: %w", err)
|
||||||
|
}
|
||||||
|
status = report.Status
|
||||||
|
}
|
||||||
|
data, err := sys.DownloadReportFile(config.ReportDownloadEndpoint, projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("Failed to download Q-Gate Report: %w", err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkArtifactStatus(config fortifyExecuteScanOptions, sys fortify.System, projectVersionID int64, buildLabel string, filterSet *models.FilterSet, artifact *models.Artifact, numInvokes int) error {
|
||||||
|
numInvokes++
|
||||||
|
if "PROCESSING" == artifact.Status || "SCHED_PROCESSING" == artifact.Status {
|
||||||
|
if numInvokes >= (config.PollingMinutes * 6) {
|
||||||
|
return fmt.Errorf("Terminating after %v minutes since artifact for Project Version %v is still in status %v", config.PollingMinutes, projectVersionID, artifact.Status)
|
||||||
|
}
|
||||||
|
log.Entry().Infof("Most recent artifact uploaded on %v of Project Version %v is still in status %v...", artifact.UploadDate, projectVersionID, artifact.Status)
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
return verifyScanResultsFinishedUploading(config, sys, projectVersionID, buildLabel, filterSet, numInvokes)
|
||||||
|
}
|
||||||
|
if "REQUIRE_AUTH" == artifact.Status {
|
||||||
|
// verify no manual issue approval needed
|
||||||
|
return fmt.Errorf("There are artifacts that require manual approval for Project Version %v\n%v/html/ssc/index.jsp#!/version/%v/artifacts?filterSet=%v", projectVersionID, config.ServerURL, projectVersionID, filterSet.GUID)
|
||||||
|
}
|
||||||
|
if "ERROR_PROCESSING" == artifact.Status {
|
||||||
|
return fmt.Errorf("There are artifacts that failed processing for Project Version %v\n%v/html/ssc/index.jsp#!/version/%v/artifacts?filterSet=%v", projectVersionID, config.ServerURL, projectVersionID, filterSet.GUID)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyScanResultsFinishedUploading(config fortifyExecuteScanOptions, sys fortify.System, projectVersionID int64, buildLabel string, filterSet *models.FilterSet, numInvokes int) error {
|
||||||
|
log.Entry().Debug("Verifying scan results have finished uploading and processing")
|
||||||
|
var artifacts []*models.Artifact
|
||||||
|
var relatedUpload *models.Artifact
|
||||||
|
for relatedUpload == nil {
|
||||||
|
artifacts, err := sys.GetArtifactsOfProjectVersion(projectVersionID)
|
||||||
|
log.Entry().Debugf("Received %v artifacts for project version ID %v", len(artifacts), projectVersionID)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Failed to fetch artifacts of project version ID %v", projectVersionID)
|
||||||
|
}
|
||||||
|
if len(artifacts) > 0 {
|
||||||
|
latest := artifacts[0]
|
||||||
|
if err := checkArtifactStatus(config, sys, projectVersionID, buildLabel, filterSet, latest, numInvokes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
notFound := true
|
||||||
|
for _, artifact := range artifacts {
|
||||||
|
if len(buildLabel) > 0 && artifact.Embed != nil && artifact.Embed.Scans != nil && len(artifact.Embed.Scans) > 0 {
|
||||||
|
scan := artifact.Embed.Scans[0]
|
||||||
|
if notFound && scan != nil && strings.HasSuffix(scan.BuildLabel, buildLabel) {
|
||||||
|
relatedUpload = artifact
|
||||||
|
notFound = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("No uploaded artifacts for assessment detected for project version with ID %v", projectVersionID)
|
||||||
|
}
|
||||||
|
if relatedUpload == nil {
|
||||||
|
log.Entry().Warn("Unable to identify artifact based on the build label, will consider most recent artifact as related to the scan")
|
||||||
|
relatedUpload = artifacts[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
differenceInSeconds := calculateTimeDifferenceToLastUpload(relatedUpload.UploadDate, projectVersionID)
|
||||||
|
// Use the absolute value for checking the time difference
|
||||||
|
if differenceInSeconds > float64(60*config.DeltaMinutes) {
|
||||||
|
return errors.New("No recent upload detected on Project Version")
|
||||||
|
}
|
||||||
|
warn := false
|
||||||
|
for _, upload := range artifacts {
|
||||||
|
if upload.Status == "ERROR_PROCESSING" {
|
||||||
|
warn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if warn {
|
||||||
|
log.Entry().Warn("Previous uploads detected that failed processing, please ensure that your scans are properly configured")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateTimeDifferenceToLastUpload(uploadDate models.Iso8601MilliDateTime, projectVersionID int64) float64 {
|
||||||
|
log.Entry().Infof("Last upload on project version %v happened on %v", projectVersionID, uploadDate)
|
||||||
|
uploadDateAsTime := time.Time(uploadDate)
|
||||||
|
duration := time.Since(uploadDateAsTime)
|
||||||
|
log.Entry().Debugf("Difference duration is %v", duration)
|
||||||
|
absoluteSeconds := math.Abs(duration.Seconds())
|
||||||
|
log.Entry().Infof("Difference since %v in seconds is %v", uploadDateAsTime, absoluteSeconds)
|
||||||
|
return absoluteSeconds
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeTemplatedCommand(command execRunner, cmdTemplate []string, context map[string]string) {
|
||||||
|
for index, cmdTemplatePart := range cmdTemplate {
|
||||||
|
result, err := piperutils.ExecuteTemplate(cmdTemplatePart, context)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatalf("Failed to transform template for command fragment: %v", cmdTemplatePart)
|
||||||
|
}
|
||||||
|
cmdTemplate[index] = result
|
||||||
|
}
|
||||||
|
err := command.RunExecutable(cmdTemplate[0], cmdTemplate[1:]...)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("command", cmdTemplate).Fatal("Failed to execute command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoresolvePipClasspath(executable string, parameters []string, file string, command execRunner) string {
|
||||||
|
// redirect stdout and create cp file from command output
|
||||||
|
outfile, err := os.Create(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatal("Failed to create classpath file")
|
||||||
|
}
|
||||||
|
defer outfile.Close()
|
||||||
|
command.Stdout(outfile)
|
||||||
|
err = command.RunExecutable(executable, parameters...)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("command", fmt.Sprintf("%v with parameters %v", executable, parameters)).Fatal("Failed to run classpath autodetection command")
|
||||||
|
}
|
||||||
|
command.Stdout(log.Entry().Writer())
|
||||||
|
return readClasspathFile(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoresolveMavenClasspath(pomFilePath, file string, command execRunner) string {
|
||||||
|
executeOptions := maven.ExecuteOptions{
|
||||||
|
PomPath: pomFilePath,
|
||||||
|
Goals: []string{"dependency:build-classpath"},
|
||||||
|
Defines: []string{fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile"},
|
||||||
|
ReturnStdout: false,
|
||||||
|
}
|
||||||
|
_, err := maven.Execute(&executeOptions, command)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Warn("failed to determine classpath using Maven")
|
||||||
|
}
|
||||||
|
return readClasspathFile(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readClasspathFile(file string) string {
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Warnf("failed to read classpath from file '%v'", file)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func triggerFortifyScan(config fortifyExecuteScanOptions, command execRunner, buildID, buildLabel string) {
|
||||||
|
// Do special Python related prep
|
||||||
|
pipVersion := "pip3"
|
||||||
|
if config.PythonVersion != "python3" {
|
||||||
|
pipVersion = "pip2"
|
||||||
|
}
|
||||||
|
|
||||||
|
classpath := ""
|
||||||
|
if config.BuildTool == "maven" {
|
||||||
|
if config.AutodetectClasspath {
|
||||||
|
classpath = autoresolveMavenClasspath(config.BuildDescriptorFile, classpathFileName, command)
|
||||||
|
}
|
||||||
|
if len(config.Translate) == 0 {
|
||||||
|
translate := `[{"classpath":"`
|
||||||
|
translate += classpath
|
||||||
|
translate += `","src":"**/*.xml **/*.html **/*.jsp **/*.js src/main/resources/**/* src/main/java/**/*"}]`
|
||||||
|
config.Translate = translate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.BuildTool == "pip" {
|
||||||
|
if config.AutodetectClasspath {
|
||||||
|
classpath = autoresolvePipClasspath(config.PythonVersion, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, classpathFileName, command)
|
||||||
|
}
|
||||||
|
// install the dev dependencies
|
||||||
|
if len(config.PythonRequirementsFile) > 0 {
|
||||||
|
context := map[string]string{}
|
||||||
|
cmdTemplate := []string{pipVersion, "install", "--user", "-r", config.PythonRequirementsFile}
|
||||||
|
cmdTemplate = append(cmdTemplate, tokenize(config.PythonRequirementsInstallSuffix)...)
|
||||||
|
executeTemplatedCommand(command, cmdTemplate, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
executeTemplatedCommand(command, tokenize(config.PythonInstallCommand), map[string]string{"Pip": pipVersion})
|
||||||
|
|
||||||
|
if len(config.Translate) == 0 {
|
||||||
|
translate := `[{"pythonPath":"`
|
||||||
|
translate += classpath
|
||||||
|
translate += ";"
|
||||||
|
translate += config.PythonAdditionalPath
|
||||||
|
translate += `","pythonIncludes":"`
|
||||||
|
translate += config.PythonIncludes
|
||||||
|
translate += `","pythonExcludes":"`
|
||||||
|
translate += strings.ReplaceAll(config.PythonExcludes, "-exclude ", "")
|
||||||
|
translate += `"}]`
|
||||||
|
config.Translate = translate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
translateProject(&config, command, buildID, classpath)
|
||||||
|
|
||||||
|
scanProject(&config, command, buildID, buildLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateProject(config *fortifyExecuteScanOptions, command execRunner, buildID, classpath string) {
|
||||||
|
var translateList []map[string]string
|
||||||
|
json.Unmarshal([]byte(config.Translate), &translateList)
|
||||||
|
log.Entry().Debugf("Translating with options: %v", translateList)
|
||||||
|
for _, translate := range translateList {
|
||||||
|
if len(classpath) > 0 {
|
||||||
|
translate["autoClasspath"] = classpath
|
||||||
|
}
|
||||||
|
handleSingleTranslate(config, command, buildID, translate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSingleTranslate(config *fortifyExecuteScanOptions, command execRunner, buildID string, t map[string]string) {
|
||||||
|
if t != nil {
|
||||||
|
log.Entry().Debugf("Handling translate config %v", t)
|
||||||
|
translateOptions := []string{
|
||||||
|
"-verbose",
|
||||||
|
"-64",
|
||||||
|
"-b",
|
||||||
|
buildID,
|
||||||
|
}
|
||||||
|
translateOptions = append(translateOptions, tokenize(config.Memory)...)
|
||||||
|
translateOptions = appendToOptions(config, translateOptions, t)
|
||||||
|
log.Entry().Debugf("Running sourceanalyzer translate command with options %v", translateOptions)
|
||||||
|
err := command.RunExecutable("sourceanalyzer", translateOptions...)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("translateOptions", translateOptions).Fatal("failed to execute sourceanalyzer translate command")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Entry().Debug("Skipping translate with nil value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanProject(config *fortifyExecuteScanOptions, command execRunner, buildID, buildLabel string) {
|
||||||
|
var scanOptions = []string{
|
||||||
|
"-verbose",
|
||||||
|
"-64",
|
||||||
|
"-b",
|
||||||
|
buildID,
|
||||||
|
"-scan",
|
||||||
|
}
|
||||||
|
scanOptions = append(scanOptions, tokenize(config.Memory)...)
|
||||||
|
if config.QuickScan {
|
||||||
|
scanOptions = append(scanOptions, "-quick")
|
||||||
|
}
|
||||||
|
if len(buildLabel) > 0 {
|
||||||
|
scanOptions = append(scanOptions, "-build-label", buildLabel)
|
||||||
|
}
|
||||||
|
scanOptions = append(scanOptions, "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr")
|
||||||
|
|
||||||
|
err := command.RunExecutable("sourceanalyzer", scanOptions...)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).WithField("scanOptions", scanOptions).Fatal("failed to execute sourceanalyzer scan command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func determinePullRequestMerge(config fortifyExecuteScanOptions) string {
|
||||||
|
ctx, client, err := piperGithub.NewClient(config.GithubToken, config.GithubAPIURL, "")
|
||||||
|
if err == nil {
|
||||||
|
result, err := determinePullRequestMergeGithub(ctx, config, client.PullRequests)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Warn("Failed to get PR metadata via GitHub client")
|
||||||
|
} else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Infof("Trying to determine PR ID in commit message: %v", config.CommitMessage)
|
||||||
|
r, _ := regexp.Compile(config.PullRequestMessageRegex)
|
||||||
|
matches := r.FindSubmatch([]byte(config.CommitMessage))
|
||||||
|
if matches != nil && len(matches) > 1 {
|
||||||
|
return string(matches[config.PullRequestMessageRegexGroup])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func determinePullRequestMergeGithub(ctx context.Context, config fortifyExecuteScanOptions, pullRequestServiceInstance pullRequestService) (string, error) {
|
||||||
|
options := github.PullRequestListOptions{State: "closed", Sort: "updated", Direction: "desc"}
|
||||||
|
prList, _, err := pullRequestServiceInstance.ListPullRequestsWithCommit(ctx, config.Owner, config.Repository, config.CommitID, &options)
|
||||||
|
if err == nil && len(prList) > 0 {
|
||||||
|
return fmt.Sprintf("%v", prList[0].GetNumber()), nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendToOptions(config *fortifyExecuteScanOptions, options []string, t map[string]string) []string {
|
||||||
|
if config.BuildTool == "windows" {
|
||||||
|
if len(t["aspnetcore"]) > 0 {
|
||||||
|
options = append(options, "-aspnetcore")
|
||||||
|
}
|
||||||
|
if len(t["dotNetCoreVersion"]) > 0 {
|
||||||
|
options = append(options, "-dotnet-core-version", t["dotNetCoreVersion"])
|
||||||
|
}
|
||||||
|
if len(t["exclude"]) > 0 {
|
||||||
|
options = append(options, "-exclude", t["exclude"])
|
||||||
|
}
|
||||||
|
if len(t["libDirs"]) > 0 {
|
||||||
|
options = append(options, "-libdirs", t["libDirs"])
|
||||||
|
}
|
||||||
|
return append(options, tokenize(t["src"])...)
|
||||||
|
}
|
||||||
|
if config.BuildTool == "maven" {
|
||||||
|
if len(t["autoClasspath"]) > 0 {
|
||||||
|
options = append(options, "-cp", t["autoClasspath"])
|
||||||
|
} else if len(t["classpath"]) > 0 {
|
||||||
|
options = append(options, "-cp", t["classpath"])
|
||||||
|
}
|
||||||
|
if len(t["extdirs"]) > 0 {
|
||||||
|
options = append(options, "-extdirs", t["extdirs"])
|
||||||
|
}
|
||||||
|
if len(t["javaBuildDir"]) > 0 {
|
||||||
|
options = append(options, "-java-build-dir", t["javaBuildDir"])
|
||||||
|
}
|
||||||
|
if len(t["source"]) > 0 {
|
||||||
|
options = append(options, "-source", t["source"])
|
||||||
|
}
|
||||||
|
if len(t["jdk"]) > 0 {
|
||||||
|
options = append(options, "-jdk", t["jdk"])
|
||||||
|
}
|
||||||
|
if len(t["sourcepath"]) > 0 {
|
||||||
|
options = append(options, "-sourcepath", t["sourcepath"])
|
||||||
|
}
|
||||||
|
return append(options, tokenize(t["src"])...)
|
||||||
|
}
|
||||||
|
if config.BuildTool == "pip" {
|
||||||
|
if len(t["autoClasspath"]) > 0 {
|
||||||
|
options = append(options, "-python-path", t["autoClasspath"])
|
||||||
|
} else if len(t["pythonPath"]) > 0 {
|
||||||
|
options = append(options, "-python-path", t["pythonPath"])
|
||||||
|
}
|
||||||
|
if len(t["djangoTemplatDirs"]) > 0 {
|
||||||
|
options = append(options, "-django-template-dirs", t["djangoTemplatDirs"])
|
||||||
|
}
|
||||||
|
if len(t["pythonExcludes"]) > 0 {
|
||||||
|
options = append(options, "-exclude", t["pythonExcludes"])
|
||||||
|
}
|
||||||
|
return append(options, t["pythonIncludes"])
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
630
cmd/fortifyExecuteScan_generated.go
Normal file
630
cmd/fortifyExecuteScan_generated.go
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SAP/jenkins-library/pkg/config"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fortifyExecuteScanOptions struct {
|
||||||
|
AuthToken string `json:"authToken,omitempty"`
|
||||||
|
GithubToken string `json:"githubToken,omitempty"`
|
||||||
|
AutoCreate bool `json:"autoCreate,omitempty"`
|
||||||
|
MvnCustomArgs string `json:"mvnCustomArgs,omitempty"`
|
||||||
|
ModulePath string `json:"modulePath,omitempty"`
|
||||||
|
PythonRequirementsFile string `json:"pythonRequirementsFile,omitempty"`
|
||||||
|
AutodetectClasspath bool `json:"autodetectClasspath,omitempty"`
|
||||||
|
MustAuditIssueGroups string `json:"mustAuditIssueGroups,omitempty"`
|
||||||
|
SpotAuditIssueGroups string `json:"spotAuditIssueGroups,omitempty"`
|
||||||
|
PythonRequirementsInstallSuffix string `json:"pythonRequirementsInstallSuffix,omitempty"`
|
||||||
|
PythonVersion string `json:"pythonVersion,omitempty"`
|
||||||
|
UploadResults bool `json:"uploadResults,omitempty"`
|
||||||
|
BuildDescriptorFile string `json:"buildDescriptorFile,omitempty"`
|
||||||
|
CommitID string `json:"commitId,omitempty"`
|
||||||
|
CommitMessage string `json:"commitMessage,omitempty"`
|
||||||
|
GithubAPIURL string `json:"githubApiUrl,omitempty"`
|
||||||
|
Owner string `json:"owner,omitempty"`
|
||||||
|
Repository string `json:"repository,omitempty"`
|
||||||
|
Memory string `json:"memory,omitempty"`
|
||||||
|
UpdateRulePack bool `json:"updateRulePack,omitempty"`
|
||||||
|
PythonExcludes string `json:"pythonExcludes,omitempty"`
|
||||||
|
ReportDownloadEndpoint string `json:"reportDownloadEndpoint,omitempty"`
|
||||||
|
PollingMinutes int `json:"pollingMinutes,omitempty"`
|
||||||
|
QuickScan bool `json:"quickScan,omitempty"`
|
||||||
|
Translate string `json:"translate,omitempty"`
|
||||||
|
APIEndpoint string `json:"apiEndpoint,omitempty"`
|
||||||
|
ReportType string `json:"reportType,omitempty"`
|
||||||
|
PythonAdditionalPath string `json:"pythonAdditionalPath,omitempty"`
|
||||||
|
ArtifactURL string `json:"artifactUrl,omitempty"`
|
||||||
|
ConsiderSuspicious bool `json:"considerSuspicious,omitempty"`
|
||||||
|
FprUploadEndpoint string `json:"fprUploadEndpoint,omitempty"`
|
||||||
|
ProjectName string `json:"projectName,omitempty"`
|
||||||
|
PythonIncludes string `json:"pythonIncludes,omitempty"`
|
||||||
|
Reporting bool `json:"reporting,omitempty"`
|
||||||
|
ServerURL string `json:"serverUrl,omitempty"`
|
||||||
|
BuildDescriptorExcludeList string `json:"buildDescriptorExcludeList,omitempty"`
|
||||||
|
PullRequestMessageRegexGroup int `json:"pullRequestMessageRegexGroup,omitempty"`
|
||||||
|
DeltaMinutes int `json:"deltaMinutes,omitempty"`
|
||||||
|
SpotCheckMinimum int `json:"spotCheckMinimum,omitempty"`
|
||||||
|
FprDownloadEndpoint string `json:"fprDownloadEndpoint,omitempty"`
|
||||||
|
DefaultVersioningModel string `json:"defaultVersioningModel,omitempty"`
|
||||||
|
PythonInstallCommand string `json:"pythonInstallCommand,omitempty"`
|
||||||
|
ReportTemplateID int `json:"reportTemplateId,omitempty"`
|
||||||
|
FilterSetTitle string `json:"filterSetTitle,omitempty"`
|
||||||
|
PullRequestName string `json:"pullRequestName,omitempty"`
|
||||||
|
PullRequestMessageRegex string `json:"pullRequestMessageRegex,omitempty"`
|
||||||
|
BuildTool string `json:"buildTool,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type fortifyExecuteScanInflux struct {
|
||||||
|
fortify_data struct {
|
||||||
|
fields struct {
|
||||||
|
projectName string
|
||||||
|
projectVersion string
|
||||||
|
violations string
|
||||||
|
corporateTotal string
|
||||||
|
corporateAudited string
|
||||||
|
auditAllTotal string
|
||||||
|
auditAllAudited string
|
||||||
|
spotChecksTotal string
|
||||||
|
spotChecksAudited string
|
||||||
|
spotChecksGap string
|
||||||
|
suspicious string
|
||||||
|
exploitable string
|
||||||
|
suppressed string
|
||||||
|
}
|
||||||
|
tags struct {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *fortifyExecuteScanInflux) persist(path, resourceName string) {
|
||||||
|
measurementContent := []struct {
|
||||||
|
measurement string
|
||||||
|
valType string
|
||||||
|
name string
|
||||||
|
value string
|
||||||
|
}{
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "projectName", value: i.fortify_data.fields.projectName},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "projectVersion", value: i.fortify_data.fields.projectVersion},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "violations", value: i.fortify_data.fields.violations},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "corporateTotal", value: i.fortify_data.fields.corporateTotal},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "corporateAudited", value: i.fortify_data.fields.corporateAudited},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "auditAllTotal", value: i.fortify_data.fields.auditAllTotal},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "auditAllAudited", value: i.fortify_data.fields.auditAllAudited},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "spotChecksTotal", value: i.fortify_data.fields.spotChecksTotal},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "spotChecksAudited", value: i.fortify_data.fields.spotChecksAudited},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "spotChecksGap", value: i.fortify_data.fields.spotChecksGap},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "suspicious", value: i.fortify_data.fields.suspicious},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "exploitable", value: i.fortify_data.fields.exploitable},
|
||||||
|
{valType: config.InfluxField, measurement: "fortify_data", name: "suppressed", value: i.fortify_data.fields.suppressed},
|
||||||
|
}
|
||||||
|
|
||||||
|
errCount := 0
|
||||||
|
for _, metric := range measurementContent {
|
||||||
|
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Error("Error persisting influx environment.")
|
||||||
|
errCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errCount > 0 {
|
||||||
|
log.Entry().Fatal("failed to persist Influx environment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FortifyExecuteScanCommand This BETA step executes a Fortify scan on the specified project to perform static code analysis and check the source code for security flaws.
|
||||||
|
func FortifyExecuteScanCommand() *cobra.Command {
|
||||||
|
const STEP_NAME = "fortifyExecuteScan"
|
||||||
|
|
||||||
|
metadata := fortifyExecuteScanMetadata()
|
||||||
|
var stepConfig fortifyExecuteScanOptions
|
||||||
|
var startTime time.Time
|
||||||
|
var influx fortifyExecuteScanInflux
|
||||||
|
|
||||||
|
var createFortifyExecuteScanCmd = &cobra.Command{
|
||||||
|
Use: STEP_NAME,
|
||||||
|
Short: "This BETA step executes a Fortify scan on the specified project to perform static code analysis and check the source code for security flaws.",
|
||||||
|
Long: `This step executes a Fortify scan on the specified project to perform static code analysis and check the source code for security flaws.
|
||||||
|
|
||||||
|
The Fortify step triggers a scan locally on your Jenkins within a docker container so finally you have to supply a docker image with a Fortify SCA
|
||||||
|
and Java plus Maven or alternatively Python installed into it for being able to perform any scans.
|
||||||
|
|
||||||
|
DISCLAIMER: The step has not yet been tested on a wide variaty of projects, and is therefore considered of BETA quality.`,
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
startTime = time.Now()
|
||||||
|
log.SetStepName(STEP_NAME)
|
||||||
|
log.SetVerbose(GeneralConfig.Verbose)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.RegisterSecret(stepConfig.AuthToken)
|
||||||
|
log.RegisterSecret(stepConfig.GithubToken)
|
||||||
|
|
||||||
|
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||||
|
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||||
|
log.RegisterHook(&sentryHook)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
telemetryData := telemetry.CustomData{}
|
||||||
|
telemetryData.ErrorCode = "1"
|
||||||
|
handler := func() {
|
||||||
|
influx.persist(GeneralConfig.EnvRootPath, "influx")
|
||||||
|
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||||
|
telemetry.Send(&telemetryData)
|
||||||
|
}
|
||||||
|
log.DeferExitHandler(handler)
|
||||||
|
defer handler()
|
||||||
|
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||||
|
fortifyExecuteScan(stepConfig, &telemetryData, &influx)
|
||||||
|
telemetryData.ErrorCode = "0"
|
||||||
|
log.Entry().Info("SUCCESS")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
addFortifyExecuteScanFlags(createFortifyExecuteScanCmd, &stepConfig)
|
||||||
|
return createFortifyExecuteScanCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFortifyExecuteScanFlags(cmd *cobra.Command, stepConfig *fortifyExecuteScanOptions) {
|
||||||
|
cmd.Flags().StringVar(&stepConfig.AuthToken, "authToken", os.Getenv("PIPER_authToken"), "The FortifyToken to use for authentication")
|
||||||
|
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().BoolVar(&stepConfig.AutoCreate, "autoCreate", false, "Whether Fortify project and project version shall be implicitly auto created in case they cannot be found in the backend")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.MvnCustomArgs, "mvnCustomArgs", ``, "Allows providing additional Maven command line parameters")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ModulePath, "modulePath", `./`, "Allows providing the path for the module to scan")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonRequirementsFile, "pythonRequirementsFile", os.Getenv("PIPER_pythonRequirementsFile"), "The requirements file used in `buildTool: 'pip'` to populate the build environment with the necessary dependencies")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.AutodetectClasspath, "autodetectClasspath", true, "Whether the classpath is automatically determined via build tool i.e. maven or pip or not at all")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.MustAuditIssueGroups, "mustAuditIssueGroups", `Corporate Security Requirements, Audit All`, "Comma separated list of issue groups that must be audited completely")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.SpotAuditIssueGroups, "spotAuditIssueGroups", `Spot Checks of Each Category`, "Comma separated list of issue groups that are spot checked and for which `spotCheckMinimum` audited issues are enforced")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonRequirementsInstallSuffix, "pythonRequirementsInstallSuffix", os.Getenv("PIPER_pythonRequirementsInstallSuffix"), "The suffix for the command used to install the requirements file in `buildTool: 'pip'` to populate the build environment with the necessary dependencies")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonVersion, "pythonVersion", `python3`, "Python version to be used in `buildTool: 'pip'`")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.UploadResults, "uploadResults", true, "Whether results shall be uploaded or not")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.BuildDescriptorFile, "buildDescriptorFile", os.Getenv("PIPER_buildDescriptorFile"), "Path to the build descriptor file addressing the module/folder to be scanned. Defaults are for buildTool=`maven`: `./pom.xml`, buildTool=`pip`: `./setup.py`.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.CommitID, "commitId", os.Getenv("PIPER_commitId"), "Set the Git commit ID for identifying artifacts throughout the scan.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.CommitMessage, "commitMessage", os.Getenv("PIPER_commitMessage"), "Set the Git commit message for identifying pull request merges throughout the scan.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.GithubAPIURL, "githubApiUrl", `https://api.github.com`, "Set the GitHub API url.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.Memory, "memory", `-Xmx4G -Xms512M`, "The amount of memory granted to the translate/scan executions")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.UpdateRulePack, "updateRulePack", true, "Whether the rule pack shall be updated and pulled from Fortify SSC before scanning or not")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonExcludes, "pythonExcludes", `-exclude ./**/tests/**/*;./**/setup.py`, "The excludes pattern used in `buildTool: 'pip'` for excluding specific .py files i.e. tests")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ReportDownloadEndpoint, "reportDownloadEndpoint", `/transfer/reportDownload.html`, "Fortify SSC endpoint for Report downloads")
|
||||||
|
cmd.Flags().IntVar(&stepConfig.PollingMinutes, "pollingMinutes", 30, "The number of minutes for which an uploaded FPR artifact's status is being polled to finish queuing/processing, if exceeded polling will be stopped and an error will be thrown")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.QuickScan, "quickScan", false, "Whether a quick scan should be performed, please consult the related Fortify documentation on JAM on the impact of this setting")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.Translate, "translate", os.Getenv("PIPER_translate"), "JSON string of list of maps with required key `'src'`, and optional keys `'exclude'`, `'libDirs'`, `'aspnetcore'`, and `'dotNetCoreVersion'`")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.APIEndpoint, "apiEndpoint", `/api/v1`, "Fortify SSC endpoint used for uploading the scan results and checking the audit state")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ReportType, "reportType", `PDF`, "The type of report to be generated")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonAdditionalPath, "pythonAdditionalPath", `./lib;.`, "The addional path which can be used in `buildTool: 'pip'` for customization purposes")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ArtifactURL, "artifactUrl", os.Getenv("PIPER_artifactUrl"), "Path/Url pointing to an additional artifact repository for resolution of additional artifacts during the build")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.ConsiderSuspicious, "considerSuspicious", true, "Whether suspicious issues should trigger the check to fail or not")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.FprUploadEndpoint, "fprUploadEndpoint", `/upload/resultFileUpload.html`, "Fortify SSC endpoint for FPR uploads")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ProjectName, "projectName", `{{list .GroupID .ArtifactID | join "-" | trimAll "-"}}`, "The project used for reporting results in SSC")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonIncludes, "pythonIncludes", `./**/*`, "The includes pattern used in `buildTool: 'pip'` for including .py files")
|
||||||
|
cmd.Flags().BoolVar(&stepConfig.Reporting, "reporting", false, "Influences whether a report is generated or not")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Fortify SSC Url to be used for accessing the APIs")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.BuildDescriptorExcludeList, "buildDescriptorExcludeList", `[]`, "Build descriptor files to exclude modules from being scanned")
|
||||||
|
cmd.Flags().IntVar(&stepConfig.PullRequestMessageRegexGroup, "pullRequestMessageRegexGroup", 1, "The group number for extracting the pull request id in `pullRequestMessageRegex`")
|
||||||
|
cmd.Flags().IntVar(&stepConfig.DeltaMinutes, "deltaMinutes", 5, "The number of minutes for which an uploaded FPR artifact is considered to be recent and healthy, if exceeded an error will be thrown")
|
||||||
|
cmd.Flags().IntVar(&stepConfig.SpotCheckMinimum, "spotCheckMinimum", 1, "The minimum number of issues that must be audited per category in the `Spot Checks of each Category` folder to avoid an error being thrown")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.FprDownloadEndpoint, "fprDownloadEndpoint", `/download/currentStateFprDownload.html`, "Fortify SSC endpoint for FPR downloads")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.DefaultVersioningModel, "defaultVersioningModel", `major`, "The default project versioning model used in case `projectVersion` parameter is empty for creating the version based on the build descriptor version to report results in SSC, can be one of `'major'`, `'major-minor'`, `'semantic'`, `'full'`")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PythonInstallCommand, "pythonInstallCommand", `{{.Pip}} install --user .`, "Additional install command that can be run when `buildTool: 'pip'` is used which allows further customizing the execution environment of the scan")
|
||||||
|
cmd.Flags().IntVar(&stepConfig.ReportTemplateID, "reportTemplateId", 18, "Report template ID to be used for generating the Fortify report")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.FilterSetTitle, "filterSetTitle", `SAP`, "Title of the filter set to use for analysing the results")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PullRequestName, "pullRequestName", os.Getenv("PIPER_pullRequestName"), "The name of the pull request branch which will trigger creation of a new version in Fortify SSC based on the master branch version")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.PullRequestMessageRegex, "pullRequestMessageRegex", `.*Merge pull request #(\\d+) from.*`, "Regex used to identify the PR-XXX reference within the merge commit message")
|
||||||
|
cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", `maven`, "Scan type used for the step which can be `'maven'`, `'pip'`")
|
||||||
|
|
||||||
|
cmd.MarkFlagRequired("authToken")
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve step metadata
|
||||||
|
func fortifyExecuteScanMetadata() config.StepData {
|
||||||
|
var theMetaData = config.StepData{
|
||||||
|
Metadata: config.StepMetadata{
|
||||||
|
Name: "fortifyExecuteScan",
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
Spec: config.StepSpec{
|
||||||
|
Inputs: config.StepInputs{
|
||||||
|
Parameters: []config.StepParameters{
|
||||||
|
{
|
||||||
|
Name: "authToken",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "githubToken",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "autoCreate",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mvnCustomArgs",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "modulePath",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonRequirementsFile",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "autodetectClasspath",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "mustAuditIssueGroups",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "spotAuditIssueGroups",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonRequirementsInstallSuffix",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonVersion",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "uploadResults",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "buildDescriptorFile",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "commitId",
|
||||||
|
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "git/commitId"}},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "commitMessage",
|
||||||
|
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "git/commitMessage"}},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "githubApiUrl",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "owner",
|
||||||
|
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "github/owner"}},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "githubOrg"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "repository",
|
||||||
|
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "github/repository"}},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "githubRepo"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "memory",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "updateRulePack",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonExcludes",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "reportDownloadEndpoint",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyReportDownloadEndpoint"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pollingMinutes",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "int",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "quickScan",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "translate",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "apiEndpoint",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyApiEndpoint"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "reportType",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonAdditionalPath",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "artifactUrl",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "considerSuspicious",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fprUploadEndpoint",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyFprUploadEndpoint"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "projectName",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyProjectName"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonIncludes",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "reporting",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "serverUrl",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyServerUrl"}, {Name: "sscUrl"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "buildDescriptorExcludeList",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pullRequestMessageRegexGroup",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "int",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "deltaMinutes",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "int",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "spotCheckMinimum",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "int",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fprDownloadEndpoint",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{{Name: "fortifyFprDownloadEndpoint"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "defaultVersioningModel",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pythonInstallCommand",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "reportTemplateId",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "int",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "filterSetTitle",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pullRequestName",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pullRequestMessageRegex",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "buildTool",
|
||||||
|
ResourceRef: []config.ResourceReference{},
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
Aliases: []config.Alias{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return theMetaData
|
||||||
|
}
|
16
cmd/fortifyExecuteScan_generated_test.go
Normal file
16
cmd/fortifyExecuteScan_generated_test.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFortifyExecuteScanCommand(t *testing.T) {
|
||||||
|
|
||||||
|
testCmd := FortifyExecuteScanCommand()
|
||||||
|
|
||||||
|
// only high level testing performed - details are tested in step generation procudure
|
||||||
|
assert.Equal(t, "fortifyExecuteScan", testCmd.Use, "command name incorrect")
|
||||||
|
|
||||||
|
}
|
612
cmd/fortifyExecuteScan_test.go
Normal file
612
cmd/fortifyExecuteScan_test.go
Normal file
@ -0,0 +1,612 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v28/github"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/piper-validation/fortify-client-go/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fortifyMock struct {
|
||||||
|
Successive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fortifyMock) GetProjectByName(name string, autoCreate bool, projectVersion string) (*models.Project, error) {
|
||||||
|
return &models.Project{Name: &name}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetProjectVersionDetailsByProjectIDAndVersionName(id int64, name string, autoCreate bool, projectName string) (*models.ProjectVersion, error) {
|
||||||
|
return &models.ProjectVersion{ID: id, Name: &name, Project: &models.Project{Name: &projectName}}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetProjectVersionAttributesByProjectVersionID(id int64) ([]*models.Attribute, error) {
|
||||||
|
return []*models.Attribute{}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) SetProjectVersionAttributesByProjectVersionID(id int64, attributes []*models.Attribute) ([]*models.Attribute, error) {
|
||||||
|
return attributes, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) CreateProjectVersionIfNotExist(projectName, projectVersionName, description string) (*models.ProjectVersion, error) {
|
||||||
|
return &models.ProjectVersion{ID: 4711, Name: &projectVersionName, Project: &models.Project{Name: &projectName}}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) LookupOrCreateProjectVersionDetailsForPullRequest(projectID int64, masterProjectVersion *models.ProjectVersion, pullRequestName string) (*models.ProjectVersion, error) {
|
||||||
|
return &models.ProjectVersion{ID: 4712, Name: &pullRequestName, Project: masterProjectVersion.Project}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) CreateProjectVersion(version *models.ProjectVersion) (*models.ProjectVersion, error) {
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fortifyMock) ProjectVersionCopyFromPartial(sourceID, targetID int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) ProjectVersionCopyCurrentState(sourceID, targetID int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) ProjectVersionCopyPermissions(sourceID, targetID int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) CommitProjectVersion(id int64) (*models.ProjectVersion, error) {
|
||||||
|
name := "Committed"
|
||||||
|
return &models.ProjectVersion{ID: id, Name: &name}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) MergeProjectVersionStateOfPRIntoMaster(downloadEndpoint, uploadEndpoint string, masterProjectID, masterProjectVersionID int64, pullRequestName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetArtifactsOfProjectVersion(id int64) ([]*models.Artifact, error) {
|
||||||
|
if id == 4711 {
|
||||||
|
return []*models.Artifact{{Status: "PROCESSED", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
|
||||||
|
}
|
||||||
|
if id == 4712 {
|
||||||
|
return []*models.Artifact{{Status: "ERROR_PROCESSING", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
|
||||||
|
}
|
||||||
|
if id == 4713 {
|
||||||
|
return []*models.Artifact{{Status: "REQUIRE_AUTH", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
|
||||||
|
}
|
||||||
|
if id == 4714 {
|
||||||
|
return []*models.Artifact{{Status: "PROCESSING", UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
|
||||||
|
}
|
||||||
|
if id == 4715 {
|
||||||
|
return []*models.Artifact{{Status: "PROCESSED", Embed: &models.EmbeddedScans{[]*models.Scan{{BuildLabel: "/commit/test"}}}, UploadDate: models.Iso8601MilliDateTime(time.Now().UTC())}}, nil
|
||||||
|
}
|
||||||
|
return []*models.Artifact{}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetFilterSetOfProjectVersionByTitle(id int64, title string) (*models.FilterSet, error) {
|
||||||
|
return &models.FilterSet{}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetIssueFilterSelectorOfProjectVersionByName(id int64, names []string, options []string) (*models.IssueFilterSelectorSet, error) {
|
||||||
|
return &models.IssueFilterSelectorSet{}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetFilterSetByDisplayName(issueFilterSelectorSet *models.IssueFilterSelectorSet, name string) *models.IssueFilterSelector {
|
||||||
|
if issueFilterSelectorSet.FilterBySet != nil {
|
||||||
|
for _, filter := range issueFilterSelectorSet.FilterBySet {
|
||||||
|
if filter.DisplayName == name {
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64, filter, filterSetGUID string, issueFilterSelectorSet *models.IssueFilterSelectorSet) ([]*models.ProjectVersionIssueGroup, error) {
|
||||||
|
if filter == "ET1:abcd" {
|
||||||
|
group := "HTTP Verb tampering"
|
||||||
|
total := int32(4)
|
||||||
|
audited := int32(3)
|
||||||
|
group2 := "Password in code"
|
||||||
|
total2 := int32(4)
|
||||||
|
audited2 := int32(4)
|
||||||
|
group3 := "Memory leak"
|
||||||
|
total3 := int32(5)
|
||||||
|
audited3 := int32(4)
|
||||||
|
return []*models.ProjectVersionIssueGroup{
|
||||||
|
{ID: &group, TotalCount: &total, AuditedCount: &audited},
|
||||||
|
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
|
||||||
|
{ID: &group3, TotalCount: &total3, AuditedCount: &audited3},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
if issueFilterSelectorSet != nil && issueFilterSelectorSet.FilterBySet[0].GUID == "3" {
|
||||||
|
group := "3"
|
||||||
|
total := int32(4)
|
||||||
|
audited := int32(0)
|
||||||
|
group2 := "4"
|
||||||
|
total2 := int32(5)
|
||||||
|
audited2 := int32(0)
|
||||||
|
return []*models.ProjectVersionIssueGroup{
|
||||||
|
{ID: &group, TotalCount: &total, AuditedCount: &audited},
|
||||||
|
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
group := "Audit All"
|
||||||
|
total := int32(15)
|
||||||
|
audited := int32(12)
|
||||||
|
group2 := "Corporate Security Requirements"
|
||||||
|
total2 := int32(20)
|
||||||
|
audited2 := int32(11)
|
||||||
|
group3 := "Spot Checks of Each Category"
|
||||||
|
total3 := int32(5)
|
||||||
|
audited3 := int32(4)
|
||||||
|
return []*models.ProjectVersionIssueGroup{
|
||||||
|
{ID: &group, TotalCount: &total, AuditedCount: &audited},
|
||||||
|
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
|
||||||
|
{ID: &group3, TotalCount: &total3, AuditedCount: &audited3},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) ReduceIssueFilterSelectorSet(issueFilterSelectorSet *models.IssueFilterSelectorSet, names []string, options []string) *models.IssueFilterSelectorSet {
|
||||||
|
return issueFilterSelectorSet
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetIssueStatisticsOfProjectVersion(id int64) ([]*models.IssueStatistics, error) {
|
||||||
|
suppressed := int32(6)
|
||||||
|
return []*models.IssueStatistics{{SuppressedCount: &suppressed}}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GenerateQGateReport(projectID, projectVersionID, reportTemplateID int64, projectName, projectVersionName, reportFormat string) (*models.SavedReport, error) {
|
||||||
|
if !f.Successive {
|
||||||
|
f.Successive = true
|
||||||
|
return &models.SavedReport{Status: "Processing"}, nil
|
||||||
|
}
|
||||||
|
f.Successive = false
|
||||||
|
return &models.SavedReport{Status: "Complete"}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) GetReportDetails(id int64) (*models.SavedReport, error) {
|
||||||
|
return &models.SavedReport{Status: "Complete"}, nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) UploadResultFile(endpoint, file string, projectVersionID int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) DownloadReportFile(endpoint string, projectVersionID int64) ([]byte, error) {
|
||||||
|
return []byte("abcd"), nil
|
||||||
|
}
|
||||||
|
func (f *fortifyMock) DownloadResultFile(endpoint string, projectVersionID int64) ([]byte, error) {
|
||||||
|
return []byte("defg"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type pullRequestServiceMock struct{}
|
||||||
|
|
||||||
|
func (prService pullRequestServiceMock) ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error) {
|
||||||
|
if owner == "A" {
|
||||||
|
result := 17
|
||||||
|
return []*github.PullRequest{{Number: &result}}, &github.Response{}, nil
|
||||||
|
} else if owner == "C" {
|
||||||
|
return []*github.PullRequest{}, &github.Response{}, errors.New("Test error")
|
||||||
|
}
|
||||||
|
return []*github.PullRequest{}, &github.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type execRunnerMock struct {
|
||||||
|
numExecutions int
|
||||||
|
current *execution
|
||||||
|
executions []*execution
|
||||||
|
}
|
||||||
|
|
||||||
|
type execution struct {
|
||||||
|
dirValue string
|
||||||
|
envValue []string
|
||||||
|
outWriter io.Writer
|
||||||
|
errWriter io.Writer
|
||||||
|
executable string
|
||||||
|
parameters []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) newExecution() *execution {
|
||||||
|
newExecution := &execution{}
|
||||||
|
er.executions = append(er.executions, newExecution)
|
||||||
|
return newExecution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) currentExecution() *execution {
|
||||||
|
if nil == er.current {
|
||||||
|
er.numExecutions = 0
|
||||||
|
er.current = er.newExecution()
|
||||||
|
}
|
||||||
|
return er.current
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) SetDir(d string) {
|
||||||
|
er.currentExecution().dirValue = d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) SetEnv(e []string) {
|
||||||
|
er.currentExecution().envValue = e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) Stdout(out io.Writer) {
|
||||||
|
er.currentExecution().outWriter = out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *execRunnerMock) Stderr(err io.Writer) {
|
||||||
|
er.currentExecution().errWriter = err
|
||||||
|
}
|
||||||
|
func (er *execRunnerMock) RunExecutable(e string, p ...string) error {
|
||||||
|
er.numExecutions++
|
||||||
|
er.currentExecution().executable = e
|
||||||
|
er.currentExecution().parameters = p
|
||||||
|
classpathPip := "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib"
|
||||||
|
classpathMaven := "some.jar;someother.jar"
|
||||||
|
if e == "python2" {
|
||||||
|
er.currentExecution().outWriter.Write([]byte(classpathPip))
|
||||||
|
} else if e == "mvn" {
|
||||||
|
path := strings.ReplaceAll(p[2], "-Dmdep.outputFile=", "")
|
||||||
|
err := ioutil.WriteFile(path, []byte(classpathMaven), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
er.current = er.newExecution()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParametersAreValidated(t *testing.T) {
|
||||||
|
type parameterTestData struct {
|
||||||
|
nameOfRun string
|
||||||
|
config fortifyExecuteScanOptions
|
||||||
|
expectedError string
|
||||||
|
}
|
||||||
|
|
||||||
|
testData := []parameterTestData{
|
||||||
|
{
|
||||||
|
nameOfRun: "all parameters empty",
|
||||||
|
config: fortifyExecuteScanOptions{},
|
||||||
|
expectedError: "unable to get artifact from descriptor : build tool '' not supported",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range testData {
|
||||||
|
t.Run(data.nameOfRun, func(t *testing.T) {
|
||||||
|
ff := fortifyMock{}
|
||||||
|
runner := execRunnerMock{}
|
||||||
|
influx := fortifyExecuteScanInflux{}
|
||||||
|
auditStatus := map[string]string{}
|
||||||
|
err := runFortifyScan(data.config, &ff, &runner, nil, &influx, auditStatus)
|
||||||
|
assert.EqualError(t, err, data.expectedError)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyseSuspiciousExploitable(t *testing.T) {
|
||||||
|
config := fortifyExecuteScanOptions{SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
|
||||||
|
ff := fortifyMock{}
|
||||||
|
influx := fortifyExecuteScanInflux{}
|
||||||
|
name := "test"
|
||||||
|
selectorGUID := "3"
|
||||||
|
selectorName := "Analysis"
|
||||||
|
selectorEntityType := "CUSTOMTAG"
|
||||||
|
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
|
||||||
|
auditStatus := map[string]string{}
|
||||||
|
selectorSet := models.IssueFilterSelectorSet{
|
||||||
|
FilterBySet: []*models.IssueFilterSelector{
|
||||||
|
{
|
||||||
|
GUID: selectorGUID,
|
||||||
|
DisplayName: selectorName,
|
||||||
|
EntityType: selectorEntityType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GroupBySet: []*models.IssueSelector{
|
||||||
|
{
|
||||||
|
GUID: &selectorGUID,
|
||||||
|
DisplayName: &selectorName,
|
||||||
|
EntityType: &selectorEntityType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
issues := analyseSuspiciousExploitable(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||||
|
assert.Equal(t, 9, issues)
|
||||||
|
|
||||||
|
assert.Equal(t, "4", influx.fortify_data.fields.suspicious)
|
||||||
|
assert.Equal(t, "5", influx.fortify_data.fields.exploitable)
|
||||||
|
assert.Equal(t, "6", influx.fortify_data.fields.suppressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyseUnauditedIssues(t *testing.T) {
|
||||||
|
config := fortifyExecuteScanOptions{SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
|
||||||
|
ff := fortifyMock{}
|
||||||
|
influx := fortifyExecuteScanInflux{}
|
||||||
|
name := "test"
|
||||||
|
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
|
||||||
|
auditStatus := map[string]string{}
|
||||||
|
selectorSet := models.IssueFilterSelectorSet{
|
||||||
|
FilterBySet: []*models.IssueFilterSelector{
|
||||||
|
{
|
||||||
|
GUID: "1",
|
||||||
|
DisplayName: "Folder",
|
||||||
|
EntityType: "ET1",
|
||||||
|
SelectorOptions: []*models.SelectorOption{
|
||||||
|
{
|
||||||
|
Value: "abcd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GUID: "2",
|
||||||
|
DisplayName: "Category",
|
||||||
|
EntityType: "ET2",
|
||||||
|
SelectorOptions: []*models.SelectorOption{
|
||||||
|
{
|
||||||
|
Value: "abcd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GUID: "3",
|
||||||
|
DisplayName: "Analysis",
|
||||||
|
EntityType: "ET3",
|
||||||
|
SelectorOptions: []*models.SelectorOption{
|
||||||
|
{
|
||||||
|
Value: "abcd",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
issues := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||||
|
assert.Equal(t, 13, issues)
|
||||||
|
|
||||||
|
assert.Equal(t, "15", influx.fortify_data.fields.auditAllTotal)
|
||||||
|
assert.Equal(t, "12", influx.fortify_data.fields.auditAllAudited)
|
||||||
|
assert.Equal(t, "20", influx.fortify_data.fields.corporateTotal)
|
||||||
|
assert.Equal(t, "11", influx.fortify_data.fields.corporateAudited)
|
||||||
|
assert.Equal(t, "13", influx.fortify_data.fields.spotChecksTotal)
|
||||||
|
assert.Equal(t, "11", influx.fortify_data.fields.spotChecksAudited)
|
||||||
|
assert.Equal(t, "1", influx.fortify_data.fields.spotChecksGap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTriggerFortifyScan(t *testing.T) {
|
||||||
|
t.Run("maven", func(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "test trigger fortify scan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to create temporary directory")
|
||||||
|
}
|
||||||
|
oldCWD, _ := os.Getwd()
|
||||||
|
_ = os.Chdir(dir)
|
||||||
|
// clean up tmp dir
|
||||||
|
defer func() {
|
||||||
|
_ = os.Chdir(oldCWD)
|
||||||
|
_ = os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
runner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "maven", AutodetectClasspath: true, BuildDescriptorFile: "./pom.xml", Memory: "-Xmx4G -Xms2G"}
|
||||||
|
triggerFortifyScan(config, &runner, "test", "testLabel")
|
||||||
|
|
||||||
|
assert.Equal(t, 3, runner.numExecutions)
|
||||||
|
|
||||||
|
assert.Equal(t, "mvn", runner.executions[0].executable)
|
||||||
|
assert.Equal(t, []string{"--file", "./pom.xml", "-Dmdep.outputFile=cp.txt", "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, runner.executions[0].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "sourceanalyzer", runner.executions[1].executable)
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-cp", "some.jar;someother.jar", "**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}, runner.executions[1].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "sourceanalyzer", runner.executions[2].executable)
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[2].parameters)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("pip", func(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "test trigger fortify scan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to create temporary directory")
|
||||||
|
}
|
||||||
|
oldCWD, _ := os.Getwd()
|
||||||
|
_ = os.Chdir(dir)
|
||||||
|
// clean up tmp dir
|
||||||
|
defer func() {
|
||||||
|
_ = os.Chdir(oldCWD)
|
||||||
|
_ = os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
runner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "pip", PythonVersion: "python2", AutodetectClasspath: true, BuildDescriptorFile: "./setup.py", PythonRequirementsFile: "./requirements.txt", PythonInstallCommand: "pip2 install --user", Memory: "-Xmx4G -Xms2G"}
|
||||||
|
triggerFortifyScan(config, &runner, "test", "testLabel")
|
||||||
|
|
||||||
|
assert.Equal(t, 5, runner.numExecutions)
|
||||||
|
|
||||||
|
assert.Equal(t, "python2", runner.executions[0].executable)
|
||||||
|
assert.Equal(t, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, runner.executions[0].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "pip2", runner.executions[1].executable)
|
||||||
|
assert.Equal(t, []string{"install", "--user", "-r", "./requirements.txt", ""}, runner.executions[1].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "pip2", runner.executions[2].executable)
|
||||||
|
assert.Equal(t, []string{"install", "--user"}, runner.executions[2].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "sourceanalyzer", runner.executions[3].executable)
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", ""}, runner.executions[3].parameters)
|
||||||
|
|
||||||
|
assert.Equal(t, "sourceanalyzer", runner.executions[4].executable)
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[4].parameters)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateAndDownloadQGateReport(t *testing.T) {
|
||||||
|
ffMock := fortifyMock{Successive: false}
|
||||||
|
config := fortifyExecuteScanOptions{ReportTemplateID: 18, ReportType: "PDF"}
|
||||||
|
name := "test"
|
||||||
|
projectVersion := models.ProjectVersion{ID: 4711, Name: &name}
|
||||||
|
project := models.Project{ID: 815, Name: &name}
|
||||||
|
projectVersion.Project = &project
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
data, err := generateAndDownloadQGateReport(config, &ffMock, &project, &projectVersion)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte("abcd"), data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyScanResultsFinishedUploading(t *testing.T) {
|
||||||
|
ffMock := fortifyMock{Successive: false}
|
||||||
|
|
||||||
|
t.Run("error no recent upload detected", func(t *testing.T) {
|
||||||
|
config := fortifyExecuteScanOptions{DeltaMinutes: -1}
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4711, "", &models.FilterSet{}, 0)
|
||||||
|
assert.EqualError(t, err, "No recent upload detected on Project Version")
|
||||||
|
})
|
||||||
|
|
||||||
|
config := fortifyExecuteScanOptions{DeltaMinutes: 20}
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4711, "", &models.FilterSet{}, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error processing", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4712, "", &models.FilterSet{}, 0)
|
||||||
|
assert.EqualError(t, err, "There are artifacts that failed processing for Project Version 4712\n/html/ssc/index.jsp#!/version/4712/artifacts?filterSet=")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error required auth", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4713, "", &models.FilterSet{}, 0)
|
||||||
|
assert.EqualError(t, err, "There are artifacts that require manual approval for Project Version 4713\n/html/ssc/index.jsp#!/version/4713/artifacts?filterSet=")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error polling timeout", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4714, "", &models.FilterSet{}, 1)
|
||||||
|
assert.EqualError(t, err, "Terminating after 0 minutes since artifact for Project Version 4714 is still in status PROCESSING")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("success build label", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4715, "/commit/test", &models.FilterSet{}, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error no artifacts", func(t *testing.T) {
|
||||||
|
err := verifyScanResultsFinishedUploading(config, &ffMock, 4716, "", &models.FilterSet{}, 0)
|
||||||
|
assert.EqualError(t, err, "No uploaded artifacts for assessment detected for project version with ID 4716")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateTimeDifferenceToLastUpload(t *testing.T) {
|
||||||
|
diffSeconds := calculateTimeDifferenceToLastUpload(models.Iso8601MilliDateTime(time.Now().UTC()), 1234)
|
||||||
|
|
||||||
|
assert.Equal(t, true, diffSeconds < 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteTemplatedCommand(t *testing.T) {
|
||||||
|
runner := execRunnerMock{}
|
||||||
|
template := []string{"{{.Executable}}", "-c", "{{.Param}}"}
|
||||||
|
context := map[string]string{"Executable": "test.cmd", "Param": "abcd"}
|
||||||
|
executeTemplatedCommand(&runner, template, context)
|
||||||
|
|
||||||
|
assert.Equal(t, "test.cmd", runner.executions[0].executable)
|
||||||
|
assert.Equal(t, []string{"-c", "abcd"}, runner.executions[0].parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeterminePullRequestMerge(t *testing.T) {
|
||||||
|
config := fortifyExecuteScanOptions{CommitMessage: "Merge pull request #2462 from branch f-test", PullRequestMessageRegex: `(?m).*Merge pull request #(\d+) from.*`, PullRequestMessageRegexGroup: 1}
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
match := determinePullRequestMerge(config)
|
||||||
|
assert.Equal(t, "2462", match, "Expected different result")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no match", func(t *testing.T) {
|
||||||
|
config.CommitMessage = "Some test commit"
|
||||||
|
match := determinePullRequestMerge(config)
|
||||||
|
assert.Equal(t, "", match, "Expected different result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeterminePullRequestMergeGithub(t *testing.T) {
|
||||||
|
prServiceMock := pullRequestServiceMock{}
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "A"}, prServiceMock)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "17", match, "Expected different result")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no match", func(t *testing.T) {
|
||||||
|
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "B"}, prServiceMock)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "", match, "Expected different result")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error", func(t *testing.T) {
|
||||||
|
match, err := determinePullRequestMergeGithub(nil, fortifyExecuteScanOptions{Owner: "C"}, prServiceMock)
|
||||||
|
assert.EqualError(t, err, "Test error")
|
||||||
|
assert.Equal(t, "", match, "Expected different result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTranslateProject(t *testing.T) {
|
||||||
|
t.Run("python", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "pip", Memory: "-Xmx4G", Translate: `[{"pythonPath":"./some/path","pythonIncludes":"./**/*","pythonExcludes":"./tests/**/*"}]`}
|
||||||
|
translateProject(&config, &execRunner, "/commit/7267658798797", "")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx4G", "-python-path", "./some/path", "-exclude", "./tests/**/*", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("asp", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "windows", Memory: "-Xmx6G", Translate: `[{"aspnetcore":"true","dotNetCoreVersion":"3.5","exclude":"./tests/**/*","libDirs":"tmp/","src":"./**/*"}]`}
|
||||||
|
translateProject(&config, &execRunner, "/commit/7267658798797", "")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx6G", "-aspnetcore", "-dotnet-core-version", "3.5", "-exclude", "./tests/**/*", "-libdirs", "tmp/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("java", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar","extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`}
|
||||||
|
translateProject(&config, &execRunner, "/commit/7267658798797", "")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./classes/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("auto classpath", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar", "extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`}
|
||||||
|
translateProject(&config, &execRunner, "/commit/7267658798797", "./WEB-INF/lib/*.jar")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./WEB-INF/lib/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScanProject(t *testing.T) {
|
||||||
|
config := fortifyExecuteScanOptions{Memory: "-Xmx4G"}
|
||||||
|
|
||||||
|
t.Run("normal", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
scanProject(&config, &execRunner, "/commit/7267658798797", "label")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-build-label", "label", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("quick", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
config.QuickScan = true
|
||||||
|
scanProject(&config, &execRunner, "/commit/7267658798797", "")
|
||||||
|
assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-quick", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutoresolveClasspath(t *testing.T) {
|
||||||
|
t.Run("success pip", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
dir, err := ioutil.TempDir("", "classpath")
|
||||||
|
assert.NoError(t, err, "Unexpected error detected")
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
file := filepath.Join(dir, "cp.txt")
|
||||||
|
|
||||||
|
result := autoresolvePipClasspath("python2", []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, file, &execRunner)
|
||||||
|
assert.Equal(t, "python2", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
assert.Equal(t, "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", result, "Expected different result")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("success maven", func(t *testing.T) {
|
||||||
|
execRunner := execRunnerMock{}
|
||||||
|
dir, err := ioutil.TempDir("", "classpath")
|
||||||
|
assert.NoError(t, err, "Unexpected error detected")
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
file := filepath.Join(dir, "cp.txt")
|
||||||
|
|
||||||
|
result := autoresolveMavenClasspath("pom.xml", file, &execRunner)
|
||||||
|
assert.Equal(t, "mvn", execRunner.executions[0].executable, "Expected different executable")
|
||||||
|
assert.Equal(t, []string{"--file", "pom.xml", fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, execRunner.executions[0].parameters, "Expected different parameters")
|
||||||
|
assert.Equal(t, "some.jar;someother.jar", result, "Expected different result")
|
||||||
|
})
|
||||||
|
}
|
@ -89,7 +89,7 @@ func addGctsCreateRepositoryFlags(cmd *cobra.Command, stepConfig *gctsCreateRepo
|
|||||||
cmd.Flags().StringVar(&stepConfig.RemoteRepositoryURL, "remoteRepositoryURL", os.Getenv("PIPER_remoteRepositoryURL"), "URL of the corresponding remote repository")
|
cmd.Flags().StringVar(&stepConfig.RemoteRepositoryURL, "remoteRepositoryURL", os.Getenv("PIPER_remoteRepositoryURL"), "URL of the corresponding remote repository")
|
||||||
cmd.Flags().StringVar(&stepConfig.Role, "role", os.Getenv("PIPER_role"), "Role of the local repository. Choose between 'TARGET' and 'SOURCE'. Local repositories with a TARGET role will NOT be able to be the source of code changes")
|
cmd.Flags().StringVar(&stepConfig.Role, "role", os.Getenv("PIPER_role"), "Role of the local repository. Choose between 'TARGET' and 'SOURCE'. Local repositories with a TARGET role will NOT be able to be the source of code changes")
|
||||||
cmd.Flags().StringVar(&stepConfig.VSID, "vSID", os.Getenv("PIPER_vSID"), "Virtual SID of the local repository. The vSID corresponds to the transport route that delivers content to the remote Git repository")
|
cmd.Flags().StringVar(&stepConfig.VSID, "vSID", os.Getenv("PIPER_vSID"), "Virtual SID of the local repository. The vSID corresponds to the transport route that delivers content to the remote Git repository")
|
||||||
cmd.Flags().StringVar(&stepConfig.Type, "type", "GIT", "Type of the used source code management tool")
|
cmd.Flags().StringVar(&stepConfig.Type, "type", `GIT`, "Type of the used source code management tool")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("username")
|
cmd.MarkFlagRequired("username")
|
||||||
cmd.MarkFlagRequired("password")
|
cmd.MarkFlagRequired("password")
|
||||||
|
@ -87,11 +87,11 @@ func addGithubCreatePullRequestFlags(cmd *cobra.Command, stepConfig *githubCreat
|
|||||||
cmd.Flags().StringSliceVar(&stepConfig.Assignees, "assignees", []string{}, "Login names of users to which the PR should be assigned to.")
|
cmd.Flags().StringSliceVar(&stepConfig.Assignees, "assignees", []string{}, "Login names of users to which the PR should be assigned to.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Base, "base", os.Getenv("PIPER_base"), "The name of the branch you want the changes pulled into.")
|
cmd.Flags().StringVar(&stepConfig.Base, "base", os.Getenv("PIPER_base"), "The name of the branch you want the changes pulled into.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Body, "body", os.Getenv("PIPER_body"), "The description text of the pull request in markdown format.")
|
cmd.Flags().StringVar(&stepConfig.Body, "body", os.Getenv("PIPER_body"), "The description text of the pull request in markdown format.")
|
||||||
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", "https://api.github.com", "Set the GitHub API url.")
|
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", `https://api.github.com`, "Set the GitHub API url.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Head, "head", os.Getenv("PIPER_head"), "The name of the branch where your changes are implemented.")
|
cmd.Flags().StringVar(&stepConfig.Head, "head", os.Getenv("PIPER_head"), "The name of the branch where your changes are implemented.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
|
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", "https://github.com", "GitHub server url for end-user access.")
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", `https://github.com`, "GitHub server url for end-user access.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Title, "title", os.Getenv("PIPER_title"), "Title of the pull request.")
|
cmd.Flags().StringVar(&stepConfig.Title, "title", os.Getenv("PIPER_title"), "Title of the pull request.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Token, "token", os.Getenv("PIPER_token"), "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.Token, "token", os.Getenv("PIPER_token"), "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().StringSliceVar(&stepConfig.Labels, "labels", []string{}, "Labels to be added to the pull request.")
|
cmd.Flags().StringSliceVar(&stepConfig.Labels, "labels", []string{}, "Labels to be added to the pull request.")
|
||||||
|
@ -96,17 +96,17 @@ The result looks like
|
|||||||
func addGithubPublishReleaseFlags(cmd *cobra.Command, stepConfig *githubPublishReleaseOptions) {
|
func addGithubPublishReleaseFlags(cmd *cobra.Command, stepConfig *githubPublishReleaseOptions) {
|
||||||
cmd.Flags().BoolVar(&stepConfig.AddClosedIssues, "addClosedIssues", false, "If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`")
|
cmd.Flags().BoolVar(&stepConfig.AddClosedIssues, "addClosedIssues", false, "If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`")
|
||||||
cmd.Flags().BoolVar(&stepConfig.AddDeltaToLastRelease, "addDeltaToLastRelease", false, "If set to `true`, a link will be added to the relese information that brings up all commits since the last release.")
|
cmd.Flags().BoolVar(&stepConfig.AddDeltaToLastRelease, "addDeltaToLastRelease", false, "If set to `true`, a link will be added to the relese information that brings up all commits since the last release.")
|
||||||
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", "https://api.github.com", "Set the GitHub API url.")
|
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", `https://api.github.com`, "Set the GitHub API url.")
|
||||||
cmd.Flags().StringVar(&stepConfig.AssetPath, "assetPath", os.Getenv("PIPER_assetPath"), "Path to a release asset which should be uploaded to the list of release assets.")
|
cmd.Flags().StringVar(&stepConfig.AssetPath, "assetPath", os.Getenv("PIPER_assetPath"), "Path to a release asset which should be uploaded to the list of release assets.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Commitish, "commitish", "master", "Target git commitish for the release")
|
cmd.Flags().StringVar(&stepConfig.Commitish, "commitish", `master`, "Target git commitish for the release")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.ExcludeLabels, "excludeLabels", []string{}, "Allows to exclude issues with dedicated list of labels.")
|
cmd.Flags().StringSliceVar(&stepConfig.ExcludeLabels, "excludeLabels", []string{}, "Allows to exclude issues with dedicated list of labels.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.Labels, "labels", []string{}, "Labels to include in issue search.")
|
cmd.Flags().StringSliceVar(&stepConfig.Labels, "labels", []string{}, "Labels to include in issue search.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ReleaseBodyHeader, "releaseBodyHeader", os.Getenv("PIPER_releaseBodyHeader"), "Content which will appear for the release.")
|
cmd.Flags().StringVar(&stepConfig.ReleaseBodyHeader, "releaseBodyHeader", os.Getenv("PIPER_releaseBodyHeader"), "Content which will appear for the release.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
|
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", "https://github.com", "GitHub server url for end-user access.")
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", `https://github.com`, "GitHub server url for end-user access.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Token, "token", os.Getenv("PIPER_token"), "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.Token, "token", os.Getenv("PIPER_token"), "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.UploadURL, "uploadUrl", "https://uploads.github.com", "Set the GitHub API url.")
|
cmd.Flags().StringVar(&stepConfig.UploadURL, "uploadUrl", `https://uploads.github.com`, "Set the GitHub API url.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Version, "version", os.Getenv("PIPER_version"), "Define the version number which will be written as tag as well as release name.")
|
cmd.Flags().StringVar(&stepConfig.Version, "version", os.Getenv("PIPER_version"), "Define the version number which will be written as tag as well as release name.")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("apiUrl")
|
cmd.MarkFlagRequired("apiUrl")
|
||||||
|
@ -83,9 +83,9 @@ In the Docker network, the containers can be referenced by the values provided i
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addKarmaExecuteTestsFlags(cmd *cobra.Command, stepConfig *karmaExecuteTestsOptions) {
|
func addKarmaExecuteTestsFlags(cmd *cobra.Command, stepConfig *karmaExecuteTestsOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.InstallCommand, "installCommand", "npm install --quiet", "The command that is executed to install the test tool.")
|
cmd.Flags().StringVar(&stepConfig.InstallCommand, "installCommand", `npm install --quiet`, "The command that is executed to install the test tool.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ModulePath, "modulePath", ".", "Define the path of the module to execute tests on.")
|
cmd.Flags().StringVar(&stepConfig.ModulePath, "modulePath", `.`, "Define the path of the module to execute tests on.")
|
||||||
cmd.Flags().StringVar(&stepConfig.RunCommand, "runCommand", "npm run karma", "The command that is executed to start the tests.")
|
cmd.Flags().StringVar(&stepConfig.RunCommand, "runCommand", `npm run karma`, "The command that is executed to start the tests.")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("installCommand")
|
cmd.MarkFlagRequired("installCommand")
|
||||||
cmd.MarkFlagRequired("modulePath")
|
cmd.MarkFlagRequired("modulePath")
|
||||||
|
@ -117,17 +117,17 @@ func addKubernetesDeployFlags(cmd *cobra.Command, stepConfig *kubernetesDeployOp
|
|||||||
cmd.Flags().StringVar(&stepConfig.ContainerRegistryPassword, "containerRegistryPassword", os.Getenv("PIPER_containerRegistryPassword"), "Password for container registry access - typically provided by the CI/CD environment.")
|
cmd.Flags().StringVar(&stepConfig.ContainerRegistryPassword, "containerRegistryPassword", os.Getenv("PIPER_containerRegistryPassword"), "Password for container registry access - typically provided by the CI/CD environment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "http(s) url of the Container registry.")
|
cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "http(s) url of the Container registry.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ContainerRegistryUser, "containerRegistryUser", os.Getenv("PIPER_containerRegistryUser"), "Username for container registry access - typically provided by the CI/CD environment.")
|
cmd.Flags().StringVar(&stepConfig.ContainerRegistryUser, "containerRegistryUser", os.Getenv("PIPER_containerRegistryUser"), "Username for container registry access - typically provided by the CI/CD environment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ContainerRegistrySecret, "containerRegistrySecret", "regsecret", "Name of the container registry secret used for pulling containers from the registry.")
|
cmd.Flags().StringVar(&stepConfig.ContainerRegistrySecret, "containerRegistrySecret", `regsecret`, "Name of the container registry secret used for pulling containers from the registry.")
|
||||||
cmd.Flags().BoolVar(&stepConfig.CreateDockerRegistrySecret, "createDockerRegistrySecret", false, "Toggle to turn on Regsecret creation with a \"deployTool:kubectl\" deployment.")
|
cmd.Flags().BoolVar(&stepConfig.CreateDockerRegistrySecret, "createDockerRegistrySecret", false, "Toggle to turn on Regsecret creation with a \"deployTool:kubectl\" deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.DeploymentName, "deploymentName", os.Getenv("PIPER_deploymentName"), "Defines the name of the deployment.")
|
cmd.Flags().StringVar(&stepConfig.DeploymentName, "deploymentName", os.Getenv("PIPER_deploymentName"), "Defines the name of the deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.DeployTool, "deployTool", "kubectl", "Defines the tool which should be used for deployment.")
|
cmd.Flags().StringVar(&stepConfig.DeployTool, "deployTool", `kubectl`, "Defines the tool which should be used for deployment.")
|
||||||
cmd.Flags().IntVar(&stepConfig.HelmDeployWaitSeconds, "helmDeployWaitSeconds", 300, "Number of seconds before helm deploy returns.")
|
cmd.Flags().IntVar(&stepConfig.HelmDeployWaitSeconds, "helmDeployWaitSeconds", 300, "Number of seconds before helm deploy returns.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Image, "image", os.Getenv("PIPER_image"), "Full name of the image to be deployed.")
|
cmd.Flags().StringVar(&stepConfig.Image, "image", os.Getenv("PIPER_image"), "Full name of the image to be deployed.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.IngressHosts, "ingressHosts", []string{}, "List of ingress hosts to be exposed via helm deployment.")
|
cmd.Flags().StringSliceVar(&stepConfig.IngressHosts, "ingressHosts", []string{}, "List of ingress hosts to be exposed via helm deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.KubeConfig, "kubeConfig", os.Getenv("PIPER_kubeConfig"), "Defines the path to the \"kubeconfig\" file.")
|
cmd.Flags().StringVar(&stepConfig.KubeConfig, "kubeConfig", os.Getenv("PIPER_kubeConfig"), "Defines the path to the \"kubeconfig\" file.")
|
||||||
cmd.Flags().StringVar(&stepConfig.KubeContext, "kubeContext", os.Getenv("PIPER_kubeContext"), "Defines the context to use from the \"kubeconfig\" file.")
|
cmd.Flags().StringVar(&stepConfig.KubeContext, "kubeContext", os.Getenv("PIPER_kubeContext"), "Defines the context to use from the \"kubeconfig\" file.")
|
||||||
cmd.Flags().StringVar(&stepConfig.KubeToken, "kubeToken", os.Getenv("PIPER_kubeToken"), "Contains the id_token used by kubectl for authentication. Consider using kubeConfig parameter instead.")
|
cmd.Flags().StringVar(&stepConfig.KubeToken, "kubeToken", os.Getenv("PIPER_kubeToken"), "Contains the id_token used by kubectl for authentication. Consider using kubeConfig parameter instead.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Namespace, "namespace", "default", "Defines the target Kubernetes namespace for the deployment.")
|
cmd.Flags().StringVar(&stepConfig.Namespace, "namespace", `default`, "Defines the target Kubernetes namespace for the deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.TillerNamespace, "tillerNamespace", os.Getenv("PIPER_tillerNamespace"), "Defines optional tiller namespace for deployments using helm.")
|
cmd.Flags().StringVar(&stepConfig.TillerNamespace, "tillerNamespace", os.Getenv("PIPER_tillerNamespace"), "Defines optional tiller namespace for deployments using helm.")
|
||||||
|
|
||||||
cmd.MarkFlagRequired("chartPath")
|
cmd.MarkFlagRequired("chartPath")
|
||||||
|
@ -79,7 +79,7 @@ supports ci friendly versioning by flattening the pom before installing.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addMavenBuildFlags(cmd *cobra.Command, stepConfig *mavenBuildOptions) {
|
func addMavenBuildFlags(cmd *cobra.Command, stepConfig *mavenBuildOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.PomPath, "pomPath", "pom.xml", "Path to the pom file which should be installed including all children.")
|
cmd.Flags().StringVar(&stepConfig.PomPath, "pomPath", `pom.xml`, "Path to the pom file which should be installed including all children.")
|
||||||
cmd.Flags().BoolVar(&stepConfig.Flatten, "flatten", true, "Defines if the pom files should be flattened to support ci friendly maven versioning.")
|
cmd.Flags().BoolVar(&stepConfig.Flatten, "flatten", true, "Defines if the pom files should be flattened to support ci friendly maven versioning.")
|
||||||
cmd.Flags().BoolVar(&stepConfig.Verify, "verify", false, "Instead of installing the artifact only the verify lifecycle phase is executed.")
|
cmd.Flags().BoolVar(&stepConfig.Verify, "verify", false, "Instead of installing the artifact only the verify lifecycle phase is executed.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path to the mvn settings file that should be used as project settings file.")
|
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path to the mvn settings file that should be used as project settings file.")
|
||||||
|
@ -111,15 +111,15 @@ func MtaBuildCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addMtaBuildFlags(cmd *cobra.Command, stepConfig *mtaBuildOptions) {
|
func addMtaBuildFlags(cmd *cobra.Command, stepConfig *mtaBuildOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.BuildTarget, "buildTarget", "NEO", "mtaBuildTool 'classic' only: The target platform to which the mtar can be deployed. Valid values: 'CF', 'NEO', 'XSA'.")
|
cmd.Flags().StringVar(&stepConfig.BuildTarget, "buildTarget", `NEO`, "mtaBuildTool 'classic' only: The target platform to which the mtar can be deployed. Valid values: 'CF', 'NEO', 'XSA'.")
|
||||||
cmd.Flags().StringVar(&stepConfig.MtaBuildTool, "mtaBuildTool", "cloudMbt", "Tool to use when building the MTA. Valid values: 'classic', 'cloudMbt'.")
|
cmd.Flags().StringVar(&stepConfig.MtaBuildTool, "mtaBuildTool", `cloudMbt`, "Tool to use when building the MTA. Valid values: 'classic', 'cloudMbt'.")
|
||||||
cmd.Flags().StringVar(&stepConfig.MtarName, "mtarName", os.Getenv("PIPER_mtarName"), "The name of the generated mtar file including its extension.")
|
cmd.Flags().StringVar(&stepConfig.MtarName, "mtarName", os.Getenv("PIPER_mtarName"), "The name of the generated mtar file including its extension.")
|
||||||
cmd.Flags().StringVar(&stepConfig.MtaJarLocation, "mtaJarLocation", "/opt/sap/mta/lib/mta.jar", "mtaBuildTool 'classic' only: The location of the SAP Multitarget Application Archive Builder jar file, including file name and extension. If you run on Docker, this must match the location of the jar file in the container as well.")
|
cmd.Flags().StringVar(&stepConfig.MtaJarLocation, "mtaJarLocation", `/opt/sap/mta/lib/mta.jar`, "mtaBuildTool 'classic' only: The location of the SAP Multitarget Application Archive Builder jar file, including file name and extension. If you run on Docker, this must match the location of the jar file in the container as well.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Extensions, "extensions", os.Getenv("PIPER_extensions"), "The path to the extension descriptor file.")
|
cmd.Flags().StringVar(&stepConfig.Extensions, "extensions", os.Getenv("PIPER_extensions"), "The path to the extension descriptor file.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Platform, "platform", "CF", "mtaBuildTool 'cloudMbt' only: The target platform to which the mtar can be deployed.")
|
cmd.Flags().StringVar(&stepConfig.Platform, "platform", `CF`, "mtaBuildTool 'cloudMbt' only: The target platform to which the mtar can be deployed.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ApplicationName, "applicationName", os.Getenv("PIPER_applicationName"), "The name of the application which is being built. If the parameter has been provided and no `mta.yaml` exists, the `mta.yaml` will be automatically generated using this parameter and the information (`name` and `version`) from 'package.json` before the actual build starts.")
|
cmd.Flags().StringVar(&stepConfig.ApplicationName, "applicationName", os.Getenv("PIPER_applicationName"), "The name of the application which is being built. If the parameter has been provided and no `mta.yaml` exists, the `mta.yaml` will be automatically generated using this parameter and the information (`name` and `version`) from 'package.json` before the actual build starts.")
|
||||||
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "Url to the npm registry that should be used for installing npm dependencies.")
|
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "Url to the npm registry that should be used for installing npm dependencies.")
|
||||||
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", "https://npm.sap.com", "Url to the sap npm registry that should be used for installing npm dependencies prefixed with @sap.")
|
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", `https://npm.sap.com`, "Url to the sap npm registry that should be used for installing npm dependencies prefixed with @sap.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path or url to the mvn settings file that should be used as project settings file.")
|
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path or url to the mvn settings file that should be used as project settings file.")
|
||||||
cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path or url to the mvn settings file that should be used as global settings file")
|
cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path or url to the mvn settings file that should be used as global settings file")
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ If an image for mavenExecute is configured, and npm packages are to be published
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addNexusUploadFlags(cmd *cobra.Command, stepConfig *nexusUploadOptions) {
|
func addNexusUploadFlags(cmd *cobra.Command, stepConfig *nexusUploadOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.Version, "version", "nexus3", "The Nexus Repository Manager version. Currently supported are 'nexus2' and 'nexus3'.")
|
cmd.Flags().StringVar(&stepConfig.Version, "version", `nexus3`, "The Nexus Repository Manager version. Currently supported are 'nexus2' and 'nexus3'.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Url, "url", os.Getenv("PIPER_url"), "URL of the nexus. The scheme part of the URL will not be considered, because only http is supported.")
|
cmd.Flags().StringVar(&stepConfig.Url, "url", os.Getenv("PIPER_url"), "URL of the nexus. The scheme part of the URL will not be considered, because only http is supported.")
|
||||||
cmd.Flags().StringVar(&stepConfig.MavenRepository, "mavenRepository", os.Getenv("PIPER_mavenRepository"), "Name of the nexus repository for Maven and MTA deployments. If this is not provided, Maven and MTA deployment is implicitly disabled.")
|
cmd.Flags().StringVar(&stepConfig.MavenRepository, "mavenRepository", os.Getenv("PIPER_mavenRepository"), "Name of the nexus repository for Maven and MTA deployments. If this is not provided, Maven and MTA deployment is implicitly disabled.")
|
||||||
cmd.Flags().StringVar(&stepConfig.NpmRepository, "npmRepository", os.Getenv("PIPER_npmRepository"), "Name of the nexus repository for npm deployments. If this is not provided, npm deployment is implicitly disabled.")
|
cmd.Flags().StringVar(&stepConfig.NpmRepository, "npmRepository", os.Getenv("PIPER_npmRepository"), "Name of the nexus repository for npm deployments. If this is not provided, npm deployment is implicitly disabled.")
|
||||||
|
@ -77,7 +77,7 @@ func addNpmExecuteScriptsFlags(cmd *cobra.Command, stepConfig *npmExecuteScripts
|
|||||||
cmd.Flags().BoolVar(&stepConfig.Install, "install", false, "Run npm install or similar commands depending on the project structure.")
|
cmd.Flags().BoolVar(&stepConfig.Install, "install", false, "Run npm install or similar commands depending on the project structure.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.RunScripts, "runScripts", []string{}, "List of additional run scripts to execute from package.json.")
|
cmd.Flags().StringSliceVar(&stepConfig.RunScripts, "runScripts", []string{}, "List of additional run scripts to execute from package.json.")
|
||||||
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "URL of the npm registry to use. Defaults to https://registry.npmjs.org/")
|
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "URL of the npm registry to use. Defaults to https://registry.npmjs.org/")
|
||||||
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", "https://npm.sap.com", "The default npm registry URL to be used as the remote mirror for the SAP npm packages.")
|
cmd.Flags().StringVar(&stepConfig.SapNpmRegistry, "sapNpmRegistry", `https://npm.sap.com`, "The default npm registry URL to be used as the remote mirror for the SAP npm packages.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ func Execute() {
|
|||||||
rootCmd.AddCommand(CloudFoundryDeleteServiceCommand())
|
rootCmd.AddCommand(CloudFoundryDeleteServiceCommand())
|
||||||
rootCmd.AddCommand(AbapEnvironmentPullGitRepoCommand())
|
rootCmd.AddCommand(AbapEnvironmentPullGitRepoCommand())
|
||||||
rootCmd.AddCommand(CheckmarxExecuteScanCommand())
|
rootCmd.AddCommand(CheckmarxExecuteScanCommand())
|
||||||
|
rootCmd.AddCommand(FortifyExecuteScanCommand())
|
||||||
rootCmd.AddCommand(MtaBuildCommand())
|
rootCmd.AddCommand(MtaBuildCommand())
|
||||||
rootCmd.AddCommand(ProtecodeExecuteScanCommand())
|
rootCmd.AddCommand(ProtecodeExecuteScanCommand())
|
||||||
rootCmd.AddCommand(MavenExecuteCommand())
|
rootCmd.AddCommand(MavenExecuteCommand())
|
||||||
|
@ -140,17 +140,17 @@ func ProtecodeExecuteScanCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addProtecodeExecuteScanFlags(cmd *cobra.Command, stepConfig *protecodeExecuteScanOptions) {
|
func addProtecodeExecuteScanFlags(cmd *cobra.Command, stepConfig *protecodeExecuteScanOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.ExcludeCVEs, "excludeCVEs", "[]", "DEPRECATED: Do use triaging within the Protecode UI instead")
|
cmd.Flags().StringVar(&stepConfig.ExcludeCVEs, "excludeCVEs", `[]`, "DEPRECATED: Do use triaging within the Protecode UI instead")
|
||||||
cmd.Flags().BoolVar(&stepConfig.FailOnSevereVulnerabilities, "failOnSevereVulnerabilities", true, "Whether to fail the job on severe vulnerabilties or not")
|
cmd.Flags().BoolVar(&stepConfig.FailOnSevereVulnerabilities, "failOnSevereVulnerabilities", true, "Whether to fail the job on severe vulnerabilties or not")
|
||||||
cmd.Flags().StringVar(&stepConfig.ScanImage, "scanImage", os.Getenv("PIPER_scanImage"), "The reference to the docker image to scan with Protecode")
|
cmd.Flags().StringVar(&stepConfig.ScanImage, "scanImage", os.Getenv("PIPER_scanImage"), "The reference to the docker image to scan with Protecode")
|
||||||
cmd.Flags().StringVar(&stepConfig.DockerRegistryURL, "dockerRegistryUrl", os.Getenv("PIPER_dockerRegistryUrl"), "The reference to the docker registry to scan with Protecode")
|
cmd.Flags().StringVar(&stepConfig.DockerRegistryURL, "dockerRegistryUrl", os.Getenv("PIPER_dockerRegistryUrl"), "The reference to the docker registry to scan with Protecode")
|
||||||
cmd.Flags().StringVar(&stepConfig.CleanupMode, "cleanupMode", "binary", "Decides which parts are removed from the Protecode backend after the scan")
|
cmd.Flags().StringVar(&stepConfig.CleanupMode, "cleanupMode", `binary`, "Decides which parts are removed from the Protecode backend after the scan")
|
||||||
cmd.Flags().StringVar(&stepConfig.FilePath, "filePath", os.Getenv("PIPER_filePath"), "The path to the file from local workspace to scan with Protecode")
|
cmd.Flags().StringVar(&stepConfig.FilePath, "filePath", os.Getenv("PIPER_filePath"), "The path to the file from local workspace to scan with Protecode")
|
||||||
cmd.Flags().BoolVar(&stepConfig.IncludeLayers, "includeLayers", false, "Flag if the docker layers should be included")
|
cmd.Flags().BoolVar(&stepConfig.IncludeLayers, "includeLayers", false, "Flag if the docker layers should be included")
|
||||||
cmd.Flags().BoolVar(&stepConfig.AddSideBarLink, "addSideBarLink", true, "Whether to create a side bar link pointing to the report produced by Protecode or not")
|
cmd.Flags().BoolVar(&stepConfig.AddSideBarLink, "addSideBarLink", true, "Whether to create a side bar link pointing to the report produced by Protecode or not")
|
||||||
cmd.Flags().StringVar(&stepConfig.TimeoutMinutes, "timeoutMinutes", "60", "The timeout to wait for the scan to finish")
|
cmd.Flags().StringVar(&stepConfig.TimeoutMinutes, "timeoutMinutes", `60`, "The timeout to wait for the scan to finish")
|
||||||
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL to the Protecode backend")
|
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "The URL to the Protecode backend")
|
||||||
cmd.Flags().StringVar(&stepConfig.ReportFileName, "reportFileName", "protecode_report.pdf", "The file name of the report to be created")
|
cmd.Flags().StringVar(&stepConfig.ReportFileName, "reportFileName", `protecode_report.pdf`, "The file name of the report to be created")
|
||||||
cmd.Flags().StringVar(&stepConfig.FetchURL, "fetchUrl", os.Getenv("PIPER_fetchUrl"), "The URL to fetch the file to scan with Protecode which must be accessible via public HTTP GET request")
|
cmd.Flags().StringVar(&stepConfig.FetchURL, "fetchUrl", os.Getenv("PIPER_fetchUrl"), "The URL to fetch the file to scan with Protecode which must be accessible via public HTTP GET request")
|
||||||
cmd.Flags().StringVar(&stepConfig.Group, "group", os.Getenv("PIPER_group"), "The Protecode group ID of your team")
|
cmd.Flags().StringVar(&stepConfig.Group, "group", os.Getenv("PIPER_group"), "The Protecode group ID of your team")
|
||||||
cmd.Flags().BoolVar(&stepConfig.ReuseExisting, "reuseExisting", false, "Whether to reuse an existing product instead of creating a new one")
|
cmd.Flags().BoolVar(&stepConfig.ReuseExisting, "reuseExisting", false, "Whether to reuse an existing product instead of creating a new one")
|
||||||
|
@ -128,25 +128,25 @@ func SonarExecuteScanCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addSonarExecuteScanFlags(cmd *cobra.Command, stepConfig *sonarExecuteScanOptions) {
|
func addSonarExecuteScanFlags(cmd *cobra.Command, stepConfig *sonarExecuteScanOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.Instance, "instance", "SonarCloud", "Jenkins only: The name of the SonarQube instance defined in the Jenkins settings. DEPRECATED: use host parameter instead")
|
cmd.Flags().StringVar(&stepConfig.Instance, "instance", `SonarCloud`, "Jenkins only: The name of the SonarQube instance defined in the Jenkins settings. DEPRECATED: use host parameter instead")
|
||||||
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "The URL to the Sonar backend.")
|
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "The URL to the Sonar backend.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Token, "token", os.Getenv("PIPER_token"), "Token used to authenticate with the Sonar Server.")
|
cmd.Flags().StringVar(&stepConfig.Token, "token", os.Getenv("PIPER_token"), "Token used to authenticate with the Sonar Server.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Organization, "organization", os.Getenv("PIPER_organization"), "SonarCloud.io only: Organization that the project will be assigned to in SonarCloud.io.")
|
cmd.Flags().StringVar(&stepConfig.Organization, "organization", os.Getenv("PIPER_organization"), "SonarCloud.io only: Organization that the project will be assigned to in SonarCloud.io.")
|
||||||
cmd.Flags().StringVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", os.Getenv("PIPER_customTlsCertificateLinks"), "List of comma-separated download links to custom TLS certificates. This is required to ensure trusted connections to instances with custom certificates.")
|
cmd.Flags().StringVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", os.Getenv("PIPER_customTlsCertificateLinks"), "List of comma-separated download links to custom TLS certificates. This is required to ensure trusted connections to instances with custom certificates.")
|
||||||
cmd.Flags().StringVar(&stepConfig.SonarScannerDownloadURL, "sonarScannerDownloadUrl", "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102-linux.zip", "URL to the sonar-scanner-cli archive.")
|
cmd.Flags().StringVar(&stepConfig.SonarScannerDownloadURL, "sonarScannerDownloadUrl", `https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.3.0.2102-linux.zip`, "URL to the sonar-scanner-cli archive.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ProjectVersion, "projectVersion", os.Getenv("PIPER_projectVersion"), "The project version that is reported to SonarQube.")
|
cmd.Flags().StringVar(&stepConfig.ProjectVersion, "projectVersion", os.Getenv("PIPER_projectVersion"), "The project version that is reported to SonarQube.")
|
||||||
cmd.Flags().StringSliceVar(&stepConfig.Options, "options", []string{}, "A list of options which are passed to the sonar-scanner.")
|
cmd.Flags().StringSliceVar(&stepConfig.Options, "options", []string{}, "A list of options which are passed to the sonar-scanner.")
|
||||||
cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", os.Getenv("PIPER_branchName"), "Non-Pull-Request only: Name of the SonarQube branch that should be used to report findings to.")
|
cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", os.Getenv("PIPER_branchName"), "Non-Pull-Request only: Name of the SonarQube branch that should be used to report findings to.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ChangeID, "changeId", os.Getenv("PIPER_changeId"), "Pull-Request only: The id of the pull-request.")
|
cmd.Flags().StringVar(&stepConfig.ChangeID, "changeId", os.Getenv("PIPER_changeId"), "Pull-Request only: The id of the pull-request.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ChangeBranch, "changeBranch", os.Getenv("PIPER_changeBranch"), "Pull-Request only: The name of the pull-request branch.")
|
cmd.Flags().StringVar(&stepConfig.ChangeBranch, "changeBranch", os.Getenv("PIPER_changeBranch"), "Pull-Request only: The name of the pull-request branch.")
|
||||||
cmd.Flags().StringVar(&stepConfig.ChangeTarget, "changeTarget", os.Getenv("PIPER_changeTarget"), "Pull-Request only: The name of the base branch.")
|
cmd.Flags().StringVar(&stepConfig.ChangeTarget, "changeTarget", os.Getenv("PIPER_changeTarget"), "Pull-Request only: The name of the base branch.")
|
||||||
cmd.Flags().StringVar(&stepConfig.PullRequestProvider, "pullRequestProvider", "GitHub", "Pull-Request only: The scm provider.")
|
cmd.Flags().StringVar(&stepConfig.PullRequestProvider, "pullRequestProvider", `GitHub`, "Pull-Request only: The scm provider.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Pull-Request only: The owner of the scm repository.")
|
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Pull-Request only: The owner of the scm repository.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Pull-Request only: The scm repository.")
|
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Pull-Request only: The scm repository.")
|
||||||
cmd.Flags().StringVar(&stepConfig.GithubToken, "githubToken", os.Getenv("PIPER_githubToken"), "Pull-Request only: Token for Github to set status on the Pull-Request.")
|
cmd.Flags().StringVar(&stepConfig.GithubToken, "githubToken", os.Getenv("PIPER_githubToken"), "Pull-Request only: Token for Github to set status on the Pull-Request.")
|
||||||
cmd.Flags().BoolVar(&stepConfig.DisableInlineComments, "disableInlineComments", false, "Pull-Request only: Disables the pull-request decoration with inline comments. DEPRECATED: only supported in SonarQube < 7.2")
|
cmd.Flags().BoolVar(&stepConfig.DisableInlineComments, "disableInlineComments", false, "Pull-Request only: Disables the pull-request decoration with inline comments. DEPRECATED: only supported in SonarQube < 7.2")
|
||||||
cmd.Flags().BoolVar(&stepConfig.LegacyPRHandling, "legacyPRHandling", false, "Pull-Request only: Activates the pull-request handling using the [GitHub Plugin](https://docs.sonarqube.org/display/PLUG/GitHub+Plugin). DEPRECATED: only supported in SonarQube < 7.2")
|
cmd.Flags().BoolVar(&stepConfig.LegacyPRHandling, "legacyPRHandling", false, "Pull-Request only: Activates the pull-request handling using the [GitHub Plugin](https://docs.sonarqube.org/display/PLUG/GitHub+Plugin). DEPRECATED: only supported in SonarQube < 7.2")
|
||||||
cmd.Flags().StringVar(&stepConfig.GithubAPIURL, "githubApiUrl", "https://api.github.com", "Pull-Request only: The URL to the Github API. see [GitHub plugin docs](https://docs.sonarqube.org/display/PLUG/GitHub+Plugin#GitHubPlugin-Usage) DEPRECATED: only supported in SonarQube < 7.2")
|
cmd.Flags().StringVar(&stepConfig.GithubAPIURL, "githubApiUrl", `https://api.github.com`, "Pull-Request only: The URL to the Github API. see [GitHub plugin docs](https://docs.sonarqube.org/display/PLUG/GitHub+Plugin#GitHubPlugin-Usage) DEPRECATED: only supported in SonarQube < 7.2")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +116,10 @@ func XsDeployCommand() *cobra.Command {
|
|||||||
|
|
||||||
func addXsDeployFlags(cmd *cobra.Command, stepConfig *xsDeployOptions) {
|
func addXsDeployFlags(cmd *cobra.Command, stepConfig *xsDeployOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.DeployOpts, "deployOpts", os.Getenv("PIPER_deployOpts"), "Additional options appended to the deploy command. Only needed for sophisticated cases. When provided it is the duty of the provider to ensure proper quoting / escaping.")
|
cmd.Flags().StringVar(&stepConfig.DeployOpts, "deployOpts", os.Getenv("PIPER_deployOpts"), "Additional options appended to the deploy command. Only needed for sophisticated cases. When provided it is the duty of the provider to ensure proper quoting / escaping.")
|
||||||
cmd.Flags().StringVar(&stepConfig.OperationIDLogPattern, "operationIdLogPattern", "^.*xs bg-deploy -i (.*) -a.*$", "Regex pattern for retrieving the ID of the operation from the xs log.")
|
cmd.Flags().StringVar(&stepConfig.OperationIDLogPattern, "operationIdLogPattern", `^.*xs bg-deploy -i (.*) -a.*$`, "Regex pattern for retrieving the ID of the operation from the xs log.")
|
||||||
cmd.Flags().StringVar(&stepConfig.MtaPath, "mtaPath", os.Getenv("PIPER_mtaPath"), "Path to deployable")
|
cmd.Flags().StringVar(&stepConfig.MtaPath, "mtaPath", os.Getenv("PIPER_mtaPath"), "Path to deployable")
|
||||||
cmd.Flags().StringVar(&stepConfig.Action, "action", "NONE", "Used for finalizing the blue-green deployment.")
|
cmd.Flags().StringVar(&stepConfig.Action, "action", `NONE`, "Used for finalizing the blue-green deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.Mode, "mode", "DEPLOY", "Controls if there is a standard deployment or a blue green deployment. Values: 'DEPLOY', 'BG_DEPLOY'")
|
cmd.Flags().StringVar(&stepConfig.Mode, "mode", `DEPLOY`, "Controls if there is a standard deployment or a blue green deployment. Values: 'DEPLOY', 'BG_DEPLOY'")
|
||||||
cmd.Flags().StringVar(&stepConfig.OperationID, "operationId", os.Getenv("PIPER_operationId"), "The operation ID. Used in case of bg-deploy in order to resume or abort a previously started deployment.")
|
cmd.Flags().StringVar(&stepConfig.OperationID, "operationId", os.Getenv("PIPER_operationId"), "The operation ID. Used in case of bg-deploy in order to resume or abort a previously started deployment.")
|
||||||
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", os.Getenv("PIPER_apiUrl"), "The api url (e.g. https://example.org:12345")
|
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", os.Getenv("PIPER_apiUrl"), "The api url (e.g. https://example.org:12345")
|
||||||
cmd.Flags().StringVar(&stepConfig.User, "user", os.Getenv("PIPER_user"), "User")
|
cmd.Flags().StringVar(&stepConfig.User, "user", os.Getenv("PIPER_user"), "User")
|
||||||
|
8
documentation/docs/steps/fortifyExecuteScan.md
Normal file
8
documentation/docs/steps/fortifyExecuteScan.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# ${docGenStepName}
|
||||||
|
|
||||||
|
## ${docGenDescription}
|
||||||
|
|
||||||
|
## ${docGenParameters}
|
||||||
|
|
||||||
|
## ${docGenConfiguration}
|
||||||
|
|
12
go.mod
12
go.mod
@ -5,6 +5,9 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
github.com/GoogleContainerTools/container-diff v0.15.0
|
github.com/GoogleContainerTools/container-diff v0.15.0
|
||||||
github.com/Jeffail/gabs/v2 v2.5.0
|
github.com/Jeffail/gabs/v2 v2.5.0
|
||||||
|
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||||
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
|
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||||
github.com/Microsoft/hcsshim v0.8.7 // indirect
|
github.com/Microsoft/hcsshim v0.8.7 // indirect
|
||||||
github.com/bmatcuk/doublestar v1.2.4
|
github.com/bmatcuk/doublestar v1.2.4
|
||||||
github.com/containerd/containerd v1.3.4 // indirect
|
github.com/containerd/containerd v1.3.4 // indirect
|
||||||
@ -12,13 +15,20 @@ require (
|
|||||||
github.com/getsentry/sentry-go v0.6.0
|
github.com/getsentry/sentry-go v0.6.0
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
github.com/go-git/go-git/v5 v5.0.0
|
github.com/go-git/go-git/v5 v5.0.0
|
||||||
|
github.com/go-openapi/runtime v0.19.11
|
||||||
|
github.com/go-openapi/strfmt v0.19.4
|
||||||
github.com/gogo/protobuf v1.3.1 // indirect
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
github.com/golang/protobuf v1.4.0 // indirect
|
github.com/golang/protobuf v1.4.0 // indirect
|
||||||
github.com/google/go-cmp v0.4.0
|
github.com/google/go-cmp v0.4.0
|
||||||
github.com/google/go-containerregistry v0.0.0-20200413145205-82d30a103c0a
|
github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2
|
||||||
github.com/google/go-github/v28 v28.1.1
|
github.com/google/go-github/v28 v28.1.1
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/huandu/xstrings v1.3.0 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.9 // indirect
|
||||||
github.com/magiconair/properties v1.8.0
|
github.com/magiconair/properties v1.8.0
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
|
github.com/motemen/go-nuts v0.0.0-20190725124253-1d2432db96b0
|
||||||
|
github.com/piper-validation/fortify-client-go v0.0.0-20200206215926-532b5b150d22
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/sirupsen/logrus v1.5.0
|
github.com/sirupsen/logrus v1.5.0
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.0.0
|
||||||
|
135
go.sum
135
go.sum
@ -32,6 +32,12 @@ github.com/Jeffail/gabs/v2 v2.5.0 h1:ERXffrksCEPjKVDWbZDBcOwrpXctXfeFGXxOQh1umOE
|
|||||||
github.com/Jeffail/gabs/v2 v2.5.0/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI=
|
github.com/Jeffail/gabs/v2 v2.5.0/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI=
|
||||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||||
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
|
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
|
||||||
|
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||||
|
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||||
|
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
||||||
@ -42,20 +48,28 @@ github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEY
|
|||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
|
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
||||||
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||||
@ -162,6 +176,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/
|
|||||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||||
|
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
@ -178,17 +194,67 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
|||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
|
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||||
|
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||||
|
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||||
|
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||||
|
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
|
||||||
|
github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI=
|
||||||
|
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
|
||||||
|
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||||
|
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||||
|
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||||
|
github.com/go-openapi/errors v0.19.3 h1:7MGZI1ibQDLasvAz8HuhvYk9eNJbJkCOXWsSjjMS+Zc=
|
||||||
|
github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
||||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||||
|
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||||
|
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||||
|
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||||
|
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||||
|
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||||
|
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||||
|
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||||
|
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||||
|
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
|
||||||
|
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
|
||||||
|
github.com/go-openapi/loads v0.19.4 h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY=
|
||||||
|
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
|
||||||
|
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
||||||
|
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
|
||||||
|
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
|
||||||
|
github.com/go-openapi/runtime v0.19.11 h1:6J11dQiIV+BOLlMbk2YmM8RvGaOU38syeqy62qhh3W8=
|
||||||
|
github.com/go-openapi/runtime v0.19.11/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
|
||||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||||
|
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||||
|
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||||
|
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||||
|
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
||||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||||
|
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||||
|
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||||
|
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||||
|
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||||
|
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
|
||||||
|
github.com/go-openapi/strfmt v0.19.4 h1:eRvaqAhpL0IL6Trh5fDsGnGhiXndzHFuA05w6sXH6/g=
|
||||||
|
github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
|
||||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||||
|
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||||
|
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
|
github.com/go-openapi/swag v0.19.7 h1:VRuXN2EnMSsZdauzdss6JBC29YotDqG59BZ+tdlIL1s=
|
||||||
|
github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
|
||||||
|
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||||
|
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||||
|
github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo=
|
||||||
|
github.com/go-openapi/validate v0.19.6 h1:WsKw9J1WzYBVxWRYwLqEk3325RL6G0SSWksuamkk6q0=
|
||||||
|
github.com/go-openapi/validate v0.19.6/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
@ -197,6 +263,7 @@ github.com/go-redis/redis v6.15.7+incompatible h1:3skhDh95XQMpnqeqNftPkQD9jL9e5e
|
|||||||
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
@ -232,8 +299,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-containerregistry v0.0.0-20200413145205-82d30a103c0a h1:XNvUa41C0oOgPmTmZKrWKhOCCFPLnOwLfm+pWU75sNs=
|
github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 h1:/z0FoA29APs30PljxT6GoZQekF5c1cYhow2osFsj1XU=
|
||||||
github.com/google/go-containerregistry v0.0.0-20200413145205-82d30a103c0a/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
|
github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs=
|
||||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
@ -242,6 +309,7 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN
|
|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@ -272,7 +340,11 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG
|
|||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
|
||||||
|
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
|
||||||
|
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
@ -327,8 +399,11 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
|
|||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
@ -344,9 +419,14 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88J
|
|||||||
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
|
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
|
||||||
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
|
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
@ -355,6 +435,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/motemen/go-nuts v0.0.0-20190725124253-1d2432db96b0 h1:CnSVrlMNAZMWI1+uH6ldpXRv2pe7t50IQX448EJrJhw=
|
||||||
|
github.com/motemen/go-nuts v0.0.0-20190725124253-1d2432db96b0/go.mod h1:vfh/NPxHgDwggXit20W1llPsXcz39xJ7I8vo7kVrOCk=
|
||||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
@ -388,10 +470,13 @@ github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJ
|
|||||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||||
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
|
github.com/piper-validation/fortify-client-go v0.0.0-20200206215926-532b5b150d22 h1:xSbcGENeXvuG+tu4suCmsr+Vm+p3peYNgJDDxUBeJa8=
|
||||||
|
github.com/piper-validation/fortify-client-go v0.0.0-20200206215926-532b5b150d22/go.mod h1:EZkdCgngw/tInYdidqDQlRIXvyM1fSbqn/vx83YNCcw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@ -416,6 +501,7 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
|||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
@ -464,6 +550,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
github.com/testcontainers/testcontainers-go v0.4.0 h1:BpzZG0/I4s4oAVrkYhf9K3R0AKLvhE0bX1kVSqyUVx8=
|
github.com/testcontainers/testcontainers-go v0.4.0 h1:BpzZG0/I4s4oAVrkYhf9K3R0AKLvhE0bX1kVSqyUVx8=
|
||||||
github.com/testcontainers/testcontainers-go v0.4.0/go.mod h1:BXwe1JilTOLT8cmVyPMDbIw7e+8UCGeAhxjBwguG5wQ=
|
github.com/testcontainers/testcontainers-go v0.4.0/go.mod h1:BXwe1JilTOLT8cmVyPMDbIw7e+8UCGeAhxjBwguG5wQ=
|
||||||
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
@ -477,7 +565,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
|
|||||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||||
github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c=
|
github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo=
|
||||||
|
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||||
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
@ -494,6 +583,10 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ
|
|||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
|
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
|
go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
|
||||||
|
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
@ -505,11 +598,14 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
@ -522,17 +618,21 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
|
|||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@ -572,6 +672,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -605,6 +706,7 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm
|
|||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
@ -615,9 +717,12 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
@ -664,6 +769,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||||
@ -695,14 +801,15 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
|
||||||
k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I=
|
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||||
k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
|
k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg=
|
||||||
k8s.io/cloud-provider v0.17.4/go.mod h1:XEjKDzfD+b9MTLXQFlDGkk6Ho8SGMpaU8Uugx/KNK9U=
|
k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
|
||||||
k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
|
k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE=
|
||||||
k8s.io/component-base v0.17.4/go.mod h1:5BRqHMbbQPm2kKu35v3G+CpVq4K0RJKC7TRioF0I9lE=
|
k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
|
||||||
k8s.io/csi-translation-lib v0.17.4/go.mod h1:CsxmjwxEI0tTNMzffIAcgR9lX4wOh6AKHdxQrT7L0oo=
|
k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc=
|
||||||
|
k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls=
|
||||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
@ -710,7 +817,7 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
|||||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||||
k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js=
|
k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8=
|
||||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||||
|
@ -3,6 +3,7 @@ package checkmarx
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -53,6 +54,9 @@ func (sm *senderMock) UploadRequest(method, url, file, fieldName string, header
|
|||||||
sm.header = header
|
sm.header = header
|
||||||
return &http.Response{StatusCode: sm.httpStatusCode, Body: ioutil.NopCloser(bytes.NewReader([]byte(sm.responseBody)))}, nil
|
return &http.Response{StatusCode: sm.httpStatusCode, Body: ioutil.NopCloser(bytes.NewReader([]byte(sm.responseBody)))}, nil
|
||||||
}
|
}
|
||||||
|
func (sm *senderMock) Upload(_ piperHttp.UploadRequestData) (*http.Response, error) {
|
||||||
|
return &http.Response{}, fmt.Errorf("not implemented")
|
||||||
|
}
|
||||||
func (sm *senderMock) SetOptions(opts piperHttp.ClientOptions) {
|
func (sm *senderMock) SetOptions(opts piperHttp.ClientOptions) {
|
||||||
sm.token = opts.Token
|
sm.token = opts.Token
|
||||||
}
|
}
|
||||||
|
741
pkg/fortify/fortify.go
Normal file
741
pkg/fortify/fortify.go
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
package fortify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ff "github.com/piper-validation/fortify-client-go/fortify"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/artifact_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/attribute_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/auth_entity_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/file_token_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/filter_set_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/issue_group_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/issue_selector_set_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/issue_statistics_of_project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/project_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/project_version_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/project_version_of_project_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/fortify/saved_report_controller"
|
||||||
|
"github.com/piper-validation/fortify-client-go/models"
|
||||||
|
|
||||||
|
piperHttp "github.com/SAP/jenkins-library/pkg/http"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||||
|
|
||||||
|
"github.com/go-openapi/runtime"
|
||||||
|
"github.com/go-openapi/strfmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// System is the interface abstraction of a specific SystemInstance
|
||||||
|
type System interface {
|
||||||
|
GetProjectByName(name string, autoCreate bool, projectVersion string) (*models.Project, error)
|
||||||
|
GetProjectVersionDetailsByProjectIDAndVersionName(id int64, name string, autoCreate bool, projectName string) (*models.ProjectVersion, error)
|
||||||
|
GetProjectVersionAttributesByProjectVersionID(id int64) ([]*models.Attribute, error)
|
||||||
|
SetProjectVersionAttributesByProjectVersionID(id int64, attributes []*models.Attribute) ([]*models.Attribute, error)
|
||||||
|
CreateProjectVersionIfNotExist(projectName, projectVersionName, description string) (*models.ProjectVersion, error)
|
||||||
|
LookupOrCreateProjectVersionDetailsForPullRequest(projectID int64, masterProjectVersion *models.ProjectVersion, pullRequestName string) (*models.ProjectVersion, error)
|
||||||
|
CreateProjectVersion(version *models.ProjectVersion) (*models.ProjectVersion, error)
|
||||||
|
ProjectVersionCopyFromPartial(sourceID, targetID int64) error
|
||||||
|
ProjectVersionCopyCurrentState(sourceID, targetID int64) error
|
||||||
|
ProjectVersionCopyPermissions(sourceID, targetID int64) error
|
||||||
|
CommitProjectVersion(id int64) (*models.ProjectVersion, error)
|
||||||
|
MergeProjectVersionStateOfPRIntoMaster(downloadEndpoint, uploadEndpoint string, masterProjectID, masterProjectVersionID int64, pullRequestName string) error
|
||||||
|
GetArtifactsOfProjectVersion(id int64) ([]*models.Artifact, error)
|
||||||
|
GetFilterSetOfProjectVersionByTitle(id int64, title string) (*models.FilterSet, error)
|
||||||
|
GetIssueFilterSelectorOfProjectVersionByName(id int64, names []string, options []string) (*models.IssueFilterSelectorSet, error)
|
||||||
|
GetFilterSetByDisplayName(issueFilterSelectorSet *models.IssueFilterSelectorSet, name string) *models.IssueFilterSelector
|
||||||
|
GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64, filter, filterSetGUID string, issueFilterSelectorSet *models.IssueFilterSelectorSet) ([]*models.ProjectVersionIssueGroup, error)
|
||||||
|
ReduceIssueFilterSelectorSet(issueFilterSelectorSet *models.IssueFilterSelectorSet, names []string, options []string) *models.IssueFilterSelectorSet
|
||||||
|
GetIssueStatisticsOfProjectVersion(id int64) ([]*models.IssueStatistics, error)
|
||||||
|
GenerateQGateReport(projectID, projectVersionID, reportTemplateID int64, projectName, projectVersionName, reportFormat string) (*models.SavedReport, error)
|
||||||
|
GetReportDetails(id int64) (*models.SavedReport, error)
|
||||||
|
UploadResultFile(endpoint, file string, projectVersionID int64) error
|
||||||
|
DownloadReportFile(endpoint string, projectVersionID int64) ([]byte, error)
|
||||||
|
DownloadResultFile(endpoint string, projectVersionID int64) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemInstance is the specific instance
|
||||||
|
type SystemInstance struct {
|
||||||
|
timeout time.Duration
|
||||||
|
token string
|
||||||
|
serverURL string
|
||||||
|
client *ff.Fortify
|
||||||
|
httpClient *piperHttp.Client
|
||||||
|
logger *logrus.Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSystemInstance - creates an returns a new SystemInstance
|
||||||
|
func NewSystemInstance(serverURL, apiEndpoint, authToken string, timeout time.Duration) *SystemInstance {
|
||||||
|
format := strfmt.Default
|
||||||
|
dateTimeFormat := models.Iso8601MilliDateTime{}
|
||||||
|
format.Add("datetime", &dateTimeFormat, models.IsDateTime)
|
||||||
|
clientInstance := ff.NewHTTPClientWithConfig(format, createTransportConfig(serverURL, apiEndpoint))
|
||||||
|
httpClientInstance := &piperHttp.Client{}
|
||||||
|
httpClientOptions := piperHttp.ClientOptions{Token: "FortifyToken " + authToken, TransportTimeout: timeout}
|
||||||
|
httpClientInstance.SetOptions(httpClientOptions)
|
||||||
|
|
||||||
|
return NewSystemInstanceForClient(clientInstance, httpClientInstance, serverURL, authToken, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTransportConfig(serverURL, apiEndpoint string) *ff.TransportConfig {
|
||||||
|
scheme, host := splitSchemeAndHost(serverURL)
|
||||||
|
host, hostEndpoint := splitHostAndEndpoint(host)
|
||||||
|
return &ff.TransportConfig{
|
||||||
|
Host: host,
|
||||||
|
Schemes: []string{scheme},
|
||||||
|
BasePath: fmt.Sprintf("%v/%v", hostEndpoint, apiEndpoint)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitSchemeAndHost(url string) (scheme, host string) {
|
||||||
|
schemeEnd := strings.Index(url, "://")
|
||||||
|
if schemeEnd >= 0 {
|
||||||
|
scheme = url[0:schemeEnd]
|
||||||
|
host = url[schemeEnd+3:]
|
||||||
|
} else {
|
||||||
|
scheme = "https"
|
||||||
|
host = url
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitHostAndEndpoint(urlWithoutScheme string) (host, endpoint string) {
|
||||||
|
hostEnd := strings.Index(urlWithoutScheme, "/")
|
||||||
|
if hostEnd >= 0 {
|
||||||
|
host = urlWithoutScheme[0:hostEnd]
|
||||||
|
endpoint = urlWithoutScheme[hostEnd+1:]
|
||||||
|
} else {
|
||||||
|
host = urlWithoutScheme
|
||||||
|
endpoint = ""
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSystemInstanceForClient - creates a new SystemInstance
|
||||||
|
func NewSystemInstanceForClient(clientInstance *ff.Fortify, httpClientInstance *piperHttp.Client, serverURL, authToken string, requestTimeout time.Duration) *SystemInstance {
|
||||||
|
return &SystemInstance{
|
||||||
|
timeout: requestTimeout,
|
||||||
|
token: authToken,
|
||||||
|
serverURL: serverURL,
|
||||||
|
client: clientInstance,
|
||||||
|
httpClient: httpClientInstance,
|
||||||
|
logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/fortify"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticateRequest authenticates the request
|
||||||
|
func (sys *SystemInstance) AuthenticateRequest(req runtime.ClientRequest, formats strfmt.Registry) error {
|
||||||
|
req.SetHeaderParam("Authorization", fmt.Sprintf("FortifyToken %v", sys.token))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectByName returns the project identified by the name provided
|
||||||
|
// autoCreate and projectVersion parameters only used if autoCreate=true
|
||||||
|
func (sys *SystemInstance) GetProjectByName(projectName string, autoCreate bool, projectVersionName string) (*models.Project, error) {
|
||||||
|
nameParam := fmt.Sprintf("name=%v", projectName)
|
||||||
|
fullText := true
|
||||||
|
params := &project_controller.ListProjectParams{Q: &nameParam, Fulltextsearch: &fullText}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.ProjectController.ListProject(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, project := range result.GetPayload().Data {
|
||||||
|
if *project.Name == projectName {
|
||||||
|
return project, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project with specified name was NOT found, check if autoCreate flag is set, if not stop otherwise create it automatically
|
||||||
|
if !autoCreate {
|
||||||
|
return nil, fmt.Errorf("Project with name %v not found in backend and automatic creation not enabled", projectName)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Debugf("No projects found with name: %v auto-creating one now...", projectName)
|
||||||
|
projectVersion, err := sys.CreateProjectVersionIfNotExist(projectName, projectVersionName, "Created by Go script")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to auto-create new project: %w", err)
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("Finished creating project: %v", projectVersion)
|
||||||
|
return projectVersion.Project, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectVersionDetailsByProjectIDAndVersionName returns the project version details of the project version identified by the id and project versionname
|
||||||
|
// projectName parameter is only used if autoCreate=true
|
||||||
|
func (sys *SystemInstance) GetProjectVersionDetailsByProjectIDAndVersionName(id int64, versionName string, autoCreate bool, projectName string) (*models.ProjectVersion, error) {
|
||||||
|
nameParam := fmt.Sprintf("name=%v", versionName)
|
||||||
|
fullText := true
|
||||||
|
params := &project_version_of_project_controller.ListProjectVersionOfProjectParams{ParentID: id, Q: &nameParam, Fulltextsearch: &fullText}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.ProjectVersionOfProjectController.ListProjectVersionOfProject(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, projectVersion := range result.GetPayload().Data {
|
||||||
|
if *projectVersion.Name == versionName {
|
||||||
|
return projectVersion, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// projectVersion not found for specified project id and name, check if autoCreate is enabled
|
||||||
|
if !autoCreate {
|
||||||
|
return nil, errors.New(fmt.Sprintf("Project version with name %v not found in project with ID %v and automatic creation not enabled", versionName, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Debugf("Could not find project version with name %v under project %v auto-creating one now...", versionName, projectName)
|
||||||
|
version, err := sys.CreateProjectVersionIfNotExist(projectName, versionName, "Created by Go script")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to auto-create project version: %v for project %v", versionName, projectName)
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("Successfully created project version %v for project %v", versionName, projectName)
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectVersionIfNotExist creates a new ProjectVersion if it does not already exist.
|
||||||
|
// If the projectName also does not exist, it will create that as well.
|
||||||
|
func (sys *SystemInstance) CreateProjectVersionIfNotExist(projectName, projectVersionName, description string) (*models.ProjectVersion, error) {
|
||||||
|
var projectID int64 = 0
|
||||||
|
// check if project with projectName exists
|
||||||
|
projectResp, err := sys.GetProjectByName(projectName, false, "")
|
||||||
|
if err == nil {
|
||||||
|
// project already exists, all we need to do is append a new ProjectVersion to it
|
||||||
|
// save the project id for later
|
||||||
|
projectID = projectResp.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
issueTemplateID := "4c5799c9-1940-4abe-b57a-3bcad88eb041"
|
||||||
|
active := true
|
||||||
|
committed := true
|
||||||
|
projectVersionDto := &models.ProjectVersion{
|
||||||
|
Name: &projectVersionName,
|
||||||
|
Description: &description,
|
||||||
|
IssueTemplateID: &issueTemplateID,
|
||||||
|
Active: &active,
|
||||||
|
Committed: &committed,
|
||||||
|
Project: &models.Project{ID: projectID},
|
||||||
|
}
|
||||||
|
|
||||||
|
if projectVersionDto.Project.ID == 0 { // project does not exist, set one up
|
||||||
|
projectVersionDto.Project = &models.Project{
|
||||||
|
Name: &projectName,
|
||||||
|
Description: description,
|
||||||
|
IssueTemplateID: &issueTemplateID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectVersion, err := sys.CreateProjectVersion(projectVersionDto)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to create new project version %v for projectName %v", projectVersionName, projectName)
|
||||||
|
}
|
||||||
|
_, err = sys.CommitProjectVersion(projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to commit project version %v: %v", projectVersion.ID, err)
|
||||||
|
}
|
||||||
|
return projectVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupOrCreateProjectVersionDetailsForPullRequest looks up a project version for pull requests or creates it from scratch
|
||||||
|
func (sys *SystemInstance) LookupOrCreateProjectVersionDetailsForPullRequest(projectID int64, masterProjectVersion *models.ProjectVersion, pullRequestName string) (*models.ProjectVersion, error) {
|
||||||
|
projectVersion, _ := sys.GetProjectVersionDetailsByProjectIDAndVersionName(projectID, pullRequestName, false, "")
|
||||||
|
if nil != projectVersion {
|
||||||
|
return projectVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newVersion := &models.ProjectVersion{}
|
||||||
|
newVersion.Name = &pullRequestName
|
||||||
|
newVersion.Description = masterProjectVersion.Description
|
||||||
|
newVersion.Active = masterProjectVersion.Active
|
||||||
|
newVersion.Committed = masterProjectVersion.Committed
|
||||||
|
newVersion.Project = &models.Project{}
|
||||||
|
newVersion.Project.Name = masterProjectVersion.Project.Name
|
||||||
|
newVersion.Project.Description = masterProjectVersion.Project.Description
|
||||||
|
newVersion.Project.ID = masterProjectVersion.Project.ID
|
||||||
|
newVersion.IssueTemplateID = masterProjectVersion.IssueTemplateID
|
||||||
|
|
||||||
|
projectVersion, err := sys.CreateProjectVersion(newVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to create new project version for pull request %v", pullRequestName)
|
||||||
|
}
|
||||||
|
attributes, err := sys.GetProjectVersionAttributesByProjectVersionID(masterProjectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to load project version attributes for master project version %v", masterProjectVersion.ID)
|
||||||
|
}
|
||||||
|
for _, attribute := range attributes {
|
||||||
|
attribute.ID = 0
|
||||||
|
}
|
||||||
|
_, err = sys.SetProjectVersionAttributesByProjectVersionID(projectVersion.ID, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to update project version attributes for pull request project version %v", projectVersion.ID)
|
||||||
|
}
|
||||||
|
err = sys.ProjectVersionCopyFromPartial(masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to copy from partial of project version %v to %v", masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
}
|
||||||
|
_, err = sys.CommitProjectVersion(projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to commit project version %v: %v", projectVersion.ID, err)
|
||||||
|
}
|
||||||
|
err = sys.ProjectVersionCopyCurrentState(masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to copy current state of project version %v to %v", masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
}
|
||||||
|
err = sys.ProjectVersionCopyPermissions(masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "Failed to copy permissions of project version %v to %v", masterProjectVersion.ID, projectVersion.ID)
|
||||||
|
}
|
||||||
|
return projectVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectVersionAttributesByProjectVersionID returns the project version attributes of the project version identified by the id
|
||||||
|
func (sys *SystemInstance) GetProjectVersionAttributesByProjectVersionID(id int64) ([]*models.Attribute, error) {
|
||||||
|
params := &attribute_of_project_version_controller.ListAttributeOfProjectVersionParams{ParentID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.AttributeOfProjectVersionController.ListAttributeOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProjectVersionAttributesByProjectVersionID sets the project version attributes of the project version identified by the id
|
||||||
|
func (sys *SystemInstance) SetProjectVersionAttributesByProjectVersionID(id int64, attributes []*models.Attribute) ([]*models.Attribute, error) {
|
||||||
|
params := &attribute_of_project_version_controller.UpdateCollectionAttributeOfProjectVersionParams{ParentID: id, Data: attributes}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.AttributeOfProjectVersionController.UpdateCollectionAttributeOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProjectVersion creates the project version with the provided details
|
||||||
|
func (sys *SystemInstance) CreateProjectVersion(version *models.ProjectVersion) (*models.ProjectVersion, error) {
|
||||||
|
params := &project_version_controller.CreateProjectVersionParams{Resource: version}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.ProjectVersionController.CreateProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectVersionCopyFromPartial copies parts of the source project version to the target project version identified by their ids
|
||||||
|
func (sys *SystemInstance) ProjectVersionCopyFromPartial(sourceID, targetID int64) error {
|
||||||
|
enable := true
|
||||||
|
settings := models.ProjectVersionCopyPartialRequest{
|
||||||
|
ProjectVersionID: &targetID,
|
||||||
|
PreviousProjectVersionID: &sourceID,
|
||||||
|
CopyAnalysisProcessingRules: &enable,
|
||||||
|
CopyBugTrackerConfiguration: &enable,
|
||||||
|
CopyCurrentStateFpr: &enable,
|
||||||
|
CopyCustomTags: &enable,
|
||||||
|
}
|
||||||
|
params := &project_version_controller.CopyProjectVersionParams{Resource: &settings}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
_, err := sys.client.ProjectVersionController.CopyProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectVersionCopyCurrentState copies the project version state of sourceID into the new project version addressed by targetID
|
||||||
|
func (sys *SystemInstance) ProjectVersionCopyCurrentState(sourceID, targetID int64) error {
|
||||||
|
enable := true
|
||||||
|
settings := models.ProjectVersionCopyCurrentStateRequest{
|
||||||
|
ProjectVersionID: &targetID,
|
||||||
|
PreviousProjectVersionID: &sourceID,
|
||||||
|
CopyCurrentStateFpr: &enable,
|
||||||
|
}
|
||||||
|
params := &project_version_controller.CopyCurrentStateForProjectVersionParams{Resource: &settings}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
_, err := sys.client.ProjectVersionController.CopyCurrentStateForProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getAuthEntityOfProjectVersion(id int64) ([]*models.AuthenticationEntity, error) {
|
||||||
|
embed := "roles"
|
||||||
|
params := &auth_entity_of_project_version_controller.ListAuthEntityOfProjectVersionParams{Embed: &embed, ParentID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.AuthEntityOfProjectVersionController.ListAuthEntityOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) updateCollectionAuthEntityOfProjectVersion(id int64, data []*models.AuthenticationEntity) error {
|
||||||
|
params := &auth_entity_of_project_version_controller.UpdateCollectionAuthEntityOfProjectVersionParams{ParentID: id, Data: data}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
_, err := sys.client.AuthEntityOfProjectVersionController.UpdateCollectionAuthEntityOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectVersionCopyPermissions copies the authentication entity of the project version addressed by sourceID to the one of targetID
|
||||||
|
func (sys *SystemInstance) ProjectVersionCopyPermissions(sourceID, targetID int64) error {
|
||||||
|
result, err := sys.getAuthEntityOfProjectVersion(sourceID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = sys.updateCollectionAuthEntityOfProjectVersion(targetID, result)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) updateProjectVersionDetails(id int64, details *models.ProjectVersion) (*models.ProjectVersion, error) {
|
||||||
|
params := &project_version_controller.UpdateProjectVersionParams{ID: id, Resource: details}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.ProjectVersionController.UpdateProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitProjectVersion commits the project version with the provided id
|
||||||
|
func (sys *SystemInstance) CommitProjectVersion(id int64) (*models.ProjectVersion, error) {
|
||||||
|
enabled := true
|
||||||
|
update := models.ProjectVersion{Committed: &enabled}
|
||||||
|
return sys.updateProjectVersionDetails(id, &update)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) inactivateProjectVersion(id int64) (*models.ProjectVersion, error) {
|
||||||
|
enabled := true
|
||||||
|
disabled := false
|
||||||
|
update := models.ProjectVersion{Committed: &enabled, Active: &disabled}
|
||||||
|
return sys.updateProjectVersionDetails(id, &update)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtifactsOfProjectVersion returns the list of artifacts related to the project version addressed with id
|
||||||
|
func (sys *SystemInstance) GetArtifactsOfProjectVersion(id int64) ([]*models.Artifact, error) {
|
||||||
|
scans := "scans"
|
||||||
|
params := &artifact_of_project_version_controller.ListArtifactOfProjectVersionParams{ParentID: id, Embed: &scans}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.ArtifactOfProjectVersionController.ListArtifactOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeProjectVersionStateOfPRIntoMaster merges the PR project version's fpr result file into the master project version
|
||||||
|
func (sys *SystemInstance) MergeProjectVersionStateOfPRIntoMaster(downloadEndpoint, uploadEndpoint string, masterProjectID, masterProjectVersionID int64, pullRequestName string) error {
|
||||||
|
log.Entry().Debugf("Looking up project version with name '%v' to merge audit status into master version", pullRequestName)
|
||||||
|
prProjectVersion, _ := sys.GetProjectVersionDetailsByProjectIDAndVersionName(masterProjectID, pullRequestName, false, "")
|
||||||
|
if nil != prProjectVersion {
|
||||||
|
log.Entry().Debugf("Found project version with ID '%v', starting transfer", prProjectVersion.ID)
|
||||||
|
data, err := sys.DownloadResultFile(downloadEndpoint, prProjectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to download current state FPR of PR project version %v", prProjectVersion.ID)
|
||||||
|
}
|
||||||
|
err = sys.uploadResultFileContent(uploadEndpoint, "prMergeTransfer.fpr", bytes.NewReader(data), masterProjectVersionID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to upload PR project version state to master project version %v", masterProjectVersionID)
|
||||||
|
}
|
||||||
|
_, err = sys.inactivateProjectVersion(prProjectVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().Warnf("Failed to inactivate merged PR project version %v", prProjectVersion.ID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Entry().Debug("No related project version found in SSC")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFilterSetOfProjectVersionByTitle returns the filter set with the given title related to the project version addressed with id, if no title is provided the default filter set will be returned
|
||||||
|
func (sys *SystemInstance) GetFilterSetOfProjectVersionByTitle(id int64, title string) (*models.FilterSet, error) {
|
||||||
|
params := &filter_set_of_project_version_controller.ListFilterSetOfProjectVersionParams{ParentID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.FilterSetOfProjectVersionController.ListFilterSetOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var defaultFilterSet *models.FilterSet
|
||||||
|
for _, filterSet := range result.GetPayload().Data {
|
||||||
|
if len(title) > 0 && filterSet.Title == title {
|
||||||
|
return filterSet, nil
|
||||||
|
}
|
||||||
|
if filterSet.DefaultFilterSet {
|
||||||
|
defaultFilterSet = filterSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(title) > 0 {
|
||||||
|
log.Entry().Warnf("Failed to load filter set with title '%v', falling back to default filter set", title)
|
||||||
|
}
|
||||||
|
if nil != defaultFilterSet {
|
||||||
|
return defaultFilterSet, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Failed to identify requested filter set and default filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueFilterSelectorOfProjectVersionByName returns the groupings with the given names related to the project version addressed with id
|
||||||
|
func (sys *SystemInstance) GetIssueFilterSelectorOfProjectVersionByName(id int64, names []string, options []string) (*models.IssueFilterSelectorSet, error) {
|
||||||
|
params := &issue_selector_set_of_project_version_controller.GetIssueSelectorSetOfProjectVersionParams{ParentID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.IssueSelectorSetOfProjectVersionController.GetIssueSelectorSetOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sys.ReduceIssueFilterSelectorSet(result.GetPayload().Data, names, options), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReduceIssueFilterSelectorSet filters the set to the relevant filter display names
|
||||||
|
func (sys *SystemInstance) ReduceIssueFilterSelectorSet(issueFilterSelectorSet *models.IssueFilterSelectorSet, names []string, options []string) *models.IssueFilterSelectorSet {
|
||||||
|
groupingList := []*models.IssueSelector{}
|
||||||
|
if issueFilterSelectorSet.GroupBySet != nil {
|
||||||
|
for _, group := range issueFilterSelectorSet.GroupBySet {
|
||||||
|
if piperutils.ContainsString(names, *group.DisplayName) {
|
||||||
|
log.Entry().Debugf("adding new grouping '%v' to reduced list", *group.DisplayName)
|
||||||
|
groupingList = append(groupingList, group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filterList := []*models.IssueFilterSelector{}
|
||||||
|
if issueFilterSelectorSet.FilterBySet != nil {
|
||||||
|
for _, filter := range issueFilterSelectorSet.FilterBySet {
|
||||||
|
if piperutils.ContainsString(names, filter.DisplayName) {
|
||||||
|
newFilter := &models.IssueFilterSelector{}
|
||||||
|
newFilter.DisplayName = filter.DisplayName
|
||||||
|
newFilter.Description = filter.Description
|
||||||
|
newFilter.EntityType = filter.EntityType
|
||||||
|
newFilter.FilterSelectorType = filter.FilterSelectorType
|
||||||
|
newFilter.GUID = filter.GUID
|
||||||
|
newFilter.Value = filter.Value
|
||||||
|
newFilter.SelectorOptions = []*models.SelectorOption{}
|
||||||
|
for _, option := range filter.SelectorOptions {
|
||||||
|
if (nil != options && piperutils.ContainsString(options, option.DisplayName)) || options == nil || len(options) == 0 {
|
||||||
|
log.Entry().Debugf("adding selector option '%v' to list for filter selector '%v'", option.DisplayName, newFilter.DisplayName)
|
||||||
|
newFilter.SelectorOptions = append(newFilter.SelectorOptions, option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("adding new filter '%v' to reduced list with selector options '%v'", newFilter.DisplayName, newFilter.SelectorOptions)
|
||||||
|
filterList = append(filterList, newFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &models.IssueFilterSelectorSet{GroupBySet: groupingList, FilterBySet: filterList}
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetFilterSetByDisplayName returns the set identified by the provided name or nil
|
||||||
|
func (sys *SystemInstance) GetFilterSetByDisplayName(issueFilterSelectorSet *models.IssueFilterSelectorSet, name string) *models.IssueFilterSelector {
|
||||||
|
if issueFilterSelectorSet.FilterBySet != nil {
|
||||||
|
for _, filter := range issueFilterSelectorSet.FilterBySet {
|
||||||
|
if filter.DisplayName == name {
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getIssuesOfProjectVersion(id int64, filter, filterset, groupingtype string) ([]*models.ProjectVersionIssueGroup, error) {
|
||||||
|
enable := true
|
||||||
|
params := &issue_group_of_project_version_controller.ListIssueGroupOfProjectVersionParams{ParentID: id, Showsuppressed: &enable, Filterset: &filterset, Groupingtype: &groupingtype}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
if len(filter) > 0 {
|
||||||
|
params.WithFilter(&filter)
|
||||||
|
}
|
||||||
|
result, err := sys.client.IssueGroupOfProjectVersionController.ListIssueGroupOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProjectIssuesByIDAndFilterSetGroupedBySelector returns issues of the project version addressed with id filtered with the respective set and grouped by the issue filter selector grouping
|
||||||
|
func (sys *SystemInstance) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64, filter, filterSetGUID string, issueFilterSelectorSet *models.IssueFilterSelectorSet) ([]*models.ProjectVersionIssueGroup, error) {
|
||||||
|
groupingTypeGUID := ""
|
||||||
|
if issueFilterSelectorSet != nil {
|
||||||
|
groupingTypeGUID = *issueFilterSelectorSet.GroupBySet[0].GUID
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := sys.getIssuesOfProjectVersion(id, filter, filterSetGUID, groupingTypeGUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIssueStatisticsOfProjectVersion returns the issue statistics related to the project version addressed with id
|
||||||
|
func (sys *SystemInstance) GetIssueStatisticsOfProjectVersion(id int64) ([]*models.IssueStatistics, error) {
|
||||||
|
params := &issue_statistics_of_project_version_controller.ListIssueStatisticsOfProjectVersionParams{ParentID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.IssueStatisticsOfProjectVersionController.ListIssueStatisticsOfProjectVersion(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateQGateReport returns the issue statistics related to the project version addressed with id
|
||||||
|
func (sys *SystemInstance) GenerateQGateReport(projectID, projectVersionID, reportTemplateID int64, projectName, projectVersionName, reportFormat string) (*models.SavedReport, error) {
|
||||||
|
paramIdentifier := "projectVersionId"
|
||||||
|
paramType := "SINGLE_PROJECT"
|
||||||
|
paramName := "Q-gate-report"
|
||||||
|
reportType := "PORTFOLIO"
|
||||||
|
inputReportParameters := []*models.InputReportParameter{&models.InputReportParameter{Name: ¶mName, Identifier: ¶mIdentifier, ParamValue: projectVersionID, Type: ¶mType}}
|
||||||
|
reportProjectVersions := []*models.ReportProjectVersion{&models.ReportProjectVersion{ID: projectVersionID, Name: projectVersionName}}
|
||||||
|
reportProjects := []*models.ReportProject{&models.ReportProject{ID: projectID, Name: projectName, Versions: reportProjectVersions}}
|
||||||
|
report := models.SavedReport{Name: fmt.Sprintf("FortifyReport: %v:%v", projectName, projectVersionName), Type: &reportType, ReportDefinitionID: &reportTemplateID, Format: &reportFormat, Projects: reportProjects, InputReportParameters: inputReportParameters}
|
||||||
|
params := &saved_report_controller.CreateSavedReportParams{Resource: &report}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.SavedReportController.CreateSavedReport(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReportDetails returns the details of the report addressed with id
|
||||||
|
func (sys *SystemInstance) GetReportDetails(id int64) (*models.SavedReport, error) {
|
||||||
|
params := &saved_report_controller.ReadSavedReportParams{ID: id}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.SavedReportController.ReadSavedReport(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) invalidateFileTokens() error {
|
||||||
|
log.Entry().Debug("invalidating file tokens")
|
||||||
|
params := &file_token_controller.MultiDeleteFileTokenParams{}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
_, err := sys.client.FileTokenController.MultiDeleteFileToken(params, sys)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getFileToken(tokenType string) (*models.FileToken, error) {
|
||||||
|
token := models.FileToken{FileTokenType: &tokenType}
|
||||||
|
params := &file_token_controller.CreateFileTokenParams{Resource: &token}
|
||||||
|
params.WithTimeout(sys.timeout)
|
||||||
|
result, err := sys.client.FileTokenController.CreateFileToken(params, sys)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result.GetPayload().Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getFileUploadToken() (*models.FileToken, error) {
|
||||||
|
log.Entry().Debug("fetching upload token")
|
||||||
|
return sys.getFileToken("UPLOAD")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getFileDownloadToken() (*models.FileToken, error) {
|
||||||
|
log.Entry().Debug("fetching download token")
|
||||||
|
return sys.getFileToken("DOWNLOAD")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) getReportFileToken() (*models.FileToken, error) {
|
||||||
|
log.Entry().Debug("fetching report download token")
|
||||||
|
return sys.getFileToken("REPORT_FILE")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadResultFile uploads a fpr file to the fortify backend
|
||||||
|
func (sys *SystemInstance) UploadResultFile(endpoint, file string, projectVersionID int64) error {
|
||||||
|
fileHandle, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Unable to locate file %v", file)
|
||||||
|
}
|
||||||
|
defer fileHandle.Close()
|
||||||
|
|
||||||
|
return sys.uploadResultFileContent(endpoint, file, fileHandle, projectVersionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *SystemInstance) uploadResultFileContent(endpoint, file string, fileContent io.Reader, projectVersionID int64) error {
|
||||||
|
token, err := sys.getFileUploadToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sys.invalidateFileTokens()
|
||||||
|
|
||||||
|
header := http.Header{}
|
||||||
|
header.Add("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
header.Add("Pragma", "no-cache")
|
||||||
|
|
||||||
|
formFields := map[string]string{}
|
||||||
|
formFields["entityId"] = fmt.Sprintf("%v", projectVersionID)
|
||||||
|
|
||||||
|
_, err = sys.httpClient.Upload(piperHttp.UploadRequestData{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
URL: fmt.Sprintf("%v%v?mat=%v", sys.serverURL, endpoint, token.Token),
|
||||||
|
File: file,
|
||||||
|
FileFieldName: "file",
|
||||||
|
FormFields: formFields,
|
||||||
|
FileContent: fileContent,
|
||||||
|
Header: header,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadFile downloads a file from Fortify backend
|
||||||
|
func (sys *SystemInstance) downloadFile(endpoint, method, acceptType, downloadToken string, projectVersionID int64) ([]byte, error) {
|
||||||
|
header := http.Header{}
|
||||||
|
header.Add("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
header.Add("Pragma", "no-cache")
|
||||||
|
header.Add("Accept", acceptType)
|
||||||
|
header.Add("Content-Type", "application/form-data")
|
||||||
|
body := url.Values{
|
||||||
|
"id": {fmt.Sprintf("%v", projectVersionID)},
|
||||||
|
"mat": {downloadToken},
|
||||||
|
}
|
||||||
|
var response *http.Response
|
||||||
|
var err error
|
||||||
|
if method == http.MethodGet {
|
||||||
|
response, err = sys.httpClient.SendRequest(method, fmt.Sprintf("%v%v?%v", sys.serverURL, endpoint, body.Encode()), nil, header, nil)
|
||||||
|
} else {
|
||||||
|
response, err = sys.httpClient.SendRequest(method, fmt.Sprintf("%v%v", sys.serverURL, endpoint), strings.NewReader(body.Encode()), header, nil)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(response.Body)
|
||||||
|
defer response.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error reading the response data")
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadReportFile downloads a report file from Fortify backend
|
||||||
|
func (sys *SystemInstance) DownloadReportFile(endpoint string, projectVersionID int64) ([]byte, error) {
|
||||||
|
token, err := sys.getReportFileToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error fetching report download token")
|
||||||
|
}
|
||||||
|
defer sys.invalidateFileTokens()
|
||||||
|
data, err := sys.downloadFile(endpoint, http.MethodGet, "application/octet-stream", token.Token, projectVersionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error downloading report file")
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadResultFile downloads a result file from Fortify backend
|
||||||
|
func (sys *SystemInstance) DownloadResultFile(endpoint string, projectVersionID int64) ([]byte, error) {
|
||||||
|
token, err := sys.getFileDownloadToken()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error fetching result file download token")
|
||||||
|
}
|
||||||
|
defer sys.invalidateFileTokens()
|
||||||
|
data, err := sys.downloadFile(endpoint, http.MethodGet, "application/zip", token.Token, projectVersionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error downloading result file")
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
1330
pkg/fortify/fortify_test.go
Normal file
1330
pkg/fortify/fortify_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,9 +7,12 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/Masterminds/sprig"
|
||||||
|
|
||||||
"github.com/SAP/jenkins-library/pkg/config"
|
"github.com/SAP/jenkins-library/pkg/config"
|
||||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||||
)
|
)
|
||||||
@ -56,8 +59,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type {{ .StepName }}Options struct {
|
type {{ .StepName }}Options struct {
|
||||||
{{- range $key, $value := .StepParameters }}
|
{{- $names := list ""}}
|
||||||
{{ $value.Name | golangName }} {{ $value.Type }} ` + "`json:\"{{$value.Name}},omitempty\"`" + `{{end}}
|
{{- range $key, $value := uniqueName .StepParameters }}
|
||||||
|
{{ if ne (has $value.Name $names) true -}}
|
||||||
|
{{ $names | last }}{{ $value.Name | golangName }} {{ $value.Type }} ` + "`json:\"{{$value.Name}},omitempty\"`" + `
|
||||||
|
{{- else -}}
|
||||||
|
{{- $names = append $names $value.Name }} {{ end -}}
|
||||||
|
{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
{{ range $notused, $oRes := .OutputResources }}
|
{{ range $notused, $oRes := .OutputResources }}
|
||||||
@ -124,7 +132,7 @@ func {{.CobraCmdFuncName}}() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func {{.FlagsFunc}}(cmd *cobra.Command, stepConfig *{{.StepName}}Options) {
|
func {{.FlagsFunc}}(cmd *cobra.Command, stepConfig *{{.StepName}}Options) {
|
||||||
{{- range $key, $value := .StepParameters }}
|
{{- range $key, $value := uniqueName .StepParameters }}
|
||||||
cmd.Flags().{{ $value.Type | flagType }}(&stepConfig.{{ $value.Name | golangName }}, "{{ $value.Name }}", {{ $value.Default }}, "{{ $value.Description }}"){{ end }}
|
cmd.Flags().{{ $value.Type | flagType }}(&stepConfig.{{ $value.Name | golangName }}, "{{ $value.Name }}", {{ $value.Default }}, "{{ $value.Description }}"){{ end }}
|
||||||
{{- printf "\n" }}
|
{{- printf "\n" }}
|
||||||
{{- range $key, $value := .StepParameters }}{{ if $value.Mandatory }}
|
{{- range $key, $value := .StepParameters }}{{ if $value.Mandatory }}
|
||||||
@ -300,9 +308,9 @@ func setDefaultParameters(stepData *config.StepData) (bool, error) {
|
|||||||
case "int":
|
case "int":
|
||||||
param.Default = fmt.Sprintf("%v", param.Default)
|
param.Default = fmt.Sprintf("%v", param.Default)
|
||||||
case "string":
|
case "string":
|
||||||
param.Default = fmt.Sprintf("\"%v\"", param.Default)
|
param.Default = fmt.Sprintf("`%v`", param.Default)
|
||||||
case "[]string":
|
case "[]string":
|
||||||
param.Default = fmt.Sprintf("[]string{\"%v\"}", strings.Join(getStringSliceFromInterface(param.Default), "\", \""))
|
param.Default = fmt.Sprintf("[]string{`%v`}", strings.Join(getStringSliceFromInterface(param.Default), "`, `"))
|
||||||
default:
|
default:
|
||||||
return false, fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
return false, fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
||||||
}
|
}
|
||||||
@ -432,12 +440,12 @@ func MetadataFiles(sourceDirectory string) ([]string, error) {
|
|||||||
|
|
||||||
func stepTemplate(myStepInfo stepInfo) []byte {
|
func stepTemplate(myStepInfo stepInfo) []byte {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := sprig.HermeticTxtFuncMap()
|
||||||
"flagType": flagType,
|
funcMap["flagType"] = flagType
|
||||||
"golangName": golangNameTitle,
|
funcMap["golangName"] = golangNameTitle
|
||||||
"title": strings.Title,
|
funcMap["title"] = strings.Title
|
||||||
"longName": longName,
|
funcMap["longName"] = longName
|
||||||
}
|
funcMap["uniqueName"] = mustUniqName
|
||||||
|
|
||||||
tmpl, err := template.New("step").Funcs(funcMap).Parse(stepGoTemplate)
|
tmpl, err := template.New("step").Funcs(funcMap).Parse(stepGoTemplate)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
@ -451,11 +459,11 @@ func stepTemplate(myStepInfo stepInfo) []byte {
|
|||||||
|
|
||||||
func stepTestTemplate(myStepInfo stepInfo) []byte {
|
func stepTestTemplate(myStepInfo stepInfo) []byte {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := sprig.HermeticTxtFuncMap()
|
||||||
"flagType": flagType,
|
funcMap["flagType"] = flagType
|
||||||
"golangName": golangNameTitle,
|
funcMap["golangName"] = golangNameTitle
|
||||||
"title": strings.Title,
|
funcMap["title"] = strings.Title
|
||||||
}
|
funcMap["uniqueName"] = mustUniqName
|
||||||
|
|
||||||
tmpl, err := template.New("stepTest").Funcs(funcMap).Parse(stepTestGoTemplate)
|
tmpl, err := template.New("stepTest").Funcs(funcMap).Parse(stepTestGoTemplate)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
@ -469,9 +477,9 @@ func stepTestTemplate(myStepInfo stepInfo) []byte {
|
|||||||
|
|
||||||
func stepImplementation(myStepInfo stepInfo) []byte {
|
func stepImplementation(myStepInfo stepInfo) []byte {
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
funcMap := sprig.HermeticTxtFuncMap()
|
||||||
"title": strings.Title,
|
funcMap["title"] = strings.Title
|
||||||
}
|
funcMap["uniqueName"] = mustUniqName
|
||||||
|
|
||||||
tmpl, err := template.New("impl").Funcs(funcMap).Parse(stepGoImplementationTemplate)
|
tmpl, err := template.New("impl").Funcs(funcMap).Parse(stepGoImplementationTemplate)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
@ -536,3 +544,27 @@ func getStringSliceFromInterface(iSlice interface{}) []string {
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustUniqName(list []config.StepParameters) ([]config.StepParameters, error) {
|
||||||
|
tp := reflect.TypeOf(list).Kind()
|
||||||
|
switch tp {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
l2 := reflect.ValueOf(list)
|
||||||
|
|
||||||
|
l := l2.Len()
|
||||||
|
names := []string{}
|
||||||
|
dest := []config.StepParameters{}
|
||||||
|
var item config.StepParameters
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
item = l2.Index(i).Interface().(config.StepParameters)
|
||||||
|
if !piperutils.ContainsString(names, item.Name) {
|
||||||
|
names = append(names, item.Name)
|
||||||
|
dest = append(dest, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Cannot find uniq on type %s", tp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -145,11 +145,11 @@ func TestSetDefaultParameters(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"\"val0\"",
|
"`val0`",
|
||||||
"os.Getenv(\"PIPER_param1\")",
|
"os.Getenv(\"PIPER_param1\")",
|
||||||
"true",
|
"true",
|
||||||
"false",
|
"false",
|
||||||
"[]string{\"val4_1\", \"val4_2\"}",
|
"[]string{`val4_1`, `val4_2`}",
|
||||||
"[]string{}",
|
"[]string{}",
|
||||||
"0",
|
"0",
|
||||||
"1",
|
"1",
|
||||||
|
@ -149,7 +149,7 @@ func TestStepCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTestStepFlags(cmd *cobra.Command, stepConfig *testStepOptions) {
|
func addTestStepFlags(cmd *cobra.Command, stepConfig *testStepOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.Param0, "param0", "val0", "param0 description")
|
cmd.Flags().StringVar(&stepConfig.Param0, "param0", `val0`, "param0 description")
|
||||||
cmd.Flags().StringVar(&stepConfig.Param1, "param1", os.Getenv("PIPER_param1"), "param1 description")
|
cmd.Flags().StringVar(&stepConfig.Param1, "param1", os.Getenv("PIPER_param1"), "param1 description")
|
||||||
cmd.Flags().StringVar(&stepConfig.Param2, "param2", os.Getenv("PIPER_param2"), "param1 description")
|
cmd.Flags().StringVar(&stepConfig.Param2, "param2", os.Getenv("PIPER_param2"), "param1 description")
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ func TestStepCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTestStepFlags(cmd *cobra.Command, stepConfig *testStepOptions) {
|
func addTestStepFlags(cmd *cobra.Command, stepConfig *testStepOptions) {
|
||||||
cmd.Flags().StringVar(&stepConfig.Param0, "param0", "val0", "param0 description")
|
cmd.Flags().StringVar(&stepConfig.Param0, "param0", `val0`, "param0 description")
|
||||||
cmd.Flags().StringVar(&stepConfig.Param1, "param1", os.Getenv("PIPER_param1"), "param1 description")
|
cmd.Flags().StringVar(&stepConfig.Param1, "param1", os.Getenv("PIPER_param1"), "param1 description")
|
||||||
cmd.Flags().StringVar(&stepConfig.Param2, "param2", os.Getenv("PIPER_param2"), "param1 description")
|
cmd.Flags().StringVar(&stepConfig.Param2, "param2", os.Getenv("PIPER_param2"), "param1 description")
|
||||||
|
|
||||||
|
203
pkg/http/http.go
203
pkg/http/http.go
@ -2,6 +2,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
@ -12,19 +13,22 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/SAP/jenkins-library/pkg/log"
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/motemen/go-nuts/roundtime"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client defines an http client object
|
// Client defines an http client object
|
||||||
type Client struct {
|
type Client struct {
|
||||||
maxRequestDuration time.Duration
|
maxRequestDuration time.Duration
|
||||||
transportTimeout time.Duration
|
transportTimeout time.Duration
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
token string
|
token string
|
||||||
logger *logrus.Entry
|
logger *logrus.Entry
|
||||||
cookieJar http.CookieJar
|
cookieJar http.CookieJar
|
||||||
|
doLogRequestBodyOnDebug bool
|
||||||
|
doLogResponseBodyOnDebug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientOptions defines the options to be set on the client
|
// ClientOptions defines the options to be set on the client
|
||||||
@ -36,12 +40,39 @@ type ClientOptions struct {
|
|||||||
MaxRequestDuration time.Duration
|
MaxRequestDuration time.Duration
|
||||||
// TransportTimeout defaults to 10 seconds, if not specified. It is
|
// TransportTimeout defaults to 10 seconds, if not specified. It is
|
||||||
// used for the transport layer and duration of handshakes and such.
|
// used for the transport layer and duration of handshakes and such.
|
||||||
TransportTimeout time.Duration
|
TransportTimeout time.Duration
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
Token string
|
Token string
|
||||||
Logger *logrus.Entry
|
Logger *logrus.Entry
|
||||||
CookieJar http.CookieJar
|
CookieJar http.CookieJar
|
||||||
|
DoLogRequestBodyOnDebug bool
|
||||||
|
DoLogResponseBodyOnDebug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransportWrapper is a wrapper for central logging capabilities
|
||||||
|
type TransportWrapper struct {
|
||||||
|
Transport http.RoundTripper
|
||||||
|
doLogRequestBodyOnDebug bool
|
||||||
|
doLogResponseBodyOnDebug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadRequestData encapsulates the parameters for calling uploader.Upload()
|
||||||
|
type UploadRequestData struct {
|
||||||
|
// Method is the HTTP method used for the request. Must be one of http.MethodPost or http.MethodPut.
|
||||||
|
Method string
|
||||||
|
// URL for the request
|
||||||
|
URL string
|
||||||
|
// File path to be stored in the created form field.
|
||||||
|
File string
|
||||||
|
// Form field name under which the file name will be stored.
|
||||||
|
FileFieldName string
|
||||||
|
// Additional form fields which will be added to the request if not nil.
|
||||||
|
FormFields map[string]string
|
||||||
|
// Reader from which the file contents will be read.
|
||||||
|
FileContent io.Reader
|
||||||
|
Header http.Header
|
||||||
|
Cookies []*http.Cookie
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sender provides an interface to the piper http client for uid/pwd and token authenticated requests
|
// Sender provides an interface to the piper http client for uid/pwd and token authenticated requests
|
||||||
@ -55,18 +86,36 @@ type Uploader interface {
|
|||||||
Sender
|
Sender
|
||||||
UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error)
|
UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error)
|
||||||
UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error)
|
UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error)
|
||||||
|
Upload(data UploadRequestData) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadFile uploads a file's content as multipart-form POST request to the specified URL
|
// UploadFile uploads a file's content as multipart-form POST request to the specified URL
|
||||||
func (c *Client) UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
func (c *Client) UploadFile(url, file, fileFieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
||||||
return c.UploadRequest(http.MethodPost, url, file, fieldName, header, cookies)
|
return c.UploadRequest(http.MethodPost, url, file, fileFieldName, header, cookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadRequest uploads a file's content as multipart-form with given http method request to the specified URL
|
// UploadRequest uploads a file's content as multipart-form with given http method request to the specified URL
|
||||||
func (c *Client) UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
func (c *Client) UploadRequest(method, url, file, fileFieldName string, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
||||||
|
fileHandle, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return &http.Response{}, errors.Wrapf(err, "unable to locate file %v", file)
|
||||||
|
}
|
||||||
|
defer fileHandle.Close()
|
||||||
|
return c.Upload(UploadRequestData{
|
||||||
|
Method: method,
|
||||||
|
URL: url,
|
||||||
|
File: file,
|
||||||
|
FileFieldName: fileFieldName,
|
||||||
|
FileContent: fileHandle,
|
||||||
|
Header: header,
|
||||||
|
Cookies: cookies,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if method != http.MethodPost && method != http.MethodPut {
|
// Upload uploads a file's content as multipart-form with given http method request to the specified URL
|
||||||
return nil, errors.New(fmt.Sprintf("Http method %v is not allowed. Possible values are %v or %v", method, http.MethodPost, http.MethodPut))
|
func (c *Client) Upload(data UploadRequestData) (*http.Response, error) {
|
||||||
|
if data.Method != http.MethodPost && data.Method != http.MethodPut {
|
||||||
|
return nil, errors.New(fmt.Sprintf("Http method %v is not allowed. Possible values are %v or %v", data.Method, http.MethodPost, http.MethodPut))
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient := c.initialize()
|
httpClient := c.initialize()
|
||||||
@ -74,27 +123,30 @@ func (c *Client) UploadRequest(method, url, file, fieldName string, header http.
|
|||||||
bodyBuffer := &bytes.Buffer{}
|
bodyBuffer := &bytes.Buffer{}
|
||||||
bodyWriter := multipart.NewWriter(bodyBuffer)
|
bodyWriter := multipart.NewWriter(bodyBuffer)
|
||||||
|
|
||||||
fileWriter, err := bodyWriter.CreateFormFile(fieldName, file)
|
if data.FormFields != nil {
|
||||||
if err != nil {
|
for fieldName, fieldValue := range data.FormFields {
|
||||||
return &http.Response{}, errors.Wrapf(err, "error creating form file %v for field %v", file, fieldName)
|
err := bodyWriter.WriteField(fieldName, fieldValue)
|
||||||
|
if err != nil {
|
||||||
|
return &http.Response{}, errors.Wrapf(err, "error writing form field %v with value %v", fieldName, fieldValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileHandle, err := os.Open(file)
|
fileWriter, err := bodyWriter.CreateFormFile(data.FileFieldName, data.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &http.Response{}, errors.Wrapf(err, "unable to locate file %v", file)
|
return &http.Response{}, errors.Wrapf(err, "error creating form file %v for field %v", data.File, data.FileFieldName)
|
||||||
}
|
}
|
||||||
defer fileHandle.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(fileWriter, fileHandle)
|
_, err = io.Copy(fileWriter, data.FileContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &http.Response{}, errors.Wrapf(err, "unable to copy file content of %v into request body", file)
|
return &http.Response{}, errors.Wrapf(err, "unable to copy file content of %v into request body", data.File)
|
||||||
}
|
}
|
||||||
err = bodyWriter.Close()
|
err = bodyWriter.Close()
|
||||||
|
|
||||||
request, err := c.createRequest(method, url, bodyBuffer, &header, cookies)
|
request, err := c.createRequest(data.Method, data.URL, bodyBuffer, &data.Header, data.Cookies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Debugf("New %v request to %v", method, url)
|
c.logger.Debugf("New %v request to %v", data.Method, data.URL)
|
||||||
return &http.Response{}, errors.Wrapf(err, "error creating %v request to %v", method, url)
|
return &http.Response{}, errors.Wrapf(err, "error creating %v request to %v", data.Method, data.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
startBoundary := strings.Index(bodyWriter.FormDataContentType(), "=") + 1
|
startBoundary := strings.Index(bodyWriter.FormDataContentType(), "=") + 1
|
||||||
@ -105,7 +157,7 @@ func (c *Client) UploadRequest(method, url, file, fieldName string, header http.
|
|||||||
|
|
||||||
response, err := httpClient.Do(request)
|
response, err := httpClient.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, errors.Wrapf(err, "HTTP %v request to %v failed with error", method, url)
|
return response, errors.Wrapf(err, "HTTP %v request to %v failed with error", data.Method, data.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.handleResponse(response)
|
return c.handleResponse(response)
|
||||||
@ -117,13 +169,12 @@ func (c *Client) SendRequest(method, url string, body io.Reader, header http.Hea
|
|||||||
|
|
||||||
request, err := c.createRequest(method, url, body, &header, cookies)
|
request, err := c.createRequest(method, url, body, &header, cookies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Debugf("New %v request to %v", method, url)
|
|
||||||
return &http.Response{}, errors.Wrapf(err, "error creating %v request to %v", method, url)
|
return &http.Response{}, errors.Wrapf(err, "error creating %v request to %v", method, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := httpClient.Do(request)
|
response, err := httpClient.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, errors.Wrapf(err, "error opening %v", url)
|
return response, errors.Wrapf(err, "error calling %v", url)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.handleResponse(response)
|
return c.handleResponse(response)
|
||||||
@ -131,6 +182,8 @@ func (c *Client) SendRequest(method, url string, body io.Reader, header http.Hea
|
|||||||
|
|
||||||
// SetOptions sets options used for the http client
|
// SetOptions sets options used for the http client
|
||||||
func (c *Client) SetOptions(options ClientOptions) {
|
func (c *Client) SetOptions(options ClientOptions) {
|
||||||
|
c.doLogRequestBodyOnDebug = options.DoLogRequestBodyOnDebug
|
||||||
|
c.doLogResponseBodyOnDebug = options.DoLogResponseBodyOnDebug
|
||||||
c.transportTimeout = options.TransportTimeout
|
c.transportTimeout = options.TransportTimeout
|
||||||
c.maxRequestDuration = options.MaxRequestDuration
|
c.maxRequestDuration = options.MaxRequestDuration
|
||||||
c.username = options.Username
|
c.username = options.Username
|
||||||
@ -149,15 +202,18 @@ func (c *Client) initialize() *http.Client {
|
|||||||
c.applyDefaults()
|
c.applyDefaults()
|
||||||
c.logger = log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")
|
c.logger = log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")
|
||||||
|
|
||||||
var transport = &http.Transport{
|
var transport = &TransportWrapper{
|
||||||
DialContext: (&net.Dialer{
|
Transport: &http.Transport{
|
||||||
Timeout: c.transportTimeout,
|
DialContext: (&net.Dialer{
|
||||||
}).DialContext,
|
Timeout: c.transportTimeout,
|
||||||
ResponseHeaderTimeout: c.transportTimeout,
|
}).DialContext,
|
||||||
ExpectContinueTimeout: c.transportTimeout,
|
ResponseHeaderTimeout: c.transportTimeout,
|
||||||
TLSHandshakeTimeout: c.transportTimeout,
|
ExpectContinueTimeout: c.transportTimeout,
|
||||||
|
TLSHandshakeTimeout: c.transportTimeout,
|
||||||
|
},
|
||||||
|
doLogRequestBodyOnDebug: c.doLogRequestBodyOnDebug,
|
||||||
|
doLogResponseBodyOnDebug: c.doLogResponseBodyOnDebug,
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpClient = &http.Client{
|
var httpClient = &http.Client{
|
||||||
Timeout: c.maxRequestDuration,
|
Timeout: c.maxRequestDuration,
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
@ -168,8 +224,71 @@ func (c *Client) initialize() *http.Client {
|
|||||||
return httpClient
|
return httpClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type contextKey struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
var contextKeyRequestStart = &contextKey{"RequestStart"}
|
||||||
|
|
||||||
|
// RoundTrip is the core part of this module and implements http.RoundTripper.
|
||||||
|
// Executes HTTP request with request/response logging.
|
||||||
|
func (t *TransportWrapper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
ctx := context.WithValue(req.Context(), contextKeyRequestStart, time.Now())
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
|
||||||
|
t.logRequest(req)
|
||||||
|
resp, err := t.Transport.RoundTrip(req)
|
||||||
|
t.logResponse(resp)
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransportWrapper) logRequest(req *http.Request) {
|
||||||
|
log.Entry().Debug("--------------------------------")
|
||||||
|
log.Entry().Debugf("--> %v request to %v", req.Method, req.URL)
|
||||||
|
log.Entry().Debugf("headers: %v", req.Header)
|
||||||
|
log.Entry().Debugf("cookies: %v", transformCookies(req.Cookies()))
|
||||||
|
if t.doLogRequestBodyOnDebug {
|
||||||
|
log.Entry().Debugf("body: %v", transformBody(req.Body))
|
||||||
|
}
|
||||||
|
log.Entry().Debug("--------------------------------")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TransportWrapper) logResponse(resp *http.Response) {
|
||||||
|
if resp != nil {
|
||||||
|
ctx := resp.Request.Context()
|
||||||
|
if start, ok := ctx.Value(contextKeyRequestStart).(time.Time); ok {
|
||||||
|
log.Entry().Debugf("<-- response %v %v (%v)", resp.StatusCode, resp.Request.URL, roundtime.Duration(time.Now().Sub(start), 2))
|
||||||
|
} else {
|
||||||
|
log.Entry().Debugf("<-- response %v %v", resp.StatusCode, resp.Request.URL)
|
||||||
|
}
|
||||||
|
if t.doLogResponseBodyOnDebug {
|
||||||
|
log.Entry().Debugf("body: %v", transformBody(resp.Body))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Entry().Debug("response <nil>")
|
||||||
|
}
|
||||||
|
log.Entry().Debug("--------------------------------")
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformCookies(cookies []*http.Cookie) string {
|
||||||
|
result := ""
|
||||||
|
for _, c := range cookies {
|
||||||
|
result = fmt.Sprintf("%v %v", result, c.String())
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformBody(body io.ReadCloser) string {
|
||||||
|
if body == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.ReadFrom(body)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) createRequest(method, url string, body io.Reader, header *http.Header, cookies []*http.Cookie) (*http.Request, error) {
|
func (c *Client) createRequest(method, url string, body io.Reader, header *http.Header, cookies []*http.Cookie) (*http.Request, error) {
|
||||||
c.logger.Debugf("New %v request to %v", method, url)
|
|
||||||
request, err := http.NewRequest(method, url, body)
|
request, err := http.NewRequest(method, url, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &http.Request{}, err
|
return &http.Request{}, err
|
||||||
@ -215,7 +334,7 @@ func (c *Client) handleResponse(response *http.Response) (*http.Response, error)
|
|||||||
case http.StatusNotFound:
|
case http.StatusNotFound:
|
||||||
c.logger.WithField("HTTP Error", "404 (Not Found)").Error("Requested resource could not be found")
|
c.logger.WithField("HTTP Error", "404 (Not Found)").Error("Requested resource could not be found")
|
||||||
case http.StatusInternalServerError:
|
case http.StatusInternalServerError:
|
||||||
c.logger.WithField("HTTP Error", "500 (Internal Server Error)").Error("Unknown error occured.")
|
c.logger.WithField("HTTP Error", "500 (Internal Server Error)").Error("Unknown error occurred.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return response, fmt.Errorf("Request to %v returned with response %v", response.Request.URL, response.Status)
|
return response, fmt.Errorf("Request to %v returned with response %v", response.Request.URL, response.Status)
|
||||||
|
@ -24,6 +24,16 @@ func ContainsString(s []string, e string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ContainsStringPart check wether the element is contained as part of one of the elements of the slice
|
||||||
|
func ContainsStringPart(s []string, part string) bool {
|
||||||
|
for _, a := range s {
|
||||||
|
if strings.Contains(a, part) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
//Prefix adds a prefix to each element of the slice
|
//Prefix adds a prefix to each element of the slice
|
||||||
func Prefix(in []string, prefix string) []string {
|
func Prefix(in []string, prefix string) []string {
|
||||||
return _prefix(in, prefix, true)
|
return _prefix(in, prefix, true)
|
||||||
|
30
pkg/piperutils/templateUtils.go
Normal file
30
pkg/piperutils/templateUtils.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package piperutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecuteTemplate parses the provided template, substitutes values and returns the output
|
||||||
|
func ExecuteTemplate(txtTemplate string, context interface{}) (string, error) {
|
||||||
|
return ExecuteTemplateFunctions(txtTemplate, nil, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteTemplateFunctions parses the provided template, applies the transformation functions, substitutes values and returns the output
|
||||||
|
func ExecuteTemplateFunctions(txtTemplate string, functionMap template.FuncMap, context interface{}) (string, error) {
|
||||||
|
template := template.New("tmp")
|
||||||
|
if functionMap != nil {
|
||||||
|
template = template.Funcs(functionMap)
|
||||||
|
}
|
||||||
|
template, err := template.Parse(txtTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "<nil>", fmt.Errorf("Failed to parse template defintion %v: %w", txtTemplate, err)
|
||||||
|
}
|
||||||
|
var output bytes.Buffer
|
||||||
|
err = template.Execute(&output, context)
|
||||||
|
if err != nil {
|
||||||
|
return "<nil>", fmt.Errorf("Failed to transform template defintion %v: %w", txtTemplate, err)
|
||||||
|
}
|
||||||
|
return output.String(), nil
|
||||||
|
}
|
46
pkg/piperutils/templateUtils_test.go
Normal file
46
pkg/piperutils/templateUtils_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package piperutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SomeDescriptor struct {
|
||||||
|
GroupID string
|
||||||
|
ArtifactID string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteTemplate(t *testing.T) {
|
||||||
|
t.Run("test success", func(t *testing.T) {
|
||||||
|
context := SomeDescriptor{GroupID: "com.sap.cp.jenkins", ArtifactID: "piper", Version: "1.2.3"}
|
||||||
|
result, err := ExecuteTemplate("{{ .GroupID }}-{{ .ArtifactID }}:{{ .Version}}", context)
|
||||||
|
assert.NoError(t, err, "Didn't expect error but got one")
|
||||||
|
assert.Equal(t, "com.sap.cp.jenkins-piper:1.2.3", result, "Expected different result")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test template error", func(t *testing.T) {
|
||||||
|
context := SomeDescriptor{GroupID: "com.sap.cp.jenkins", ArtifactID: "piper", Version: "1.2.3"}
|
||||||
|
_, err := ExecuteTemplate("{{ $+++.+++GroupID }}-{{ .ArtifactID }}:{{ .Version}}", context)
|
||||||
|
assert.Error(t, err, "Expected error but got none")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test functions", func(t *testing.T) {
|
||||||
|
functions := template.FuncMap{
|
||||||
|
"testFunc": reverse,
|
||||||
|
}
|
||||||
|
context := SomeDescriptor{GroupID: "com.sap.cp.jenkins", ArtifactID: "piper", Version: "1.2.3"}
|
||||||
|
result, err := ExecuteTemplateFunctions("{{ testFunc .GroupID }}-{{ .ArtifactID }}:{{ .Version}}", functions, context)
|
||||||
|
assert.NoError(t, err, "Didn't expect error but got one")
|
||||||
|
assert.Equal(t, "sniknej.pc.pas.moc-piper:1.2.3", result, "Expected different result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func reverse(s string) string {
|
||||||
|
runes := []rune(s)
|
||||||
|
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
runes[i], runes[j] = runes[j], runes[i]
|
||||||
|
}
|
||||||
|
return string(runes)
|
||||||
|
}
|
22
pkg/piperutils/testdata/2_setup.py
vendored
Normal file
22
pkg/piperutils/testdata/2_setup.py
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
from codecs import open
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
with open('version.txt') as ver_file:
|
||||||
|
version_str = ver_file.readline().rstrip()
|
||||||
|
return version_str
|
||||||
|
|
||||||
|
|
||||||
|
def get_install_requires():
|
||||||
|
with open('requirements.txt') as reqs_file:
|
||||||
|
reqs = [line.rstrip() for line in reqs_file.readlines()]
|
||||||
|
return reqs
|
||||||
|
|
||||||
|
setup(name="some-test",
|
||||||
|
version="1.0.0",
|
||||||
|
python_requires='>=3',
|
||||||
|
packages=find_packages(exclude=['contrib', 'docs', 'tests*', 'coverage', 'bin']),
|
||||||
|
description="test",
|
||||||
|
install_requires=get_install_requires(),
|
||||||
|
)
|
1
pkg/piperutils/testdata/VERSION.TXT
vendored
Normal file
1
pkg/piperutils/testdata/VERSION.TXT
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
1.0.0-SNAPSHOT
|
22
pkg/piperutils/testdata/setup.py
vendored
Normal file
22
pkg/piperutils/testdata/setup.py
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
from codecs import open
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
def get_version():
|
||||||
|
with open('version.txt') as ver_file:
|
||||||
|
version_str = ver_file.readline().rstrip()
|
||||||
|
return version_str
|
||||||
|
|
||||||
|
|
||||||
|
def get_install_requires():
|
||||||
|
with open('requirements.txt') as reqs_file:
|
||||||
|
reqs = [line.rstrip() for line in reqs_file.readlines()]
|
||||||
|
return reqs
|
||||||
|
|
||||||
|
setup(name="some-test",
|
||||||
|
version=get_version(),
|
||||||
|
python_requires='>=3',
|
||||||
|
packages=find_packages(exclude=['contrib', 'docs', 'tests*', 'coverage', 'bin']),
|
||||||
|
description="test",
|
||||||
|
install_requires=get_install_requires(),
|
||||||
|
)
|
15
pkg/piperutils/testdata/test2_pom.xml
vendored
Normal file
15
pkg/piperutils/testdata/test2_pom.xml
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>parent-inherit-test</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.sap.ldi</groupId>
|
||||||
|
<artifactId>ldi-parent-root</artifactId>
|
||||||
|
<version>7.4.0</version>
|
||||||
|
</parent>
|
||||||
|
</project>
|
9
pkg/piperutils/testdata/test_pom.xml
vendored
Normal file
9
pkg/piperutils/testdata/test_pom.xml
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>test.groupID</groupId>
|
||||||
|
<artifactId>test-articatID</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</project>
|
47
pkg/versioning/descriptorUtils.go
Normal file
47
pkg/versioning/descriptorUtils.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Masterminds/sprig"
|
||||||
|
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SchemeMajorVersion is the versioning scheme based on the major version only
|
||||||
|
SchemeMajorVersion = `{{(split "." (split "-" .Version)._0)._0}}`
|
||||||
|
// SchemeMajorMinorVersion is the versioning scheme based on the major version only
|
||||||
|
SchemeMajorMinorVersion = `{{(split "." (split "-" .Version)._0)._0}}.{{(split "." (split "-" .Version)._0)._1}}`
|
||||||
|
// SchemeSemanticVersion is the versioning scheme based on the major.minor.micro version
|
||||||
|
SchemeSemanticVersion = `{{(split "-" .Version)._0}}`
|
||||||
|
// SchemeFullVersion is the versioning scheme based on the full version
|
||||||
|
SchemeFullVersion = "{{.Version}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DetermineProjectCoordinates resolve the coordinates of the project for use in 3rd party scan tools
|
||||||
|
func DetermineProjectCoordinates(nameTemplate, versionScheme string, gav Coordinates) (string, string) {
|
||||||
|
projectName, err := piperutils.ExecuteTemplateFunctions(nameTemplate, sprig.HermeticTxtFuncMap(), gav)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().Warnf("Unable to resolve fortify project name: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var versionTemplate string
|
||||||
|
if versionScheme == "full" {
|
||||||
|
versionTemplate = SchemeFullVersion
|
||||||
|
}
|
||||||
|
if versionScheme == "major" {
|
||||||
|
versionTemplate = SchemeMajorVersion
|
||||||
|
}
|
||||||
|
if versionScheme == "major-minor" {
|
||||||
|
versionTemplate = SchemeMajorMinorVersion
|
||||||
|
}
|
||||||
|
if versionScheme == "semantic" {
|
||||||
|
versionTemplate = SchemeSemanticVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
projectVersion, err := piperutils.ExecuteTemplateFunctions(versionTemplate, sprig.HermeticTxtFuncMap(), gav)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().Warnf("Unable to resolve fortify project version: %v", err)
|
||||||
|
}
|
||||||
|
return projectName, projectVersion
|
||||||
|
}
|
92
pkg/versioning/descriptorUtils_test.go
Normal file
92
pkg/versioning/descriptorUtils_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mavenMock struct {
|
||||||
|
groupID string
|
||||||
|
artifactID string
|
||||||
|
version string
|
||||||
|
packaging string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mavenMock) VersioningScheme() string {
|
||||||
|
return "maven"
|
||||||
|
}
|
||||||
|
func (m *mavenMock) GetVersion() (string, error) {
|
||||||
|
return m.version, nil
|
||||||
|
}
|
||||||
|
func (m *mavenMock) SetVersion(v string) error {
|
||||||
|
m.version = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mavenMock) GetCoordinates() (Coordinates, error) {
|
||||||
|
return &MavenDescriptor{GroupID: m.groupID, ArtifactID: m.artifactID, Version: m.version, Packaging: m.packaging}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipMock struct {
|
||||||
|
artifactID string
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipMock) VersioningScheme() string {
|
||||||
|
return "pep440"
|
||||||
|
}
|
||||||
|
func (p *pipMock) GetVersion() (string, error) {
|
||||||
|
return p.version, nil
|
||||||
|
}
|
||||||
|
func (p *pipMock) SetVersion(v string) error {
|
||||||
|
p.version = v
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (p *pipMock) GetCoordinates() (Coordinates, error) {
|
||||||
|
return &PipDescriptor{ArtifactID: p.artifactID, Version: p.version}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetermineProjectCoordinates(t *testing.T) {
|
||||||
|
nameTemplate := `{{list .GroupID .ArtifactID | join "-" | trimAll "-"}}`
|
||||||
|
|
||||||
|
t.Run("maven", func(t *testing.T) {
|
||||||
|
gav, _ := (&mavenMock{groupID: "com.test.pkg", artifactID: "analyzer", version: "1.2.3"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "major", gav)
|
||||||
|
assert.Equal(t, "com.test.pkg-analyzer", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "1", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("maven major-minor", func(t *testing.T) {
|
||||||
|
gav, _ := (&mavenMock{groupID: "com.test.pkg", artifactID: "analyzer", version: "1.2.3"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "major-minor", gav)
|
||||||
|
assert.Equal(t, "com.test.pkg-analyzer", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "1.2", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("maven full", func(t *testing.T) {
|
||||||
|
gav, _ := (&mavenMock{groupID: "com.test.pkg", artifactID: "analyzer", version: "1.2.3-7864387648746"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "full", gav)
|
||||||
|
assert.Equal(t, "com.test.pkg-analyzer", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "1.2.3-7864387648746", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("maven semantic", func(t *testing.T) {
|
||||||
|
gav, _ := (&mavenMock{groupID: "com.test.pkg", artifactID: "analyzer", version: "1.2.3-7864387648746"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "semantic", gav)
|
||||||
|
assert.Equal(t, "com.test.pkg-analyzer", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "1.2.3", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("maven empty", func(t *testing.T) {
|
||||||
|
gav, _ := (&mavenMock{groupID: "com.test.pkg", artifactID: "analyzer", version: "0-SNAPSHOT"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "snapshot", gav)
|
||||||
|
assert.Equal(t, "com.test.pkg-analyzer", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("python", func(t *testing.T) {
|
||||||
|
gav, _ := (&pipMock{artifactID: "python-test", version: "2.2.3"}).GetCoordinates()
|
||||||
|
name, version := DetermineProjectCoordinates(nameTemplate, "major", gav)
|
||||||
|
assert.Equal(t, "python-test", name, "Expected different project name")
|
||||||
|
assert.Equal(t, "2", version, "Expected different project version")
|
||||||
|
})
|
||||||
|
}
|
@ -141,3 +141,8 @@ func (d *Docker) versionFromBaseImageTag() string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the coordinates
|
||||||
|
func (d *Docker) GetCoordinates() (Coordinates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -85,3 +85,8 @@ func (i *INIfile) SetVersion(version string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the coordinates
|
||||||
|
func (i *INIfile) GetCoordinates() (Coordinates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -76,3 +76,8 @@ func (j *JSONfile) SetVersion(version string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the coordinates
|
||||||
|
func (j *JSONfile) GetCoordinates() (Coordinates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -21,6 +21,14 @@ type mavenRunner interface {
|
|||||||
Evaluate(string, string, mavenExecRunner) (string, error)
|
Evaluate(string, string, mavenExecRunner) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MavenDescriptor holds the unique identifier combination for Maven built Java artifacts
|
||||||
|
type MavenDescriptor struct {
|
||||||
|
GroupID string
|
||||||
|
ArtifactID string
|
||||||
|
Version string
|
||||||
|
Packaging string
|
||||||
|
}
|
||||||
|
|
||||||
// Maven defines a maven artifact used for versioning
|
// Maven defines a maven artifact used for versioning
|
||||||
type Maven struct {
|
type Maven struct {
|
||||||
pomPath string
|
pomPath string
|
||||||
@ -46,6 +54,62 @@ func (m *Maven) VersioningScheme() string {
|
|||||||
return "maven"
|
return "maven"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates reads the coordinates from the maven pom.xml descriptor file
|
||||||
|
func (m *Maven) GetCoordinates() (Coordinates, error) {
|
||||||
|
result := &MavenDescriptor{}
|
||||||
|
var err error
|
||||||
|
result.GroupID, err = m.GetGroupID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.ArtifactID, err = m.GetArtifactID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.Version, err = m.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result.Packaging, err = m.GetPackaging()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPackaging returns the current ID of the Group
|
||||||
|
func (m *Maven) GetPackaging() (string, error) {
|
||||||
|
m.init()
|
||||||
|
|
||||||
|
packaging, err := m.runner.Evaluate(m.pomPath, "project.packaging", m.execRunner)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Maven - getting packaging failed")
|
||||||
|
}
|
||||||
|
return packaging, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupID returns the current ID of the Group
|
||||||
|
func (m *Maven) GetGroupID() (string, error) {
|
||||||
|
m.init()
|
||||||
|
|
||||||
|
groupID, err := m.runner.Evaluate(m.pomPath, "project.groupId", m.execRunner)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Maven - getting groupId failed")
|
||||||
|
}
|
||||||
|
return groupID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtifactID returns the current ID of the artifact
|
||||||
|
func (m *Maven) GetArtifactID() (string, error) {
|
||||||
|
m.init()
|
||||||
|
|
||||||
|
artifactID, err := m.runner.Evaluate(m.pomPath, "project.artifactId", m.execRunner)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "Maven - getting artifactId failed")
|
||||||
|
}
|
||||||
|
return artifactID, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetVersion returns the current version of the artifact
|
// GetVersion returns the current version of the artifact
|
||||||
func (m *Maven) GetVersion() (string, error) {
|
func (m *Maven) GetVersion() (string, error) {
|
||||||
m.init()
|
m.init()
|
||||||
|
146
pkg/versioning/pip.go
Normal file
146
pkg/versioning/pip.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NameRegex is used to match the pip descriptor artifact name
|
||||||
|
NameRegex = "(?s)(.*)name=['\"](.*?)['\"](.*)"
|
||||||
|
// VersionRegex is used to match the pip descriptor artifact version
|
||||||
|
VersionRegex = "(?s)(.*)version=['\"](.*?)['\"](.*)"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PipDescriptor holds the unique identifier combination for pip built Python artifacts
|
||||||
|
type PipDescriptor struct {
|
||||||
|
GroupID string
|
||||||
|
ArtifactID string
|
||||||
|
Version string
|
||||||
|
Packaging string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pip utility to interact with Python specific versioning
|
||||||
|
type Pip struct {
|
||||||
|
path string
|
||||||
|
readFile func(string) ([]byte, error)
|
||||||
|
writeFile func(string, []byte, os.FileMode) error
|
||||||
|
fileExists func(string) (bool, error)
|
||||||
|
buildDescriptorContent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pip) init() error {
|
||||||
|
if p.readFile == nil {
|
||||||
|
p.readFile = ioutil.ReadFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.writeFile == nil {
|
||||||
|
p.writeFile = ioutil.WriteFile
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.buildDescriptorContent) > 0 {
|
||||||
|
content, err := p.readFile(p.path)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to read file '%v'", p.path)
|
||||||
|
}
|
||||||
|
p.buildDescriptorContent = string(content)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion returns the Pip descriptor version property
|
||||||
|
func (p *Pip) GetVersion() (string, error) {
|
||||||
|
buildDescriptorFilePath := p.path
|
||||||
|
var err error
|
||||||
|
if strings.Contains(p.path, "setup.py") {
|
||||||
|
buildDescriptorFilePath, err = searchDescriptor([]string{"version.txt", "VERSION"}, p.fileExists)
|
||||||
|
if err != nil {
|
||||||
|
err = p.init()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "failed to read file '%v'", p.path)
|
||||||
|
}
|
||||||
|
if evaluateResult(p.buildDescriptorContent, VersionRegex) {
|
||||||
|
compile := regexp.MustCompile(VersionRegex)
|
||||||
|
values := compile.FindStringSubmatch(p.buildDescriptorContent)
|
||||||
|
return values[2], nil
|
||||||
|
}
|
||||||
|
return "", errors.Wrap(err, "failed to retrieve version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
artifact := &Versionfile{
|
||||||
|
path: buildDescriptorFilePath,
|
||||||
|
versioningScheme: p.VersioningScheme(),
|
||||||
|
}
|
||||||
|
return artifact.GetVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVersion sets the Pip descriptor version property
|
||||||
|
func (p *Pip) SetVersion(v string) error {
|
||||||
|
buildDescriptorFilePath := p.path
|
||||||
|
var err error
|
||||||
|
if strings.Contains(p.path, "setup.py") {
|
||||||
|
buildDescriptorFilePath, err = searchDescriptor([]string{"version.txt", "VERSION"}, p.fileExists)
|
||||||
|
if err != nil {
|
||||||
|
err = p.init()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to read file '%v'", p.path)
|
||||||
|
}
|
||||||
|
if evaluateResult(p.buildDescriptorContent, VersionRegex) {
|
||||||
|
compile := regexp.MustCompile(VersionRegex)
|
||||||
|
values := compile.FindStringSubmatch(p.buildDescriptorContent)
|
||||||
|
p.buildDescriptorContent = strings.ReplaceAll(p.buildDescriptorContent, fmt.Sprintf("version='%v'", values[2]), fmt.Sprintf("version='%v'", v))
|
||||||
|
p.buildDescriptorContent = strings.ReplaceAll(p.buildDescriptorContent, fmt.Sprintf("version=\"%v\"", values[2]), fmt.Sprintf("version=\"%v\"", v))
|
||||||
|
p.writeFile(p.path, []byte(p.buildDescriptorContent), 0600)
|
||||||
|
} else {
|
||||||
|
return errors.Wrap(err, "failed to retrieve version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
artifact := &Versionfile{
|
||||||
|
path: buildDescriptorFilePath,
|
||||||
|
versioningScheme: p.VersioningScheme(),
|
||||||
|
}
|
||||||
|
return artifact.SetVersion(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersioningScheme returns the relevant versioning scheme
|
||||||
|
func (p *Pip) VersioningScheme() string {
|
||||||
|
return "pep440"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the pip build descriptor coordinates
|
||||||
|
func (p *Pip) GetCoordinates() (Coordinates, error) {
|
||||||
|
err := p.init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor := &PipDescriptor{}
|
||||||
|
if evaluateResult(p.buildDescriptorContent, NameRegex) {
|
||||||
|
compile := regexp.MustCompile(NameRegex)
|
||||||
|
values := compile.FindStringSubmatch(p.buildDescriptorContent)
|
||||||
|
descriptor.ArtifactID = values[2]
|
||||||
|
} else {
|
||||||
|
descriptor.ArtifactID = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.Version, err = p.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to retrieve coordinates")
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func evaluateResult(value, regex string) bool {
|
||||||
|
if len(value) > 0 {
|
||||||
|
match, _ := regexp.MatchString(regex, value)
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
3
pkg/versioning/pip_test.go
Normal file
3
pkg/versioning/pip_test.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package versioning
|
||||||
|
|
||||||
|
import ()
|
@ -60,3 +60,8 @@ func (v *Versionfile) SetVersion(version string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the coordinates
|
||||||
|
func (v *Versionfile) GetCoordinates() (Coordinates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -9,11 +9,15 @@ import (
|
|||||||
"github.com/SAP/jenkins-library/pkg/maven"
|
"github.com/SAP/jenkins-library/pkg/maven"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Coordinates to address the artifact
|
||||||
|
type Coordinates interface{}
|
||||||
|
|
||||||
// Artifact defines the versioning operations for various build tools
|
// Artifact defines the versioning operations for various build tools
|
||||||
type Artifact interface {
|
type Artifact interface {
|
||||||
VersioningScheme() string
|
VersioningScheme() string
|
||||||
GetVersion() (string, error)
|
GetVersion() (string, error)
|
||||||
SetVersion(string) error
|
SetVersion(string) error
|
||||||
|
GetCoordinates() (Coordinates, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options define build tool specific settings in order to properly retrieve e.g. the version of an artifact
|
// Options define build tool specific settings in order to properly retrieve e.g. the version of an artifact
|
||||||
@ -109,14 +113,14 @@ func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execR
|
|||||||
case "pip":
|
case "pip":
|
||||||
if len(buildDescriptorFilePath) == 0 {
|
if len(buildDescriptorFilePath) == 0 {
|
||||||
var err error
|
var err error
|
||||||
buildDescriptorFilePath, err = searchDescriptor([]string{"version.txt", "VERSION"}, fileExists)
|
buildDescriptorFilePath, err = searchDescriptor([]string{"version.txt", "VERSION", "setup.py"}, fileExists)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return artifact, err
|
return artifact, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
artifact = &Versionfile{
|
artifact = &Pip{
|
||||||
path: buildDescriptorFilePath,
|
path: buildDescriptorFilePath,
|
||||||
versioningScheme: "pep440",
|
fileExists: fileExists,
|
||||||
}
|
}
|
||||||
case "sbt":
|
case "sbt":
|
||||||
if len(buildDescriptorFilePath) == 0 {
|
if len(buildDescriptorFilePath) == 0 {
|
||||||
|
@ -112,7 +112,7 @@ func TestGetArtifact(t *testing.T) {
|
|||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
theType, ok := pip.(*Versionfile)
|
theType, ok := pip.(*Pip)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, "version.txt", theType.path)
|
assert.Equal(t, "version.txt", theType.path)
|
||||||
assert.Equal(t, "pep440", pip.VersioningScheme())
|
assert.Equal(t, "pep440", pip.VersioningScheme())
|
||||||
@ -122,7 +122,7 @@ func TestGetArtifact(t *testing.T) {
|
|||||||
fileExists = func(string) (bool, error) { return false, nil }
|
fileExists = func(string) (bool, error) { return false, nil }
|
||||||
_, err := GetArtifact("pip", "", &Options{}, nil)
|
_, err := GetArtifact("pip", "", &Options{}, nil)
|
||||||
|
|
||||||
assert.EqualError(t, err, "no build descriptor available, supported: [version.txt VERSION]")
|
assert.EqualError(t, err, "no build descriptor available, supported: [version.txt VERSION setup.py]")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("sbt", func(t *testing.T) {
|
t.Run("sbt", func(t *testing.T) {
|
||||||
|
@ -77,3 +77,8 @@ func (y *YAMLfile) SetVersion(version string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoordinates returns the coordinates
|
||||||
|
func (y *YAMLfile) GetCoordinates() (Coordinates, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
472
resources/metadata/fortify.yaml
Normal file
472
resources/metadata/fortify.yaml
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
metadata:
|
||||||
|
name: fortifyExecuteScan
|
||||||
|
description: This BETA step executes a Fortify scan on the specified project to perform static code analysis and check the source code for security flaws.
|
||||||
|
longDescription: |-
|
||||||
|
This step executes a Fortify scan on the specified project to perform static code analysis and check the source code for security flaws.
|
||||||
|
|
||||||
|
The Fortify step triggers a scan locally on your Jenkins within a docker container so finally you have to supply a docker image with a Fortify SCA
|
||||||
|
and Java plus Maven or alternatively Python installed into it for being able to perform any scans.
|
||||||
|
|
||||||
|
DISCLAIMER: The step has not yet been tested on a wide variaty of projects, and is therefore considered of BETA quality.
|
||||||
|
spec:
|
||||||
|
inputs:
|
||||||
|
secrets:
|
||||||
|
- name: fortifyCredentialsId
|
||||||
|
description: Jenkins 'Secret text' credentials ID containing token to authenticate to Fortify SSC.
|
||||||
|
type: jenkins
|
||||||
|
- name: githubTokenCredentialsId
|
||||||
|
description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub.
|
||||||
|
type: jenkins
|
||||||
|
resources:
|
||||||
|
- name: commonPipelineEnvironment
|
||||||
|
resourceSpec:
|
||||||
|
type: piperEnvironment
|
||||||
|
- name: buildDescriptor
|
||||||
|
type: stash
|
||||||
|
- name: deployDescriptor
|
||||||
|
type: stash
|
||||||
|
- name: tests
|
||||||
|
type: stash
|
||||||
|
- name: opensourceConfiguration
|
||||||
|
type: stash
|
||||||
|
params:
|
||||||
|
- name: authToken
|
||||||
|
type: string
|
||||||
|
description: The FortifyToken to use for authentication
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
mandatory: true
|
||||||
|
secret: true
|
||||||
|
- 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
|
||||||
|
- name: autoCreate
|
||||||
|
type: bool
|
||||||
|
description: Whether Fortify project and project version shall be implicitly auto created in case they cannot be found in the backend
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: mvnCustomArgs
|
||||||
|
type: string
|
||||||
|
description: Allows providing additional Maven command line parameters
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: ''
|
||||||
|
- name: modulePath
|
||||||
|
type: string
|
||||||
|
description: Allows providing the path for the module to scan
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: './'
|
||||||
|
- name: pythonRequirementsFile
|
||||||
|
type: string
|
||||||
|
description: 'The requirements file used in `buildTool: ''pip''` to populate
|
||||||
|
the build environment with the necessary dependencies'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: autodetectClasspath
|
||||||
|
type: bool
|
||||||
|
description: Whether the classpath is automatically determined via build tool i.e. maven or pip or not at all
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: true
|
||||||
|
- name: mustAuditIssueGroups
|
||||||
|
type: string
|
||||||
|
description: Comma separated list of issue groups that must be audited completely
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 'Corporate Security Requirements, Audit All'
|
||||||
|
- name: spotAuditIssueGroups
|
||||||
|
type: string
|
||||||
|
description: 'Comma separated list of issue groups that are spot checked and for which `spotCheckMinimum` audited issues are enforced'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 'Spot Checks of Each Category'
|
||||||
|
- name: pythonRequirementsInstallSuffix
|
||||||
|
type: string
|
||||||
|
description: 'The suffix for the command used to install the requirements file in `buildTool: ''pip''` to populate
|
||||||
|
the build environment with the necessary dependencies'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: pythonVersion
|
||||||
|
type: string
|
||||||
|
description: 'Python version to be used in `buildTool: ''pip''`'
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: python3
|
||||||
|
- name: uploadResults
|
||||||
|
type: bool
|
||||||
|
description: Whether results shall be uploaded or not
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: true
|
||||||
|
- name: buildDescriptorFile
|
||||||
|
type: string
|
||||||
|
description: 'Path to the build descriptor file addressing the module/folder
|
||||||
|
to be scanned. Defaults are for buildTool=`maven`: `./pom.xml`, buildTool=`pip`:
|
||||||
|
`./setup.py`.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: commitId
|
||||||
|
description: 'Set the Git commit ID for identifying artifacts throughout the scan.'
|
||||||
|
resourceRef:
|
||||||
|
- name: commonPipelineEnvironment
|
||||||
|
param: git/commitId
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
- name: commitMessage
|
||||||
|
description: 'Set the Git commit message for identifying pull request merges throughout the scan.'
|
||||||
|
resourceRef:
|
||||||
|
- name: commonPipelineEnvironment
|
||||||
|
param: git/commitMessage
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
- name: githubApiUrl
|
||||||
|
description: Set the GitHub API url.
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
default: https://api.github.com
|
||||||
|
- name: owner
|
||||||
|
aliases:
|
||||||
|
- name: githubOrg
|
||||||
|
description: 'Set the GitHub organization.'
|
||||||
|
resourceRef:
|
||||||
|
- name: commonPipelineEnvironment
|
||||||
|
param: github/owner
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
- name: repository
|
||||||
|
aliases:
|
||||||
|
- name: githubRepo
|
||||||
|
description: 'Set the GitHub repository.'
|
||||||
|
resourceRef:
|
||||||
|
- name: commonPipelineEnvironment
|
||||||
|
param: github/repository
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
- name: memory
|
||||||
|
type: string
|
||||||
|
description: The amount of memory granted to the translate/scan executions
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: -Xmx4G -Xms512M
|
||||||
|
- name: updateRulePack
|
||||||
|
type: bool
|
||||||
|
description: Whether the rule pack shall be updated and pulled from Fortify SSC before scanning or not
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: true
|
||||||
|
- name: pythonExcludes
|
||||||
|
type: string
|
||||||
|
description: 'The excludes pattern used in `buildTool: ''pip''` for excluding
|
||||||
|
specific .py files i.e. tests'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: -exclude ./**/tests/**/*;./**/setup.py
|
||||||
|
deprecated: true
|
||||||
|
- name: reportDownloadEndpoint
|
||||||
|
aliases:
|
||||||
|
- name: fortifyReportDownloadEndpoint
|
||||||
|
type: string
|
||||||
|
description: Fortify SSC endpoint for Report downloads
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: /transfer/reportDownload.html
|
||||||
|
- name: pollingMinutes
|
||||||
|
type: int
|
||||||
|
description: The number of minutes for which an uploaded FPR artifact's status is being polled to finish queuing/processing, if exceeded polling will be stopped and an error will be thrown
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 30
|
||||||
|
- name: quickScan
|
||||||
|
type: bool
|
||||||
|
description: Whether a quick scan should be performed, please consult the related Fortify documentation on JAM on the impact of this setting
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: false
|
||||||
|
- name: translate
|
||||||
|
type: string
|
||||||
|
description: JSON string of list of maps with required key `'src'`, and optional keys `'exclude'`, `'libDirs'`, `'aspnetcore'`, and `'dotNetCoreVersion'`
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: apiEndpoint
|
||||||
|
aliases:
|
||||||
|
- name: fortifyApiEndpoint
|
||||||
|
type: string
|
||||||
|
description: Fortify SSC endpoint used for uploading the scan results and checking the audit state
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: /api/v1
|
||||||
|
- name: reportType
|
||||||
|
type: string
|
||||||
|
description: The type of report to be generated
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: PDF
|
||||||
|
- name: pythonAdditionalPath
|
||||||
|
type: string
|
||||||
|
description: 'The addional path which can be used in `buildTool: ''pip''` for
|
||||||
|
customization purposes'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: ./lib;.
|
||||||
|
deprecated: true
|
||||||
|
- name: artifactUrl
|
||||||
|
type: string
|
||||||
|
description: 'Path/Url pointing to an additional artifact repository for resolution of additional artifacts during the build'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: considerSuspicious
|
||||||
|
type: bool
|
||||||
|
description: Whether suspicious issues should trigger the check to fail or not
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: true
|
||||||
|
- name: fprUploadEndpoint
|
||||||
|
aliases:
|
||||||
|
- name: fortifyFprUploadEndpoint
|
||||||
|
type: string
|
||||||
|
description: Fortify SSC endpoint for FPR uploads
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: /upload/resultFileUpload.html
|
||||||
|
- name: projectName
|
||||||
|
aliases:
|
||||||
|
- name: fortifyProjectName
|
||||||
|
type: string
|
||||||
|
description: The project used for reporting results in SSC
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: '{{list .GroupID .ArtifactID | join "-" | trimAll "-"}}'
|
||||||
|
- name: pythonIncludes
|
||||||
|
type: string
|
||||||
|
description: 'The includes pattern used in `buildTool: ''pip''` for including
|
||||||
|
.py files'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: ./**/*
|
||||||
|
deprecated: true
|
||||||
|
- name: reporting
|
||||||
|
type: bool
|
||||||
|
description: Influences whether a report is generated or not
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: false
|
||||||
|
- name: serverUrl
|
||||||
|
aliases:
|
||||||
|
- name: fortifyServerUrl
|
||||||
|
- name: sscUrl
|
||||||
|
deprecated: true
|
||||||
|
type: string
|
||||||
|
description: Fortify SSC Url to be used for accessing the APIs
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: buildDescriptorExcludeList
|
||||||
|
type: string
|
||||||
|
description: Build descriptor files to exclude modules from being scanned
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: []
|
||||||
|
- name: pullRequestMessageRegexGroup
|
||||||
|
type: int
|
||||||
|
description: The group number for extracting the pull request id in `pullRequestMessageRegex`
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 1
|
||||||
|
- name: deltaMinutes
|
||||||
|
type: int
|
||||||
|
description: The number of minutes for which an uploaded FPR artifact is considered to be recent and healthy, if exceeded an error will be thrown
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 5
|
||||||
|
- name: spotCheckMinimum
|
||||||
|
type: int
|
||||||
|
description: The minimum number of issues that must be audited per category in the `Spot Checks of each Category` folder to avoid an error being thrown
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 1
|
||||||
|
- name: fprDownloadEndpoint
|
||||||
|
aliases:
|
||||||
|
- name: fortifyFprDownloadEndpoint
|
||||||
|
type: string
|
||||||
|
description: Fortify SSC endpoint for FPR downloads
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: /download/currentStateFprDownload.html
|
||||||
|
- name: defaultVersioningModel
|
||||||
|
type: string
|
||||||
|
description: The default project versioning model used in case `projectVersion` parameter is empty for creating the version based on the build descriptor version to report results in SSC, can be one of `'major'`, `'major-minor'`, `'semantic'`, `'full'`
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 'major'
|
||||||
|
- name: pythonInstallCommand
|
||||||
|
type: string
|
||||||
|
description: 'Additional install command that can be run when `buildTool: ''pip''`
|
||||||
|
is used which allows further customizing the execution environment of the
|
||||||
|
scan'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: "{{.Pip}} install --user ."
|
||||||
|
- name: reportTemplateId
|
||||||
|
type: int
|
||||||
|
description: Report template ID to be used for generating the Fortify report
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: 18
|
||||||
|
- name: filterSetTitle
|
||||||
|
type: string
|
||||||
|
description: Title of the filter set to use for analysing the results
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: "SAP"
|
||||||
|
- name: pullRequestName
|
||||||
|
type: string
|
||||||
|
description: The name of the pull request branch which will trigger creation of a new version in Fortify SSC based on the master branch version
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
- name: pullRequestMessageRegex
|
||||||
|
type: string
|
||||||
|
description: Regex used to identify the PR-XXX reference within the merge commit message
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: '.*Merge pull request #(\\d+) from.*'
|
||||||
|
- name: buildTool
|
||||||
|
type: string
|
||||||
|
description: Scan type used for the step which can be `'maven'`, `'pip'`
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
default: maven
|
||||||
|
containers:
|
||||||
|
- image: ppiper/fortify
|
||||||
|
workingDir: /home/piper
|
||||||
|
outputs:
|
||||||
|
resources:
|
||||||
|
- name: influx
|
||||||
|
type: influx
|
||||||
|
params:
|
||||||
|
- name: fortify_data
|
||||||
|
fields:
|
||||||
|
- name: projectName
|
||||||
|
- name: projectVersion
|
||||||
|
- name: violations
|
||||||
|
- name: corporateTotal
|
||||||
|
- name: corporateAudited
|
||||||
|
- name: auditAllTotal
|
||||||
|
- name: auditAllAudited
|
||||||
|
- name: spotChecksTotal
|
||||||
|
- name: spotChecksAudited
|
||||||
|
- name: spotChecksGap
|
||||||
|
- name: suspicious
|
||||||
|
- name: exploitable
|
||||||
|
- name: suppressed
|
@ -136,6 +136,7 @@ public class CommonStepsTest extends BasePiperTest{
|
|||||||
'abapEnvironmentRunATCCheck', //implementing new golang pattern without fields
|
'abapEnvironmentRunATCCheck', //implementing new golang pattern without fields
|
||||||
'sonarExecuteScan', //implementing new golang pattern without fields
|
'sonarExecuteScan', //implementing new golang pattern without fields
|
||||||
'gctsCreateRepository', //implementing new golang pattern without fields
|
'gctsCreateRepository', //implementing new golang pattern without fields
|
||||||
|
'fortifyExecuteScan', //implementing new golang pattern without fields
|
||||||
'gctsDeploy', //implementing new golang pattern without fields
|
'gctsDeploy', //implementing new golang pattern without fields
|
||||||
]
|
]
|
||||||
|
|
||||||
|
17
vars/fortifyExecuteScan.groovy
Normal file
17
vars/fortifyExecuteScan.groovy
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import com.sap.piper.DownloadCacheUtils
|
||||||
|
import groovy.transform.Field
|
||||||
|
|
||||||
|
import static com.sap.piper.Prerequisites.checkScript
|
||||||
|
|
||||||
|
@Field String STEP_NAME = getClass().getName()
|
||||||
|
@Field String METADATA_FILE = 'metadata/fortify.yaml'
|
||||||
|
|
||||||
|
//Metadata maintained in file project://resources/metadata/fortify.yaml
|
||||||
|
|
||||||
|
void call(Map parameters = [:]) {
|
||||||
|
final script = checkScript(this, parameters) ?: this
|
||||||
|
parameters = DownloadCacheUtils.injectDownloadCacheInMavenParameters(script, parameters)
|
||||||
|
|
||||||
|
List credentials = [[type: 'token', id: 'fortifyCredentialsId', env: ['PIPER_authToken']]]
|
||||||
|
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
|
||||||
|
}
|
Reference in New Issue
Block a user