1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-03 15:02:35 +02:00

feat(checkmarxExecuteScan): Improve cx report (#2991)

* Improve checkmarx report

* Fix test and fmt

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
Sven Merk 2021-09-15 09:45:56 +02:00 committed by GitHub
parent d3e2086410
commit 86e8125279
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 128 additions and 50 deletions

View File

@ -304,18 +304,26 @@ func verifyCxProjectCompliance(config checkmarxExecuteScanOptions, sys checkmarx
reports = append(reports, piperutils.Path{Target: toolRecordFileName})
}
scanReport := checkmarx.CreateCustomReport(results)
paths, err := checkmarx.WriteCustomReports(scanReport, fmt.Sprint(results["ProjectName"]), fmt.Sprint(results["ProjectID"]))
reports = append(reports, paths...)
links := []piperutils.Path{{Target: results["DeepLink"].(string), Name: "Checkmarx Web UI"}}
piperutils.PersistReportsAndLinks("checkmarxExecuteScan", utils.GetWorkspace(), reports, links)
reportToInflux(results, influx)
insecure := false
insecureResults := []string{}
neutralResults := []string{}
err = nil
if config.VulnerabilityThresholdEnabled {
insecure = enforceThresholds(config, results)
insecure, insecureResults, neutralResults = enforceThresholds(config, results)
scanReport := checkmarx.CreateCustomReport(results, insecureResults, neutralResults)
paths, err := checkmarx.WriteCustomReports(scanReport, fmt.Sprint(results["ProjectName"]), fmt.Sprint(results["ProjectID"]))
if err != nil {
// do not fail until we have a better idea to handle it
log.Entry().Warning("failed to write HTML/MarkDown report file ...", err)
} else {
reports = append(reports, paths...)
}
}
if insecure {
@ -429,7 +437,9 @@ func downloadAndSaveReport(sys checkmarx.System, reportFileName string, scanID i
return utils.WriteFile(reportFileName, report, 0700)
}
func enforceThresholds(config checkmarxExecuteScanOptions, results map[string]interface{}) bool {
func enforceThresholds(config checkmarxExecuteScanOptions, results map[string]interface{}) (bool, []string, []string) {
neutralResults := []string{}
insecureResults := []string{}
insecure := false
cxHighThreshold := config.VulnerabilityThresholdHigh
cxMediumThreshold := config.VulnerabilityThresholdMedium
@ -494,13 +504,32 @@ func enforceThresholds(config checkmarxExecuteScanOptions, results map[string]in
}
}
highText := fmt.Sprintf("High %v%v %v", highValue, unit, highViolation)
mediumText := fmt.Sprintf("Medium %v%v %v", mediumValue, unit, mediumViolation)
lowText := fmt.Sprintf("Low %v%v %v", lowValue, unit, lowViolation)
if len(highViolation) > 0 {
insecureResults = append(insecureResults, highText)
} else {
neutralResults = append(neutralResults, highText)
}
if len(mediumViolation) > 0 {
insecureResults = append(insecureResults, mediumText)
} else {
neutralResults = append(neutralResults, mediumText)
}
if len(lowViolation) > 0 {
insecureResults = append(insecureResults, lowText)
} else {
neutralResults = append(neutralResults, lowText)
}
log.Entry().Infoln("")
log.Entry().Infof("High %v%v %v", highValue, unit, highViolation)
log.Entry().Infof("Medium %v%v %v", mediumValue, unit, mediumViolation)
log.Entry().Infof("Low %v%v %v", lowValue, unit, lowViolation)
log.Entry().Info(highText)
log.Entry().Info(mediumText)
log.Entry().Info(lowText)
log.Entry().Infoln("")
return insecure
return insecure, insecureResults, neutralResults
}
func createAndConfigureNewProject(sys checkmarx.System, projectName, teamID string, presetIDValue int, presetValue, engineConfiguration string) (checkmarx.Project, error) {

View File

@ -899,72 +899,88 @@ func TestEnforceThresholds(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdHigh: 100, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 1, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 2, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("absolute high violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdHigh: 5, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 3, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 0, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("percentage medium violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdMedium: 100, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 1, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 2, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("absolute medium violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdMedium: 5, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 3, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 0, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("percentage low violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdLow: 100, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 1, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 2, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("absolute low violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdLow: 5, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, true, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 3, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 0, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("percentage no violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "percentage", VulnerabilityThresholdLow: 0, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, false, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 0, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 3, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
t.Run("absolute no violation", func(t *testing.T) {
t.Parallel()
options := checkmarxExecuteScanOptions{VulnerabilityThresholdUnit: "absolute", VulnerabilityThresholdLow: 15, VulnerabilityThresholdMedium: 15, VulnerabilityThresholdHigh: 15, VulnerabilityThresholdEnabled: true}
insecure := enforceThresholds(options, results)
insecure, insecureResults, neutralResults := enforceThresholds(options, results)
assert.Equal(t, false, insecure, "Expected results to be insecure but where not")
assert.Equal(t, 0, len(insecureResults), fmt.Sprintf("Unexpected number of results: %v", insecureResults))
assert.Equal(t, 3, len(neutralResults), fmt.Sprintf("Unexpected number of results: %v", neutralResults))
})
}

View File

@ -14,7 +14,9 @@ import (
"github.com/pkg/errors"
)
func CreateCustomReport(data map[string]interface{}) reporting.ScanReport {
func CreateCustomReport(data map[string]interface{}, insecure, neutral []string) reporting.ScanReport {
deepLink := fmt.Sprintf(`<a href="%v" target="_blank">Link to scan in CX UI</a>`, data["DeepLink"])
scanReport := reporting.ScanReport{
Title: "Checkmarx SAST Report",
Subheaders: []reporting.Subheader{
@ -32,41 +34,72 @@ func CreateCustomReport(data map[string]interface{}) reporting.ScanReport {
{Description: "Lines of code scanned", Details: fmt.Sprint(data["LinesOfCodeScanned)"])},
{Description: "Files scanned", Details: fmt.Sprint(data["FilesScanned)"])},
{Description: "Checkmarx version", Details: fmt.Sprint(data["CheckmarxVersion"])},
{Description: "Deep link", Details: fmt.Sprint(data["DeepLink"])},
},
Overview: []reporting.OverviewRow{
{Description: "High issues", Details: fmt.Sprint(data["High"].(map[string]int)["Issues"])},
{Description: "High not false positive issues", Details: fmt.Sprint(data["High"].(map[string]int)["NotFalsePositive"])},
{Description: "High not exploitable issues", Details: fmt.Sprint(data["High"].(map[string]int)["NotExploitable"])},
{Description: "High confirmed issues", Details: fmt.Sprint(data["High"].(map[string]int)["Confirmed"])},
{Description: "High urgent issues", Details: fmt.Sprint(data["High"].(map[string]int)["Urgent"])},
{Description: "High proposed not exploitable issues", Details: fmt.Sprint(data["High"].(map[string]int)["ProposedNotExploitable"])},
{Description: "High to verify issues", Details: fmt.Sprint(data["High"].(map[string]int)["ToVerify"])},
{Description: "Medium issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Issues"])},
{Description: "Medium not false positive issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["NotFalsePositive"])},
{Description: "Medium not exploitable issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["NotExploitable"])},
{Description: "Medium confirmed issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Confirmed"])},
{Description: "Medium urgent issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Urgent"])},
{Description: "Medium proposed not exploitable issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Medium to verify issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["ToVerify"])},
{Description: "Low issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Issues"])},
{Description: "Low not false positive issues", Details: fmt.Sprint(data["Low"].(map[string]int)["NotFalsePositive"])},
{Description: "Low not exploitable issues", Details: fmt.Sprint(data["Low"].(map[string]int)["NotExploitable"])},
{Description: "Low confirmed issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Confirmed"])},
{Description: "Low urgent issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Urgent"])},
{Description: "Low proposed not exploitable issues", Details: fmt.Sprint(data["Low"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Low to verify issues", Details: fmt.Sprint(data["Low"].(map[string]int)["ToVerify"])},
{Description: "Informational issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Issues"])},
{Description: "Informational not false positive issues", Details: fmt.Sprint(data["Information"].(map[string]int)["NotFalsePositive"])},
{Description: "Informational not exploitable issues", Details: fmt.Sprint(data["Information"].(map[string]int)["NotExploitable"])},
{Description: "Informational confirmed issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Confirmed"])},
{Description: "Informational urgent issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Urgent"])},
{Description: "Informational proposed not exploitable issues", Details: fmt.Sprint(data["Information"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Informational to verify issues", Details: fmt.Sprint(data["Information"].(map[string]int)["ToVerify"])},
{Description: "Deep link", Details: deepLink},
},
Overview: []reporting.OverviewRow{},
ReportTime: time.Now(),
}
for _, issue := range insecure {
row := reporting.OverviewRow{}
row.Description = fmt.Sprint(issue)
row.Style = reporting.Red
scanReport.Overview = append(scanReport.Overview, row)
}
for _, issue := range neutral {
row := reporting.OverviewRow{}
row.Description = fmt.Sprint(issue)
scanReport.Overview = append(scanReport.Overview, row)
}
detailTable := reporting.ScanDetailTable{
Headers: []string{
"KPI",
"Count",
},
WithCounter: false,
}
detailRows := []reporting.OverviewRow{
{Description: "High issues", Details: fmt.Sprint(data["High"].(map[string]int)["Issues"])},
{Description: "High not false positive issues", Details: fmt.Sprint(data["High"].(map[string]int)["NotFalsePositive"])},
{Description: "High not exploitable issues", Details: fmt.Sprint(data["High"].(map[string]int)["NotExploitable"])},
{Description: "High confirmed issues", Details: fmt.Sprint(data["High"].(map[string]int)["Confirmed"])},
{Description: "High urgent issues", Details: fmt.Sprint(data["High"].(map[string]int)["Urgent"])},
{Description: "High proposed not exploitable issues", Details: fmt.Sprint(data["High"].(map[string]int)["ProposedNotExploitable"])},
{Description: "High to verify issues", Details: fmt.Sprint(data["High"].(map[string]int)["ToVerify"])},
{Description: "Medium issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Issues"])},
{Description: "Medium not false positive issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["NotFalsePositive"])},
{Description: "Medium not exploitable issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["NotExploitable"])},
{Description: "Medium confirmed issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Confirmed"])},
{Description: "Medium urgent issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["Urgent"])},
{Description: "Medium proposed not exploitable issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Medium to verify issues", Details: fmt.Sprint(data["Medium"].(map[string]int)["ToVerify"])},
{Description: "Low issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Issues"])},
{Description: "Low not false positive issues", Details: fmt.Sprint(data["Low"].(map[string]int)["NotFalsePositive"])},
{Description: "Low not exploitable issues", Details: fmt.Sprint(data["Low"].(map[string]int)["NotExploitable"])},
{Description: "Low confirmed issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Confirmed"])},
{Description: "Low urgent issues", Details: fmt.Sprint(data["Low"].(map[string]int)["Urgent"])},
{Description: "Low proposed not exploitable issues", Details: fmt.Sprint(data["Low"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Low to verify issues", Details: fmt.Sprint(data["Low"].(map[string]int)["ToVerify"])},
{Description: "Informational issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Issues"])},
{Description: "Informational not false positive issues", Details: fmt.Sprint(data["Information"].(map[string]int)["NotFalsePositive"])},
{Description: "Informational not exploitable issues", Details: fmt.Sprint(data["Information"].(map[string]int)["NotExploitable"])},
{Description: "Informational confirmed issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Confirmed"])},
{Description: "Informational urgent issues", Details: fmt.Sprint(data["Information"].(map[string]int)["Urgent"])},
{Description: "Informational proposed not exploitable issues", Details: fmt.Sprint(data["Information"].(map[string]int)["ProposedNotExploitable"])},
{Description: "Informational to verify issues", Details: fmt.Sprint(data["Information"].(map[string]int)["ToVerify"])},
}
for _, detailRow := range detailRows {
row := reporting.ScanRow{}
row.AddColumn(detailRow.Description, 0)
row.AddColumn(detailRow.Details, 0)
detailTable.Rows = append(detailTable.Rows, row)
}
scanReport.DetailTable = detailTable
return scanReport
}