Skip to content

Commit

Permalink
ScsSupportReports(AST-43345) (#902)
Browse files Browse the repository at this point in the history
* Added results to json Summary. Removed code that kept results only to console summary. Updated unit tests

* Added SCS to markdown. Added unit tests covering it

* Added markdown to default scs integration test

* Fixed unit tests

* Changed scs to scsType in countResult

* Cleaned up code. Improved tests

* Moved removal of sscs results per agent to ReadResults. updated tests

* Adding sscs results to sarif, needs testing

* Updated filename field

* Added unit tests for Sscs sarif

* Created new test for RuleID in sarif report

* Updated the assertTypePresentJSON method

* Added SCS results to report html format

* Added sscs to sonar report. Added snippet to sarif report

* Created tests for sonar. Updated existing tests for agents

* Created the remaining fields in json report

* Fixed linter issues

* Restoring cx_result_sonar file. Adding test for total count in json

* Fixing linter result

* Fix snippet in sarif report

* Moved adding Scs issues to total issues to existing IF block

* Using results api instead of overview API for counts. Update critical behavior for reports

* Fixed newline that was created during merge in github

* Fixing linter issue

* Fixing invalid sarif fields

* Fixing new util.go file

* Moved trimOsSeparator to just sscs sarif. Removed isFilePath method, insuficient to detect file

* Scanning different branch in integration tests for SCS for higher coverage. Merged two methods to remove result types from json

* Updated scsRepoURL

---------

Co-authored-by: Leonardo Fontes <[email protected]>
  • Loading branch information
diogo-fjrocha and LeonardoLordelloFontes authored Oct 7, 2024
1 parent f66a655 commit e325358
Show file tree
Hide file tree
Showing 11 changed files with 789 additions and 228 deletions.
2 changes: 1 addition & 1 deletion internal/commands/cx_result_sonar.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"issues":[{"engineId":"sast","ruleId":"1","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-1","filePath":"dummy-file-name-1","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-1","filePath":"dummy-file-name-1","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"2","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"3","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":11,"startColumn":3,"endColumn":13}},{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":12,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"4","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-3","filePath":"dummy-file-name-3","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-3","filePath":"dummy-file-name-3","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"5","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-3","filePath":"dummy-file-name-4","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-3","filePath":"dummy-file-name-4","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"kics","type":"VULNERABILITY","primaryLocation":{"textRange":{"endColumn":1}},"secondaryLocations":null}]}
{"issues":[{"engineId":"sast","ruleId":"1","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-1","filePath":"dummy-file-name-1","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-1","filePath":"dummy-file-name-1","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"2","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"3","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":11,"startColumn":3,"endColumn":13}},{"message":"mock-query-name-2","filePath":"dummy-file-name-2","textRange":{"startLine":12,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"4","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-3","filePath":"dummy-file-name-3","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-3","filePath":"dummy-file-name-3","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"sast","ruleId":"5","type":"VULNERABILITY","primaryLocation":{"message":"mock-query-name-3","filePath":"dummy-file-name-4","textRange":{"startLine":10,"startColumn":10,"endColumn":30}},"secondaryLocations":[{"message":"mock-query-name-3","filePath":"dummy-file-name-4","textRange":{"startLine":11,"startColumn":3,"endColumn":13}}]},{"engineId":"kics","type":"VULNERABILITY","primaryLocation":{"textRange":{"endColumn":1}},"secondaryLocations":null}]}
273 changes: 199 additions & 74 deletions internal/commands/result.go

Large diffs are not rendered by default.

469 changes: 411 additions & 58 deletions internal/commands/result_test.go

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions internal/commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -1956,12 +1956,13 @@ func applyThreshold(
}

sastRedundancy, _ := cmd.Flags().GetBool(commonParams.SastRedundancyFlag)
agent, _ := cmd.Flags().GetString(commonParams.AgentFlag)
params := make(map[string]string)
if sastRedundancy {
params[commonParams.SastRedundancyFlag] = ""
}

summaryMap, err := getSummaryThresholdMap(resultsWrapper, exportWrapper, scanResponseModel, params, risksOverviewWrapper)
summaryMap, err := getSummaryThresholdMap(resultsWrapper, exportWrapper, scanResponseModel, params, risksOverviewWrapper, agent)

if err != nil {
return err
Expand Down Expand Up @@ -2051,9 +2052,10 @@ func getSummaryThresholdMap(
scan *wrappers.ScanResponseModel,
resultsParams map[string]string,
risksOverviewWrapper wrappers.RisksOverviewWrapper,
agent string,
) (map[string]int, error) {
summaryMap := make(map[string]int)
results, err := ReadResults(resultsWrapper, exportWrapper, scan, resultsParams)
results, err := ReadResults(resultsWrapper, exportWrapper, scan, resultsParams, agent)

if err != nil {
return nil, err
Expand Down
39 changes: 21 additions & 18 deletions internal/params/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,24 +234,27 @@ const (

// Results
const (
SastType = "sast"
KicsType = "kics"
APISecurityType = "api-security"
AIProtectionType = "AI Protection"
ContainersType = "containers"
APIDocumentationFlag = "apisec-swagger-filter"
IacType = "iac-security"
IacLabel = "IaC Security"
APISecurityLabel = "API Security"
ScaType = "sca"
APISecType = "apisec"
ScsType = "scs"
MicroEnginesType = "microengines" // the scs scan type for scans API
Success = "success"
SCSScorecardType = "sscs-scorecard"
SCSSecretDetectionType = "sscs-secret-detection"
EnterpriseSecretsLabel = "Enterprise Secrets"
EnterpriseSecretsType = "enterprise-secrets"
SastType = "sast"
KicsType = "kics"
APISecurityType = "api-security"
AIProtectionType = "AI Protection"
ContainersType = "containers"
APIDocumentationFlag = "apisec-swagger-filter"
IacType = "iac-security"
IacLabel = "IaC Security"
APISecurityLabel = "API Security"
ScaType = "sca"
APISecType = "apisec"
ScsType = "scs"
SscsType = "sscs"
MicroEnginesType = "microengines" // the scs scan type for scans API
Success = "success"
SCSScorecardType = "sscs-scorecard"
SCSSecretDetectionType = "sscs-secret-detection"
EnterpriseSecretsLabel = "Enterprise Secrets"
EnterpriseSecretsType = "enterprise-secrets"
SCSScorecardOverviewType = "Scorecard"
SCSSecretDetectionOverviewType = "2ms"
)

// ScaAgent AST Role
Expand Down
101 changes: 66 additions & 35 deletions internal/wrappers/mock/results-mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mock

import (
"fmt"

"github.com/checkmarx/ast-cli/internal/params"

"github.com/checkmarx/ast-cli/internal/wrappers"
Expand Down Expand Up @@ -30,37 +31,51 @@ var containersResults = &wrappers.ScanResult{
CweID: "CWE-1234",
},
}
var scsResults = &wrappers.ScanResultsCollection{
TotalCount: 2,
Results: []*wrappers.ScanResult{
{
Type: params.SCSSecretDetectionType,
ID: "bhXbZjjoQZdGAwUhj6MLo9sh4fA=",
SimilarityID: "6deb156f325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "HIGH",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "Generic API Key has detected secret for file application.properties.",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
{
Type: params.SCSScorecardType,
ID: "n2a8iCzrIgbCe+dGKYk+cAApO0U=",
SimilarityID: "65323789a325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "HIGH",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "score is 0: branch protection not enabled on development/release branches:\\nWarn: branch protection not enabled for branch 'main'",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},

var scsResultsSecretDetection = []*wrappers.ScanResult{
{
Type: params.SCSSecretDetectionType,
ID: "bhXbZjjoQZdGAwUhj6MLo9sh4fA=",
SimilarityID: "6deb156f325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "HIGH",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "Generic API Key has detected secret for file application.properties.",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
{
Type: params.SCSSecretDetectionType,
ID: "bhXbZjjoQZdGAwUhj6MLo9sh4fA=",
SimilarityID: "6deb156f325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "MEDIUM",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "Generic API Key has detected secret for file application.properties.",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
}
var scsResultScorecard = []*wrappers.ScanResult{
{
Type: params.SCSScorecardType,
ID: "n2a8iCzrIgbCe+dGKYk+cAApO0U=",
SimilarityID: "65323789a325544aaefecee846b49a948571cecd4445d2b2b391a490641be5845",
Status: "NEW",
State: "TO_VERIFY",
Severity: "LOW",
Created: "2024-07-30T12:49:56Z",
FirstFoundAt: "2023-07-06T10:28:49Z",
FoundAt: "2024-07-30T12:49:56Z",
FirstScanID: "3d922bcd-00fe-4774-b182-d51e739dff81",
Description: "score is 0: branch protection not enabled on development/release branches:\\nWarn: branch protection not enabled for branch 'main'",
VulnerabilityDetails: wrappers.VulnerabilityDetails{},
},
}

Expand Down Expand Up @@ -113,15 +128,17 @@ func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
},
}, nil, nil
}
if params["scan-id"] == "SCS" {
if params["scan-id"] == "SCS_ONLY" {
scsResults := &wrappers.ScanResultsCollection{}
addSCSResults(scsResults)
return scsResults, nil, nil
}

const mock = "mock"
var dependencyPath = wrappers.DependencyPath{ID: mock, Name: mock, Version: mock, IsResolved: true, IsDevelopment: false, Locations: nil}
var dependencyArray = [][]wrappers.DependencyPath{{dependencyPath}}
return &wrappers.ScanResultsCollection{
TotalCount: 8,
scanResults := &wrappers.ScanResultsCollection{
TotalCount: 10,
Results: []*wrappers.ScanResult{
{
Type: "sast",
Expand Down Expand Up @@ -280,9 +297,23 @@ func (r ResultsMockWrapper) GetAllResultsByScanID(params map[string]string) (
Severity: "low",
},
},
}, nil, nil
}
addSCSResults(scanResults)
return scanResults, nil, nil
}

func (r ResultsMockWrapper) GetResultsURL(projectID string) (string, error) {
return fmt.Sprintf("projects/%s/overview", projectID), nil
}

// addSCSResults adds the SCS results to the scan results depending on the mock flags. Values in this mock should be in accordance with ScanOverviewMockWrapper
func addSCSResults(scanResults *wrappers.ScanResultsCollection) {
// the mock always has a result for Secret Detection
scanResults.Results = append(scanResults.Results, scsResultsSecretDetection...)
scanResults.TotalCount += uint(len(scsResultsSecretDetection))

if ScorecardScanned && !ScsScanPartial {
scanResults.Results = append(scanResults.Results, scsResultScorecard...)
scanResults.TotalCount += uint(len(scsResultScorecard))
}
}
54 changes: 27 additions & 27 deletions internal/wrappers/mock/scan-overview-mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@ func (s ScanOverviewMockWrapper) GetSCSOverviewByScanID(scanID string) (
if ScsScanPartial {
return &wrappers.SCSOverview{
Status: "Partial",
TotalRisksCount: 10,
TotalRisksCount: 2,
RiskSummary: map[string]int{
"critical": 0,
"high": 5,
"medium": 3,
"low": 2,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
MicroEngineOverviews: []*wrappers.MicroEngineOverview{
{
Name: "2ms",
FullName: "Secret Detection",
Status: "Completed",
TotalRisks: 10,
TotalRisks: 2,
RiskSummary: map[string]interface{}{
"critical": 0,
"high": 5,
"medium": 3,
"low": 2,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
},
Expand All @@ -59,37 +59,37 @@ func (s ScanOverviewMockWrapper) GetSCSOverviewByScanID(scanID string) (
if ScorecardScanned {
return &wrappers.SCSOverview{
Status: "Completed",
TotalRisksCount: 14,
TotalRisksCount: 3,
RiskSummary: map[string]int{
"critical": 0,
"high": 7,
"medium": 4,
"low": 3,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
MicroEngineOverviews: []*wrappers.MicroEngineOverview{
{
Name: "2ms",
FullName: "Secret Detection",
Status: "Completed",
TotalRisks: 10,
TotalRisks: 2,
RiskSummary: map[string]interface{}{
"critical": 0,
"high": 5,
"medium": 3,
"low": 2,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
},
{
Name: "Scorecard",
FullName: "Scorecard",
Status: "Completed",
TotalRisks: 4,
TotalRisks: 1,
RiskSummary: map[string]interface{}{
"critical": 0,
"high": 2,
"medium": 1,
"high": 0,
"medium": 0,
"low": 1,
"info": 0,
},
Expand All @@ -100,25 +100,25 @@ func (s ScanOverviewMockWrapper) GetSCSOverviewByScanID(scanID string) (
// default Overview
return &wrappers.SCSOverview{
Status: "Completed",
TotalRisksCount: 10,
TotalRisksCount: 2,
RiskSummary: map[string]int{
"critical": 0,
"high": 5,
"medium": 3,
"low": 2,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
MicroEngineOverviews: []*wrappers.MicroEngineOverview{
{
Name: "2ms",
FullName: "Secret Detection",
Status: "Completed",
TotalRisks: 10,
TotalRisks: 2,
RiskSummary: map[string]interface{}{
"critical": 0,
"high": 5,
"medium": 3,
"low": 2,
"high": 1,
"medium": 1,
"low": 0,
"info": 0,
},
},
Expand Down
14 changes: 12 additions & 2 deletions internal/wrappers/results-json.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,27 @@ type ScanResultData struct {
ScaPackageCollection *ScaPackageCollection `json:"scaPackageData,omitempty"`
RecommendedVersion interface{} `json:"recommendedVersion,omitempty"`
// Added to support kics results
Line uint `json:"line,omitempty"`
Line uint `json:"line,omitempty"` // also used by SSCS results
Platform string `json:"platform,omitempty"`
IssueType string `json:"issueType,omitempty"`
ExpectedValue string `json:"expectedValue,omitempty"`
Value string `json:"value,omitempty"`
Filename string `json:"filename,omitempty"`
Filename string `json:"filename,omitempty"` // also used by SSCS results
// Added to support containers results
PackageName string `json:"packageName,omitempty"`
PackageVersion string `json:"packageVersion,omitempty"`
ImageName string `json:"imageName,omitempty"`
ImageTag string `json:"imageTag,omitempty"`
ImageFilePath string `json:"imageFilePath,omitempty"`
ImageOrigin string `json:"imageOrigin,omitempty"`
// Added to support SSCS results
RuleID *string `json:"ruleId,omitempty"`
RuleName string `json:"ruleName,omitempty"`
Snippet string `json:"snippet,omitempty"`
SlsaStep string `json:"slsaStep,omitempty"`
RuleDescription string `json:"ruleDescription,omitempty"`
Remediation string `json:"remediation,omitempty"`
RemediationLink string `json:"remediationLink,omitempty"`
RemediationAdditional string `json:"remediationAdditional,omitempty"`
Validity string `json:"validity,omitempty"`
}
Loading

0 comments on commit e325358

Please sign in to comment.