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
|
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)
|
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 {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to analyze unaudited issues"), reports
|
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.projectVersionID = projectVersion.ID
|
||||||
influx.fortify_data.fields.violations = numberOfViolations
|
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)
|
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...)
|
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 {
|
if numberOfViolations > 0 {
|
||||||
log.SetErrorCategory(log.ErrorCompliance)
|
log.SetErrorCategory(log.ErrorCompliance)
|
||||||
return errors.New("fortify scan failed, the project is not compliant. For details check the archived report"), reports
|
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.Exploitable = input.exploitable
|
||||||
output.Suppressed = input.suppressed
|
output.Suppressed = input.suppressed
|
||||||
output.Suspicious = input.suspicious
|
output.Suspicious = input.suspicious
|
||||||
|
output.ProjectVersionID = input.projectVersionID
|
||||||
return output
|
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")
|
log.Entry().Info("Analyzing unaudited issues")
|
||||||
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Folder"}, nil)
|
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Folder"}, nil)
|
||||||
fetchedIssueGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
|
fetchedIssueGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
|
||||||
@ -327,7 +342,7 @@ func analyseUnauditedIssues(config fortifyExecuteScanOptions, sys fortify.System
|
|||||||
}
|
}
|
||||||
overallViolations := 0
|
overallViolations := 0
|
||||||
for _, issueGroup := range fetchedIssueGroups {
|
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 {
|
if err != nil {
|
||||||
return overallViolations, fetchedIssueGroups, errors.Wrap(err, "failed to get issue delta")
|
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
|
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
|
totalMinusAuditedDelta := 0
|
||||||
group := ""
|
group := ""
|
||||||
total := 0
|
total := 0
|
||||||
@ -378,13 +393,13 @@ func getIssueDeltaFor(config fortifyExecuteScanOptions, sys fortify.System, issu
|
|||||||
if err != nil {
|
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)
|
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
|
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
|
overallDelta := 0
|
||||||
overallIssues := 0
|
overallIssues := 0
|
||||||
overallIssuesAudited := 0
|
overallIssuesAudited := 0
|
||||||
@ -418,6 +433,7 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
|
|||||||
overallIssuesAudited += audited
|
overallIssuesAudited += audited
|
||||||
|
|
||||||
auditStatus[group] = fmt.Sprintf("%v total : %v audited %v", total, audited, flagOutput)
|
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
|
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.NoError(t, err)
|
||||||
assert.Equal(t, 13, issues)
|
assert.Equal(t, 13, issues)
|
||||||
assert.Equal(t, 3, len(groups))
|
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, 13, influx.fortify_data.fields.spotChecksTotal)
|
||||||
assert.Equal(t, 11, influx.fortify_data.fields.spotChecksAudited)
|
assert.Equal(t, 11, influx.fortify_data.fields.spotChecksAudited)
|
||||||
assert.Equal(t, 1, influx.fortify_data.fields.spotChecksGap)
|
assert.Equal(t, 1, influx.fortify_data.fields.spotChecksGap)
|
||||||
|
assert.Equal(t, 3, len(spotChecksCountByCategory))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTriggerFortifyScan(t *testing.T) {
|
func TestTriggerFortifyScan(t *testing.T) {
|
||||||
|
@ -1314,3 +1314,36 @@ func TestBase64EndodePlainToken(t *testing.T) {
|
|||||||
assert.Equal(t, "OTUzODcwNDYtNWFjOC00NTcwLTg3NWQtYTVlYzhiZDhkM2Qy", encodedToken)
|
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 (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -16,19 +18,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type FortifyReportData struct {
|
type FortifyReportData struct {
|
||||||
ProjectName string
|
ToolName string `json:"toolName"`
|
||||||
ProjectVersion string
|
ToolInstance string `json:"toolInstance"`
|
||||||
Violations int
|
ProjectName string `json:"projectName"`
|
||||||
CorporateTotal int
|
ProjectVersion string `json:"projectVersion"`
|
||||||
CorporateAudited int
|
ProjectVersionID int64 `json:"projectVersionID"`
|
||||||
AuditAllTotal int
|
Violations int `json:"violations"`
|
||||||
AuditAllAudited int
|
CorporateTotal int `json:"corporateTotal"`
|
||||||
SpotChecksTotal int
|
CorporateAudited int `json:"corporateAudited"`
|
||||||
SpotChecksAudited int
|
AuditAllTotal int `json:"auditAllTotal"`
|
||||||
SpotChecksGap int
|
AuditAllAudited int `json:"auditAllAudited"`
|
||||||
Suspicious int
|
SpotChecksTotal int `json:"spotChecksTotal"`
|
||||||
Exploitable int
|
SpotChecksAudited int `json:"spotChecksAudited"`
|
||||||
Suppressed int
|
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 {
|
func CreateCustomReport(data FortifyReportData, issueGroups []*models.ProjectVersionIssueGroup) reporting.ScanReport {
|
||||||
@ -77,7 +91,45 @@ func CreateCustomReport(data FortifyReportData, issueGroups []*models.ProjectVer
|
|||||||
return scanReport
|
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{}
|
utils := piperutils.Files{}
|
||||||
reportPaths := []piperutils.Path{}
|
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,
|
// 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
|
// since it is just an intermediary report used as input for later
|
||||||
// and there does not seem to be real benefit in archiving it.
|
// and there does not seem to be real benefit in archiving it.
|
||||||
|
|
||||||
return reportPaths, nil
|
return reportPaths, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user