You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-11-06 09:09:19 +02:00
feat(fortifyExecuteScan): HTML report for Fortify (#2879)
* Tune test * Fix report implementation * Fix tests * Fix values * Fix code and test * Report writing fix * Commit generated sources * Update cmd/fortifyExecuteScan.go Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> * Externalize report generation * Fix fmt * Fix fmt 2 Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
This commit is contained in:
@@ -174,7 +174,9 @@ func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, utils
|
||||
|
||||
if config.VerifyOnly {
|
||||
log.Entry().Infof("Starting audit status check on project %v with version %v and project version ID %v", fortifyProjectName, fortifyProjectVersion, projectVersion.ID)
|
||||
return reports, verifyFFProjectCompliance(config, sys, project, projectVersion, filterSet, influx, auditStatus)
|
||||
err, paths := verifyFFProjectCompliance(config, sys, project, projectVersion, filterSet, influx, auditStatus)
|
||||
reports = append(reports, paths...)
|
||||
return reports, err
|
||||
}
|
||||
|
||||
log.Entry().Infof("Scanning and uploading to project %v with version %v and projectVersionId %v", fortifyProjectName, fortifyProjectVersion, projectVersion.ID)
|
||||
@@ -196,10 +198,12 @@ func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, utils
|
||||
}
|
||||
}
|
||||
|
||||
triggerFortifyScan(config, utils, buildID, buildLabel, fortifyProjectName)
|
||||
|
||||
err = triggerFortifyScan(config, utils, buildID, buildLabel, fortifyProjectName)
|
||||
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)})
|
||||
if err != nil {
|
||||
return reports, errors.Wrapf(err, "failed to scan project")
|
||||
}
|
||||
|
||||
var message string
|
||||
if config.UploadResults {
|
||||
@@ -228,7 +232,9 @@ func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, utils
|
||||
return reports, err
|
||||
}
|
||||
|
||||
return reports, verifyFFProjectCompliance(config, sys, project, projectVersion, filterSet, influx, auditStatus)
|
||||
err, paths := verifyFFProjectCompliance(config, sys, project, projectVersion, filterSet, influx, auditStatus)
|
||||
reports = append(reports, paths...)
|
||||
return reports, err
|
||||
}
|
||||
|
||||
func classifyErrorOnLookup(err error) {
|
||||
@@ -237,7 +243,8 @@ func classifyErrorOnLookup(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.System, project *models.Project, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) error {
|
||||
func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.System, project *models.Project, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) (error, []piperutils.Path) {
|
||||
reports := []piperutils.Path{}
|
||||
// Generate report
|
||||
if config.Reporting {
|
||||
resultURL := []byte(fmt.Sprintf("https://fortify.tools.sap/ssc/html/ssc/version/%v/fix/null/", projectVersion.ID))
|
||||
@@ -245,7 +252,7 @@ func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.Sys
|
||||
|
||||
data, err := generateAndDownloadQGateReport(config, sys, project, projectVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return err, reports
|
||||
}
|
||||
ioutil.WriteFile(fmt.Sprintf("%vtarget/%v-%v.%v", config.ModulePath, *project.Name, *projectVersion.Name, config.ReportType), data, 0700)
|
||||
}
|
||||
@@ -253,43 +260,67 @@ func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.Sys
|
||||
// Perform audit compliance checks
|
||||
issueFilterSelectorSet, err := sys.GetIssueFilterSelectorOfProjectVersionByName(projectVersion.ID, []string{"Analysis", "Folder", "Category"}, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to fetch project version issue filter selector for project version ID %v", projectVersion.ID)
|
||||
return errors.Wrapf(err, "failed to fetch project version issue filter selector for project version ID %v", projectVersion.ID), reports
|
||||
}
|
||||
log.Entry().Debugf("initial filter selector set: %v", issueFilterSelectorSet)
|
||||
numberOfViolations, err := analyseUnauditedIssues(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
numberOfViolations, issueGroups, err := analyseUnauditedIssues(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to analyze unaudited issues")
|
||||
return errors.Wrap(err, "failed to analyze unaudited issues"), reports
|
||||
}
|
||||
numberOfViolations += analyseSuspiciousExploitable(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
numberOfSuspiciousExplotable, issueGroupsSuspiciousExploitable := analyseSuspiciousExploitable(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
numberOfViolations += numberOfSuspiciousExplotable
|
||||
issueGroups = append(issueGroups, issueGroupsSuspiciousExploitable...)
|
||||
|
||||
log.Entry().Infof("Counted %v violations, details: %v", numberOfViolations, auditStatus)
|
||||
|
||||
influx.fortify_data.fields.projectName = *project.Name
|
||||
influx.fortify_data.fields.projectVersion = *projectVersion.Name
|
||||
influx.fortify_data.fields.violations = numberOfViolations
|
||||
|
||||
scanReport := fortify.CreateCustomReport(prepareReportData(influx), issueGroups)
|
||||
paths, err := fortify.WriteCustomReports(scanReport, influx.fortify_data.fields.projectName, influx.fortify_data.fields.projectVersion)
|
||||
reports = append(reports, paths...)
|
||||
if numberOfViolations > 0 {
|
||||
log.SetErrorCategory(log.ErrorCompliance)
|
||||
return errors.New("fortify scan failed, the project is not compliant. For details check the archived report")
|
||||
return errors.New("fortify scan failed, the project is not compliant. For details check the archived report"), reports
|
||||
}
|
||||
return nil
|
||||
return nil, reports
|
||||
}
|
||||
|
||||
func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) (int, error) {
|
||||
func prepareReportData(influx *fortifyExecuteScanInflux) fortify.FortifyReportData {
|
||||
input := influx.fortify_data.fields
|
||||
output := fortify.FortifyReportData{}
|
||||
output.ProjectName = input.projectName
|
||||
output.ProjectVersion = input.projectVersion
|
||||
output.AuditAllAudited = input.auditAllAudited
|
||||
output.AuditAllTotal = input.auditAllTotal
|
||||
output.CorporateAudited = input.corporateAudited
|
||||
output.CorporateTotal = input.corporateTotal
|
||||
output.SpotChecksAudited = input.spotChecksAudited
|
||||
output.SpotChecksGap = input.spotChecksGap
|
||||
output.SpotChecksTotal = input.spotChecksTotal
|
||||
output.Exploitable = input.exploitable
|
||||
output.Suppressed = input.suppressed
|
||||
output.Suspicious = input.suspicious
|
||||
return output
|
||||
}
|
||||
|
||||
func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) (int, []*models.ProjectVersionIssueGroup, error) {
|
||||
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 {
|
||||
return 0, errors.Wrapf(err, "failed to fetch project version issue groups with filter set %v and selector %v for project version ID %v", filterSet, issueFilterSelectorSet, projectVersion.ID)
|
||||
return 0, fetchedIssueGroups, errors.Wrapf(err, "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 {
|
||||
issueDelta, err := getIssueDeltaFor(config, sys, issueGroup, projectVersion.ID, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
if err != nil {
|
||||
return overallViolations, errors.Wrap(err, "failed to get issue delata")
|
||||
return overallViolations, fetchedIssueGroups, errors.Wrap(err, "failed to get issue delta")
|
||||
}
|
||||
overallViolations += issueDelta
|
||||
}
|
||||
return overallViolations, nil
|
||||
return overallViolations, fetchedIssueGroups, nil
|
||||
}
|
||||
|
||||
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, error) {
|
||||
@@ -383,7 +414,7 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
|
||||
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 {
|
||||
func analyseSuspiciousExploitable(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) (int, []*models.ProjectVersionIssueGroup) {
|
||||
log.Entry().Info("Analyzing suspicious and exploitable issues")
|
||||
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Analysis"}, []string{})
|
||||
fetchedGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
|
||||
@@ -418,7 +449,7 @@ func analyseSuspiciousExploitable(config fortifyExecuteScanOptions, sys fortify.
|
||||
influx.fortify_data.fields.exploitable = exploitableCount
|
||||
influx.fortify_data.fields.suppressed = int(suppressedCount)
|
||||
|
||||
return result
|
||||
return result, fetchedGroups
|
||||
}
|
||||
|
||||
func logIssueURL(config fortifyExecuteScanOptions, projectVersionID int64, folderSelector, analysisSelector *models.IssueFilterSelector) {
|
||||
|
||||
@@ -217,6 +217,8 @@ func (f *fortifyMock) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64
|
||||
}, nil
|
||||
}
|
||||
if issueFilterSelectorSet != nil && issueFilterSelectorSet.FilterBySet != nil && len(issueFilterSelectorSet.FilterBySet) > 0 && issueFilterSelectorSet.FilterBySet[0].GUID == "3" {
|
||||
groupName := "Suspicious"
|
||||
groupName2 := "Exploitable"
|
||||
group := "3"
|
||||
total := int32(4)
|
||||
audited := int32(0)
|
||||
@@ -224,8 +226,8 @@ func (f *fortifyMock) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64
|
||||
total2 := int32(5)
|
||||
audited2 := int32(0)
|
||||
return []*models.ProjectVersionIssueGroup{
|
||||
{ID: &group, TotalCount: &total, AuditedCount: &audited},
|
||||
{ID: &group2, TotalCount: &total2, AuditedCount: &audited2},
|
||||
{ID: &group, CleanName: &groupName, TotalCount: &total, AuditedCount: &audited},
|
||||
{ID: &group2, CleanName: &groupName2, TotalCount: &total2, AuditedCount: &audited2},
|
||||
}, nil
|
||||
}
|
||||
group := "Audit All"
|
||||
@@ -238,9 +240,9 @@ func (f *fortifyMock) GetProjectIssuesByIDAndFilterSetGroupedBySelector(id int64
|
||||
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},
|
||||
{ID: &group, CleanName: &group, TotalCount: &total, AuditedCount: &audited},
|
||||
{ID: &group2, CleanName: &group2, TotalCount: &total2, AuditedCount: &audited2},
|
||||
{ID: &group3, CleanName: &group3, TotalCount: &total3, AuditedCount: &audited3},
|
||||
}, nil
|
||||
}
|
||||
func (f *fortifyMock) ReduceIssueFilterSelectorSet(issueFilterSelectorSet *models.IssueFilterSelectorSet, names []string, options []string) *models.IssueFilterSelectorSet {
|
||||
@@ -432,8 +434,9 @@ func TestAnalyseSuspiciousExploitable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
issues := analyseSuspiciousExploitable(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||
issues, groups := analyseSuspiciousExploitable(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||
assert.Equal(t, 9, issues)
|
||||
assert.Equal(t, 2, len(groups))
|
||||
|
||||
assert.Equal(t, 4, influx.fortify_data.fields.suspicious)
|
||||
assert.Equal(t, 5, influx.fortify_data.fields.exploitable)
|
||||
@@ -481,9 +484,10 @@ func TestAnalyseUnauditedIssues(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
issues, err := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||
issues, groups, err := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 13, issues)
|
||||
assert.Equal(t, 3, len(groups))
|
||||
|
||||
assert.Equal(t, 15, influx.fortify_data.fields.auditAllTotal)
|
||||
assert.Equal(t, 12, influx.fortify_data.fields.auditAllAudited)
|
||||
|
||||
Reference in New Issue
Block a user