1
0
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:
Sven Merk
2021-06-15 14:53:42 +02:00
committed by GitHub
parent d1c8abc6b3
commit a43f46465a
5 changed files with 209 additions and 54 deletions

View File

@@ -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) {

View File

@@ -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)