Skip to content

Commit

Permalink
Add Critical Severity - AST 21466 (#644)
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagobcx authored Aug 2, 2024
1 parent 16cef5a commit 6b5e08e
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 58 deletions.
19 changes: 12 additions & 7 deletions internal/commands/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import (
"github.com/spf13/cobra"
)

func NewResultsPredicatesCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) *cobra.Command {
func NewResultsPredicatesCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
triageCmd := &cobra.Command{
Use: "triage",
Short: "Manage results",
Long: "The 'triage' command enables the ability to manage results in Checkmarx One.",
}
triageShowCmd := triageShowSubCommand(resultsPredicatesWrapper)
triageUpdateCmd := triageUpdateSubCommand(resultsPredicatesWrapper)
triageUpdateCmd := triageUpdateSubCommand(resultsPredicatesWrapper, featureFlagsWrapper)

addFormatFlagToMultipleCommands(
[]*cobra.Command{triageShowCmd},
Expand Down Expand Up @@ -55,7 +55,7 @@ func triageShowSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWra
return triageShowCmd
}

func triageUpdateSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) *cobra.Command {
func triageUpdateSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) *cobra.Command {
triageUpdateCmd := &cobra.Command{
Use: "update",
Short: "Update the state, severity or comment for the given issue",
Expand All @@ -66,12 +66,12 @@ func triageUpdateSubCommand(resultsPredicatesWrapper wrappers.ResultsPredicatesW
--similarity-id <SimilarityID>
--project-id <ProjectID>
--state <TO_VERIFY|NOT_EXPLOITABLE|PROPOSED_NOT_EXPLOITABLE|CONFIRMED|URGENT>
--severity <HIGH|MEDIUM|LOW|INFO>
--severity <CRITICAL|HIGH|MEDIUM|LOW|INFO>
--comment <Comment(Optional)>
--scan-type <SAST|IAC-SECURITY>
`,
),
RunE: runTriageUpdate(resultsPredicatesWrapper),
RunE: runTriageUpdate(resultsPredicatesWrapper, featureFlagsWrapper),
}

triageUpdateCmd.PersistentFlags().String(params.SimilarityIDFlag, "", "Similarity ID")
Expand Down Expand Up @@ -134,15 +134,20 @@ func runTriageShow(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) f
}
}

func runTriageUpdate(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper) func(*cobra.Command, []string) error {
func runTriageUpdate(resultsPredicatesWrapper wrappers.ResultsPredicatesWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, _ []string) error {
similarityID, _ := cmd.Flags().GetString(params.SimilarityIDFlag)
projectID, _ := cmd.Flags().GetString(params.ProjectIDFlag)
severity, _ := cmd.Flags().GetString(params.SeverityFlag)
state, _ := cmd.Flags().GetString(params.StateFlag)
comment, _ := cmd.Flags().GetString(params.CommentFlag)
scanType, _ := cmd.Flags().GetString(params.ScanTypeFlag)

// check if the current tenant has critical severity available
flagResponse, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.CVSSV3Enabled)
criticalEnabled := flagResponse.Status
if !criticalEnabled && strings.EqualFold(severity, "critical") {
return errors.Errorf("%s", "Critical severity is not available for your tenant.This severity status will be enabled shortly")
}
predicate := &wrappers.PredicateRequest{
SimilarityID: similarityID,
ProjectID: projectID,
Expand Down
119 changes: 80 additions & 39 deletions internal/commands/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
failedListingResults = "Failed listing results"
failedListingCodeBashing = "Failed codebashing link"
mediumLabel = "medium"
criticalLabel = "critical"
highLabel = "high"
lowLabel = "low"
infoLabel = "info"
Expand All @@ -48,6 +49,7 @@ const (
lowSonar = "MINOR"
mediumSonar = "MAJOR"
highSonar = "CRITICAL"
criticalSonar = "BLOCKER"
infoLowSarif = "note"
mediumSarif = "warning"
highSarif = "error"
Expand All @@ -56,15 +58,17 @@ const (
lowCx = "LOW"
mediumCx = "MEDIUM"
highCx = "HIGH"
tableResultsFormat = " | %-10s %4d %6d %4d %4d %-9s |\n"
stringTableResultsFormat = " | %-10s %4s %6s %4s %4s %5s |\n"
TableTitleFormat = " | %-11s %4s %6s %4s %4s %6s |\n"
criticalCx = "CRITICAL"
tableResultsFormat = " | %-10s %6v %5d %6d %5d %4d %-9s |\n"
stringTableResultsFormat = " | %-10s %5s %6s %6s %5s %4s %5s |\n"
TableTitleFormat = " | %-11s %4s %4s %6s %4s %4s %6s |\n"
twoNewLines = "\n\n"
tableLine = " --------------------------------------------------------- "
tableLine = " --------------------------------------------------------------------- "
codeBashingKey = "cb-url"
failedGettingBfl = "Failed getting BFL"
notAvailableString = "-"
scanFailedString = "Failed"
disabledString = "N/A"
scanFailedString = "Failed "
scanCanceledString = "Canceled"
scanSuccessString = "Completed"
scanPartialString = "Partial"
Expand Down Expand Up @@ -133,19 +137,22 @@ var filterResultsListFlagUsage = fmt.Sprintf(
),
)

// Follows: over 9.0 is critical, 7.0 to 8.9 is high, 4.0 to 6.9 is medium and 3.9 or less is low.
var securities = map[string]string{
infoCx: "3.5",
lowCx: "6.5",
mediumCx: "8.5",
highCx: "9.5",
infoCx: "1.0",
lowCx: "2.0",
mediumCx: "4.0",
highCx: "7.0",
criticalCx: "9.0",
}

// Match cx severity with sonar severity
var sonarSeverities = map[string]string{
infoCx: infoSonar,
lowCx: lowSonar,
mediumCx: mediumSonar,
highCx: highSonar,
infoCx: infoSonar,
lowCx: lowSonar,
mediumCx: mediumSonar,
highCx: highSonar,
criticalCx: criticalSonar,
}

var containerEngineUnsupportedAgents = []string{
Expand Down Expand Up @@ -501,11 +508,12 @@ func convertScanToResultsSummary(scanInfo *wrappers.ScanResponseModel, resultsWr
scsIssues := 0
var containersIssues *int
enginesStatusCode := map[string]int{
commonParams.SastType: 0,
commonParams.ScaType: 0,
commonParams.KicsType: 0,
commonParams.APISecType: 0,
commonParams.ScsType: 0,
commonParams.SastType: 0,
commonParams.ScaType: 0,
commonParams.KicsType: 0,
commonParams.APISecType: 0,
commonParams.ScsType: 0,
commonParams.ContainersType: 0,
}
if wrappers.IsContainersEnabled {
containersIssues = new(int)
Expand Down Expand Up @@ -543,6 +551,7 @@ func convertScanToResultsSummary(scanInfo *wrappers.ScanResponseModel, resultsWr
ProjectID: scanInfo.ProjectID,
RiskStyle: "",
RiskMsg: "",
CriticalIssues: 0,
HighIssues: 0,
MediumIssues: 0,
LowIssues: 0,
Expand All @@ -557,11 +566,12 @@ func convertScanToResultsSummary(scanInfo *wrappers.ScanResponseModel, resultsWr
BranchName: scanInfo.Branch,
EnginesEnabled: scanInfo.Engines,
EnginesResult: map[string]*wrappers.EngineResultSummary{
commonParams.SastType: {StatusCode: enginesStatusCode[commonParams.SastType]},
commonParams.ScaType: {StatusCode: enginesStatusCode[commonParams.ScaType]},
commonParams.KicsType: {StatusCode: enginesStatusCode[commonParams.KicsType]},
commonParams.APISecType: {StatusCode: enginesStatusCode[commonParams.APISecType]},
commonParams.ScsType: {StatusCode: enginesStatusCode[commonParams.ScsType]},
commonParams.SastType: {StatusCode: enginesStatusCode[commonParams.SastType]},
commonParams.ScaType: {StatusCode: enginesStatusCode[commonParams.ScaType]},
commonParams.KicsType: {StatusCode: enginesStatusCode[commonParams.KicsType]},
commonParams.APISecType: {StatusCode: enginesStatusCode[commonParams.APISecType]},
commonParams.ScsType: {StatusCode: enginesStatusCode[commonParams.ScsType]},
commonParams.ContainersType: {StatusCode: enginesStatusCode[commonParams.ContainersType]},
},
}
if wrappers.IsContainersEnabled {
Expand Down Expand Up @@ -592,6 +602,7 @@ func summaryReport(
policies *wrappers.PolicyResponseModel,
risksOverviewWrapper wrappers.RisksOverviewWrapper,
scsScanOverviewWrapper wrappers.ScanOverviewWrapper,
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
results *wrappers.ScanResultsCollection,
) (*wrappers.ResultSummary, error) {
if summary.HasAPISecurity() {
Expand All @@ -614,7 +625,7 @@ func summaryReport(
summary.Policies = filterViolatedRules(*policies)
}

enhanceWithScanSummary(summary, results)
enhanceWithScanSummary(summary, results, featureFlagsWrapper)

setNotAvailableNumberIfZero(summary, &summary.SastIssues, commonParams.SastType)
setNotAvailableNumberIfZero(summary, &summary.ScaIssues, commonParams.ScaType)
Expand All @@ -636,7 +647,10 @@ func setNotAvailableEnginesStatusCode(summary *wrappers.ResultSummary) {
}

func setRiskMsgAndStyle(summary *wrappers.ResultSummary) {
if summary.HighIssues > 0 {
if summary.CriticalIssues > 0 {
summary.RiskStyle = criticalLabel
summary.RiskMsg = "Critical Risk"
} else if summary.HighIssues > 0 {
summary.RiskStyle = highLabel
summary.RiskMsg = "High Risk"
} else if summary.MediumIssues > 0 {
Expand All @@ -656,14 +670,20 @@ func setNotAvailableNumberIfZero(summary *wrappers.ResultSummary, counter *int,
}
}

func enhanceWithScanSummary(summary *wrappers.ResultSummary, results *wrappers.ScanResultsCollection) {
func enhanceWithScanSummary(summary *wrappers.ResultSummary, results *wrappers.ScanResultsCollection, featureFlagsWrapper wrappers.FeatureFlagsWrapper) {
for _, result := range results.Results {
countResult(summary, result)
}
// Set critical count for a specific engine if critical is disabled
flagResponse, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.CVSSV3Enabled)
criticalEnabled := flagResponse.Status
if summary.HasAPISecurity() {
summary.EnginesResult[commonParams.APISecType].Low = summary.APISecurity.Risks[3]
summary.EnginesResult[commonParams.APISecType].Medium = summary.APISecurity.Risks[2]
summary.EnginesResult[commonParams.APISecType].High = summary.APISecurity.Risks[1]
if !criticalEnabled {
summary.EnginesResult[commonParams.APISecType].Critical = notAvailableNumber
}
}

if summary.HasSCS() && wrappers.IsSCSEnabled {
Expand All @@ -678,13 +698,22 @@ func enhanceWithScanSummary(summary *wrappers.ResultSummary, results *wrappers.S
if summary.SCSOverview.Status == scanPartialString {
summary.EnginesResult[commonParams.ScsType].StatusCode = scanPartialNumber
}
if !criticalEnabled {
summary.EnginesResult[commonParams.ScsType].Critical = notAvailableNumber
}
}
summary.TotalIssues = summary.SastIssues + summary.ScaIssues + summary.KicsIssues + summary.GetAPISecurityDocumentationTotal()
if wrappers.IsContainersEnabled {
if *summary.ContainersIssues >= 0 {
summary.TotalIssues += *summary.ContainersIssues
}
}
if !criticalEnabled {
summary.EnginesResult[commonParams.SastType].Critical = notAvailableNumber
summary.EnginesResult[commonParams.KicsType].Critical = notAvailableNumber
summary.EnginesResult[commonParams.ScaType].Critical = notAvailableNumber
summary.EnginesResult[commonParams.ContainersType].Critical = notAvailableNumber
}
}

func writeHTMLSummary(targetFile string, summary *wrappers.ResultSummary) error {
Expand Down Expand Up @@ -786,15 +815,15 @@ func printAPIsSecuritySummary(summary *wrappers.ResultSummary) {
func printTableRow(title string, counts *wrappers.EngineResultSummary, statusNumber int) {
switch statusNumber {
case notAvailableNumber:
fmt.Printf(stringTableResultsFormat, title, notAvailableString, notAvailableString, notAvailableString, notAvailableString, notAvailableString)
fmt.Printf(stringTableResultsFormat, title, notAvailableString, notAvailableString, notAvailableString, notAvailableString, notAvailableString, notAvailableString)
case scanFailedNumber:
fmt.Printf(tableResultsFormat, title, counts.High, counts.Medium, counts.Low, counts.Info, scanFailedString)
fmt.Printf(tableResultsFormat, title, getCountValue(counts.Critical), counts.High, counts.Medium, counts.Low, counts.Info, scanFailedString)
case scanCanceledNumber:
fmt.Printf(tableResultsFormat, title, counts.High, counts.Medium, counts.Low, counts.Info, scanCanceledString)
fmt.Printf(tableResultsFormat, title, getCountValue(counts.Critical), counts.High, counts.Medium, counts.Low, counts.Info, scanCanceledString)
case scanPartialNumber:
fmt.Printf(tableResultsFormat, title, counts.High, counts.Medium, counts.Low, counts.Info, scanPartialString)
fmt.Printf(tableResultsFormat, title, getCountValue(counts.Critical), counts.High, counts.Medium, counts.Low, counts.Info, scanPartialString)
default:
fmt.Printf(tableResultsFormat, title, counts.High, counts.Medium, counts.Low, counts.Info, scanSuccessString)
fmt.Printf(tableResultsFormat, title, getCountValue(counts.Critical), counts.High, counts.Medium, counts.Low, counts.Info, scanSuccessString)
}
}

Expand Down Expand Up @@ -823,16 +852,25 @@ func printSCSTableRow(microEngineOverview *wrappers.MicroEngineOverview) {
}
}

func getCountValue(count int) interface{} {
if count < 0 {
return disabledString
}
return count
}

func printResultsSummaryTable(summary *wrappers.ResultSummary) {
totalCriticalIssues := summary.EnginesResult.GetCriticalIssues()
totalHighIssues := summary.EnginesResult.GetHighIssues()
totalMediumIssues := summary.EnginesResult.GetMediumIssues()
totalLowIssues := summary.EnginesResult.GetLowIssues()
totalInfoIssues := summary.EnginesResult.GetInfoIssues()

totalIssues := summary.TotalIssues + summary.ScsIssues
fmt.Printf(tableLine + twoNewLines)
fmt.Printf(" Total Results: %d \n", totalIssues)
fmt.Println(tableLine)
fmt.Printf(TableTitleFormat, " ", "High", "Medium", "Low", "Info", "Status")
fmt.Printf(TableTitleFormat, " ", "Critical", "High", "Medium", "Low", "Info", "Status")

printTableRow("APIs", summary.EnginesResult[commonParams.APISecType], summary.EnginesResult[commonParams.APISecType].StatusCode)
printTableRow("IAC", summary.EnginesResult[commonParams.KicsType], summary.EnginesResult[commonParams.KicsType].StatusCode)
Expand All @@ -847,7 +885,7 @@ func printResultsSummaryTable(summary *wrappers.ResultSummary) {

fmt.Println(tableLine)
fmt.Printf(tableResultsFormat,
"TOTAL", totalHighIssues, totalMediumIssues, totalLowIssues, totalInfoIssues, summary.Status)
"TOTAL", getCountValue(totalCriticalIssues), totalHighIssues, totalMediumIssues, totalLowIssues, totalInfoIssues, summary.Status)
fmt.Printf(tableLine + twoNewLines)
}

Expand Down Expand Up @@ -1025,7 +1063,7 @@ func CreateScanReport(
}
isSummaryNeeded := verifyFormatsByReportList(reportList, summaryFormats...)
if isSummaryNeeded && !scanPending {
summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, scsScanOverviewWrapper, results)
summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, scsScanOverviewWrapper, featureFlagsWrapper, results)
if err != nil {
return err
}
Expand Down Expand Up @@ -1061,7 +1099,10 @@ func countResult(summary *wrappers.ResultSummary, result *wrappers.ScanResult) {
return
}
}

switch severity {
case criticalLabel:
summary.CriticalIssues++
case highLabel:
summary.HighIssues++
case mediumLabel:
Expand Down Expand Up @@ -2055,16 +2096,16 @@ func findProperties(result *wrappers.ScanResult) wrappers.SarifProperties {
sarifProperties.Description = findDescriptionText(result)
sarifProperties.SecuritySeverity = securities[result.Severity]
sarifProperties.Tags = []string{"security", "checkmarx", result.Type}

return sarifProperties
}

func findSarifLevel(result *wrappers.ScanResult) string {
level := map[string]string{
infoCx: infoLowSarif,
lowCx: infoLowSarif,
mediumCx: mediumSarif,
highCx: highSarif,
infoCx: infoLowSarif,
lowCx: infoLowSarif,
mediumCx: mediumSarif,
highCx: highSarif,
criticalCx: highSarif,
}
return level[result.Severity]
}
Expand Down
Loading

0 comments on commit 6b5e08e

Please sign in to comment.