Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(contrastExecuteScan): added new step contrastExecuteScan #4818

Merged
merged 27 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a0973bc
added new step contrastExecuteScan
daskuznetsova Feb 5, 2024
33435ac
fixed checking vulnerabilities statuses
daskuznetsova Feb 6, 2024
107bddb
updated step description
daskuznetsova Feb 6, 2024
8e93663
Merge branch 'master' into contrast-step
daskuznetsova Feb 6, 2024
0cb07c8
fixed tests
daskuznetsova Feb 6, 2024
2ece666
added resources to metadata
daskuznetsova Feb 6, 2024
617e174
added outputs to metadata
daskuznetsova Feb 6, 2024
23775cf
added contrastExecuteStep to CommonStepsTest
daskuznetsova Feb 7, 2024
ebdd93c
fixed vault secret resource name
daskuznetsova Feb 7, 2024
e26ad2c
updated docs
daskuznetsova Feb 9, 2024
4ea3b2c
Merge branch 'master' into contrast-step
daskuznetsova Feb 13, 2024
da0d8c1
removed log for debug, added tests
daskuznetsova Feb 13, 2024
302000b
Contrast Mandatory params
sumeetpatil Feb 19, 2024
f9f86b7
Remove null checks as being considered in mandatory params
sumeetpatil Feb 19, 2024
758e689
Merge branch 'master' into contrast-step
sumeetpatil Feb 27, 2024
1fbda8f
added back contrast validate configs
sumeetpatil Feb 28, 2024
b0843ab
fix mandatory params
sumeetpatil Feb 28, 2024
1f32751
fix mandatory params
sumeetpatil Feb 28, 2024
226bac5
go generate
sumeetpatil Feb 28, 2024
f51e6a6
timeout for client
sumeetpatil Feb 28, 2024
8b19896
debug log
sumeetpatil Feb 28, 2024
7c53468
bug fix in request
sumeetpatil Feb 28, 2024
01438f4
Merge branch 'SAP:master' into contrast-step
daskuznetsova Mar 4, 2024
1ae41fa
Merge branch 'master' into contrast-step
daskuznetsova Mar 5, 2024
d0875df
fixed params with keys
daskuznetsova Mar 5, 2024
566f54d
Merge branch 'master' into contrast-step
sumeetpatil Mar 11, 2024
6beb914
Merge branch 'master' into contrast-step
daskuznetsova Mar 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions cmd/contrastExecuteScan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
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))
}
Loading
Loading