mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
Update format output support to v2
This commit is contained in:
@@ -96,29 +96,6 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser
|
||||
brew install kubescape
|
||||
```
|
||||
|
||||
## Flags
|
||||
|
||||
| flag | default | description | options |
|
||||
|-----------------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
|
||||
| `-e`/`--exclude-namespaces` | Scan all namespaces | Namespaces to exclude from scanning. Recommended to exclude `kube-system` and `kube-public` namespaces | |
|
||||
| `--include-namespaces` | Scan all namespaces | Scan specific namespaces | |
|
||||
| `-s`/`--silent` | Display progress messages | Silent progress messages | |
|
||||
| `-t`/`--fail-threshold` | `100` (do not fail) | fail command (return exit code 1) if result is above threshold | `0` -> `100` |
|
||||
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit`/`prometheus`/`pdf` |
|
||||
| `-o`/`--output` | print to stdout | Save scan result in file | |
|
||||
| `--use-from` | | Load local framework object from specified path. If not used will download latest ||
|
||||
| `--use-artifacts-from` | | Load artifacts (frameworks, control-config, exceptions) from local directory. If not used will download them | |
|
||||
| `--use-default` | `false` | Load local framework object from default path. If not used will download latest | `true`/`false` |
|
||||
| `--exceptions` | | Path to an exceptions obj, [examples](https://github.com/armosec/kubescape/tree/master/examples/exceptions/README.md). Default will download exceptions from Kubescape SaaS ||
|
||||
| `--controls-config` | | Path to a controls-config obj. If not set will download controls-config from ARMO management portal. [docs](https://hub.armo.cloud/docs/configuration-parameters) | |
|
||||
| `--submit` | `false` | If set, Kubescape will 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 sent | `true`/`false` |
|
||||
| `--keep-local` | `false` | Kubescape will not send scan results to Armo management portal. Use this flag if you ran with the `--submit` flag in the past and you do not want to submit your current scan results | `true`/`false` |
|
||||
| `--account` | | Armo portal account ID. Default will load account ID from configMap or config file | |
|
||||
| `--kube-context` | current-context | Cluster context to scan | |
|
||||
| `--verbose` | `false` | Display all of the input resources and not only failed resources | `true`/`false` |
|
||||
| `--logger` | `info` | Set the logger level | `debug`/`info`/`success`/`warning`/`error`/`fatal` |
|
||||
|
||||
|
||||
## Usage & Examples
|
||||
|
||||
### Examples
|
||||
@@ -173,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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ======================================
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/armosec/kubescape/hostsensorutils"
|
||||
"github.com/armosec/kubescape/resourcehandler"
|
||||
"github.com/armosec/kubescape/resultshandling/reporter"
|
||||
reporterv1 "github.com/armosec/kubescape/resultshandling/reporter/v1"
|
||||
reporterv2 "github.com/armosec/kubescape/resultshandling/reporter/v2"
|
||||
|
||||
"github.com/armosec/opa-utils/reporthandling"
|
||||
@@ -51,10 +50,12 @@ func getRBACHandler(tenantConfig cautils.ITenantConfig, k8s *k8sinterface.Kubern
|
||||
|
||||
func getReporter(tenantConfig cautils.ITenantConfig, submit bool) reporter.IReport {
|
||||
if submit {
|
||||
// return reporterv1.NewReportEventReceiver(tenantConfig.GetConfigObj())
|
||||
return reporterv2.NewReportEventReceiver(tenantConfig.GetConfigObj())
|
||||
}
|
||||
return reporterv1.NewReportMock()
|
||||
if tenantConfig.GetAccountID() == "" {
|
||||
return reporterv2.NewReportMock(reporterv2.NO_SUBMIT_QUERY)
|
||||
}
|
||||
return reporterv2.NewReportMock("")
|
||||
}
|
||||
|
||||
func getResourceHandler(scanInfo *cautils.ScanInfo, tenantConfig cautils.ITenantConfig, k8s *k8sinterface.KubernetesApi, hostSensorHandler hostsensorutils.IHostSensor, registryAdaptors *resourcehandler.RegistryAdaptors) resourcehandler.IResourceHandler {
|
||||
|
||||
@@ -24,6 +24,7 @@ e.g. When a `kube-system` resource fails and it is ok, simply add the resource t
|
||||
* `controlID` - Control ID can be find [here](https://github.com/armosec/regolibrary/tree/master/controls) (regex supported)
|
||||
* `ruleName` - Rule names can be find [here](https://github.com/armosec/regolibrary/tree/master/rules) (regex supported)
|
||||
|
||||
You can find [here](https://github.com/armosec/kubescape/tree/master/examples/exceptions) some examples of exceptions files
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ func GetWriter(outputFile string) *os.File {
|
||||
f, err := os.OpenFile(outputFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
logger.L().Error(fmt.Sprintf("failed to open file for writing, reason: %s", err.Error()))
|
||||
return os.Stderr
|
||||
return os.Stdout
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
@@ -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,12 +4,16 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"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/kubescape/resultshandling/printer"
|
||||
"github.com/armosec/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/armosec/opa-utils/shared"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -99,183 +103,109 @@ 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, err := junitPrinter.convertPostureReportToJunitResult(opaSessionObj)
|
||||
if err != nil {
|
||||
logger.L().Fatal("failed to build xml result object", helpers.Error(err))
|
||||
}
|
||||
junitResult := testsSuites(opaSessionObj)
|
||||
postureReportStr, err := xml.Marshal(junitResult)
|
||||
if err != nil {
|
||||
logger.L().Fatal("failed to Marshal xml result object", helpers.Error(err))
|
||||
}
|
||||
|
||||
logOUtputFile(junitPrinter.writer.Name())
|
||||
|
||||
junitPrinter.writer.Write(postureReportStr)
|
||||
}
|
||||
|
||||
func (junitPrinter *JunitPrinter) convertPostureReportToJunitResult(results *cautils.OPASessionObj) (*JUnitTestSuites, error) {
|
||||
|
||||
// // Frameworks
|
||||
// for _, frameworksReports := range results.Report.ListFrameworks().All() {
|
||||
// fw := JUnitFrameworks{}
|
||||
// fw.Name = frameworksReports.GetName()
|
||||
// fw.RiskScore = frameworksReports.GetScore()
|
||||
// fw.Status = string(frameworksReports.GetStatus().Status())
|
||||
// juResult.Frameworks = append(juResult.Frameworks, fw)
|
||||
// }
|
||||
testSuites := JUnitTestSuites{
|
||||
XMLName: xml.Name{
|
||||
Local: "Kubescape scan results",
|
||||
},
|
||||
func testsSuites(results *cautils.OPASessionObj) *JUnitTestSuites {
|
||||
return &JUnitTestSuites{
|
||||
Suites: listTestsSuite(results),
|
||||
Tests: results.Report.SummaryDetails.NumberOfControls().All(),
|
||||
Name: "Kubescape Scanning",
|
||||
Failures: results.Report.SummaryDetails.NumberOfControls().Failed(),
|
||||
}
|
||||
testSuites.Failures = results.Report.SummaryDetails.NumberOfResources().Failed()
|
||||
testSuites.Tests = results.Report.SummaryDetails.NumberOfResources().All()
|
||||
testSuites.Disabled = results.Report.SummaryDetails.NumberOfResources().Skipped()
|
||||
// summary.errors =
|
||||
// summary.Name = "?"
|
||||
}
|
||||
func listTestsSuite(results *cautils.OPASessionObj) []JUnitTestSuite {
|
||||
var testSuites []JUnitTestSuite
|
||||
|
||||
// resources
|
||||
counter := 0
|
||||
for resourceID, resourceResult := range results.ResourcesResult {
|
||||
counter++
|
||||
|
||||
// resource data
|
||||
testSuite := JUnitTestSuite{
|
||||
XMLName: xml.Name{
|
||||
Local: resourceID,
|
||||
},
|
||||
}
|
||||
testSuite.Name = resourceID
|
||||
testSuite.Disabled = 0
|
||||
testSuite.Errors = 0
|
||||
testSuite.Failures = len(resourceResult.ListControlsIDs(nil).Failed())
|
||||
testSuite.Hostname = ""
|
||||
testSuite.ID = counter
|
||||
// testSuite.Skipped = ""
|
||||
testSuite.Time = ""
|
||||
testSuite.Timestamp = results.PostureReport.ReportGenerationTime.String()
|
||||
|
||||
testSuite.Properties = []JUnitProperty{
|
||||
{
|
||||
Name: "ID",
|
||||
Value: resourceID,
|
||||
},
|
||||
}
|
||||
|
||||
// controls
|
||||
for _, control := range resourceResult.ListControls() {
|
||||
testCase := JUnitTestCase{
|
||||
XMLName: xml.Name{
|
||||
Local: control.GetName(),
|
||||
Space: getControlURL(control.GetID()),
|
||||
},
|
||||
}
|
||||
testCase.Name = control.GetName()
|
||||
testCase.Classname = control.GetID()
|
||||
testCase.Status = string(control.GetStatus(nil).Status())
|
||||
|
||||
if control.GetStatus(nil).IsFailed() {
|
||||
paths := failedPathsToString(&control)
|
||||
|
||||
testCaseFailure := JUnitFailure{}
|
||||
testCaseFailure.Contents = fmt.Sprintf("More deatiles: %s", getControlURL(control.GetID()))
|
||||
testCaseFailure.Message = strings.Join(paths, ";")
|
||||
testCaseFailure.Type = "" // TODO - suppot add/modify
|
||||
|
||||
testCase.Failure = &testCaseFailure
|
||||
}
|
||||
|
||||
testSuite.TestCases = append(testSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
testSuites.Suites = append(testSuites.Suites, testSuite)
|
||||
// control scan
|
||||
if len(results.Report.SummaryDetails.ListFrameworks().All()) == 0 {
|
||||
testSuite := JUnitTestSuite{}
|
||||
testSuite.Failures = results.Report.SummaryDetails.NumberOfControls().Failed()
|
||||
testSuite.Timestamp = results.Report.ReportGenerationTime.String()
|
||||
testSuite.ID = 0
|
||||
testSuite.Name = "kubescape"
|
||||
testSuite.Properties = properties(results.Report.SummaryDetails.Score)
|
||||
testSuite.TestCases = testsCases(results, &results.Report.SummaryDetails.Controls, "Kubescape")
|
||||
testSuites = append(testSuites, testSuite)
|
||||
return testSuites
|
||||
}
|
||||
|
||||
return &testSuites, nil
|
||||
for i, f := range results.Report.SummaryDetails.Frameworks {
|
||||
testSuite := JUnitTestSuite{}
|
||||
testSuite.Failures = f.NumberOfControls().Failed()
|
||||
testSuite.Timestamp = results.Report.ReportGenerationTime.String()
|
||||
testSuite.ID = i
|
||||
testSuite.Name = f.Name
|
||||
testSuite.Properties = properties(f.Score)
|
||||
testSuite.TestCases = testsCases(results, f.ListControls(), f.GetName())
|
||||
testSuites = append(testSuites, testSuite)
|
||||
}
|
||||
|
||||
return testSuites
|
||||
}
|
||||
func testsCases(results *cautils.OPASessionObj, controls reportsummary.IControlsSummaries, classname string) []JUnitTestCase {
|
||||
var testCases []JUnitTestCase
|
||||
|
||||
for _, cID := range controls.ListControlsIDs().All() {
|
||||
testCase := JUnitTestCase{}
|
||||
control := results.Report.SummaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, cID)
|
||||
|
||||
testCase.Name = control.GetName()
|
||||
testCase.Classname = classname
|
||||
testCase.Status = string(control.GetStatus().Status())
|
||||
|
||||
if control.GetStatus().IsFailed() {
|
||||
resources := map[string]interface{}{}
|
||||
resourceIDs := control.ListResourcesIDs().Failed()
|
||||
for j := range resourceIDs {
|
||||
resource := results.AllResources[resourceIDs[j]]
|
||||
resources[resourceToString(resource)] = nil
|
||||
}
|
||||
resourcesStr := shared.MapStringToSlice(resources)
|
||||
sort.Strings(resourcesStr)
|
||||
testCaseFailure := JUnitFailure{}
|
||||
testCaseFailure.Type = "Control"
|
||||
// testCaseFailure.Contents =
|
||||
testCaseFailure.Message = fmt.Sprintf("Remediation: %s\nMore details: %s\n\n%s", control.GetRemediation(), getControlURL(control.GetID()), strings.Join(resourcesStr, "\n"))
|
||||
|
||||
testCase.Failure = &testCaseFailure
|
||||
} else if control.GetStatus().IsSkipped() {
|
||||
testCase.SkipMessage = &JUnitSkipMessage{
|
||||
Message: "", // TODO - fill after statusInfo is supportred
|
||||
}
|
||||
|
||||
}
|
||||
testCases = append(testCases, testCase)
|
||||
}
|
||||
return testCases
|
||||
}
|
||||
|
||||
// func (junitPrinter *JunitPrinter) convertPostureReportToJunitResult(results *cautils.OPASessionObj) (*JUnitTestSuites, error) {
|
||||
func resourceToString(resource workloadinterface.IMetadata) string {
|
||||
sep := "; "
|
||||
s := ""
|
||||
s += fmt.Sprintf("apiVersion: %s", resource.GetApiVersion()) + sep
|
||||
s += fmt.Sprintf("kind: %s", resource.GetKind()) + sep
|
||||
if resource.GetNamespace() != "" {
|
||||
s += fmt.Sprintf("namespace: %s", resource.GetNamespace()) + sep
|
||||
}
|
||||
s += fmt.Sprintf("name: %s", resource.GetName())
|
||||
return s
|
||||
}
|
||||
|
||||
// // // Frameworks
|
||||
// // for _, frameworksReports := range results.Report.ListFrameworks().All() {
|
||||
// // fw := JUnitFrameworks{}
|
||||
// // fw.Name = frameworksReports.GetName()
|
||||
// // fw.RiskScore = frameworksReports.GetScore()
|
||||
// // fw.Status = string(frameworksReports.GetStatus().Status())
|
||||
// // juResult.Frameworks = append(juResult.Frameworks, fw)
|
||||
// // }
|
||||
// testSuites := JUnitTestSuites{
|
||||
// XMLName: xml.Name{
|
||||
// Local: "Kubescape scan results",
|
||||
// },
|
||||
// }
|
||||
// testSuites.Failures = results.Report.SummaryDetails.NumberOfControls().Failed()
|
||||
// testSuites.Tests = results.Report.SummaryDetails.NumberOfControls().All()
|
||||
// testSuites.Disabled = results.Report.SummaryDetails.NumberOfControls().Skipped()
|
||||
// // summary.errors =
|
||||
// // summary.Name = "?"
|
||||
|
||||
// // controls
|
||||
// for _, controlIDs := range results.Report.ListControlsIDs().All() {
|
||||
// controlReport := results.Report.SummaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, controlIDs)
|
||||
|
||||
// // control data
|
||||
// testSuite := JUnitTestSuite{
|
||||
// XMLName: xml.Name{
|
||||
// Local: controlReport.GetName(),
|
||||
// Space: getControlURL(controlReport.GetID()),
|
||||
// },
|
||||
// }
|
||||
// testSuite.Name = controlReport.GetName()
|
||||
// testSuite.Disabled = 0
|
||||
// testSuite.Errors = 0
|
||||
// testSuite.Failures = controlReport.NumberOfResources().Failed()
|
||||
// testSuite.Hostname = ""
|
||||
// testSuite.ID = 0
|
||||
// // testSuite.Skipped = ""
|
||||
// testSuite.Time = ""
|
||||
// testSuite.Timestamp = ""
|
||||
|
||||
// testCase.Classname = controlReport.GetID()
|
||||
// testCase.Url = getControlURL(controlReport.GetID())
|
||||
// testCase.Name = controlReport.GetName()
|
||||
// testCase.Status = string(controlReport.GetStatus().Status())
|
||||
|
||||
// // resources counters
|
||||
// testCase.AllResources = controlReport.NumberOfResources().All()
|
||||
// testCase.Excluded = controlReport.NumberOfResources().Excluded()
|
||||
// testCase.Failed = controlReport.NumberOfResources().Failed()
|
||||
|
||||
// // resources
|
||||
// var jUnitResources []JUnitResource
|
||||
// for _, resourceID := range controlReport.ListResourcesIDs().All() {
|
||||
// result, ok := results.ResourcesResult[resourceID]
|
||||
// if !ok {
|
||||
// continue
|
||||
// }
|
||||
// if result.GetStatus(nil).IsPassed() && !junitPrinter.verbose { // add passed resources only in verbose mode
|
||||
// continue
|
||||
// }
|
||||
|
||||
// jUnitResource := JUnitResource{}
|
||||
// rules := result.ListRulesOfControl(controlReport.GetID(), "")
|
||||
// for _, rule := range rules {
|
||||
// jUnitResource.FailedPaths = append(jUnitResource.FailedPaths, rule.Paths...)
|
||||
// }
|
||||
// if resource, ok := results.AllResources[resourceID]; ok {
|
||||
// jUnitResource.Name = resource.GetName()
|
||||
// jUnitResource.Namespace = resource.GetNamespace()
|
||||
// jUnitResource.Kind = resource.GetKind()
|
||||
// jUnitResource.ApiVersion = resource.GetApiVersion()
|
||||
// }
|
||||
|
||||
// jUnitResources = append(jUnitResources, jUnitResource)
|
||||
// }
|
||||
// testCase.Resources = jUnitResources
|
||||
// juResult.Suites = append(juResult.Suites, testCase)
|
||||
// }
|
||||
|
||||
// return &juResult, nil
|
||||
// }
|
||||
func properties(riskScore float32) []JUnitProperty {
|
||||
return []JUnitProperty{
|
||||
{
|
||||
Name: "riskScore",
|
||||
Value: fmt.Sprintf("%.2f", riskScore),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
)
|
||||
|
||||
type ReportMock struct {
|
||||
}
|
||||
|
||||
func NewReportMock() *ReportMock {
|
||||
return &ReportMock{}
|
||||
}
|
||||
func (reportMock *ReportMock) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) SetCustomerGUID(customerGUID string) {
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) SetClusterName(clusterName string) {
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) DisplayReportURL() {
|
||||
message := fmt.Sprintf("\nScan results have not been submitted.\nYou 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 registering here: https://%s/cli-signup \n", getter.GetArmoAPIConnector().GetFrontendURL())
|
||||
cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n%s\n", message))
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/armosec/kubescape/cautils"
|
||||
"github.com/armosec/kubescape/cautils/getter"
|
||||
)
|
||||
|
||||
const NO_SUBMIT_QUERY = "utm_source=GitHub&utm_medium=CLI&utm_campaign=no_submit"
|
||||
|
||||
type ReportMock struct {
|
||||
query string
|
||||
}
|
||||
|
||||
func NewReportMock(query string) *ReportMock {
|
||||
return &ReportMock{
|
||||
query: query,
|
||||
}
|
||||
}
|
||||
func (reportMock *ReportMock) ActionSendReport(opaSessionObj *cautils.OPASessionObj) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) SetCustomerGUID(customerGUID string) {
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) SetClusterName(clusterName string) {
|
||||
}
|
||||
|
||||
func (reportMock *ReportMock) DisplayReportURL() {
|
||||
u := fmt.Sprintf("https://%s/account/login", getter.GetArmoAPIConnector().GetFrontendURL())
|
||||
if reportMock.query != "" {
|
||||
u += fmt.Sprintf("?%s", reportMock.query)
|
||||
}
|
||||
sep := "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
|
||||
message := sep + "\n"
|
||||
message += "Scan results have not been submitted." + "\n"
|
||||
message += "Sign up for free: "
|
||||
message += u + "\n"
|
||||
message += sep + "\n"
|
||||
cautils.InfoTextDisplay(os.Stderr, fmt.Sprintf("\n%s\n", message))
|
||||
}
|
||||
@@ -87,12 +87,6 @@ func (report *ReportEventReceiver) prepareReport(postureReport *reporthandlingv2
|
||||
if err := report.sendResources(host, postureReport, &reportCounter, false); err != nil {
|
||||
return err
|
||||
}
|
||||
// reportCounter++
|
||||
|
||||
// // send results
|
||||
// if err := report.sendResults(host, postureReport, &reportCounter, true); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -156,38 +150,6 @@ func (report *ReportEventReceiver) sendResources(host string, postureReport *rep
|
||||
return report.sendReport(host, splittedPostureReport, *reportCounter, true)
|
||||
}
|
||||
|
||||
// func (report *ReportEventReceiver) sendResults(host string, postureReport *reporthandlingv2.PostureReport, reportCounter *int, isLastReport bool) error {
|
||||
// splittedPostureReport := setSubReport(postureReport)
|
||||
// counter := 0
|
||||
|
||||
// for _, v := range postureReport.Results {
|
||||
// r, err := json.Marshal(v)
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("failed to unmarshal resource '%s', reason: %v", v.GetResourceID(), err)
|
||||
// }
|
||||
|
||||
// if counter+len(r) >= MAX_REPORT_SIZE && len(splittedPostureReport.Resources) > 0 {
|
||||
|
||||
// // send report
|
||||
// if err := report.sendReport(host, splittedPostureReport, *reportCounter, false); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// *reportCounter++
|
||||
|
||||
// // delete results
|
||||
// splittedPostureReport.Results = []resourcesresults.Result{}
|
||||
|
||||
// // restart counter
|
||||
// counter = 0
|
||||
// }
|
||||
|
||||
// counter += len(r)
|
||||
// splittedPostureReport.Results = append(splittedPostureReport.Results, v)
|
||||
// }
|
||||
|
||||
// return report.sendReport(host, splittedPostureReport, *reportCounter, isLastReport)
|
||||
// }
|
||||
|
||||
func (report *ReportEventReceiver) sendReport(host string, postureReport *reporthandlingv2.PostureReport, counter int, isLastReport bool) error {
|
||||
postureReport.PaginationInfo = reporthandlingv2.PaginationMarks{
|
||||
ReportNumber: counter,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user