Skip to content

Commit 11e20cc

Browse files
hubadrthtri
andauthored
CxOne: Update compliance check for audited findings (#5480)
Co-authored-by: thtri <[email protected]>
1 parent 9a51d88 commit 11e20cc

File tree

2 files changed

+89
-26
lines changed

2 files changed

+89
-26
lines changed

cmd/checkmarxOneExecuteScan.go

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ func (c *checkmarxOneExecuteScanHelper) PostScanSummaryInPullRequest(detailedRes
619619
if len(c.config.Repository) == 0 {
620620
repository = pathParts[len(pathParts)-1]
621621
}
622-
log.Entry().Infof("Found repository %s and owner %s from orchestrator", c.config.Repository, c.config.Owner)
622+
log.Entry().Debugf("Found repository %s and owner %s from orchestrator", repository, owner)
623623
} else {
624624
return fmt.Errorf("failed to extract owner and repository from URL %s", repoUrl)
625625
}
@@ -636,23 +636,60 @@ func (c *checkmarxOneExecuteScanHelper) PostScanSummaryInPullRequest(detailedRes
636636
ghIssues := c.utils.GetIssueService()
637637
log.Entry().Debugf("Creating/updating GitHub issue with check results with PR: %s, GithubAPIURL: %s, Owner: %s, Repository: %s", c.config.PullRequestName, c.config.GithubAPIURL, owner, repository)
638638
scanReportOverview := checkmarxOne.CreateJSONHeaderReport(detailedResults)
639-
var criticalSeverityString, highSeverityString, mediumSeverityString, lowSeverityString string
639+
var criticalSeverityString, highSeverityString, mediumSeverityString, lowSeverityString, criticalComplianceCheckString, highComplianceCheckString, mediumComplianceCheckString, lowComplianceCheckString string
640640
for _, finding := range *scanReportOverview.Findings {
641641
switch finding.ClassificationName {
642642
case "Critical":
643-
criticalSeverityString = fmt.Sprintf("%d", finding.Total-*finding.Audited)
643+
// TODO: check if config threshold unit is percent or absolute number
644+
if *finding.Audited < int(math.Ceil((float64(c.config.VulnerabilityThresholdCritical)/100.0)*float64(finding.Total))) {
645+
criticalComplianceCheckString = ":x:"
646+
} else {
647+
criticalComplianceCheckString = ":white_check_mark:"
648+
}
649+
if finding.Confirmed > 0 {
650+
criticalSeverityString = fmt.Sprintf("%s %d (%d confirmed)", criticalComplianceCheckString, finding.Total-*finding.Audited, finding.Confirmed)
651+
} else {
652+
criticalSeverityString = fmt.Sprintf("%s %d", criticalComplianceCheckString, finding.Total-*finding.Audited)
653+
}
644654
case "High":
645-
highSeverityString = fmt.Sprintf("%d", finding.Total-*finding.Audited)
655+
if *finding.Audited < int(math.Ceil((float64(c.config.VulnerabilityThresholdHigh)/100.0)*float64(finding.Total))) {
656+
highComplianceCheckString = ":x:"
657+
} else {
658+
highComplianceCheckString = ":white_check_mark:"
659+
}
660+
if finding.Confirmed > 0 {
661+
highSeverityString = fmt.Sprintf("%s %d (%d confirmed)", highComplianceCheckString, finding.Total-*finding.Audited, finding.Confirmed)
662+
} else {
663+
highSeverityString = fmt.Sprintf("%s %d", highComplianceCheckString, finding.Total-*finding.Audited)
664+
}
646665
case "Medium":
647-
mediumSeverityString = fmt.Sprintf("%d", finding.Total-*finding.Audited)
666+
if *finding.Audited < int(math.Ceil((float64(c.config.VulnerabilityThresholdMedium)/100.0)*float64(finding.Total))) {
667+
mediumComplianceCheckString = ":x:"
668+
} else {
669+
mediumComplianceCheckString = ":white_check_mark:"
670+
}
671+
if finding.Confirmed > 0 {
672+
mediumSeverityString = fmt.Sprintf("%s %d (%d confirmed)", mediumComplianceCheckString, finding.Total-*finding.Audited, finding.Confirmed)
673+
} else {
674+
mediumSeverityString = fmt.Sprintf("%s %d", mediumComplianceCheckString, finding.Total-*finding.Audited)
675+
}
648676
case "Low":
649677
if finding.LowPerQuery != nil {
650678
for _, lowFinding := range *finding.LowPerQuery {
651679
if c.config.VulnerabilityThresholdLowPerQuery {
680+
confirmedLowString := ""
681+
if lowFinding.Confirmed > 0 {
682+
confirmedLowString = fmt.Sprintf(", of which %d confirmed", lowFinding.Confirmed)
683+
}
652684
lowAuditedRequiredPerQuery := min(int(math.Ceil(float64(lowFinding.Total)*float64(c.config.VulnerabilityThresholdLow)/100.0)), c.config.VulnerabilityThresholdLowPerQueryMax)
653-
lowSeverityString = fmt.Sprintf("%s%d %s (%d audits / %d required) <br>", lowSeverityString, lowFinding.Total-lowFinding.Audited, lowFinding.QueryName, lowFinding.Audited, lowAuditedRequiredPerQuery)
685+
if lowFinding.Audited < lowAuditedRequiredPerQuery {
686+
lowComplianceCheckString = ":x:"
687+
} else {
688+
lowComplianceCheckString = ":white_check_mark:"
689+
}
690+
lowSeverityString = fmt.Sprintf("%s%s %d %s (%d audited / %d required%s) <br>", lowSeverityString, lowComplianceCheckString, lowFinding.Total-lowFinding.Audited, lowFinding.QueryName, lowFinding.Audited, lowAuditedRequiredPerQuery, confirmedLowString)
654691
} else {
655-
lowSeverityString = fmt.Sprintf("%s%d %s<br>", lowSeverityString, lowFinding.Total-lowFinding.Audited, lowFinding.QueryName)
692+
lowSeverityString = fmt.Sprintf("%s%s %d %s<br>", lowSeverityString, lowComplianceCheckString, lowFinding.Total-lowFinding.Audited, lowFinding.QueryName)
656693
}
657694
}
658695
}
@@ -669,7 +706,7 @@ func (c *checkmarxOneExecuteScanHelper) PostScanSummaryInPullRequest(detailedRes
669706
**Project**: %s
670707
**ScanId**: %s
671708
**Preset**: %s
672-
Severity | Number of open findings
709+
Severity | Number of unaudited findings
673710
--- | ---
674711
:bangbang: Critical | %s
675712
:red_circle: High | %s
@@ -1252,36 +1289,41 @@ func (c *checkmarxOneExecuteScanHelper) enforceThresholds(results *map[string]in
12521289
cxLowThreshold := c.config.VulnerabilityThresholdLow
12531290
cxLowThresholdPerQuery := c.config.VulnerabilityThresholdLowPerQuery
12541291
cxLowThresholdPerQueryMax := c.config.VulnerabilityThresholdLowPerQueryMax
1255-
criticalValue := (*results)["Critical"].(map[string]int)["NotFalsePositive"]
1256-
highValue := (*results)["High"].(map[string]int)["NotFalsePositive"]
1257-
mediumValue := (*results)["Medium"].(map[string]int)["NotFalsePositive"]
1258-
lowValue := (*results)["Low"].(map[string]int)["NotFalsePositive"]
1292+
// findings are audited if they are in state Confirmed, Urgent or NotExploitable
1293+
criticalValue := (*results)["Critical"].(map[string]int)["ToVerify"] + (*results)["Critical"].(map[string]int)["ProposedNotExploitable"]
1294+
confirmedCriticalValue := (*results)["Critical"].(map[string]int)["Confirmed"] + (*results)["Critical"].(map[string]int)["Urgent"]
1295+
highValue := (*results)["High"].(map[string]int)["ToVerify"] + (*results)["High"].(map[string]int)["ProposedNotExploitable"]
1296+
confirmedHighValue := (*results)["High"].(map[string]int)["Confirmed"] + (*results)["High"].(map[string]int)["Urgent"]
1297+
mediumValue := (*results)["Medium"].(map[string]int)["ToVerify"] + (*results)["Medium"].(map[string]int)["ProposedNotExploitable"]
1298+
confirmedMediumValue := (*results)["Medium"].(map[string]int)["Confirmed"] + (*results)["Medium"].(map[string]int)["Urgent"]
1299+
lowValue := (*results)["Low"].(map[string]int)["ToVerify"] + (*results)["Low"].(map[string]int)["ProposedNotExploitable"]
1300+
confirmedLowValue := (*results)["Low"].(map[string]int)["Confirmed"] + (*results)["Low"].(map[string]int)["Urgent"]
12591301
var unit string
12601302
criticalViolation := ""
12611303
highViolation := ""
12621304
mediumViolation := ""
12631305
lowViolation := ""
12641306
if c.config.VulnerabilityThresholdUnit == "percentage" {
12651307
unit = "%"
1266-
criticalAudited := (*results)["Critical"].(map[string]int)["Issues"] - (*results)["Critical"].(map[string]int)["NotFalsePositive"]
1308+
criticalAudited := (*results)["Critical"].(map[string]int)["NotExploitable"] + (*results)["Critical"].(map[string]int)["Confirmed"] + (*results)["Critical"].(map[string]int)["Urgent"]
12671309
criticalOverall := (*results)["Critical"].(map[string]int)["Issues"]
12681310
if criticalOverall == 0 {
12691311
criticalAudited = 1
12701312
criticalOverall = 1
12711313
}
1272-
highAudited := (*results)["High"].(map[string]int)["Issues"] - (*results)["High"].(map[string]int)["NotFalsePositive"]
1314+
highAudited := (*results)["High"].(map[string]int)["NotExploitable"] + (*results)["High"].(map[string]int)["Confirmed"] + (*results)["High"].(map[string]int)["Urgent"]
12731315
highOverall := (*results)["High"].(map[string]int)["Issues"]
12741316
if highOverall == 0 {
12751317
highAudited = 1
12761318
highOverall = 1
12771319
}
1278-
mediumAudited := (*results)["Medium"].(map[string]int)["Issues"] - (*results)["Medium"].(map[string]int)["NotFalsePositive"]
1320+
mediumAudited := (*results)["Medium"].(map[string]int)["NotExploitable"] + (*results)["Medium"].(map[string]int)["Confirmed"] + (*results)["Medium"].(map[string]int)["Urgent"]
12791321
mediumOverall := (*results)["Medium"].(map[string]int)["Issues"]
12801322
if mediumOverall == 0 {
12811323
mediumAudited = 1
12821324
mediumOverall = 1
12831325
}
1284-
lowAudited := (*results)["Low"].(map[string]int)["Confirmed"] + (*results)["Low"].(map[string]int)["NotExploitable"]
1326+
lowAudited := (*results)["Low"].(map[string]int)["Confirmed"] + (*results)["Low"].(map[string]int)["NotExploitable"] + (*results)["Low"].(map[string]int)["Urgent"]
12851327
lowOverall := (*results)["Low"].(map[string]int)["Issues"]
12861328
if lowOverall == 0 {
12871329
lowAudited = 1
@@ -1310,7 +1352,7 @@ func (c *checkmarxOneExecuteScanHelper) enforceThresholds(results *map[string]in
13101352
lowPerQueryMap := (*results)["LowPerQuery"].(map[string]map[string]int)
13111353

13121354
for lowQuery, resultsLowQuery := range lowPerQueryMap {
1313-
lowAuditedPerQuery := resultsLowQuery["Confirmed"] + resultsLowQuery["NotExploitable"]
1355+
lowAuditedPerQuery := resultsLowQuery["Confirmed"] + resultsLowQuery["NotExploitable"] + resultsLowQuery["Urgent"]
13141356
lowOverallPerQuery := resultsLowQuery["Issues"]
13151357
lowAuditedRequiredPerQuery := min(int(math.Ceil(float64(lowOverallPerQuery)*float64(cxLowThreshold)/100.0)), cxLowThresholdPerQueryMax)
13161358
if lowAuditedPerQuery < lowAuditedRequiredPerQuery && lowAuditedPerQuery < cxLowThresholdPerQueryMax {
@@ -1351,10 +1393,24 @@ func (c *checkmarxOneExecuteScanHelper) enforceThresholds(results *map[string]in
13511393
}
13521394
}
13531395

1354-
criticalText := fmt.Sprintf("Critical %v%v %v", criticalValue, unit, criticalViolation)
1355-
highText := fmt.Sprintf("High %v%v %v", highValue, unit, highViolation)
1356-
mediumText := fmt.Sprintf("Medium %v%v %v", mediumValue, unit, mediumViolation)
1357-
lowText := fmt.Sprintf("Low %v%v %v", lowValue, unit, lowViolation)
1396+
var confirmedCriticalString, confirmedHighString, confirmedMediumString, confirmedLowString string
1397+
if confirmedCriticalValue > 0 {
1398+
confirmedCriticalString = fmt.Sprintf(" (of which %v confirmed)", confirmedCriticalValue)
1399+
}
1400+
if confirmedHighValue > 0 {
1401+
confirmedHighString = fmt.Sprintf(" (of which %v confirmed)", confirmedHighValue)
1402+
}
1403+
if confirmedMediumValue > 0 {
1404+
confirmedMediumString = fmt.Sprintf(" (of which %v confirmed)", confirmedMediumValue)
1405+
}
1406+
if confirmedLowValue > 0 {
1407+
confirmedLowString = fmt.Sprintf(" (of which %v confirmed)", confirmedLowValue)
1408+
}
1409+
criticalText := fmt.Sprintf("Critical %v%v %v %v", criticalValue, unit, confirmedCriticalString, criticalViolation)
1410+
highText := fmt.Sprintf("High %v%v %v %v", highValue, unit, confirmedHighString, highViolation)
1411+
mediumText := fmt.Sprintf("Medium %v%v %v %v", mediumValue, unit, confirmedMediumString, mediumViolation)
1412+
lowText := fmt.Sprintf("Low %v%v %v %v", lowValue, unit, confirmedLowString, lowViolation)
1413+
log.Entry().Info("Result auditing status per severity:")
13581414
if len(criticalViolation) > 0 {
13591415
insecureResults = append(insecureResults, criticalText)
13601416
log.Entry().Error(criticalText)

pkg/checkmarxone/reporting.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ type Finding struct {
3737
ClassificationName string `json:"classificationName"`
3838
Total int `json:"total,omitempty"`
3939
Audited *int `json:"audited,omitempty"`
40+
Confirmed int `json:"confirmed,omitempty"`
4041
LowPerQuery *[]LowPerQuery `json:"categories,omitempty"`
4142
}
4243

4344
type LowPerQuery struct {
4445
QueryName string `json:"name"`
4546
Audited int `json:"audited"`
4647
Total int `json:"total"`
48+
Confirmed int `json:"confirmed"`
4749
}
4850

4951
func CreateCustomReport(data *map[string]interface{}, insecure, neutral []string) reporting.ScanReport {
@@ -163,22 +165,25 @@ func CreateJSONHeaderReport(data *map[string]interface{}) CheckmarxOneReportData
163165
criticalFindings := Finding{}
164166
criticalFindings.ClassificationName = "Critical"
165167
criticalFindings.Total = (*data)["Critical"].(map[string]int)["Issues"]
166-
criticalAudited := (*data)["Critical"].(map[string]int)["Issues"] - (*data)["Critical"].(map[string]int)["NotFalsePositive"]
168+
criticalAudited := (*data)["Critical"].(map[string]int)["NotExploitable"] + (*data)["Critical"].(map[string]int)["Urgent"] + (*data)["Critical"].(map[string]int)["Confirmed"]
167169
criticalFindings.Audited = &criticalAudited
170+
criticalFindings.Confirmed = (*data)["Critical"].(map[string]int)["Confirmed"] + (*data)["Critical"].(map[string]int)["Urgent"]
168171
findings = append(findings, criticalFindings)
169172
// High
170173
highFindings := Finding{}
171174
highFindings.ClassificationName = "High"
172175
highFindings.Total = (*data)["High"].(map[string]int)["Issues"]
173-
highAudited := (*data)["High"].(map[string]int)["Issues"] - (*data)["High"].(map[string]int)["NotFalsePositive"]
176+
highAudited := (*data)["High"].(map[string]int)["NotExploitable"] + (*data)["High"].(map[string]int)["Urgent"] + (*data)["High"].(map[string]int)["Confirmed"]
174177
highFindings.Audited = &highAudited
178+
highFindings.Confirmed = (*data)["High"].(map[string]int)["Confirmed"] + (*data)["High"].(map[string]int)["Urgent"]
175179
findings = append(findings, highFindings)
176180
// Medium
177181
mediumFindings := Finding{}
178182
mediumFindings.ClassificationName = "Medium"
179183
mediumFindings.Total = (*data)["Medium"].(map[string]int)["Issues"]
180-
mediumAudited := (*data)["Medium"].(map[string]int)["Issues"] - (*data)["Medium"].(map[string]int)["NotFalsePositive"]
184+
mediumAudited := (*data)["Medium"].(map[string]int)["NotExploitable"] + (*data)["Medium"].(map[string]int)["Urgent"] + (*data)["Medium"].(map[string]int)["Confirmed"]
181185
mediumFindings.Audited = &mediumAudited
186+
mediumFindings.Confirmed = (*data)["Medium"].(map[string]int)["Confirmed"] + (*data)["Medium"].(map[string]int)["Urgent"]
182187
findings = append(findings, mediumFindings)
183188
// Low
184189
lowFindings := Finding{}
@@ -187,19 +192,21 @@ func CreateJSONHeaderReport(data *map[string]interface{}) CheckmarxOneReportData
187192
lowPerQueryList := []LowPerQuery{}
188193
lowPerQueryMap := (*data)["LowPerQuery"].(map[string]map[string]int)
189194
for queryName, resultsLowQuery := range lowPerQueryMap {
190-
audited := resultsLowQuery["Confirmed"] + resultsLowQuery["NotExploitable"]
195+
audited := resultsLowQuery["Confirmed"] + resultsLowQuery["NotExploitable"] + resultsLowQuery["Urgent"]
191196
total := resultsLowQuery["Issues"]
192197
lowPerQuery := LowPerQuery{}
193198
lowPerQuery.QueryName = queryName
194199
lowPerQuery.Audited = audited
200+
lowPerQuery.Confirmed = resultsLowQuery["Confirmed"] + resultsLowQuery["Urgent"]
195201
lowPerQuery.Total = total
196202
lowPerQueryList = append(lowPerQueryList, lowPerQuery)
197203
}
198204
lowFindings.LowPerQuery = &lowPerQueryList
199205
findings = append(findings, lowFindings)
200206
} else {
201207
lowFindings.Total = (*data)["Low"].(map[string]int)["Issues"]
202-
lowAudited := (*data)["Low"].(map[string]int)["Confirmed"] + (*data)["Low"].(map[string]int)["NotExploitable"]
208+
lowAudited := (*data)["Low"].(map[string]int)["Confirmed"] + (*data)["Low"].(map[string]int)["NotExploitable"] + (*data)["Low"].(map[string]int)["Urgent"]
209+
lowFindings.Confirmed = (*data)["Low"].(map[string]int)["Confirmed"] + (*data)["Low"].(map[string]int)["Urgent"]
203210
lowFindings.Audited = &lowAudited
204211
findings = append(findings, lowFindings)
205212
}

0 commit comments

Comments
 (0)