Update format output support to v2

This commit is contained in:
David Wertenteil
2022-03-03 13:24:45 +02:00
committed by GitHub
16 changed files with 218 additions and 288 deletions
+1 -24
View File
@@ -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
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 ======================================
+4 -3
View File
@@ -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 {
+1
View File
@@ -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
+1 -1
View File
@@ -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
}
+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)
}
+95 -165
View File
@@ -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),
},
}
}
+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))
}
}
@@ -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,
+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)
}
}