mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-14 18:09:55 +00:00
Add severity field to controls in JSON output
Co-authored-by: matthyx <20683409+matthyx@users.noreply.github.com>
This commit is contained in:
@@ -120,7 +120,11 @@ func printConfigurationsScanning(opaSessionObj *cautils.OPASessionObj, imageScan
|
||||
opaSessionObj.Report.SummaryDetails.Vulnerabilities.Images = imageScanSummary.Images
|
||||
}
|
||||
|
||||
r, err := json.Marshal(FinalizeResults(opaSessionObj))
|
||||
// Convert to PostureReportWithSeverity to add severity field to controls
|
||||
finalizedReport := FinalizeResults(opaSessionObj)
|
||||
reportWithSeverity := ConvertToPostureReportWithSeverity(finalizedReport)
|
||||
|
||||
r, err := json.Marshal(reportWithSeverity)
|
||||
_, err = jp.writer.Write(r)
|
||||
|
||||
return err
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -192,3 +193,85 @@ func TestConvertToReportSummary(t *testing.T) {
|
||||
|
||||
assert.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestEnrichControlsWithSeverity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
scoreFactor float32
|
||||
wantSeverity string
|
||||
}{
|
||||
{
|
||||
name: "Critical severity",
|
||||
scoreFactor: 9.0,
|
||||
wantSeverity: "Critical",
|
||||
},
|
||||
{
|
||||
name: "High severity",
|
||||
scoreFactor: 8.0,
|
||||
wantSeverity: "High",
|
||||
},
|
||||
{
|
||||
name: "Medium severity",
|
||||
scoreFactor: 6.0,
|
||||
wantSeverity: "Medium",
|
||||
},
|
||||
{
|
||||
name: "Low severity",
|
||||
scoreFactor: 3.0,
|
||||
wantSeverity: "Low",
|
||||
},
|
||||
{
|
||||
name: "Unknown severity",
|
||||
scoreFactor: 0.0,
|
||||
wantSeverity: "Unknown",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controls := reportsummary.ControlSummaries{
|
||||
"C-0001": reportsummary.ControlSummary{
|
||||
ControlID: "C-0001",
|
||||
Name: "Test Control",
|
||||
ScoreFactor: tt.scoreFactor,
|
||||
},
|
||||
}
|
||||
|
||||
enrichedControls := enrichControlsWithSeverity(controls)
|
||||
|
||||
assert.Equal(t, 1, len(enrichedControls))
|
||||
assert.Equal(t, tt.wantSeverity, enrichedControls["C-0001"].Severity)
|
||||
assert.Equal(t, "Test Control", enrichedControls["C-0001"].Name)
|
||||
assert.Equal(t, tt.scoreFactor, enrichedControls["C-0001"].ScoreFactor)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToPostureReportWithSeverity(t *testing.T) {
|
||||
// Create a mock PostureReport with controls having different severity levels
|
||||
mockReport := reportsummary.MockSummaryDetails()
|
||||
|
||||
// Get the controls from mock data
|
||||
controls := mockReport.Controls
|
||||
|
||||
// Create a minimal PostureReport
|
||||
report := &reporthandlingv2.PostureReport{
|
||||
SummaryDetails: *mockReport,
|
||||
}
|
||||
|
||||
// Convert to PostureReportWithSeverity
|
||||
reportWithSeverity := ConvertToPostureReportWithSeverity(report)
|
||||
|
||||
// Verify controls have severity field
|
||||
assert.NotNil(t, reportWithSeverity)
|
||||
assert.NotNil(t, reportWithSeverity.SummaryDetails.Controls)
|
||||
|
||||
// Verify each control in the original report has a corresponding enriched control with severity
|
||||
for controlID, control := range controls {
|
||||
enrichedControl, exists := reportWithSeverity.SummaryDetails.Controls[controlID]
|
||||
assert.True(t, exists, "Control %s should exist in enriched controls", controlID)
|
||||
assert.NotEmpty(t, enrichedControl.Severity, "Severity should not be empty for control %s", controlID)
|
||||
assert.Equal(t, control.ControlID, enrichedControl.ControlID, "Control ID should match")
|
||||
assert.Equal(t, control.ScoreFactor, enrichedControl.ScoreFactor, "ScoreFactor should match")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
@@ -16,6 +17,80 @@ import (
|
||||
|
||||
const indicator = "†"
|
||||
|
||||
// ControlSummaryWithSeverity wraps ControlSummary to add severity field for JSON output
|
||||
type ControlSummaryWithSeverity struct {
|
||||
reportsummary.ControlSummary
|
||||
Severity string `json:"severity"`
|
||||
}
|
||||
|
||||
// SummaryDetailsWithSeverity wraps SummaryDetails to include enriched controls
|
||||
type SummaryDetailsWithSeverity struct {
|
||||
Controls map[string]ControlSummaryWithSeverity `json:"controls,omitempty"`
|
||||
Status apis.ScanningStatus `json:"status"`
|
||||
Frameworks []reportsummary.FrameworkSummary `json:"frameworks"`
|
||||
ResourcesSeverityCounters reportsummary.SeverityCounters `json:"resourcesSeverityCounters,omitempty"`
|
||||
ControlsSeverityCounters reportsummary.SeverityCounters `json:"controlsSeverityCounters,omitempty"`
|
||||
StatusCounters reportsummary.StatusCounters `json:"ResourceCounters"`
|
||||
Vulnerabilities reportsummary.VulnerabilitySummary `json:"vulnerabilities,omitempty"`
|
||||
Score float32 `json:"score"`
|
||||
ComplianceScore float32 `json:"complianceScore"`
|
||||
}
|
||||
|
||||
// PostureReportWithSeverity wraps PostureReport to include severity in controls
|
||||
type PostureReportWithSeverity struct {
|
||||
ReportGenerationTime string `json:"generationTime"`
|
||||
ClusterAPIServerInfo interface{} `json:"clusterAPIServerInfo"`
|
||||
ClusterCloudProvider string `json:"clusterCloudProvider"`
|
||||
CustomerGUID string `json:"customerGUID"`
|
||||
ClusterName string `json:"clusterName"`
|
||||
SummaryDetails SummaryDetailsWithSeverity `json:"summaryDetails,omitempty"`
|
||||
Resources []reporthandling.Resource `json:"resources,omitempty"`
|
||||
Attributes []reportsummary.PostureAttributes `json:"attributes"`
|
||||
Results []resourcesresults.Result `json:"results,omitempty"`
|
||||
Metadata reporthandlingv2.Metadata `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// enrichControlsWithSeverity adds severity field to controls based on scoreFactor
|
||||
func enrichControlsWithSeverity(controls reportsummary.ControlSummaries) map[string]ControlSummaryWithSeverity {
|
||||
enrichedControls := make(map[string]ControlSummaryWithSeverity)
|
||||
for controlID, control := range controls {
|
||||
enrichedControl := ControlSummaryWithSeverity{
|
||||
ControlSummary: control,
|
||||
Severity: apis.ControlSeverityToString(control.GetScoreFactor()),
|
||||
}
|
||||
enrichedControls[controlID] = enrichedControl
|
||||
}
|
||||
return enrichedControls
|
||||
}
|
||||
|
||||
// ConvertToPostureReportWithSeverity converts PostureReport to PostureReportWithSeverity
|
||||
func ConvertToPostureReportWithSeverity(report *reporthandlingv2.PostureReport) *PostureReportWithSeverity {
|
||||
enrichedControls := enrichControlsWithSeverity(report.SummaryDetails.Controls)
|
||||
|
||||
return &PostureReportWithSeverity{
|
||||
ReportGenerationTime: report.ReportGenerationTime.Format("2006-01-02T15:04:05Z07:00"),
|
||||
ClusterAPIServerInfo: report.ClusterAPIServerInfo,
|
||||
ClusterCloudProvider: report.ClusterCloudProvider,
|
||||
CustomerGUID: report.CustomerGUID,
|
||||
ClusterName: report.ClusterName,
|
||||
SummaryDetails: SummaryDetailsWithSeverity{
|
||||
Controls: enrichedControls,
|
||||
Status: report.SummaryDetails.Status,
|
||||
Frameworks: report.SummaryDetails.Frameworks,
|
||||
ResourcesSeverityCounters: report.SummaryDetails.ResourcesSeverityCounters,
|
||||
ControlsSeverityCounters: report.SummaryDetails.ControlsSeverityCounters,
|
||||
StatusCounters: report.SummaryDetails.StatusCounters,
|
||||
Vulnerabilities: report.SummaryDetails.Vulnerabilities,
|
||||
Score: report.SummaryDetails.Score,
|
||||
ComplianceScore: report.SummaryDetails.ComplianceScore,
|
||||
},
|
||||
Resources: report.Resources,
|
||||
Attributes: report.Attributes,
|
||||
Results: report.Results,
|
||||
Metadata: report.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
// FinalizeResults finalize the results objects by copying data from map to lists
|
||||
func FinalizeResults(data *cautils.OPASessionObj) *reporthandlingv2.PostureReport {
|
||||
report := reporthandlingv2.PostureReport{
|
||||
|
||||
Reference in New Issue
Block a user