json v2 support

This commit is contained in:
dwertent
2022-03-03 13:05:36 +02:00
parent cda9bb0e45
commit ec30ed8439
10 changed files with 73 additions and 32 deletions
+1 -1
View File
@@ -150,7 +150,7 @@ kubescape scan --verbose
#### Output in `json` format
```
kubescape scan --format json --output results.json
kubescape scan --format json --format-version v2 --output results.json
```
#### Output in `junit xml` format
+1 -1
View File
@@ -68,7 +68,7 @@ type ScanInfo struct {
VerboseMode bool // Display all of the input resources and not only failed resources
Format string // Format results (table, json, junit ...)
Output string // Store results in an output file, Output file name
OutputVersion string // Output object can be differnet between versions, this is for testing and backward compatibility
FormatVersion string // Output object can be differnet between versions, this is for testing and backward compatibility
ExcludedNamespaces string // used for host sensor namespace
IncludeNamespaces string // DEPRECATED?
InputPatterns []string // Yaml files input patterns
+2 -2
View File
@@ -79,12 +79,12 @@ func init() {
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "Silent progress messages")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Submit, "submit", "", false, "Send the scan results to Armo management portal where you can see the results in a user-friendly UI, choose your preferred compliance framework, check risk results history and trends, manage exceptions, get remediation recommendations and much more. By default the results are not submitted")
scanCmd.PersistentFlags().StringVar(&scanInfo.HostSensorYamlPath, "host-scan-yaml", "", "Override default host sensor DaemonSet. Use this flag cautiously")
scanCmd.PersistentFlags().StringVar(&scanInfo.OutputVersion, "output-version", "v1", "Output object can be differnet between versions, this is for testing and backward compatibility")
scanCmd.PersistentFlags().StringVar(&scanInfo.FormatVersion, "format-version", "v1", "Output object can be differnet between versions, this is for testing and backward compatibility")
// hidden flags
scanCmd.PersistentFlags().MarkHidden("host-scan-yaml") // this flag should be used very cautiously. We prefer users will not use it at all unless the DaemoSet can not run pods on the nodes
scanCmd.PersistentFlags().MarkHidden("silent") // this flag should be deprecated since we added the --logger support
scanCmd.PersistentFlags().MarkHidden("output-version") // meant for testing different output approaches and not for common use
scanCmd.PersistentFlags().MarkHidden("format-version") // meant for testing different output approaches and not for common use
hostF := scanCmd.PersistentFlags().VarPF(&scanInfo.HostSensorEnabled, "enable-host-scan", "", "Deploy ARMO K8s host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data. Required to collect valueable data from cluster nodes for certain controls. Yaml file: https://raw.githubusercontent.com/armosec/kubescape/master/hostsensorutils/hostsensor.yaml")
hostF.NoOptDefVal = "true"
+1 -1
View File
@@ -83,7 +83,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
reportHandler := getReporter(tenantConfig, scanInfo.Submit)
// setup printer
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.OutputVersion, scanInfo.VerboseMode)
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.FormatVersion, scanInfo.VerboseMode)
printerHandler.SetWriter(scanInfo.Output)
// ================== return interface ======================================
+36
View File
@@ -0,0 +1,36 @@
package v2
import (
"encoding/json"
"fmt"
"os"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/resultshandling/printer"
)
type JsonPrinter struct {
writer *os.File
}
func NewJsonPrinter() *JsonPrinter {
return &JsonPrinter{}
}
func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) {
jsonPrinter.writer = printer.GetWriter(outputFile)
}
func (jsonPrinter *JsonPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
}
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
finalizeJson(opaSessionObj)
r, err := json.Marshal(opaSessionObj.Report)
if err != nil {
logger.L().Fatal("failed to Marshal posture report object")
}
jsonPrinter.writer.Write(r)
}
-4
View File
@@ -103,10 +103,6 @@ func (junitPrinter *JunitPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", int(score))
}
func (junitPrinter *JunitPrinter) FinalizeData(opaSessionObj *cautils.OPASessionObj) {
finalizeReport(opaSessionObj)
}
func (junitPrinter *JunitPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
junitResult := testsSuites(opaSessionObj)
postureReportStr, err := xml.Marshal(junitResult)
+8 -9
View File
@@ -17,24 +17,27 @@ import (
)
type PrettyPrinter struct {
outputVersion string
formatVersion string
writer *os.File
verboseMode bool
sortedControlNames []string
}
func NewPrettyPrinter(verboseMode bool, outputVersion string) *PrettyPrinter {
func NewPrettyPrinter(verboseMode bool, formatVersion string) *PrettyPrinter {
return &PrettyPrinter{
verboseMode: verboseMode,
outputVersion: outputVersion,
formatVersion: formatVersion,
}
}
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
prettyPrinter.sortedControlNames = getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
prettyPrinter.resourceTable(opaSessionObj.ResourcesResult, opaSessionObj.AllResources)
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources)
if prettyPrinter.formatVersion == "v1" {
prettyPrinter.resourceTable(opaSessionObj.ResourcesResult, opaSessionObj.AllResources)
} else if prettyPrinter.formatVersion == "v2" {
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources)
}
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails)
}
@@ -47,10 +50,6 @@ func (prettyPrinter *PrettyPrinter) Score(score float32) {
}
func (prettyPrinter *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata) {
if prettyPrinter.outputVersion != "v1" {
return
}
for i := 0; i < len(prettyPrinter.sortedControlNames); i++ {
controlSummary := controls.GetControl(reportsummary.EControlCriteriaName, prettyPrinter.sortedControlNames[i]) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
+1 -3
View File
@@ -11,9 +11,7 @@ import (
)
func (prettyPrinter *PrettyPrinter) resourceTable(results map[string]resourcesresults.Result, allResources map[string]workloadinterface.IMetadata) {
if prettyPrinter.outputVersion != "v2" {
return
}
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
summaryTable.SetAutoWrapText(true)
summaryTable.SetAutoMergeCells(true)
+15 -8
View File
@@ -3,22 +3,22 @@ package v2
import (
"github.com/armosec/k8s-interface/workloadinterface"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/logger"
"github.com/armosec/kubescape/cautils/logger/helpers"
"github.com/armosec/opa-utils/reporthandling"
"github.com/armosec/opa-utils/reporthandling/results/v1/resourcesresults"
)
// finalizeV2Report finalize the results objects by copying data from map to lists
func finalizeReport(opaSessionObj *cautils.OPASessionObj) {
func finalizeJson(opaSessionObj *cautils.OPASessionObj) {
if len(opaSessionObj.Report.Results) == 0 {
opaSessionObj.Report.Results = make([]resourcesresults.Result, len(opaSessionObj.ResourcesResult))
finalizeResults(opaSessionObj.Report.Results, opaSessionObj.ResourcesResult)
opaSessionObj.ResourcesResult = nil
}
if len(opaSessionObj.Report.Resources) == 0 {
opaSessionObj.Report.Resources = make([]reporthandling.Resource, len(opaSessionObj.AllResources))
finalizeResources(opaSessionObj.Report.Resources, opaSessionObj.AllResources)
opaSessionObj.AllResources = nil
finalizeResources(opaSessionObj.Report.Resources, opaSessionObj.Report.Results, opaSessionObj.AllResources)
}
}
@@ -30,15 +30,22 @@ func finalizeResults(results []resourcesresults.Result, resourcesResult map[stri
}
}
func finalizeResources(resources []reporthandling.Resource, allResources map[string]workloadinterface.IMetadata) {
func finalizeResources(resources []reporthandling.Resource, results []resourcesresults.Result, allResources map[string]workloadinterface.IMetadata) {
index := 0
for resourceID := range allResources {
if obj, ok := allResources[resourceID]; ok {
for i := range results {
if obj, ok := allResources[results[i].ResourceID]; ok {
r := *reporthandling.NewResource(obj.GetObject())
r.ResourceID = resourceID
r.ResourceID = results[i].ResourceID
resources[index] = r
}
index++
}
}
func logOUtputFile(fileName string) {
if fileName != "/dev/stdout" && fileName != "/dev/stderr" {
logger.L().Success("Scan results saved", helpers.String("filename", fileName))
}
}
+8 -3
View File
@@ -53,11 +53,16 @@ func CalculatePostureScore(postureReport *reporthandling.PostureReport) float32
return (float32(len(allResources)) - float32(len(failedResources))) / float32(len(allResources))
}
func NewPrinter(printFormat, outputVersion string, verboseMode bool) printer.IPrinter {
func NewPrinter(printFormat, formatVersion string, verboseMode bool) printer.IPrinter {
switch printFormat {
case printer.JsonFormat:
return printerv1.NewJsonPrinter()
switch formatVersion {
case "v2":
return printerv2.NewJsonPrinter()
default:
return printerv1.NewJsonPrinter()
}
case printer.JunitResultFormat:
return printerv2.NewJunitPrinter(verboseMode)
case printer.PrometheusFormat:
@@ -65,6 +70,6 @@ func NewPrinter(printFormat, outputVersion string, verboseMode bool) printer.IPr
case printer.PdfFormat:
return printerv2.NewPdfPrinter()
default:
return printerv2.NewPrettyPrinter(verboseMode, outputVersion)
return printerv2.NewPrettyPrinter(verboseMode, formatVersion)
}
}