Skip to content

Commit 2ad9fc9

Browse files
Implemented a new api for api-security result count
1 parent 1f26f40 commit 2ad9fc9

File tree

11 files changed

+309
-28
lines changed

11 files changed

+309
-28
lines changed

cmd/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func main() {
3737
results := viper.GetString(params.ResultsPathKey)
3838
scanSummary := viper.GetString(params.ScanSummaryPathKey)
3939
risksOverview := viper.GetString(params.RisksOverviewPathKey)
40+
apiSecurityResult := viper.GetString(params.APISecurityResultPathKey)
4041
riskManagement := viper.GetString(params.RiskManagementPathKey)
4142
scsScanOverview := viper.GetString(params.ScsScanOverviewPathKey)
4243
uploads := viper.GetString(params.UploadsPathKey)
@@ -69,7 +70,7 @@ func main() {
6970
uploadsWrapper := wrappers.NewUploadsHTTPWrapper(uploads)
7071
projectsWrapper := wrappers.NewHTTPProjectsWrapper(projects)
7172
applicationsWrapper := wrappers.NewApplicationsHTTPWrapper(applications)
72-
risksOverviewWrapper := wrappers.NewHTTPRisksOverviewWrapper(risksOverview)
73+
risksOverviewWrapper := wrappers.NewHTTPRisksOverviewWrapper(risksOverview, apiSecurityResult)
7374
riskManagementWrapper := wrappers.NewHTTPRiskManagementWrapper(riskManagement)
7475
scsScanOverviewWrapper := wrappers.NewHTTPScanOverviewWrapper(scsScanOverview)
7576
resultsWrapper := wrappers.NewHTTPResultsWrapper(results, scanSummary)

internal/commands/result.go

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -693,15 +693,24 @@ func summaryReport(
693693
scsScanOverviewWrapper wrappers.ScanOverviewWrapper,
694694
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
695695
results *wrappers.ScanResultsCollection,
696+
resultsParams map[string]string,
696697
) (*wrappers.ResultSummary, error) {
697698
if summary.HasAPISecurity() {
699+
apiSecFilterRisks, err := getFilterResultsForAPISecScanner(risksOverviewWrapper, summary.ScanID, resultsParams)
700+
if err != nil {
701+
return nil, err
702+
}
703+
if apiSecFilterRisks != nil {
704+
summary.APISecurity = *apiSecFilterRisks
705+
}
698706
apiSecRisks, err := getResultsForAPISecScanner(risksOverviewWrapper, summary.ScanID)
699707
if err != nil {
700708
return nil, err
701709
}
702-
summary.APISecurity = *apiSecRisks
710+
if apiSecRisks != nil {
711+
summary.APISecurity.APICount = apiSecRisks.APICount
712+
}
703713
}
704-
705714
if summary.HasSCS() {
706715
// Getting the base SCS overview. Results counts are overwritten in enhanceWithScanSummary->countResult
707716
SCSOverview, err := getScanOverviewForSCSScanner(scsScanOverviewWrapper, summary.ScanID)
@@ -770,13 +779,13 @@ func enhanceWithScanSummary(summary *wrappers.ResultSummary, results *wrappers.S
770779
flagResponse, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.CVSSV3Enabled)
771780
criticalEnabled := flagResponse.Status
772781
if summary.HasAPISecurity() {
773-
summary.EnginesResult[commonParams.APISecType].Low = summary.APISecurity.Risks[3]
774-
summary.EnginesResult[commonParams.APISecType].Medium = summary.APISecurity.Risks[2]
775-
summary.EnginesResult[commonParams.APISecType].High = summary.APISecurity.Risks[1]
782+
summary.EnginesResult[commonParams.APISecType].Low = summary.APISecurity.SeverityCount["low"]
783+
summary.EnginesResult[commonParams.APISecType].Medium = summary.APISecurity.SeverityCount["medium"]
784+
summary.EnginesResult[commonParams.APISecType].High = summary.APISecurity.SeverityCount["high"]
776785
if !criticalEnabled {
777786
summary.EnginesResult[commonParams.APISecType].Critical = notAvailableNumber
778787
} else {
779-
summary.EnginesResult[commonParams.APISecType].Critical = summary.APISecurity.Risks[0]
788+
summary.EnginesResult[commonParams.APISecType].Critical = summary.APISecurity.SeverityCount["critical"]
780789
}
781790
}
782791

@@ -1211,7 +1220,7 @@ func CreateScanReport(
12111220
}
12121221
isSummaryNeeded := verifyFormatsByReportList(reportList, summaryFormats...)
12131222
if isSummaryNeeded && !scanPending {
1214-
summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, scsScanOverviewWrapper, featureFlagsWrapper, results)
1223+
summary, err = summaryReport(summary, policyResponseModel, risksOverviewWrapper, scsScanOverviewWrapper, featureFlagsWrapper, results, resultsParams)
12151224
if err != nil {
12161225
return nil, err
12171226
}
@@ -2888,3 +2897,44 @@ func parseURI(summaryBaseURI string) (hostName string) {
28882897
func printWarningIfIgnorePolicyOmiited() {
28892898
fmt.Printf("\n Warning: The --ignore-policy flag was not implemented because you don’t have the required permission.\n Only users with 'override-policy-management' permission can use this flag. \n\n")
28902899
}
2900+
2901+
func getFilterResultsForAPISecScanner(risksOverviewWrapper wrappers.RisksOverviewWrapper, scanID string, resultsParams map[string]string) (aPISecSeveritySummary *wrappers.APISecFilteredResult, err error) {
2902+
var apiSecRiskEntriesResult wrappers.APISecRiskEntriesResult
2903+
var errorModel *wrappers.WebError
2904+
2905+
apiSecRiskEntriesResult, errorModel, err = risksOverviewWrapper.GetFilterResultForAPISecByScanID(scanID, resultsParams)
2906+
if err != nil {
2907+
return nil, errors.Wrapf(err, "%s", failedListingResults)
2908+
}
2909+
if errorModel != nil {
2910+
return nil, errors.Errorf("%s: CODE: %d, %s", failedListingResults, errorModel.Code, errorModel.Message)
2911+
}
2912+
if len(apiSecRiskEntriesResult.Entries) > 0 {
2913+
entries := apiSecRiskEntriesResult.Entries
2914+
severityCount := make(map[string]int)
2915+
originCount := make(map[string]int)
2916+
totalRecords := 0
2917+
for _, entry := range entries {
2918+
if isExploitable(entry.State) {
2919+
sev := strings.ToLower(entry.Severity)
2920+
severityCount[sev]++
2921+
orig := strings.ToLower(entry.Origin)
2922+
originCount[orig]++
2923+
totalRecords++
2924+
}
2925+
}
2926+
var riskDistribution []wrappers.RiskDistributionEntry
2927+
if originCount["code"] > 0 {
2928+
riskDistribution = append(riskDistribution, wrappers.RiskDistributionEntry{Origin: "code", Total: originCount["code"]})
2929+
}
2930+
if originCount["documentation"] > 0 {
2931+
riskDistribution = append(riskDistribution, wrappers.RiskDistributionEntry{Origin: "documentation", Total: originCount["documentation"]})
2932+
}
2933+
return &wrappers.APISecFilteredResult{
2934+
SeverityCount: severityCount,
2935+
RiskDistribution: riskDistribution,
2936+
TotalRisksCount: totalRecords,
2937+
}, nil
2938+
}
2939+
return nil, nil
2940+
}

internal/commands/result_test.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,11 +1278,10 @@ func createEmptyResultSummary() *wrappers.ResultSummary {
12781278
KicsIssues: 0,
12791279
ContainersIssues: containersIssues,
12801280
SCSOverview: &wrappers.SCSOverview{},
1281-
APISecurity: wrappers.APISecResult{
1281+
APISecurity: wrappers.APISecFilteredResult{
12821282
APICount: 0,
12831283
TotalRisksCount: 0,
1284-
Risks: []int{0, 0, 0, 0},
1285-
StatusCode: 0,
1284+
SeverityCount: map[string]int{"critical": 0, "high": 0, "medium": 0, "low": 0},
12861285
},
12871286
EnginesEnabled: []string{"sast", "sca", "kics", "containers"},
12881287
EnginesResult: wrappers.EnginesResultsSummary{
@@ -1702,3 +1701,42 @@ func extractURLFromDescription(description string) string {
17021701
}
17031702
return ""
17041703
}
1704+
1705+
func TestGetFilterResultsForAPISecScanner(t *testing.T) {
1706+
mockWrapper := mock.RisksOverviewMockWrapper{}
1707+
scanID := "test-scan-id"
1708+
resultsParams := map[string]string{}
1709+
1710+
result, err := getFilterResultsForAPISecScanner(mockWrapper, scanID, resultsParams)
1711+
assert.NilError(t, err)
1712+
assert.Assert(t, result == nil, "Expected nil result for empty entries")
1713+
1714+
mockEntries := []wrappers.APISecRiskEntry{
1715+
{Severity: "Critical", Origin: "code", State: "to_verify"},
1716+
{Severity: "High", Origin: "documentation", State: "to_verify"},
1717+
{Severity: "Medium", Origin: "code", State: "to_verify"},
1718+
{Severity: "Low", Origin: "documentation", State: "to_verify"},
1719+
{Severity: "Critical", Origin: "code", State: "not_exploitable"},
1720+
}
1721+
mockWrapperWithEntries := &mock.RisksOverviewMockWrapperWithEntries{Entries: mockEntries}
1722+
result, err = getFilterResultsForAPISecScanner(mockWrapperWithEntries, scanID, resultsParams)
1723+
assert.NilError(t, err)
1724+
assert.Assert(t, result != nil, "Expected non-nil result for entries")
1725+
if result == nil {
1726+
return
1727+
}
1728+
assert.Equal(t, result.SeverityCount["critical"], 1)
1729+
assert.Equal(t, result.SeverityCount["high"], 1)
1730+
assert.Equal(t, result.SeverityCount["medium"], 1)
1731+
assert.Equal(t, result.SeverityCount["low"], 1)
1732+
assert.Equal(t, result.TotalRisksCount, 4)
1733+
assert.Equal(t, len(result.RiskDistribution), 2)
1734+
for _, dist := range result.RiskDistribution {
1735+
if dist.Origin == "code" {
1736+
assert.Equal(t, dist.Total, 2)
1737+
}
1738+
if dist.Origin == "documentation" {
1739+
assert.Equal(t, dist.Total, 2)
1740+
}
1741+
}
1742+
}

internal/commands/scan.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2463,7 +2463,7 @@ func runCreateScanCommand(
24632463
return reportErr
24642464
}
24652465

2466-
err = applyThreshold(cmd, scanResponseModel, thresholdMap, risksOverviewWrapper, results)
2466+
err = applyThreshold(cmd, scanResponseModel, thresholdMap, risksOverviewWrapper, results, featureFlagsWrapper)
24672467

24682468
if err != nil {
24692469
return err
@@ -2731,6 +2731,7 @@ func applyThreshold(
27312731
thresholdMap map[string]int,
27322732
risksOverviewWrapper wrappers.RisksOverviewWrapper,
27332733
results *wrappers.ScanResultsCollection,
2734+
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
27342735
) error {
27352736
if len(thresholdMap) == 0 {
27362737
return nil
@@ -2742,7 +2743,11 @@ func applyThreshold(
27422743
params[commonParams.SastRedundancyFlag] = ""
27432744
}
27442745

2745-
summaryMap, err := getSummaryThresholdMap(scanResponseModel, risksOverviewWrapper, results)
2746+
resultsParams, err := getFilters(cmd)
2747+
if err != nil {
2748+
return err
2749+
}
2750+
summaryMap, err := getSummaryThresholdMap(scanResponseModel, risksOverviewWrapper, results, featureFlagsWrapper, resultsParams)
27462751

27472752
if err != nil {
27482753
return err
@@ -2830,6 +2835,8 @@ func getSummaryThresholdMap(
28302835
scan *wrappers.ScanResponseModel,
28312836
risksOverviewWrapper wrappers.RisksOverviewWrapper,
28322837
results *wrappers.ScanResultsCollection,
2838+
featureFlagsWrapper wrappers.FeatureFlagsWrapper,
2839+
resultsParam map[string]string,
28332840
) (map[string]int, error) {
28342841
summaryMap := make(map[string]int)
28352842

@@ -2841,13 +2848,21 @@ func getSummaryThresholdMap(
28412848
}
28422849

28432850
if slices.Contains(scan.Engines, commonParams.APISecType) {
2844-
apiSecRisks, err := getResultsForAPISecScanner(risksOverviewWrapper, scan.ID)
2851+
apiSecFilterRisks, err := getFilterResultsForAPISecScanner(risksOverviewWrapper, scan.ID, resultsParam)
28452852
if err != nil {
28462853
return nil, err
28472854
}
2848-
summaryMap["api-security-high"] = apiSecRisks.Risks[1]
2849-
summaryMap["api-security-medium"] = apiSecRisks.Risks[2]
2850-
summaryMap["api-security-low"] = apiSecRisks.Risks[3]
2855+
if apiSecFilterRisks != nil && apiSecFilterRisks.SeverityCount != nil {
2856+
summaryMap["api-security-high"] = apiSecFilterRisks.SeverityCount["high"]
2857+
summaryMap["api-security-medium"] = apiSecFilterRisks.SeverityCount["medium"]
2858+
summaryMap["api-security-low"] = apiSecFilterRisks.SeverityCount["low"]
2859+
2860+
flagResponse, _ := wrappers.GetSpecificFeatureFlag(featureFlagsWrapper, wrappers.CVSSV3Enabled)
2861+
criticalEnabled := flagResponse.Status
2862+
if criticalEnabled {
2863+
summaryMap["api-security-critical"] = apiSecFilterRisks.SeverityCount["critical"]
2864+
}
2865+
}
28512866
}
28522867
return summaryMap, nil
28532868
}

internal/params/binds.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var EnvVarsBinds = []struct {
2525
{ResultsPathKey, ResultsPathEnv, "api/results"},
2626
{ScanSummaryPathKey, ScanSummaryPathEnv, "api/scan-summary"},
2727
{RisksOverviewPathKey, RisksOverviewPathEnv, "api/apisec/static/api/scan/%s/risks-overview"},
28+
{APISecurityResultPathKey, APISecurityResultPathEnv, "api/apisec/static/api/risks"},
2829
{ScsScanOverviewPathKey, ScsScanOverviewPathEnv, "api/micro-engines/read/scans/%s/scan-overview"},
2930
{SastResultsPathKey, SastResultsPathEnv, "api/sast-results"},
3031
{SastResultsPredicatesPathKey, SastResultsPredicatesPathEnv, "api/sast-results-predicates"},

internal/params/envs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
ResultsPathEnv = "CX_RESULTS_PATH"
3131
ScanSummaryPathEnv = "CX_SCAN_SUMMARY_PATH"
3232
RisksOverviewPathEnv = "CX_RISKS_OVERVIEW_PATH"
33+
APISecurityResultPathEnv = "API_SECURITY_RESULT_PATH"
3334
ScsScanOverviewPathEnv = "CX_SCS_SCAN_OVERVIEW_PATH"
3435
SastResultsPathEnv = "CX_SAST_RESULTS_PATH"
3536
SastResultsPredicatesPathEnv = "CX_SAST_RESULTS_PREDICATES_PATH"

internal/params/keys.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var (
2929
ResultsPathKey = strings.ToLower(ResultsPathEnv)
3030
ScanSummaryPathKey = strings.ToLower(ScanSummaryPathEnv)
3131
RisksOverviewPathKey = strings.ToLower(RisksOverviewPathEnv)
32+
APISecurityResultPathKey = strings.ToLower(APISecurityResultPathEnv)
3233
ScsScanOverviewPathKey = strings.ToLower(ScsScanOverviewPathEnv)
3334
SastResultsPathKey = strings.ToLower(SastResultsPathEnv)
3435
KicsResultsPathKey = strings.ToLower(KicsResultsPathEnv)

internal/wrappers/mock/risks-overview-mock.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,25 @@ func (r RisksOverviewMockWrapper) GetAllAPISecRisksByScanID(scanID string) (
1515
Risks: []int{},
1616
}, nil, nil
1717
}
18+
func (r RisksOverviewMockWrapper) GetFilterResultForAPISecByScanID(scanID string, queryParam map[string]string) (wrappers.APISecRiskEntriesResult, *wrappers.WebError, error) {
19+
return wrappers.APISecRiskEntriesResult{
20+
Entries: []wrappers.APISecRiskEntry{},
21+
}, nil, nil
22+
}
23+
24+
type RisksOverviewMockWrapperWithEntries struct {
25+
Entries []wrappers.APISecRiskEntry
26+
}
27+
28+
func (r *RisksOverviewMockWrapperWithEntries) GetFilterResultForAPISecByScanID(scanID string, queryParam map[string]string) (wrappers.APISecRiskEntriesResult, *wrappers.WebError, error) {
29+
return wrappers.APISecRiskEntriesResult{
30+
Entries: r.Entries,
31+
}, nil, nil
32+
}
33+
func (r RisksOverviewMockWrapperWithEntries) GetAllAPISecRisksByScanID(scanID string) (
34+
*wrappers.APISecResult,
35+
*wrappers.WebError,
36+
error,
37+
) {
38+
return &wrappers.APISecResult{}, nil, nil
39+
}

internal/wrappers/results-summary.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type ResultSummary struct {
2020
ContainersIssues *int `json:"ContainersIssues,omitempty"`
2121
ScsIssues *int `json:"ScsIssues,omitempty"`
2222
SCSOverview *SCSOverview `json:"ScsOverview,omitempty"`
23-
APISecurity APISecResult
23+
APISecurity APISecFilteredResult
2424
RiskStyle string
2525
RiskMsg string
2626
Status string
@@ -41,14 +41,20 @@ type ResultSummary struct {
4141

4242
// nolint: govet
4343
type APISecResult struct {
44-
APICount int `json:"api_count,omitempty"`
45-
TotalRisksCount int `json:"total_risks_count,omitempty"`
46-
Risks []int `json:"risks,omitempty"`
47-
RiskDistribution []riskDistribution `json:"risk_distribution,omitempty"`
44+
APICount int `json:"api_count,omitempty"`
45+
TotalRisksCount int `json:"total_risks_count,omitempty"`
46+
Risks []int `json:"risks,omitempty"`
47+
RiskDistribution []RiskDistributionEntry `json:"risk_distribution,omitempty"`
4848
StatusCode int
4949
}
5050

51-
type riskDistribution struct {
51+
type APISecFilteredResult struct {
52+
SeverityCount map[string]int
53+
TotalRisksCount int
54+
RiskDistribution []RiskDistributionEntry
55+
APICount int
56+
}
57+
type RiskDistributionEntry struct {
5258
Origin string `json:"origin,omitempty"`
5359
Total int `json:"total,omitempty"`
5460
}
@@ -166,7 +172,7 @@ func (r *ResultSummary) SCSIssuesValue() int {
166172
return *r.ScsIssues
167173
}
168174

169-
func (r *ResultSummary) getRiskFromAPISecurity(origin string) *riskDistribution {
175+
func (r *ResultSummary) getRiskFromAPISecurity(origin string) *RiskDistributionEntry {
170176
for _, risk := range r.APISecurity.RiskDistribution {
171177
if strings.EqualFold(risk.Origin, origin) {
172178
return &risk

0 commit comments

Comments
 (0)