mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-02-07 13:42:23 +02:00
136 lines
4.0 KiB
Go
136 lines
4.0 KiB
Go
|
package cmd
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/SAP/jenkins-library/pkg/command"
|
||
|
"github.com/SAP/jenkins-library/pkg/contrast"
|
||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||
|
)
|
||
|
|
||
|
type contrastExecuteScanUtils interface {
|
||
|
command.ExecRunner
|
||
|
piperutils.FileUtils
|
||
|
}
|
||
|
|
||
|
type contrastExecuteScanUtilsBundle struct {
|
||
|
*command.Command
|
||
|
*piperutils.Files
|
||
|
}
|
||
|
|
||
|
func newContrastExecuteScanUtils() contrastExecuteScanUtils {
|
||
|
utils := contrastExecuteScanUtilsBundle{
|
||
|
Command: &command.Command{},
|
||
|
Files: &piperutils.Files{},
|
||
|
}
|
||
|
utils.Stdout(log.Writer())
|
||
|
utils.Stderr(log.Writer())
|
||
|
return &utils
|
||
|
}
|
||
|
|
||
|
func contrastExecuteScan(config contrastExecuteScanOptions, telemetryData *telemetry.CustomData) {
|
||
|
utils := newContrastExecuteScanUtils()
|
||
|
|
||
|
reports, err := runContrastExecuteScan(&config, telemetryData, utils)
|
||
|
piperutils.PersistReportsAndLinks("contrastExecuteScan", "./", utils, reports, nil)
|
||
|
if err != nil {
|
||
|
log.Entry().WithError(err).Fatal("step execution failed")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func validateConfigs(config *contrastExecuteScanOptions) error {
|
||
|
validations := map[string]string{
|
||
|
"server": config.Server,
|
||
|
"organizationId": config.OrganizationID,
|
||
|
"applicationId": config.ApplicationID,
|
||
|
"userApiKey": config.UserAPIKey,
|
||
|
"username": config.Username,
|
||
|
"serviceKey": config.ServiceKey,
|
||
|
}
|
||
|
|
||
|
for k, v := range validations {
|
||
|
if v == "" {
|
||
|
return fmt.Errorf("%s is empty", k)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !strings.HasPrefix(config.Server, "https://") {
|
||
|
config.Server = "https://" + config.Server
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func runContrastExecuteScan(config *contrastExecuteScanOptions, telemetryData *telemetry.CustomData, utils contrastExecuteScanUtils) (reports []piperutils.Path, err error) {
|
||
|
err = validateConfigs(config)
|
||
|
if err != nil {
|
||
|
log.Entry().Errorf("config is invalid: %v", err)
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
auth := getAuth(config)
|
||
|
appAPIUrl, appUIUrl := getApplicationUrls(config)
|
||
|
|
||
|
contrastInstance := contrast.NewContrastInstance(appAPIUrl, config.UserAPIKey, auth)
|
||
|
appInfo, err := contrastInstance.GetAppInfo(appUIUrl, config.Server)
|
||
|
if err != nil {
|
||
|
log.Entry().Errorf("error while getting app info")
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
findings, err := contrastInstance.GetVulnerabilities()
|
||
|
if err != nil {
|
||
|
log.Entry().Errorf("error while getting vulns")
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
contrastAudit := contrast.ContrastAudit{
|
||
|
ToolName: "contrast",
|
||
|
ApplicationUrl: appInfo.Url,
|
||
|
ScanResults: findings,
|
||
|
}
|
||
|
paths, err := contrast.WriteJSONReport(contrastAudit, "./")
|
||
|
if err != nil {
|
||
|
log.Entry().Errorf("error while writing json report")
|
||
|
return nil, err
|
||
|
}
|
||
|
reports = append(reports, paths...)
|
||
|
|
||
|
if config.CheckForCompliance {
|
||
|
for _, results := range findings {
|
||
|
if results.ClassificationName == "Audit All" {
|
||
|
unaudited := results.Total - results.Audited
|
||
|
if unaudited > config.VulnerabilityThresholdTotal {
|
||
|
msg := fmt.Sprintf("Your application %v in organization %v is not compliant. Total unaudited issues are %v which is greater than the VulnerabilityThresholdTotal count %v",
|
||
|
config.ApplicationID, config.OrganizationID, unaudited, config.VulnerabilityThresholdTotal)
|
||
|
return reports, fmt.Errorf(msg)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
toolRecordFileName, err := contrast.CreateAndPersistToolRecord(utils, appInfo, "./")
|
||
|
if err != nil {
|
||
|
log.Entry().Warning("TR_CONTRAST: Failed to create toolrecord file ...", err)
|
||
|
} else {
|
||
|
reports = append(reports, piperutils.Path{Target: toolRecordFileName})
|
||
|
}
|
||
|
|
||
|
return reports, nil
|
||
|
}
|
||
|
|
||
|
func getApplicationUrls(config *contrastExecuteScanOptions) (string, string) {
|
||
|
appURL := fmt.Sprintf("%s/api/v4/organizations/%s/applications/%s", config.Server, config.OrganizationID, config.ApplicationID)
|
||
|
guiURL := fmt.Sprintf("%s/Contrast/static/ng/index.html#/%s/applications/%s", config.Server, config.OrganizationID, config.ApplicationID)
|
||
|
|
||
|
return appURL, guiURL
|
||
|
}
|
||
|
|
||
|
func getAuth(config *contrastExecuteScanOptions) string {
|
||
|
return base64.StdEncoding.EncodeToString([]byte(config.Username + ":" + config.ServiceKey))
|
||
|
}
|