mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
Fortify JSON Report (#3212)
Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
This commit is contained in:
parent
88bd8f1303
commit
732845507d
@ -275,7 +275,9 @@ func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.Sys
|
||||
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, issueGroups, err := analyseUnauditedIssues(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
|
||||
spotChecksCountByCategory := []fortify.SpotChecksAuditCount{}
|
||||
numberOfViolations, issueGroups, err := analyseUnauditedIssues(config, sys, projectVersion, filterSet, issueFilterSelectorSet, influx, auditStatus, &spotChecksCountByCategory)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to analyze unaudited issues"), reports
|
||||
}
|
||||
@ -290,9 +292,21 @@ func verifyFFProjectCompliance(config fortifyExecuteScanOptions, sys fortify.Sys
|
||||
influx.fortify_data.fields.projectVersionID = projectVersion.ID
|
||||
influx.fortify_data.fields.violations = numberOfViolations
|
||||
|
||||
scanReport := fortify.CreateCustomReport(prepareReportData(influx), issueGroups)
|
||||
fortifyReportingData := prepareReportData(influx)
|
||||
scanReport := fortify.CreateCustomReport(fortifyReportingData, issueGroups)
|
||||
paths, err := fortify.WriteCustomReports(scanReport, influx.fortify_data.fields.projectName, influx.fortify_data.fields.projectVersion)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write custom reports"), reports
|
||||
}
|
||||
reports = append(reports, paths...)
|
||||
|
||||
jsonReport := fortify.CreateJSONReport(fortifyReportingData, spotChecksCountByCategory, config.ServerURL)
|
||||
paths, err = fortify.WriteJSONReport(jsonReport)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write json report"), reports
|
||||
}
|
||||
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"), reports
|
||||
@ -315,10 +329,11 @@ func prepareReportData(influx *fortifyExecuteScanInflux) fortify.FortifyReportDa
|
||||
output.Exploitable = input.exploitable
|
||||
output.Suppressed = input.suppressed
|
||||
output.Suspicious = input.suspicious
|
||||
output.ProjectVersionID = input.projectVersionID
|
||||
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) {
|
||||
func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System, projectVersion *models.ProjectVersion, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string, spotChecksCountByCategory *[]fortify.SpotChecksAuditCount) (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)
|
||||
@ -327,7 +342,7 @@ func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System
|
||||
}
|
||||
overallViolations := 0
|
||||
for _, issueGroup := range fetchedIssueGroups {
|
||||
issueDelta, err := getIssueDeltaFor(config, sys, issueGroup, projectVersion.ID, filterSet, issueFilterSelectorSet, influx, auditStatus)
|
||||
issueDelta, err := getIssueDeltaFor(config, sys, issueGroup, projectVersion.ID, filterSet, issueFilterSelectorSet, influx, auditStatus, spotChecksCountByCategory)
|
||||
if err != nil {
|
||||
return overallViolations, fetchedIssueGroups, errors.Wrap(err, "failed to get issue delta")
|
||||
}
|
||||
@ -336,7 +351,7 @@ func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System
|
||||
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) {
|
||||
func getIssueDeltaFor(config fortifyExecuteScanOptions, sys fortify.System, issueGroup *models.ProjectVersionIssueGroup, projectVersionID int64, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string, spotChecksCountByCategory *[]fortify.SpotChecksAuditCount) (int, error) {
|
||||
totalMinusAuditedDelta := 0
|
||||
group := ""
|
||||
total := 0
|
||||
@ -378,13 +393,13 @@ func getIssueDeltaFor(config fortifyExecuteScanOptions, sys fortify.System, issu
|
||||
if err != nil {
|
||||
return totalMinusAuditedDelta, errors.Wrapf(err, "failed to fetch project version issue groups with filter %v, filter set %v and selector %v for project version ID %v", filter, filterSet, issueFilterSelectorSet, projectVersionID)
|
||||
}
|
||||
totalMinusAuditedDelta += getSpotIssueCount(config, sys, fetchedIssueGroups, projectVersionID, filterSet, reducedFilterSelectorSet, influx, auditStatus)
|
||||
totalMinusAuditedDelta += getSpotIssueCount(config, sys, fetchedIssueGroups, projectVersionID, filterSet, reducedFilterSelectorSet, influx, auditStatus, spotChecksCountByCategory)
|
||||
}
|
||||
}
|
||||
return totalMinusAuditedDelta, nil
|
||||
}
|
||||
|
||||
func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spotCheckCategories []*models.ProjectVersionIssueGroup, projectVersionID int64, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string) int {
|
||||
func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spotCheckCategories []*models.ProjectVersionIssueGroup, projectVersionID int64, filterSet *models.FilterSet, issueFilterSelectorSet *models.IssueFilterSelectorSet, influx *fortifyExecuteScanInflux, auditStatus map[string]string, spotChecksCountByCategory *[]fortify.SpotChecksAuditCount) int {
|
||||
overallDelta := 0
|
||||
overallIssues := 0
|
||||
overallIssuesAudited := 0
|
||||
@ -418,6 +433,7 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
|
||||
overallIssuesAudited += audited
|
||||
|
||||
auditStatus[group] = fmt.Sprintf("%v total : %v audited %v", total, audited, flagOutput)
|
||||
*spotChecksCountByCategory = append(*spotChecksCountByCategory, fortify.SpotChecksAuditCount{Audited: audited, Total: total, Type: group})
|
||||
}
|
||||
|
||||
influx.fortify_data.fields.spotChecksTotal = overallIssues
|
||||
|
@ -491,7 +491,9 @@ func TestAnalyseUnauditedIssues(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
issues, groups, err := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus)
|
||||
|
||||
spotChecksCountByCategory := []fortify.SpotChecksAuditCount{}
|
||||
issues, groups, err := analyseUnauditedIssues(config, &ff, &projectVersion, &models.FilterSet{}, &selectorSet, &influx, auditStatus, &spotChecksCountByCategory)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 13, issues)
|
||||
assert.Equal(t, 3, len(groups))
|
||||
@ -503,6 +505,7 @@ func TestAnalyseUnauditedIssues(t *testing.T) {
|
||||
assert.Equal(t, 13, influx.fortify_data.fields.spotChecksTotal)
|
||||
assert.Equal(t, 11, influx.fortify_data.fields.spotChecksAudited)
|
||||
assert.Equal(t, 1, influx.fortify_data.fields.spotChecksGap)
|
||||
assert.Equal(t, 3, len(spotChecksCountByCategory))
|
||||
}
|
||||
|
||||
func TestTriggerFortifyScan(t *testing.T) {
|
||||
|
@ -1314,3 +1314,36 @@ func TestBase64EndodePlainToken(t *testing.T) {
|
||||
assert.Equal(t, "OTUzODcwNDYtNWFjOC00NTcwLTg3NWQtYTVlYzhiZDhkM2Qy", encodedToken)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateJSONReport(t *testing.T) {
|
||||
t.Run("test success", func(t *testing.T) {
|
||||
spotChecksCountByCategory := []SpotChecksAuditCount{}
|
||||
spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 3, Total: 3, Type: "J2EE Misconfiguration: Missing Error Handling"})
|
||||
spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 1, Total: 3, Type: "J2EE Bad Practices: Leftover Debug Code"})
|
||||
fortifyReportData := FortifyReportData{CorporateAudited: 30, CorporateTotal: 30, AuditAllTotal: 1, AuditAllAudited: 1, ProjectVersionID: 4999}
|
||||
jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
|
||||
assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
|
||||
assert.Equal(t, 1, jsonReport.AuditAllAudited)
|
||||
assert.Equal(t, 1, jsonReport.AuditAllTotal)
|
||||
assert.Equal(t, 30, jsonReport.CorporateAudited)
|
||||
assert.Equal(t, 30, jsonReport.CorporateTotal)
|
||||
assert.Equal(t, "https://fortify-test.com/ssc/html/ssc/version/4999", jsonReport.URL)
|
||||
assert.Equal(t, "https://fortify-test.com/ssc", jsonReport.ToolInstance)
|
||||
})
|
||||
|
||||
t.Run("atleast one category spotchecks failed", func(t *testing.T) {
|
||||
spotChecksCountByCategory := []SpotChecksAuditCount{}
|
||||
spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 3, Total: 3, Type: "J2EE Misconfiguration: Missing Error Handling"})
|
||||
spotChecksCountByCategory = append(spotChecksCountByCategory, SpotChecksAuditCount{Audited: 0, Total: 1, Type: "J2EE Bad Practices: Leftover Debug Code"})
|
||||
fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
|
||||
jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
|
||||
assert.Equal(t, false, jsonReport.AtleastOneSpotChecksCategoryAudited)
|
||||
})
|
||||
|
||||
t.Run("no spot checks audited", func(t *testing.T) {
|
||||
spotChecksCountByCategory := []SpotChecksAuditCount{}
|
||||
fortifyReportData := FortifyReportData{CorporateAudited: 0, CorporateTotal: 0, AuditAllTotal: 0, AuditAllAudited: 0}
|
||||
jsonReport := CreateJSONReport(fortifyReportData, spotChecksCountByCategory, "https://fortify-test.com/ssc")
|
||||
assert.Equal(t, true, jsonReport.AtleastOneSpotChecksCategoryAudited)
|
||||
})
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package fortify
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -16,19 +18,31 @@ import (
|
||||
)
|
||||
|
||||
type FortifyReportData struct {
|
||||
ProjectName string
|
||||
ProjectVersion string
|
||||
Violations int
|
||||
CorporateTotal int
|
||||
CorporateAudited int
|
||||
AuditAllTotal int
|
||||
AuditAllAudited int
|
||||
SpotChecksTotal int
|
||||
SpotChecksAudited int
|
||||
SpotChecksGap int
|
||||
Suspicious int
|
||||
Exploitable int
|
||||
Suppressed int
|
||||
ToolName string `json:"toolName"`
|
||||
ToolInstance string `json:"toolInstance"`
|
||||
ProjectName string `json:"projectName"`
|
||||
ProjectVersion string `json:"projectVersion"`
|
||||
ProjectVersionID int64 `json:"projectVersionID"`
|
||||
Violations int `json:"violations"`
|
||||
CorporateTotal int `json:"corporateTotal"`
|
||||
CorporateAudited int `json:"corporateAudited"`
|
||||
AuditAllTotal int `json:"auditAllTotal"`
|
||||
AuditAllAudited int `json:"auditAllAudited"`
|
||||
SpotChecksTotal int `json:"spotChecksTotal"`
|
||||
SpotChecksAudited int `json:"spotChecksAudited"`
|
||||
SpotChecksGap int `json:"spotChecksGap"`
|
||||
Suspicious int `json:"suspicious"`
|
||||
Exploitable int `json:"exploitable"`
|
||||
Suppressed int `json:"suppressed"`
|
||||
AtleastOneSpotChecksCategoryAudited bool `json:"atleastOneSpotChecksCategoryAudited"`
|
||||
URL string `json:"url"`
|
||||
SpotChecksCategories *[]SpotChecksAuditCount `json:"spotChecksCategories"`
|
||||
}
|
||||
|
||||
type SpotChecksAuditCount struct {
|
||||
Audited int `json:"spotChecksCategories"`
|
||||
Total int `json:"total"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func CreateCustomReport(data FortifyReportData, issueGroups []*models.ProjectVersionIssueGroup) reporting.ScanReport {
|
||||
@ -77,7 +91,45 @@ func CreateCustomReport(data FortifyReportData, issueGroups []*models.ProjectVer
|
||||
return scanReport
|
||||
}
|
||||
|
||||
func WriteCustomReports(scanReport reporting.ScanReport, projectName, projectVersion string) ([]piperutils.Path, error) {
|
||||
func CreateJSONReport(reportData FortifyReportData, spotChecksCountByCategory []SpotChecksAuditCount, serverURL string) FortifyReportData {
|
||||
reportData.AtleastOneSpotChecksCategoryAudited = true
|
||||
for _, spotChecksElement := range spotChecksCountByCategory {
|
||||
if spotChecksElement.Total > 0 && spotChecksElement.Audited == 0 {
|
||||
reportData.AtleastOneSpotChecksCategoryAudited = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
reportData.SpotChecksCategories = &spotChecksCountByCategory
|
||||
reportData.URL = serverURL + "/html/ssc/version/" + strconv.FormatInt(reportData.ProjectVersionID, 10)
|
||||
reportData.ToolInstance = serverURL
|
||||
reportData.ToolName = "fortify"
|
||||
|
||||
return reportData
|
||||
}
|
||||
|
||||
func WriteJSONReport(jsonReport FortifyReportData) ([]piperutils.Path, error) {
|
||||
utils := piperutils.Files{}
|
||||
reportPaths := []piperutils.Path{}
|
||||
|
||||
// Standard JSON Report
|
||||
jsonComplianceReportPath := filepath.Join(ReportsDirectory, "piper_fortify_report.json")
|
||||
// Ensure reporting directory exists
|
||||
if err := utils.MkdirAll(ReportsDirectory, 0777); err != nil {
|
||||
return reportPaths, errors.Wrapf(err, "failed to create report directory")
|
||||
}
|
||||
|
||||
file, _ := json.Marshal(jsonReport)
|
||||
if err := utils.FileWrite(jsonComplianceReportPath, file, 0666); err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return reportPaths, errors.Wrapf(err, "failed to write fortify json compliance report")
|
||||
}
|
||||
reportPaths = append(reportPaths, piperutils.Path{Name: "Fortify JSON Compliance Report", Target: jsonComplianceReportPath})
|
||||
|
||||
return reportPaths, nil
|
||||
}
|
||||
|
||||
func WriteCustomReports(scanReport reporting.ScanReport, projectName string, projectVersion string) ([]piperutils.Path, error) {
|
||||
utils := piperutils.Files{}
|
||||
reportPaths := []piperutils.Path{}
|
||||
|
||||
@ -109,7 +161,6 @@ func WriteCustomReports(scanReport reporting.ScanReport, projectName, projectVer
|
||||
// we do not add the json report to the overall list of reports for now,
|
||||
// since it is just an intermediary report used as input for later
|
||||
// and there does not seem to be real benefit in archiving it.
|
||||
|
||||
return reportPaths, nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user