1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

feat(fortifyExecuteScan): new spotcheck flags (#3923)

This commit is contained in:
sumeet patil 2022-08-01 23:06:05 +02:00 committed by GitHub
parent 2f1f4b18ac
commit c8f069efb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 6 deletions

View File

@ -386,6 +386,11 @@ func prepareReportData(influx *fortifyExecuteScanInflux) fortify.FortifyReportDa
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")
if config.SpotCheckMinimumUnit != "percentage" && config.SpotCheckMinimumUnit != "number" {
return 0, nil, fmt.Errorf("Invalid spotCheckMinimumUnit. Please set it as 'percentage' or 'number'.")
}
reducedFilterSelectorSet := sys.ReduceIssueFilterSelectorSet(issueFilterSelectorSet, []string{"Folder"}, nil)
fetchedIssueGroups, err := sys.GetProjectIssuesByIDAndFilterSetGroupedBySelector(projectVersion.ID, "", filterSet.GUID, reducedFilterSelectorSet)
if err != nil {
@ -454,6 +459,7 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
overallDelta := 0
overallIssues := 0
overallIssuesAudited := 0
for _, issueGroup := range spotCheckCategories {
group := ""
total := 0
@ -465,9 +471,12 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
}
flagOutput := ""
if ((total <= config.SpotCheckMinimum || config.SpotCheckMinimum < 0) && audited != total) || (total > config.SpotCheckMinimum && audited < config.SpotCheckMinimum) {
currentDelta := config.SpotCheckMinimum - audited
if config.SpotCheckMinimum < 0 || config.SpotCheckMinimum > total {
minSpotChecksPerCategory := getMinSpotChecksPerCategory(config, total)
log.Entry().Debugf("Minimum spot checks for group %v is %v with audit count %v and total issue count %v", group, minSpotChecksPerCategory, audited, total)
if ((total <= minSpotChecksPerCategory || minSpotChecksPerCategory < 0) && audited != total) || (total > minSpotChecksPerCategory && audited < minSpotChecksPerCategory) {
currentDelta := minSpotChecksPerCategory - audited
if minSpotChecksPerCategory < 0 || minSpotChecksPerCategory > total {
currentDelta = total - audited
}
if currentDelta > 0 {
@ -494,6 +503,30 @@ func getSpotIssueCount(config fortifyExecuteScanOptions, sys fortify.System, spo
return overallDelta
}
func getMinSpotChecksPerCategory(config fortifyExecuteScanOptions, totalCount int) int {
if config.SpotCheckMinimumUnit == "percentage" {
spotCheckMinimumPercentageValue := int(math.Round(float64(config.SpotCheckMinimum) / 100.0 * float64(totalCount)))
if spotCheckMinimumPercentageValue == 0 {
return 1
}
return getSpotChecksMinAsPerMaximum(config.SpotCheckMaximum, spotCheckMinimumPercentageValue)
}
return getSpotChecksMinAsPerMaximum(config.SpotCheckMaximum, config.SpotCheckMinimum)
}
func getSpotChecksMinAsPerMaximum(spotCheckMax int, spotCheckMin int) int {
if spotCheckMax == 0 {
return spotCheckMin
}
if spotCheckMin > spotCheckMax {
return spotCheckMax
}
return spotCheckMin
}
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{})

View File

@ -65,6 +65,8 @@ type fortifyExecuteScanOptions struct {
PullRequestMessageRegexGroup int `json:"pullRequestMessageRegexGroup,omitempty"`
DeltaMinutes int `json:"deltaMinutes,omitempty"`
SpotCheckMinimum int `json:"spotCheckMinimum,omitempty"`
SpotCheckMinimumUnit string `json:"spotCheckMinimumUnit,omitempty" validate:"possible-values=number percentage"`
SpotCheckMaximum int `json:"SpotCheckMaximum,omitempty"`
FprDownloadEndpoint string `json:"fprDownloadEndpoint,omitempty"`
VersioningModel string `json:"versioningModel,omitempty" validate:"possible-values=major major-minor semantic full"`
PythonInstallCommand string `json:"pythonInstallCommand,omitempty"`
@ -343,7 +345,9 @@ func addFortifyExecuteScanFlags(cmd *cobra.Command, stepConfig *fortifyExecuteSc
cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", os.Getenv("PIPER_serverUrl"), "Fortify SSC Url to be used for accessing the APIs")
cmd.Flags().IntVar(&stepConfig.PullRequestMessageRegexGroup, "pullRequestMessageRegexGroup", 1, "The group number for extracting the pull request id in `'pullRequestMessageRegex'`")
cmd.Flags().IntVar(&stepConfig.DeltaMinutes, "deltaMinutes", 5, "The number of minutes for which an uploaded FPR artifact is considered to be recent and healthy, if exceeded an error will be thrown")
cmd.Flags().IntVar(&stepConfig.SpotCheckMinimum, "spotCheckMinimum", 1, "The minimum number of issues that must be audited per category in the `Spot Checks of each Category` folder to avoid an error being thrown")
cmd.Flags().IntVar(&stepConfig.SpotCheckMinimum, "spotCheckMinimum", 1, "The minimum number/percentage of issues that must be audited per category in the `Spot Checks of each Category` folder to avoid an error being thrown")
cmd.Flags().StringVar(&stepConfig.SpotCheckMinimumUnit, "spotCheckMinimumUnit", `number`, "The unit for the spotCheckMinimum to apply.")
cmd.Flags().IntVar(&stepConfig.SpotCheckMaximum, "SpotCheckMaximum", 0, "The maximum number of issues that must be audited per category in the `Spot Checks of each Category` folder to avoid an error being thrown. Note that this flag depends on the result of spotCheckMinimum. For example if spotCheckMinimum percentage value exceeds spotCheckMaximum then spotCheckMaximum will be considerd else spotCheckMinimum is considered. If zero, this flag will be ignored.")
cmd.Flags().StringVar(&stepConfig.FprDownloadEndpoint, "fprDownloadEndpoint", `/download/currentStateFprDownload.html`, "Fortify SSC endpoint for FPR downloads")
cmd.Flags().StringVar(&stepConfig.VersioningModel, "versioningModel", `major`, "The default project versioning model used for creating the version based on the build descriptor version to report results in SSC, can be one of `'major'`, `'major-minor'`, `'semantic'`, `'full'`")
cmd.Flags().StringVar(&stepConfig.PythonInstallCommand, "pythonInstallCommand", `{{.Pip}} install --user .`, "Additional install command that can be run when `buildTool: 'pip'` is used which allows further customizing the execution environment of the scan")
@ -842,6 +846,24 @@ func fortifyExecuteScanMetadata() config.StepData {
Aliases: []config.Alias{},
Default: 1,
},
{
Name: "spotCheckMinimumUnit",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: `number`,
},
{
Name: "SpotCheckMaximum",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "int",
Mandatory: false,
Aliases: []config.Alias{},
Default: 0,
},
{
Name: "fprDownloadEndpoint",
ResourceRef: []config.ResourceReference{},

View File

@ -494,7 +494,7 @@ func TestAnalyseSuspiciousExploitable(t *testing.T) {
}
func TestAnalyseUnauditedIssues(t *testing.T) {
config := fortifyExecuteScanOptions{SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
config := fortifyExecuteScanOptions{SpotCheckMinimumUnit: "number", SpotCheckMinimum: 4, MustAuditIssueGroups: "Audit All, Corporate Security Requirements", SpotAuditIssueGroups: "Spot Checks of Each Category"}
ff := fortifyMock{}
influx := fortifyExecuteScanInflux{}
name := "test"
@ -551,6 +551,16 @@ func TestAnalyseUnauditedIssues(t *testing.T) {
assert.Equal(t, 3, len(spotChecksCountByCategory))
}
func TestAnalyseUnauditedIssuesWithWrongConfig(t *testing.T) {
config := fortifyExecuteScanOptions{SpotCheckMinimumUnit: "float"}
spotChecksCountByCategory := []fortify.SpotChecksAuditCount{}
ff := fortifyMock{}
auditStatus := map[string]string{}
_, _, err := analyseUnauditedIssues(config, &ff, &models.ProjectVersion{}, &models.FilterSet{}, &models.IssueFilterSelectorSet{}, &fortifyExecuteScanInflux{}, auditStatus, &spotChecksCountByCategory)
assert.Error(t, err)
assert.Equal(t, "Invalid spotCheckMinimumUnit. Please set it as 'percentage' or 'number'.", err.Error())
}
func TestTriggerFortifyScan(t *testing.T) {
t.Run("maven", func(t *testing.T) {
dir := t.TempDir()
@ -637,6 +647,30 @@ func TestTriggerFortifyScan(t *testing.T) {
})
}
func TestGetMinSpotChecksPerCategory(t *testing.T) {
testExpectedGetMinSpotChecksPerCategory := func(spotChecksMinUnit string, spotChecksMax int, spotChecksMin int, issuesPerCategory int, spotChecksMinCalculatedExpected int) {
testName := fmt.Sprintf("Test GetMinSpotChecksPerCategory for SpotCheckMinimumUnit: %v, SpotCheckMaximum: %v, SpotCheckMinimum: %v, issuesPerCategory: %v", spotChecksMinUnit, spotChecksMax, spotChecksMin, issuesPerCategory)
t.Run(testName, func(t *testing.T) {
config := fortifyExecuteScanOptions{SpotCheckMinimumUnit: spotChecksMinUnit, SpotCheckMaximum: spotChecksMax, SpotCheckMinimum: spotChecksMin}
spotCheckMin := getMinSpotChecksPerCategory(config, issuesPerCategory)
assert.Equal(t, spotChecksMinCalculatedExpected, spotCheckMin)
})
}
testExpectedGetMinSpotChecksPerCategory("percentage", 0, 1, 10, 1)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 3, 1)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 8, 1)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 10, 1)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 24, 2)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 26, 3)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 100, 10)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 10, 200, 10)
testExpectedGetMinSpotChecksPerCategory("percentage", 10, 50, 10, 5)
testExpectedGetMinSpotChecksPerCategory("number", 0, 1, 10, 1)
testExpectedGetMinSpotChecksPerCategory("number", 5, 10, 100, 5)
}
func TestGenerateAndDownloadQGateReport(t *testing.T) {
ffMock := fortifyMock{Successive: false}
config := fortifyExecuteScanOptions{ReportTemplateID: 18, ReportType: "PDF"}

View File

@ -490,13 +490,39 @@ spec:
- name: spotCheckMinimum
type: int
description:
"The minimum number of issues that must be audited per category in the `Spot Checks of each
"The minimum number/percentage of issues that must be audited per category in the `Spot Checks of each
Category` folder to avoid an error being thrown"
scope:
- PARAMETERS
- STAGES
- STEPS
default: 1
- name: spotCheckMinimumUnit
type: string
description:
"The unit for the spotCheckMinimum to apply."
scope:
- PARAMETERS
- STAGES
- STEPS
default: 'number'
possibleValues:
- number
- percentage
- name: SpotCheckMaximum
type: int
description:
"The maximum number of issues that must be audited per category in the `Spot Checks of each
Category` folder to avoid an error being thrown.
Note that this flag depends on the result of spotCheckMinimum.
For example if spotCheckMinimum percentage value exceeds spotCheckMaximum then
spotCheckMaximum will be considerd else spotCheckMinimum is considered.
If zero, this flag will be ignored."
scope:
- PARAMETERS
- STAGES
- STEPS
default: 0
- name: fprDownloadEndpoint
aliases:
- name: fortifyFprDownloadEndpoint