Merge remote-tracking branch 'upstream/dev'

This commit is contained in:
dwertent
2021-10-28 09:40:26 +03:00
12 changed files with 252 additions and 114 deletions
+6 -2
View File
@@ -129,7 +129,7 @@ func (c *EmptyConfig) GetCustomerGUID() string { return "" }
func (c *EmptyConfig) GetK8sAPI() *k8sinterface.KubernetesApi { return nil } // TODO: return mock obj
func (c *EmptyConfig) GetDefaultNS() string { return k8sinterface.GetDefaultNamespace() }
func (c *EmptyConfig) GetBackendAPI() getter.IBackend { return nil } // TODO: return mock obj
func (c *EmptyConfig) GetClusterName() string { return k8sinterface.GetClusterName() }
func (c *EmptyConfig) GetClusterName() string { return adoptClusterName(k8sinterface.GetClusterName()) }
func (c *EmptyConfig) GenerateURL() {
message := fmt.Sprintf("\nCheckout for more cool features: https://%s\n", getter.GetArmoAPIConnector().GetFrontendURL())
InfoTextDisplay(os.Stdout, fmt.Sprintf("\n%s\n", message))
@@ -243,7 +243,7 @@ func (c *ClusterConfig) setCustomerGUID(customerGUID string) {
}
func (c *ClusterConfig) setClusterName(clusterName string) {
c.configObj.ClusterName = clusterName
c.configObj.ClusterName = adoptClusterName(clusterName)
}
func (c *ClusterConfig) GetClusterName() string {
return c.configObj.ClusterName
@@ -472,3 +472,7 @@ func DeleteConfigMap(k8s *k8sinterface.KubernetesApi) error {
func DeleteConfigFile() error {
return os.Remove(ConfigFileFullPath())
}
func adoptClusterName(clusterName string) string {
return strings.ReplaceAll(clusterName, "/", "-")
}
+39 -16
View File
@@ -17,12 +17,12 @@ const DefaultLocalStore = ".kubescape"
// Load policies from a local repository
type LoadPolicy struct {
filePath string
filePaths []string
}
func NewLoadPolicy(filePath string) *LoadPolicy {
func NewLoadPolicy(filePaths []string) *LoadPolicy {
return &LoadPolicy{
filePath: filePath,
filePaths: filePaths,
}
}
@@ -30,7 +30,8 @@ func NewLoadPolicy(filePath string) *LoadPolicy {
func (lp *LoadPolicy) GetControl(controlName string) (*reporthandling.Control, error) {
control := &reporthandling.Control{}
f, err := os.ReadFile(lp.filePath)
filePath := lp.getFileForControl()
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
@@ -38,35 +39,49 @@ func (lp *LoadPolicy) GetControl(controlName string) (*reporthandling.Control, e
if err = json.Unmarshal(f, control); err != nil {
return control, err
}
if controlName != "" && !strings.EqualFold(controlName, control.Name) && !strings.EqualFold(controlName, control.ControlID) {
return nil, fmt.Errorf("control from file not matching")
framework, err := lp.GetFramework(controlName)
if err != nil {
return nil, fmt.Errorf("control from file not matching")
} else {
for _, ctrl := range framework.Controls {
if strings.EqualFold(ctrl.Name, controlName) || strings.EqualFold(ctrl.ControlID, controlName) {
control = &ctrl
break
}
}
}
}
return control, err
}
func (lp *LoadPolicy) GetFramework(frameworkName string) (*reporthandling.Framework, error) {
framework := &reporthandling.Framework{}
f, err := os.ReadFile(lp.filePath)
if err != nil {
return nil, err
}
var err error
for _, filePath := range lp.filePaths {
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
if err = json.Unmarshal(f, framework); err != nil {
return framework, err
if err = json.Unmarshal(f, framework); err != nil {
return framework, err
}
if strings.EqualFold(frameworkName, framework.Name) {
break
}
}
if frameworkName != "" && !strings.EqualFold(frameworkName, framework.Name) {
return nil, fmt.Errorf("framework from file not matching")
}
return framework, err
}
func (lp *LoadPolicy) GetExceptions(customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
filePath := lp.getFileForException()
exception := []armotypes.PostureExceptionPolicy{}
f, err := os.ReadFile(lp.filePath)
f, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
@@ -74,3 +89,11 @@ func (lp *LoadPolicy) GetExceptions(customerGUID, clusterName string) ([]armotyp
err = json.Unmarshal(f, &exception)
return exception, err
}
func (lp *LoadPolicy) getFileForException() string {
return lp.filePaths[0]
}
func (lp *LoadPolicy) getFileForControl() string {
return lp.filePaths[0]
}
+7 -8
View File
@@ -9,9 +9,9 @@ import (
type ScanInfo struct {
Getters
PolicyIdentifier reporthandling.PolicyIdentifier
PolicyIdentifier []reporthandling.PolicyIdentifier
UseExceptions string // Load exceptions configuration
UseFrom string // Load framework from local file (instead of download). Use when running offline
UseFrom []string // Load framework from local file (instead of download). Use when running offline
UseDefault bool // Load framework from cached file (instead of download). Use when running offline
Format string // Format results (table, json, junit ...)
Output string // Store results in an output file, Output file name
@@ -41,22 +41,21 @@ func (scanInfo *ScanInfo) Init() {
func (scanInfo *ScanInfo) setUseExceptions() {
if scanInfo.UseExceptions != "" {
// load exceptions from file
scanInfo.ExceptionsGetter = getter.NewLoadPolicy(scanInfo.UseExceptions)
scanInfo.ExceptionsGetter = getter.NewLoadPolicy([]string{scanInfo.UseExceptions})
} else {
scanInfo.ExceptionsGetter = getter.GetArmoAPIConnector()
}
}
func (scanInfo *ScanInfo) setUseFrom() {
if scanInfo.UseFrom != "" {
return
}
if scanInfo.UseDefault {
scanInfo.UseFrom = getter.GetDefaultPath(scanInfo.PolicyIdentifier.Name + ".json")
for _, policy := range scanInfo.PolicyIdentifier {
scanInfo.UseFrom = append(scanInfo.UseFrom, getter.GetDefaultPath(policy.Name+".json"))
}
}
}
func (scanInfo *ScanInfo) setGetter() {
if scanInfo.UseFrom != "" {
if len(scanInfo.UseFrom) > 0 {
// load from file
scanInfo.PolicyGetter = getter.NewLoadPolicy(scanInfo.UseFrom)
} else {
+44 -7
View File
@@ -13,22 +13,40 @@ import (
// controlCmd represents the control command
var controlCmd = &cobra.Command{
Use: "control <control name>/<control id>",
Use: "control <control names list>/<control ids list>.\nExamples:\n$ kubescape scan control C-0058,C-0057 [flags]\n$ kubescape scan contol C-0058 [flags]\n$ kubescape scan control 'privileged container,allowed hostpath' [flags]",
Short: fmt.Sprintf("The control you wish to use for scan. It must be present in at least one of the folloiwng frameworks: %s", clihandler.ValidFrameworks),
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 && !(cmd.Flags().Lookup("use-from").Changed) {
return fmt.Errorf("requires at least one argument")
if len(args) > 0 {
controls := strings.Split(args[0], ",")
if len(controls) > 1 {
if controls[1] == "" {
return fmt.Errorf("usage: <control_one>,<control_two>")
}
}
} else {
return fmt.Errorf("requires at least one control name")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
flagValidationControl()
scanInfo.PolicyIdentifier = reporthandling.PolicyIdentifier{}
if !(cmd.Flags().Lookup("use-from").Changed) {
scanInfo.PolicyIdentifier.Name = strings.ToLower(args[0])
scanInfo.PolicyIdentifier = []reporthandling.PolicyIdentifier{}
if len(args) < 1 {
scanInfo.PolicyIdentifier = SetScanForGivenFrameworks(clihandler.SupportedFrameworks)
} else {
var controls []string
if len(args) > 0 {
controls = strings.Split(args[0], ",")
scanInfo.PolicyIdentifier = []reporthandling.PolicyIdentifier{}
scanInfo.PolicyIdentifier = setScanForFirstControl(controls)
}
if len(controls) > 1 {
scanInfo.PolicyIdentifier = SetScanForGivenControls(controls[1:])
}
}
scanInfo.FrameworkScan = false
scanInfo.PolicyIdentifier.Kind = reporthandling.KindControl
scanInfo.Init()
cautils.SetSilentMode(scanInfo.Silent)
err := clihandler.CliSetup(&scanInfo)
@@ -51,3 +69,22 @@ func flagValidationControl() {
os.Exit(1)
}
}
func setScanForFirstControl(controls []string) []reporthandling.PolicyIdentifier {
newPolicy := reporthandling.PolicyIdentifier{}
newPolicy.Kind = reporthandling.KindControl
newPolicy.Name = controls[0]
scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
return scanInfo.PolicyIdentifier
}
func SetScanForGivenControls(controls []string) []reporthandling.PolicyIdentifier {
for _, control := range controls {
control := strings.TrimLeft(control, " ")
newPolicy := reporthandling.PolicyIdentifier{}
newPolicy.Kind = reporthandling.KindControl
newPolicy.Name = control
scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
}
return scanInfo.PolicyIdentifier
}
+38 -13
View File
@@ -9,32 +9,42 @@ import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/clihandler"
"github.com/armosec/opa-utils/reporthandling"
"github.com/spf13/cobra"
)
var frameworkCmd = &cobra.Command{
Use: fmt.Sprintf("framework <framework name> [`<glob pattern>`/`-`] [flags]\nSupported frameworks: %s", clihandler.ValidFrameworks),
Use: fmt.Sprintf("framework <framework names list> [`<glob pattern>`/`-`] [flags]\nExamples:\n$ kubescape scan framework nsa [flags]\n$ kubescape scan framework mitre,nsa [flags]\n$ kubescape scan framework 'nsa, mitre' [flags]\nSupported frameworks: %s", clihandler.ValidFrameworks),
Short: fmt.Sprintf("The framework you wish to use. Supported frameworks: %s", strings.Join(clihandler.SupportedFrameworks, ", ")),
Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin",
ValidArgs: clihandler.SupportedFrameworks,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 && !(cmd.Flags().Lookup("use-from").Changed) {
return fmt.Errorf("requires at least one argument")
} else if len(args) > 0 {
if !isValidFramework(strings.ToLower(args[0])) {
return fmt.Errorf(fmt.Sprintf("supported frameworks: %s", strings.Join(clihandler.SupportedFrameworks, ", ")))
if len(args) > 0 {
// "nsa, mitre" -> ["nsa", "mitre"] and nsa,mitre -> ["nsa", "mitre"]
frameworks := strings.Split(strings.Join(strings.Fields(args[0]), ""), ",")
for _, framework := range frameworks {
if !isValidFramework(strings.ToLower(framework)) {
return fmt.Errorf(fmt.Sprintf("supported frameworks: %s", strings.Join(clihandler.SupportedFrameworks, ", ")))
}
}
} else {
return fmt.Errorf("requires at least one framework name")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
scanInfo.PolicyIdentifier = reporthandling.PolicyIdentifier{}
scanInfo.PolicyIdentifier.Kind = reporthandling.KindFramework
flagValidationFramework()
if !(cmd.Flags().Lookup("use-from").Changed) {
scanInfo.PolicyIdentifier.Name = strings.ToLower(args[0])
scanInfo.PolicyIdentifier = []reporthandling.PolicyIdentifier{}
// If no framework provided, use all
if len(args) < 1 {
scanInfo.PolicyIdentifier = SetScanForGivenFrameworks(clihandler.SupportedFrameworks)
} else {
// Read frameworks from input args
scanInfo.PolicyIdentifier = []reporthandling.PolicyIdentifier{}
frameworks := strings.Split(strings.Join(strings.Fields(args[0]), ""), ",")
scanInfo.PolicyIdentifier = SetScanForFirstFramework(frameworks)
if len(frameworks) > 1 {
scanInfo.PolicyIdentifier = SetScanForGivenFrameworks(frameworks[1:])
}
}
if len(args) > 0 {
if len(args[1:]) == 0 || args[1] != "-" {
@@ -74,11 +84,26 @@ func init() {
frameworkCmd.Flags().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")
frameworkCmd.Flags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to Armo backend. Use this flag if you ran with the '--submit' flag in the past and you do not want to submit your current scan results")
frameworkCmd.Flags().StringVarP(&scanInfo.Account, "account", "", "", "Armo portal account ID. Default will load account ID from configMap or config file")
}
func SetScanForGivenFrameworks(frameworks []string) []reporthandling.PolicyIdentifier {
for _, framework := range frameworks {
newPolicy := reporthandling.PolicyIdentifier{}
newPolicy.Kind = reporthandling.KindFramework
newPolicy.Name = framework
scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
}
return scanInfo.PolicyIdentifier
}
func SetScanForFirstFramework(frameworks []string) []reporthandling.PolicyIdentifier {
newPolicy := reporthandling.PolicyIdentifier{}
newPolicy.Kind = reporthandling.KindFramework
newPolicy.Name = frameworks[0]
scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
return scanInfo.PolicyIdentifier
}
func flagValidationFramework() {
if scanInfo.Submit && scanInfo.Local {
fmt.Println("You can use `keep-local` or `submit`, but not both")
os.Exit(1)
+12 -7
View File
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/clihandler"
"github.com/spf13/cobra"
)
@@ -16,15 +17,19 @@ var scanCmd = &cobra.Command{
Short: "Scan the current running cluster or yaml files",
Long: `The action you want to perform`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("requires one argument: framework/control")
}
if !strings.EqualFold(args[0], "framework") && !strings.EqualFold(args[0], "control") {
return fmt.Errorf("invalid parameter '%s'. Supported parameters: framework, control", args[0])
if len(args) > 0 {
if !strings.EqualFold(args[0], "framework") && !strings.EqualFold(args[0], "control") {
return fmt.Errorf("invalid parameter '%s'. Supported parameters: framework, control", args[0])
}
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
frameworkArgs := []string{clihandler.ValidFrameworks}
frameworkArgs = append(frameworkArgs, args...)
frameworkCmd.RunE(cmd, frameworkArgs)
}
},
}
@@ -35,7 +40,7 @@ func init() {
scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Silent, "silent", "s", false, "Silent progress messages")
scanCmd.PersistentFlags().Uint16VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 0, "Failure threshold is the percent bellow which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVar(&scanInfo.UseFrom, "use-from", "", "Load local framework object from specified path. If not used will download latest")
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local framework object from default path. If not used will download latest")
scanCmd.PersistentFlags().StringSliceVar(&scanInfo.UseFrom, "use-from", nil, "Load local policy object from specified path. If not used will download latest")
scanCmd.PersistentFlags().BoolVar(&scanInfo.UseDefault, "use-default", false, "Load local policy object from default path. If not used will download latest")
scanCmd.PersistentFlags().StringVar(&scanInfo.UseExceptions, "exceptions", "", "Path to an exceptions obj. If not set will download exceptions from Armo management portal")
}
+1 -1
View File
@@ -29,7 +29,7 @@ func GetLatestVersion() (string, error) {
}
defer resp.Body.Close()
if resp.StatusCode < 200 || 301 < resp.StatusCode {
return "unknown", fmt.Errorf("failed to download file, status code: %s", resp.Status)
return "unknown", nil
}
body, err := io.ReadAll(resp.Body)
+2 -4
View File
@@ -135,10 +135,8 @@ func (clihandler *CLIHandler) Scan() error {
cautils.ScanStartDisplay()
policyNotification := &reporthandling.PolicyNotification{
NotificationType: reporthandling.TypeExecPostureScan,
Rules: []reporthandling.PolicyIdentifier{
clihandler.scanInfo.PolicyIdentifier,
},
Designators: armotypes.PortalDesignator{},
Rules: clihandler.scanInfo.PolicyIdentifier,
Designators: armotypes.PortalDesignator{},
}
switch policyNotification.NotificationType {
case reporthandling.TypeExecPostureScan:
+10 -4
View File
@@ -5,19 +5,25 @@ import (
"os"
"github.com/armosec/kubescape/clihandler/cmd"
pkgutils "github.com/armosec/utils-go/utils"
)
const SKIP_VERSION_CHECK = "KUBESCAPE_SKIP_UPDATE_CHECK"
func main() {
CheckLatestVersion()
cmd.Execute()
}
func CheckLatestVersion() {
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK); ok && pkgutils.StringToBool(v) {
return
}
latest, err := cmd.GetLatestVersion()
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
} else if latest != cmd.BuildNumber {
if err != nil || latest == "unknown" {
return
}
if latest != cmd.BuildNumber {
fmt.Println("Warning: You are not updated to the latest release: " + latest)
}
}
+38 -25
View File
@@ -14,9 +14,11 @@ func (policyHandler *PolicyHandler) GetPoliciesFromBackend(notification *reporth
frameworks := []reporthandling.Framework{}
exceptionPolicies := []armotypes.PostureExceptionPolicy{}
// Get - cacli opa get
for _, rule := range notification.Rules {
switch rule.Kind {
case reporthandling.KindFramework:
rule := GetScanKind(notification)
switch rule.Kind {
case reporthandling.KindFramework:
for _, rule := range notification.Rules {
receivedFramework, recExceptionPolicies, err := policyHandler.getFrameworkPolicies(rule.Name)
if receivedFramework != nil {
frameworks = append(frameworks, *receivedFramework)
@@ -29,27 +31,32 @@ func (policyHandler *PolicyHandler) GetPoliciesFromBackend(notification *reporth
}
return nil, nil, fmt.Errorf("kind: %v, name: %s, error: %s", rule.Kind, rule.Name, err.Error())
}
case reporthandling.KindControl:
receivedControls, recExceptionPolicies, err := policyHandler.getControl(rule.Name)
if receivedControls != nil {
f := reporthandling.Framework{
Controls: receivedControls,
}
frameworks = append(frameworks, f)
}
case reporthandling.KindControl:
f := reporthandling.Framework{}
var receivedControl *reporthandling.Control
var recExceptionPolicies []armotypes.PostureExceptionPolicy
var err error
for _, rule := range notification.Rules {
receivedControl, recExceptionPolicies, err = policyHandler.getControl(rule.Name)
if receivedControl != nil {
f.Controls = append(f.Controls, *receivedControl)
if recExceptionPolicies != nil {
exceptionPolicies = append(exceptionPolicies, recExceptionPolicies...)
}
} else if err != nil {
if strings.Contains(err.Error(), "unsupported protocol scheme") {
err = fmt.Errorf("failed to download from GitHub release, try running with `--use-default` flag")
}
return nil, nil, fmt.Errorf("error: %s", err.Error())
}
// TODO: add case for control from file
default:
err := fmt.Errorf("missing rule kind, expected: %s", reporthandling.KindFramework)
errs = fmt.Errorf("%s", err.Error())
}
frameworks = append(frameworks, f)
// TODO: add case for control from file
default:
err := fmt.Errorf("missing rule kind, expected: %s", reporthandling.KindFramework)
errs = fmt.Errorf("%s", err.Error())
}
return frameworks, exceptionPolicies, errs
}
@@ -68,24 +75,30 @@ func (policyHandler *PolicyHandler) getFrameworkPolicies(policyName string) (*re
return receivedFramework, receivedException, nil
}
func GetScanKind(notification *reporthandling.PolicyNotification) *reporthandling.PolicyIdentifier {
if len(notification.Rules) > 0 {
return &notification.Rules[0]
}
return nil
}
// Get control by name
func (policyHandler *PolicyHandler) getControl(policyName string) ([]reporthandling.Control, []armotypes.PostureExceptionPolicy, error) {
func (policyHandler *PolicyHandler) getControl(policyName string) (*reporthandling.Control, []armotypes.PostureExceptionPolicy, error) {
controls := []reporthandling.Control{}
control, err := policyHandler.getters.PolicyGetter.GetControl(policyName)
control := &reporthandling.Control{}
var err error
control, err = policyHandler.getters.PolicyGetter.GetControl(policyName)
if err != nil {
return nil, nil, err
return control, nil, err
}
if control == nil {
return nil, nil, fmt.Errorf("control not found")
}
controls = append(controls, *control)
// if control == nil {
// return control, nil, fmt.Errorf("control not found")
// }
exceptions, err := policyHandler.getters.ExceptionsGetter.GetExceptions(cautils.CustomerGUID, cautils.ClusterName)
if err != nil {
return controls, nil, err
return control, nil, err
}
return controls, exceptions, nil
return control, exceptions, nil
}
+9 -1
View File
@@ -25,7 +25,15 @@ func (jsonPrinter *JsonPrinter) Score(score float32) {
}
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
postureReportStr, err := json.Marshal(opaSessionObj.PostureReport.FrameworkReports[0])
var postureReportStr []byte
var err error
if len(opaSessionObj.PostureReport.FrameworkReports) == 1 {
postureReportStr, err = json.Marshal(opaSessionObj.PostureReport.FrameworkReports[0])
} else {
postureReportStr, err = json.Marshal(opaSessionObj.PostureReport.FrameworkReports)
}
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
+46 -26
View File
@@ -24,12 +24,25 @@ func NewPrettyPrinter() *PrettyPrinter {
}
}
// Initializes empty printer for new table
func (printer *PrettyPrinter) init() *PrettyPrinter {
printer.frameworkSummary = ControlSummary{}
printer.summary = Summary{}
printer.sortedControlNames = []string{}
return printer
}
func (printer *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
// score := calculatePostureScore(opaSessionObj.PostureReport)
printer.summarySetup(opaSessionObj.PostureReport)
printer.printResults()
printer.printSummaryTable()
for _, report := range opaSessionObj.PostureReport.FrameworkReports {
// Print summary table together for control scan
if report.Name != "" {
printer = printer.init()
}
printer.summarySetup(report)
printer.printResults()
printer.printSummaryTable(report.Name)
}
// return score
}
@@ -41,29 +54,27 @@ func (printer *PrettyPrinter) SetWriter(outputFile string) {
func (printer *PrettyPrinter) Score(score float32) {
}
func (printer *PrettyPrinter) summarySetup(postureReport *reporthandling.PostureReport) {
for _, fr := range postureReport.FrameworkReports {
printer.frameworkSummary = ControlSummary{
TotalResources: fr.GetNumberOfResources(),
TotalFailed: fr.GetNumberOfFailedResources(),
TotalWarnign: fr.GetNumberOfWarningResources(),
func (printer *PrettyPrinter) summarySetup(fr reporthandling.FrameworkReport) {
printer.frameworkSummary = ControlSummary{
TotalResources: fr.GetNumberOfResources(),
TotalFailed: fr.GetNumberOfFailedResources(),
TotalWarnign: fr.GetNumberOfWarningResources(),
}
for _, cr := range fr.ControlReports {
if len(cr.RuleReports) == 0 {
continue
}
for _, cr := range fr.ControlReports {
if len(cr.RuleReports) == 0 {
continue
}
workloadsSummary := listResultSummary(cr.RuleReports)
workloadsSummary := listResultSummary(cr.RuleReports)
printer.summary[cr.Name] = ControlSummary{
TotalResources: cr.GetNumberOfResources(),
TotalFailed: cr.GetNumberOfFailedResources(),
TotalWarnign: cr.GetNumberOfWarningResources(),
FailedWorkloads: groupByNamespace(workloadsSummary, workloadSummaryFailed),
ExcludedWorkloads: groupByNamespace(workloadsSummary, workloadSummaryExclude),
Description: cr.Description,
Remediation: cr.Remediation,
ListInputKinds: cr.ListControlsInputKinds(),
}
printer.summary[cr.Name] = ControlSummary{
TotalResources: cr.GetNumberOfResources(),
TotalFailed: cr.GetNumberOfFailedResources(),
TotalWarnign: cr.GetNumberOfWarningResources(),
FailedWorkloads: groupByNamespace(workloadsSummary, workloadSummaryFailed),
ExcludedWorkloads: groupByNamespace(workloadsSummary, workloadSummaryExclude),
Description: cr.Description,
Remediation: cr.Remediation,
ListInputKinds: cr.ListControlsInputKinds(),
}
}
printer.sortedControlNames = printer.getSortedControlsNames()
@@ -179,7 +190,10 @@ func generateFooter(numControlers, sumFailed, sumWarning, sumTotal int) []string
}
return row
}
func (printer *PrettyPrinter) printSummaryTable() {
func (printer *PrettyPrinter) printSummaryTable(framework string) {
// For control scan framework will be nil
printer.printFramework(framework)
summaryTable := tablewriter.NewWriter(printer.writer)
summaryTable.SetAutoWrapText(false)
summaryTable.SetHeader(generateHeader())
@@ -195,6 +209,12 @@ func (printer *PrettyPrinter) printSummaryTable() {
summaryTable.Render()
}
func (printer *PrettyPrinter) printFramework(framework string) {
if framework != "" {
cautils.InfoTextDisplay(printer.writer, fmt.Sprintf("%s FRAMEWORK\n", framework))
}
}
func (printer *PrettyPrinter) getSortedControlsNames() []string {
controlNames := make([]string, 0, len(printer.summary))
for k := range printer.summary {