Merge pull request #991 from kubescape/dev

Release
This commit is contained in:
David Wertenteil
2022-12-22 18:12:37 +02:00
committed by GitHub
63 changed files with 813 additions and 491 deletions

View File

@@ -1,127 +1,3 @@
# Contributor Covenant Code of Conduct
## Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement [here](mailto:ben@armosec.io).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
The Kubescape project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).

View File

@@ -1,10 +1,11 @@
# Maintainers
The following table lists Kubescape project maintainers
The following table lists the Kubescape project maintainers:
| Name | GitHub | Email | Organization | Role | Added/Renewed On |
| --- | --- | --- | --- | --- | --- |
| [Ben Hirschberg](https://www.linkedin.com/in/benyamin-ben-hirschberg-66141890) | [@slashben](https://github.com/slashben) | ben@armosec.io | [ARMO](https://www.armosec.io/) | VP R&D | 2021-09-01 |
| [Rotem Refael](https://www.linkedin.com/in/rotem-refael) | [@rotemamsa](https://github.com/rotemamsa) | rrefael@armosec.io | [ARMO](https://www.armosec.io/) | Team Leader | 2021-10-11 |
| [David Wertenteil](https://www.linkedin.com/in/david-wertenteil-0ba277b9) | [@dwertent](https://github.com/dwertent) | dwertent@armosec.io | [ARMO](https://www.armosec.io/) | Kubescape CLI Developer | 2021-09-01 |
| [Bezalel Brandwine](https://www.linkedin.com/in/bezalel-brandwine) | [@Bezbran](https://github.com/Bezbran) | bbrandwine@armosec.io | [ARMO](https://www.armosec.io/) | Kubescape SaaS Developer | 2021-09-01 |
| Name | GitHub | Organization | Added/Renewed On |
| --- | --- | --- | --- |
| [Ben Hirschberg](https://www.linkedin.com/in/benyamin-ben-hirschberg-66141890) | [@slashben](https://github.com/slashben) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Rotem Refael](https://www.linkedin.com/in/rotem-refael) | [@rotemamsa](https://github.com/rotemamsa) | [ARMO](https://www.armosec.io/) | 2021-10-11 |
| [David Wertenteil](https://www.linkedin.com/in/david-wertenteil-0ba277b9) | [@dwertent](https://github.com/dwertent) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Bezalel Brandwine](https://www.linkedin.com/in/bezalel-brandwine) | [@Bezbran](https://github.com/Bezbran) | [ARMO](https://www.armosec.io/) | 2021-09-01 |
| [Craig Box](https://www.linkedin.com/in/crbnz/) | [@craigbox](https://github.com/craigbox) | [ARMO](https://www.armosec.io/) | 2022-10-31 |

View File

@@ -24,8 +24,8 @@ var (
# Download the NSA framework. Run 'kubescape list frameworks' for all frameworks names
kubescape download framework nsa
# Download the "HostPath mount" control. Run 'kubescape list controls' for all controls names
kubescape download control "HostPath mount"
# Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids
kubescape download control "C-0001"
# Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids
kubescape download control C-0001
@@ -70,7 +70,9 @@ func GeDownloadCmd(ks meta.IKubescape) *cobra.Command {
}
downloadInfo.Target = args[0]
if len(args) >= 2 {
downloadInfo.Name = args[1]
downloadInfo.Identifier = args[1]
}
if err := ks.Download(&downloadInfo); err != nil {
logger.L().Fatal(err.Error())

View File

@@ -16,7 +16,6 @@ import (
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/meta"
"github.com/enescakir/emoji"
"github.com/spf13/cobra"
)
@@ -113,7 +112,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {
cautils.SimpleDisplay(os.Stderr, "%s Run with '--verbose'/'-v' flag for detailed resources view\n\n", emoji.Detective)
cautils.SimpleDisplay(os.Stderr, "Run with '--verbose'/'-v' flag for detailed resources view\n\n")
}
if results.GetRiskScore() > float32(scanInfo.FailThreshold) {
logger.L().Fatal("scan risk-score is above permitted threshold", helpers.String("risk-score", fmt.Sprintf("%.2f", results.GetRiskScore())), helpers.String("fail-threshold", fmt.Sprintf("%.2f", scanInfo.FailThreshold)))

View File

@@ -76,7 +76,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
scanCmd.PersistentFlags().Float32VarP(&scanInfo.FailThreshold, "fail-threshold", "t", 100, "Failure threshold is the percent above which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVar(&scanInfo.FailThresholdSeverity, "severity-threshold", "", "Severity threshold is the severity of failed controls at which the command fails and returns exit code 1")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "pretty-printer", `Output format. Supported formats: "pretty-printer", "json", "junit", "prometheus", "pdf", "html", "sarif"`)
scanCmd.PersistentFlags().StringVarP(&scanInfo.Format, "format", "f", "", `Output file format. Supported formats: "pretty-printer", "json", "junit", "prometheus", "pdf", "html", "sarif"`)
scanCmd.PersistentFlags().StringVar(&scanInfo.IncludeNamespaces, "include-namespaces", "", "scan specific namespaces. e.g: --include-namespaces ns-a,ns-b")
scanCmd.PersistentFlags().BoolVarP(&scanInfo.Local, "keep-local", "", false, "If you do not want your Kubescape results reported to configured backend.")
scanCmd.PersistentFlags().StringVarP(&scanInfo.Output, "output", "o", "", "Output file. Print output to file and not stdout")

View File

@@ -25,11 +25,11 @@ func NewDownloadReleasedPolicy() *DownloadReleasedPolicy {
}
}
func (drp *DownloadReleasedPolicy) GetControl(policyName string) (*reporthandling.Control, error) {
func (drp *DownloadReleasedPolicy) GetControl(ID string) (*reporthandling.Control, error) {
var control *reporthandling.Control
var err error
control, err = drp.gs.GetOPAControl(policyName)
control, err = drp.gs.GetOPAControlByID(ID)
if err != nil {
return nil, err
}

View File

@@ -9,7 +9,7 @@ import (
type IPolicyGetter interface {
GetFramework(name string) (*reporthandling.Framework, error)
GetFrameworks() ([]reporthandling.Framework, error)
GetControl(name string) (*reporthandling.Control, error)
GetControl(ID string) (*reporthandling.Control, error)
ListFrameworks() ([]string, error)
ListControls() ([]string, error)

View File

@@ -192,7 +192,7 @@ func (api *KSCloudAPI) GetFrameworks() ([]reporthandling.Framework, error) {
return frameworks, err
}
func (api *KSCloudAPI) GetControl(policyName string) (*reporthandling.Control, error) {
func (api *KSCloudAPI) GetControl(ID string) (*reporthandling.Control, error) {
return nil, fmt.Errorf("control api is not public")
}

View File

@@ -37,7 +37,7 @@ func NewLoadPolicy(filePaths []string) *LoadPolicy {
}
// Return control from file
func (lp *LoadPolicy) GetControl(controlName string) (*reporthandling.Control, error) {
func (lp *LoadPolicy) GetControl(controlID string) (*reporthandling.Control, error) {
control := &reporthandling.Control{}
filePath := lp.filePath()
@@ -49,13 +49,13 @@ 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) {
if controlID != "" && !strings.EqualFold(controlID, control.ControlID) && !strings.EqualFold(controlID, control.ControlID) {
framework, err := lp.GetFramework(control.Name)
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) {
if strings.EqualFold(ctrl.ControlID, controlID) || strings.EqualFold(ctrl.ControlID, controlID) {
control = &ctrl
break
}

View File

@@ -94,7 +94,7 @@ const (
)
type PolicyIdentifier struct {
Name string // policy name e.g. nsa,mitre,c-0012
Identifier string // policy Identifier e.g. c-0012 for control, nsa,mitre for frameworks
Kind apisv1.NotificationPolicyKind // policy kind e.g. Framework,Control,Rule
Designators armotypes.PortalDesignator
}
@@ -140,7 +140,6 @@ type Getters struct {
func (scanInfo *ScanInfo) Init() {
scanInfo.setUseFrom()
scanInfo.setOutputFile()
scanInfo.setUseArtifactsFrom()
if scanInfo.ScanID == "" {
scanInfo.ScanID = uuid.NewString()
@@ -183,29 +182,18 @@ func (scanInfo *ScanInfo) setUseArtifactsFrom() {
func (scanInfo *ScanInfo) setUseFrom() {
if scanInfo.UseDefault {
for _, policy := range scanInfo.PolicyIdentifier {
scanInfo.UseFrom = append(scanInfo.UseFrom, getter.GetDefaultPath(policy.Name+".json"))
scanInfo.UseFrom = append(scanInfo.UseFrom, getter.GetDefaultPath(policy.Identifier+".json"))
}
}
}
func (scanInfo *ScanInfo) setOutputFile() {
if scanInfo.Output == "" {
return
}
if scanInfo.Format == "json" {
if filepath.Ext(scanInfo.Output) != ".json" {
scanInfo.Output += ".json"
}
}
if scanInfo.Format == "junit" {
if filepath.Ext(scanInfo.Output) != ".xml" {
scanInfo.Output += ".xml"
}
}
if scanInfo.Format == "pdf" {
if filepath.Ext(scanInfo.Output) != ".pdf" {
scanInfo.Output += ".pdf"
}
// Formats returns a slice of output formats that have been requested for a given scan
func (scanInfo *ScanInfo) Formats() []string {
formatString := scanInfo.Format
if formatString != "" {
return strings.Split(scanInfo.Format, ",")
} else {
return []string{}
}
}
@@ -214,7 +202,7 @@ func (scanInfo *ScanInfo) SetPolicyIdentifiers(policies []string, kind apisv1.No
if !scanInfo.contains(policy) {
newPolicy := PolicyIdentifier{}
newPolicy.Kind = kind
newPolicy.Name = policy
newPolicy.Identifier = policy
scanInfo.PolicyIdentifier = append(scanInfo.PolicyIdentifier, newPolicy)
}
}
@@ -222,7 +210,7 @@ func (scanInfo *ScanInfo) SetPolicyIdentifiers(policies []string, kind apisv1.No
func (scanInfo *ScanInfo) contains(policyName string) bool {
for _, policy := range scanInfo.PolicyIdentifier {
if policy.Name == policyName {
if policy.Identifier == policyName {
return true
}
}
@@ -250,7 +238,7 @@ func scanInfoToScanMetadata(scanInfo *ScanInfo) *reporthandlingv2.Metadata {
}
// append frameworks
for _, policy := range scanInfo.PolicyIdentifier {
metadata.ScanMetadata.TargetNames = append(metadata.ScanMetadata.TargetNames, policy.Name)
metadata.ScanMetadata.TargetNames = append(metadata.ScanMetadata.TargetNames, policy.Identifier)
}
metadata.ScanMetadata.KubescapeVersion = BuildNumber

View File

@@ -43,3 +43,30 @@ func TestGetScanningContext(t *testing.T) {
assert.Equal(t, ContextCluster, GetScanningContext(""))
assert.Equal(t, ContextGitURL, GetScanningContext("https://github.com/kubescape/kubescape"))
}
func TestScanInfoFormats(t *testing.T) {
testCases := []struct {
Input string
Want []string
}{
{"", []string{}},
{"json", []string{"json"}},
{"pdf", []string{"pdf"}},
{"html", []string{"html"}},
{"sarif", []string{"sarif"}},
{"html,pdf,sarif", []string{"html", "pdf", "sarif"}},
{"pretty-printer,pdf,sarif", []string{"pretty-printer", "pdf", "sarif"}},
}
for _, tc := range testCases {
t.Run(tc.Input, func(t *testing.T) {
input := tc.Input
want := tc.Want
scanInfo := &ScanInfo{Format: input}
got := scanInfo.Formats()
assert.Equal(t, want, got)
})
}
}

View File

@@ -13,13 +13,22 @@ import (
metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1"
)
const (
TargetControlsInputs = "controls-inputs"
TargetExceptions = "exceptions"
TargetControl = "control"
TargetFramework = "framework"
TargetArtifacts = "artifacts"
TargetAttackTracks = "attack-tracks"
)
var downloadFunc = map[string]func(*metav1.DownloadInfo) error{
"controls-inputs": downloadConfigInputs,
"exceptions": downloadExceptions,
"control": downloadControl,
"framework": downloadFramework,
"artifacts": downloadArtifacts,
"attack-tracks": downloadAttackTracks,
TargetControlsInputs: downloadConfigInputs,
TargetExceptions: downloadExceptions,
TargetControl: downloadControl,
TargetFramework: downloadFramework,
TargetArtifacts: downloadArtifacts,
TargetAttackTracks: downloadAttackTracks,
}
func DownloadSupportCommands() []string {
@@ -84,7 +93,7 @@ func downloadArtifacts(downloadInfo *metav1.DownloadInfo) error {
func downloadConfigInputs(downloadInfo *metav1.DownloadInfo) error {
tenant := getTenantConfig(&downloadInfo.Credentials, "", "", getKubernetesApi())
controlsInputsGetter := getConfigInputsGetter(downloadInfo.Name, tenant.GetAccountID(), nil)
controlsInputsGetter := getConfigInputsGetter(downloadInfo.Identifier, tenant.GetAccountID(), nil)
controlInputs, err := controlsInputsGetter.GetControlsInputs(tenant.GetContextName())
if err != nil {
return err
@@ -158,7 +167,7 @@ func downloadFramework(downloadInfo *metav1.DownloadInfo) error {
g := getPolicyGetter(nil, tenant.GetTenantEmail(), true, nil)
if downloadInfo.Name == "" {
if downloadInfo.Identifier == "" {
// if framework name not specified - download all frameworks
frameworks, err := g.GetFrameworks()
if err != nil {
@@ -175,9 +184,9 @@ func downloadFramework(downloadInfo *metav1.DownloadInfo) error {
// return fmt.Errorf("missing framework name")
} else {
if downloadInfo.FileName == "" {
downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Name)
downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Identifier)
}
framework, err := g.GetFramework(downloadInfo.Name)
framework, err := g.GetFramework(downloadInfo.Identifier)
if err != nil {
return err
}
@@ -200,25 +209,25 @@ func downloadControl(downloadInfo *metav1.DownloadInfo) error {
g := getPolicyGetter(nil, tenant.GetTenantEmail(), false, nil)
if downloadInfo.Name == "" {
if downloadInfo.Identifier == "" {
// TODO - support
return fmt.Errorf("missing control name")
return fmt.Errorf("missing control ID")
}
if downloadInfo.FileName == "" {
downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Name)
downloadInfo.FileName = fmt.Sprintf("%s.json", downloadInfo.Identifier)
}
controls, err := g.GetControl(downloadInfo.Name)
controls, err := g.GetControl(downloadInfo.Identifier)
if err != nil {
return err
return fmt.Errorf("failed to download control id '%s', %s", downloadInfo.Identifier, err.Error())
}
if controls == nil {
return fmt.Errorf("failed to download control - received an empty objects")
return fmt.Errorf("failed to download control id '%s' - received an empty objects", downloadInfo.Identifier)
}
downloadTo := filepath.Join(downloadInfo.Path, downloadInfo.FileName)
err = getter.SaveInFile(controls, downloadTo)
if err != nil {
return err
}
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("name", downloadInfo.Name), helpers.String("path", downloadTo))
logger.L().Success("Downloaded", helpers.String("artifact", downloadInfo.Target), helpers.String("ID", downloadInfo.Identifier), helpers.String("path", downloadTo))
return nil
}

View File

@@ -2,6 +2,7 @@ package core
import (
"fmt"
"os"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
@@ -10,6 +11,8 @@ import (
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/kubescape/v2/core/pkg/hostsensorutils"
"github.com/kubescape/kubescape/v2/core/pkg/resourcehandler"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer"
printerv2 "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer/v2"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter"
reporterv2 "github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter/v2"
@@ -99,7 +102,7 @@ func getHostSensorHandler(scanInfo *cautils.ScanInfo, k8s *k8sinterface.Kubernet
// we need to determined which controls needs host scanner
if scanInfo.HostSensorEnabled.Get() == nil && hasHostSensorControls {
scanInfo.HostSensorEnabled.SetBool(false) // default - do not run host scanner
logger.L().Warning("Kubernetes cluster nodes scanning is disabled. This is required to collect valuable data for certain controls. You can enable it using the --enable-host-scan flag")
logger.L().Warning("Kubernetes cluster nodes scanning is disabled. This is required to collect valuable data for certain controls. You can enable it using the --enable-host-scan flag")
}
if hostSensorVal := scanInfo.HostSensorEnabled.Get(); hostSensorVal != nil && *hostSensorVal {
hostSensorHandler, err := hostsensorutils.NewHostSensorHandler(k8s, scanInfo.HostSensorYamlPath)
@@ -122,18 +125,18 @@ func getFieldSelector(scanInfo *cautils.ScanInfo) resourcehandler.IFieldSelector
return &resourcehandler.EmptySelector{}
}
func policyIdentifierNames(pi []cautils.PolicyIdentifier) string {
policiesNames := ""
func policyIdentifierIdentities(pi []cautils.PolicyIdentifier) string {
policiesIdentities := ""
for i := range pi {
policiesNames += pi[i].Name
policiesIdentities += pi[i].Identifier
if i+1 < len(pi) {
policiesNames += ","
policiesIdentities += ","
}
}
if policiesNames == "" {
policiesNames = "all"
if policiesIdentities == "" {
policiesIdentities = "all"
}
return policiesNames
return policiesIdentities
}
// setSubmitBehavior - Setup the desired cluster behavior regarding submitting to the Kubescape Cloud BE
@@ -254,3 +257,13 @@ func getAttackTracksGetter(accountID string, downloadReleasedPolicy *getter.Down
}
return downloadReleasedPolicy
}
// getUIPrinter returns a printer that will be used to print to the programs UI (terminal)
func getUIPrinter(verboseMode bool, formatVersion string, viewType cautils.ViewTypes) printer.IPrinter {
p := printerv2.NewPrettyPrinter(verboseMode, formatVersion, viewType)
// Since the UI of the program is a CLI (Stdout), it means that it should always print to Stdout
p.SetWriter(os.Stdout.Name())
return p
}

View File

@@ -0,0 +1,39 @@
package core
import (
"reflect"
"testing"
"github.com/kubescape/kubescape/v2/core/cautils"
)
func Test_getUIPrinter(t *testing.T) {
scanInfo := &cautils.ScanInfo{
FormatVersion: "v2",
VerboseMode: true,
View: "control",
}
wantFormatVersion := scanInfo.FormatVersion
wantVerboseMode := scanInfo.VerboseMode
wantViewType := cautils.ViewTypes(scanInfo.View)
got := getUIPrinter(scanInfo.VerboseMode, scanInfo.FormatVersion, cautils.ViewTypes(scanInfo.View))
gotValue := reflect.ValueOf(got).Elem()
gotFormatVersion := gotValue.FieldByName("formatVersion").String()
gotVerboseMode := gotValue.FieldByName("verboseMode").Bool()
gotViewType := cautils.ViewTypes(gotValue.FieldByName("viewType").String())
if gotFormatVersion != wantFormatVersion {
t.Errorf("Got: %s, want: %s", gotFormatVersion, wantFormatVersion)
}
if gotVerboseMode != wantVerboseMode {
t.Errorf("Got: %t, want: %t", gotVerboseMode, wantVerboseMode)
}
if gotViewType != wantViewType {
t.Errorf("Got: %v, want: %v", gotViewType, wantViewType)
}
}

View File

@@ -27,7 +27,8 @@ type componentInterfaces struct {
tenantConfig cautils.ITenantConfig
resourceHandler resourcehandler.IResourceHandler
report reporter.IReport
printerHandler printer.IPrinter
outputPrinters []printer.IPrinter
uiPrinter printer.IPrinter
hostSensorHandler hostsensorutils.IHostSensor
}
@@ -63,7 +64,7 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// ================== version testing ======================================
v := cautils.NewIVersionCheckHandler()
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierNames(scanInfo.PolicyIdentifier), "", cautils.ScanningContextToScanningScope(scanInfo.GetScanningContext())))
v.CheckLatestVersion(cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierIdentities(scanInfo.PolicyIdentifier), "", cautils.ScanningContextToScanningScope(scanInfo.GetScanningContext())))
// ================== setup host scanner object ======================================
@@ -93,9 +94,17 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
// reporting behavior - setup reporter
reportHandler := getReporter(tenantConfig, scanInfo.ScanID, scanInfo.Submit, scanInfo.FrameworkScan, scanInfo.GetScanningContext())
// setup printer
printerHandler := resultshandling.NewPrinter(scanInfo.Format, scanInfo.FormatVersion, scanInfo.VerboseMode, cautils.ViewTypes(scanInfo.View))
printerHandler.SetWriter(scanInfo.Output)
// setup printers
formats := scanInfo.Formats()
outputPrinters := make([]printer.IPrinter, 0)
for _, format := range formats {
printerHandler := resultshandling.NewPrinter(format, scanInfo.FormatVersion, scanInfo.VerboseMode, cautils.ViewTypes(scanInfo.View))
printerHandler.SetWriter(scanInfo.Output)
outputPrinters = append(outputPrinters, printerHandler)
}
uiPrinter := getUIPrinter(scanInfo.VerboseMode, scanInfo.FormatVersion, cautils.ViewTypes(scanInfo.View))
// ================== return interface ======================================
@@ -103,7 +112,8 @@ func getInterfaces(scanInfo *cautils.ScanInfo) componentInterfaces {
tenantConfig: tenantConfig,
resourceHandler: resourceHandler,
report: reportHandler,
printerHandler: printerHandler,
outputPrinters: outputPrinters,
uiPrinter: uiPrinter,
hostSensorHandler: hostSensorHandler,
}
}
@@ -141,7 +151,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
}
}()
resultsHandling := resultshandling.NewResultsHandler(interfaces.report, interfaces.printerHandler)
resultsHandling := resultshandling.NewResultsHandler(interfaces.report, interfaces.outputPrinters, interfaces.uiPrinter)
// ===================== policies & resources =====================
policyHandler := policyhandler.NewPolicyHandler(interfaces.resourceHandler)

View File

@@ -6,6 +6,6 @@ type DownloadInfo struct {
Path string // directory to save artifact. Default is "~/.kubescape/"
FileName string // can be empty
Target string // type of artifact to download
Name string // name of artifact to download
Identifier string // identifier of artifact to download
Credentials cautils.Credentials
}

View File

@@ -38,6 +38,7 @@ spec:
- name: host-sensor
image: quay.io/kubescape/host-scanner:v1.0.39
securityContext:
allowPrivilegeEscalation: true
privileged: true
readOnlyRootFilesystem: true
procMount: Unmasked

View File

@@ -3,11 +3,16 @@ package policyhandler
import (
"fmt"
cloudsupportv1 "github.com/kubescape/k8s-interface/cloudsupport/v1"
helpersv1 "github.com/kubescape/opa-utils/reporthandling/helpers/v1"
reportv2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/k8s-interface/cloudsupport"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/pkg/resourcehandler"
"github.com/kubescape/opa-utils/reporthandling/apis"
)
// PolicyHandler -
@@ -51,15 +56,8 @@ func (policyHandler *PolicyHandler) CollectResources(policyIdentifier []cautils.
func (policyHandler *PolicyHandler) getResources(policyIdentifier []cautils.PolicyIdentifier, opaSessionObj *cautils.OPASessionObj, scanInfo *cautils.ScanInfo) error {
opaSessionObj.Report.ClusterAPIServerInfo = policyHandler.resourceHandler.GetClusterAPIServerInfo()
// attempting to get cloud provider from API server git version
if opaSessionObj.Report.ClusterAPIServerInfo != nil {
opaSessionObj.Report.ClusterCloudProvider = cloudsupport.GetCloudProvider(opaSessionObj.Report.ClusterAPIServerInfo.GitVersion)
}
// if didn't succeed getting cloud provider from API server git version, try from context.
if opaSessionObj.Report.ClusterCloudProvider == "" {
clusterName := k8sinterface.GetContextName()
opaSessionObj.Report.ClusterCloudProvider = cloudsupport.GetCloudProvider(clusterName)
if cloudMetadata := getCloudMetadata(opaSessionObj); cloudMetadata != nil {
opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudMetadata = reportv2.NewCloudMetadata(cloudMetadata)
}
resourcesMap, allResources, ksResources, err := policyHandler.resourceHandler.GetResources(opaSessionObj, &policyIdentifier[0].Designators)
@@ -80,3 +78,40 @@ func getDesignator(policyIdentifier []cautils.PolicyIdentifier) *armotypes.Porta
}
return &armotypes.PortalDesignator{}
}
func setCloudMetadata(opaSessionObj *cautils.OPASessionObj) {
cloudMetadata := getCloudMetadata(opaSessionObj)
if cloudMetadata == nil {
return
}
opaSessionObj.Report.Metadata.ClusterMetadata.CloudMetadata = reportv2.NewCloudMetadata(cloudMetadata)
opaSessionObj.Report.Metadata.ContextMetadata.ClusterContextMetadata.CloudMetadata = reportv2.NewCloudMetadata(cloudMetadata)
opaSessionObj.Report.ClusterCloudProvider = string(cloudMetadata.Provider()) // Fallback
}
func getCloudMetadata(opaSessionObj *cautils.OPASessionObj) apis.ICloudParser {
var provider string
context := k8sinterface.GetContextName()
// attempting to get cloud provider from API server git version
if opaSessionObj.Report.ClusterAPIServerInfo != nil {
provider = cloudsupport.GetCloudProvider(opaSessionObj.Report.ClusterAPIServerInfo.GitVersion)
}
if provider == "" {
// Fallback - get provider from context
provider = cloudsupport.GetCloudProvider(context)
}
switch provider {
case cloudsupportv1.GKE:
return helpersv1.NewGKEMetadata(context)
case cloudsupportv1.EKS:
return helpersv1.NewEKSMetadata(context)
// case cloudsupportv1.AKS: TODO: Implement AKS support
// return helpersv1.NewAKSMetadata()
}
return nil
}

View File

@@ -0,0 +1,45 @@
package policyhandler
import (
"testing"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/kubescape/opa-utils/reporthandling/apis"
helpersv1 "github.com/kubescape/opa-utils/reporthandling/helpers/v1"
"github.com/kubescape/kubescape/v2/core/cautils"
"k8s.io/apimachinery/pkg/version"
)
func Test_getCloudMetadata(t *testing.T) {
type args struct {
opaSessionObj *cautils.OPASessionObj
}
tests := []struct {
want apis.ICloudParser
args args
name string
}{
{
name: "Test_getCloudMetadata",
args: args{
opaSessionObj: &cautils.OPASessionObj{
Report: &reporthandlingv2.PostureReport{
ClusterAPIServerInfo: &version.Info{
GitVersion: "v1.25.4-gke.1600",
},
},
},
},
want: helpersv1.NewGKEMetadata(""),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getCloudMetadata(tt.args.opaSessionObj); got.Provider() != tt.want.Provider() {
t.Errorf("getCloudMetadata() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -56,14 +56,16 @@ func (policyHandler *PolicyHandler) getScanPolicies(policyIdentifier []cautils.P
switch getScanKind(policyIdentifier) {
case apisv1.KindFramework: // Download frameworks
for _, rule := range policyIdentifier {
receivedFramework, err := policyHandler.getters.PolicyGetter.GetFramework(rule.Name)
receivedFramework, err := policyHandler.getters.PolicyGetter.GetFramework(rule.Identifier)
if err != nil {
return frameworks, policyDownloadError(err)
}
if err := validateFramework(receivedFramework); err != nil {
return frameworks, err
}
if receivedFramework != nil {
frameworks = append(frameworks, *receivedFramework)
cache := getter.GetDefaultPath(rule.Name + ".json")
cache := getter.GetDefaultPath(rule.Identifier + ".json")
if err := getter.SaveInFile(receivedFramework, cache); err != nil {
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
}
@@ -73,15 +75,15 @@ func (policyHandler *PolicyHandler) getScanPolicies(policyIdentifier []cautils.P
f := reporthandling.Framework{}
var receivedControl *reporthandling.Control
var err error
for _, rule := range policyIdentifier {
receivedControl, err = policyHandler.getters.PolicyGetter.GetControl(rule.Name)
for _, policy := range policyIdentifier {
receivedControl, err = policyHandler.getters.PolicyGetter.GetControl(policy.Identifier)
if err != nil {
return frameworks, policyDownloadError(err)
}
if receivedControl != nil {
f.Controls = append(f.Controls, *receivedControl)
cache := getter.GetDefaultPath(rule.Name + ".json")
cache := getter.GetDefaultPath(policy.Identifier + ".json")
if err := getter.SaveInFile(receivedControl, cache); err != nil {
logger.L().Warning("failed to cache file", helpers.String("file", cache), helpers.Error(err))
}
@@ -98,7 +100,7 @@ func (policyHandler *PolicyHandler) getScanPolicies(policyIdentifier []cautils.P
func policyIdentifierToSlice(rules []cautils.PolicyIdentifier) []string {
s := []string{}
for i := range rules {
s = append(s, fmt.Sprintf("%s: %s", rules[i].Kind, rules[i].Name))
s = append(s, fmt.Sprintf("%s: %s", rules[i].Kind, rules[i].Identifier))
}
return s
}

View File

@@ -1,23 +0,0 @@
package policyhandler
// func TestGetPoliciesFromBackend(t *testing.T) {
// notification := reporthandling.PolicyNotification{
// Rules: []reporthandling.PolicyIdentifier{
// {
// Kind: reporthandling.KindFramework,
// Name: "mitretest",
// },
// },
// }
// // os.Setenv(cacli., "")
// ph := PolicyHandler{
// cacli: &cacli.Cacli{},
// }
// f, err := ph.GetPoliciesFromBackend(&notification)
// if err != nil {
// t.Error(err)
// }
// if len(f) == 0 {
// t.Errorf("empty")
// }
// }

View File

@@ -5,6 +5,7 @@ import (
"strings"
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/kubescape/v2/core/cautils"
)
@@ -21,3 +22,16 @@ func policyDownloadError(err error) error {
}
return err
}
// validate the framework
func validateFramework(framework *reporthandling.Framework) error {
if framework == nil {
return fmt.Errorf("received empty framework")
}
// validate the controls are not empty
if len(framework.Controls) == 0 {
return fmt.Errorf("failed to load controls for framework: %s: empty list of controls", framework.Name)
}
return nil
}

View File

@@ -0,0 +1,48 @@
package policyhandler
import (
"testing"
"github.com/kubescape/opa-utils/reporthandling"
)
func Test_validateFramework(t *testing.T) {
type args struct {
framework *reporthandling.Framework
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "empty framework",
args: args{
framework: &reporthandling.Framework{
Controls: []reporthandling.Control{},
},
},
wantErr: true,
},
{
name: "none empty framework",
args: args{
framework: &reporthandling.Framework{
Controls: []reporthandling.Control{
{
ControlID: "c-0001",
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := validateFramework(tt.args.framework); (err != nil) != tt.wantErr {
t.Errorf("validateControls() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@@ -43,7 +43,7 @@ type Vulnerability struct {
Categories Categories `json:"categories"`
NoteName string `json:",omitempty"`
CreateTime time.Time `json:",omitempty"`
UpdateTime time.Time `json:",omitempty"` // Vulnerablity started
UpdateTime time.Time `json:",omitempty"` // Vulnerablity started
CVSS float32 `json:",omitempty"` // other cvss versions are available
AffectedCPEURI string `json:",omitempty"` // Package issue
AffectedPackage string `json:",omitempty"`

View File

@@ -88,7 +88,6 @@ func (k8sHandler *K8sResourceHandler) GetResources(sessionObj *cautils.OPASessio
logger.L().Info("Requesting images vulnerabilities results")
cautils.StartSpinner()
if err := k8sHandler.registryAdaptors.collectImagesVulnerabilities(k8sResourcesMap, allResources, ksResourceMap); err != nil {
logger.L().Warning("failed to collect image vulnerabilities", helpers.Error(err), helpers.String("Read more here", "https://hub.armosec.io/docs/configuration-of-image-vulnerabilities"))
cautils.SetInfoMapForResources(fmt.Sprintf("failed to pull image scanning data: %s. for more information: https://hub.armosec.io/docs/configuration-of-image-vulnerabilities", err.Error()), imgVulnResources, sessionObj.InfoMap)
} else {
if isEmptyImgVulns(*ksResourceMap) {

View File

@@ -38,6 +38,17 @@ func isGitTokenPresent(gitURL giturl.IGitAPI) bool {
return true
}
// Get the error message according to the provider
func getProviderError(gitURL giturl.IGitAPI) error {
switch gitURL.GetProvider(){
case "github":
return fmt.Errorf("%w", errors.New("GITHUB_TOKEN is not present"))
case "gitlab":
return fmt.Errorf("%w", errors.New("GITLAB_TOKEN is not present"))
}
return fmt.Errorf("%w", errors.New("unable to find the host name"))
}
// cloneRepo clones a repository to a local temporary directory and returns the directory
func cloneRepo(gitURL giturl.IGitAPI) (string, error) {
@@ -60,9 +71,9 @@ func cloneRepo(gitURL giturl.IGitAPI) (string, error) {
auth = nil
} else {
// Return Error if the GITHUB_TOKEN is not present
// Return Error if the AUTH_TOKEN is not present
if isGitTokenPresent := isGitTokenPresent(gitURL); !isGitTokenPresent {
return "", fmt.Errorf("%w", errors.New("GITHUB_TOKEN is not present"))
return "", getProviderError(gitURL)
}
auth = &http.BasicAuth{
Username: "anything Except Empty String",

View File

@@ -6,6 +6,7 @@ import (
"path/filepath"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v2/core/cautils"
)
@@ -43,3 +44,9 @@ func GetWriter(outputFile string) *os.File {
return os.Stdout
}
func LogOutputFile(fileName string) {
if fileName != os.Stdout.Name() && fileName != os.Stderr.Name() {
logger.L().Success("Scan results saved", helpers.String("filename", fileName))
}
}

View File

@@ -1,15 +1,22 @@
package v1
package printer
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer"
)
const (
jsonOutputFile = "report"
jsonOutputExt = ".json"
)
type JsonPrinter struct {
writer *os.File
}
@@ -19,6 +26,12 @@ func NewJsonPrinter() *JsonPrinter {
}
func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) {
if strings.TrimSpace(outputFile) == "" {
outputFile = jsonOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != jsonOutputExt {
outputFile = outputFile + jsonOutputExt
}
jsonPrinter.writer = printer.GetWriter(outputFile)
}
@@ -41,5 +54,12 @@ func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj
if err != nil {
logger.L().Fatal("failed to convert posture report object")
}
jsonPrinter.writer.Write(postureReportStr)
_, err = jsonPrinter.writer.Write(postureReportStr)
if err != nil {
logger.L().Fatal("failed to Write posture report object into JSON output")
} else {
printer.LogOutputFile(jsonPrinter.writer.Name())
}
}

View File

@@ -1,4 +1,4 @@
package v1
package printer
import (
"fmt"
@@ -22,23 +22,23 @@ func NewPrometheusPrinter(verboseMode bool) *PrometheusPrinter {
}
}
func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) {
prometheusPrinter.writer = printer.GetWriter(outputFile)
func (p *PrometheusPrinter) SetWriter(outputFile string) {
p.writer = printer.GetWriter(outputFile)
}
func (prometheusPrinter *PrometheusPrinter) Score(score float32) {
func (p *PrometheusPrinter) Score(score float32) {
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", cautils.Float32ToInt(score))
}
func (printer *PrometheusPrinter) printResources(allResources map[string]workloadinterface.IMetadata, resourcesIDs *reporthandling.ResourcesIDs, frameworkName, controlName string) {
printer.printDetails(allResources, resourcesIDs.GetFailedResources(), frameworkName, controlName, "failed")
printer.printDetails(allResources, resourcesIDs.GetWarningResources(), frameworkName, controlName, "excluded")
if printer.verboseMode {
printer.printDetails(allResources, resourcesIDs.GetPassedResources(), frameworkName, controlName, "passed")
func (p *PrometheusPrinter) printResources(allResources map[string]workloadinterface.IMetadata, resourcesIDs *reporthandling.ResourcesIDs, frameworkName, controlName string) {
p.printDetails(allResources, resourcesIDs.GetFailedResources(), frameworkName, controlName, "failed")
p.printDetails(allResources, resourcesIDs.GetWarningResources(), frameworkName, controlName, "excluded")
if p.verboseMode {
p.printDetails(allResources, resourcesIDs.GetPassedResources(), frameworkName, controlName, "passed")
}
}
func (printer *PrometheusPrinter) printDetails(allResources map[string]workloadinterface.IMetadata, resourcesIDs []string, frameworkName, controlName, status string) {
func (p *PrometheusPrinter) printDetails(allResources map[string]workloadinterface.IMetadata, resourcesIDs []string, frameworkName, controlName, status string) {
objs := make(map[string]map[string]map[string]int)
for _, resourceID := range resourcesIDs {
resource := allResources[resourceID]
@@ -56,18 +56,18 @@ func (printer *PrometheusPrinter) printDetails(allResources map[string]workloadi
for gvk, namespaces := range objs {
for namespace, names := range namespaces {
for name, value := range names {
fmt.Fprintf(printer.writer, "# Failed object from \"%s\" control \"%s\"\n", frameworkName, controlName)
fmt.Fprintf(p.writer, "# Failed object from \"%s\" control \"%s\"\n", frameworkName, controlName)
if namespace != "" {
fmt.Fprintf(printer.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",namespace=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, namespace, name, gvk, value)
fmt.Fprintf(p.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",namespace=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, namespace, name, gvk, value)
} else {
fmt.Fprintf(printer.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, name, gvk, value)
fmt.Fprintf(p.writer, "kubescape_object_failed_count{framework=\"%s\",control=\"%s\",name=\"%s\",groupVersionKind=\"%s\"} %d\n", frameworkName, controlName, name, gvk, value)
}
}
}
}
}
func (printer *PrometheusPrinter) printReports(allResources map[string]workloadinterface.IMetadata, frameworks []reporthandling.FrameworkReport) error {
func (p *PrometheusPrinter) printReports(allResources map[string]workloadinterface.IMetadata, frameworks []reporthandling.FrameworkReport) error {
for _, frameworkReport := range frameworks {
for _, controlReport := range frameworkReport.ControlReports {
if controlReport.GetNumberOfResources() == 0 {
@@ -76,21 +76,24 @@ func (printer *PrometheusPrinter) printReports(allResources map[string]workloadi
if controlReport.Passed() {
continue // control passed, do not print results
}
fmt.Fprintf(printer.writer, "# Number of resources found as part of %s control %s\nkubescape_resources_found_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfResources())
fmt.Fprintf(printer.writer, "# Number of resources excluded as part of %s control %s\nkubescape_resources_excluded_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfWarningResources())
fmt.Fprintf(printer.writer, "# Number of resources failed as part of %s control %s\nkubescape_resources_failed_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfFailedResources())
fmt.Fprintf(p.writer, "# Number of resources found as part of %s control %s\nkubescape_resources_found_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfResources())
fmt.Fprintf(p.writer, "# Number of resources excluded as part of %s control %s\nkubescape_resources_excluded_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfWarningResources())
fmt.Fprintf(p.writer, "# Number of resources failed as part of %s control %s\nkubescape_resources_failed_count{framework=\"%s\",control=\"%s\"} %d\n", frameworkReport.Name, controlReport.Name, frameworkReport.Name, controlReport.Name, controlReport.GetNumberOfFailedResources())
printer.printResources(allResources, controlReport.ListResourcesIDs(), frameworkReport.Name, controlReport.Name)
p.printResources(allResources, controlReport.ListResourcesIDs(), frameworkReport.Name, controlReport.Name)
}
}
return nil
}
func (printer *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
func (p *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
report := cautils.ReportV2ToV1(opaSessionObj)
err := printer.printReports(opaSessionObj.AllResources, report.FrameworkReports)
err := p.printReports(opaSessionObj.AllResources, report.FrameworkReports)
if err != nil {
logger.L().Fatal(err.Error())
} else {
printer.LogOutputFile(p.writer.Name())
}
}

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"fmt"
@@ -78,6 +78,19 @@ func getColor(controlSeverity int) color.Attribute {
}
}
func getSortedControlsIDs(controls reportsummary.ControlSummaries) [][]string {
controlIDs := make([][]string, 5)
for k := range controls {
c := controls[k]
i := apis.ControlSeverityToInt(c.GetScoreFactor())
controlIDs[i] = append(controlIDs[i], c.GetID())
}
for i := range controlIDs {
sort.Strings(controlIDs[i])
}
return controlIDs
}
func getSortedControlsNames(controls reportsummary.ControlSummaries) [][]string {
controlNames := make([][]string, 5)
for k := range controls {

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
_ "embed"
@@ -38,17 +38,17 @@ func NewHtmlPrinter() *HtmlPrinter {
return &HtmlPrinter{}
}
func (htmlPrinter *HtmlPrinter) SetWriter(outputFile string) {
if outputFile == "" {
func (hp *HtmlPrinter) SetWriter(outputFile string) {
if strings.TrimSpace(outputFile) == "" {
outputFile = htmlOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != htmlOutputExt {
outputFile = outputFile + htmlOutputExt
}
htmlPrinter.writer = printer.GetWriter(outputFile)
hp.writer = printer.GetWriter(outputFile)
}
func (htmlPrinter *HtmlPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
func (hp *HtmlPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
tplFuncMap := template.FuncMap{
"sum": func(nums ...int) int {
total := 0
@@ -104,13 +104,16 @@ func (htmlPrinter *HtmlPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj
resourceTableView := buildResourceTableView(opaSessionObj)
reportingCtx := HTMLReportingCtx{opaSessionObj, resourceTableView}
err := tpl.Execute(htmlPrinter.writer, reportingCtx)
err := tpl.Execute(hp.writer, reportingCtx)
if err != nil {
logger.L().Error("failed to render template", helpers.Error(err))
} else {
printer.LogOutputFile(hp.writer.Name())
}
}
func (htmlPrinter *HtmlPrinter) Score(score float32) {
func (hp *HtmlPrinter) Score(score float32) {
return
}
@@ -141,7 +144,7 @@ func buildResourceControlResultTable(resourceControls []resourcesresults.Resourc
var ctlResults []ResourceControlResult
for _, resourceControl := range resourceControls {
if resourceControl.GetStatus(nil).IsFailed() {
control := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, resourceControl.GetName())
control := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, resourceControl.GetID())
ctlResult := buildResourceControlResult(resourceControl, control)
ctlResults = append(ctlResults, ctlResult)

View File

@@ -1,9 +1,11 @@
package v2
package printer
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
@@ -11,6 +13,11 @@ import (
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer"
)
const (
jsonOutputFile = "report"
jsonOutputExt = ".json"
)
type JsonPrinter struct {
writer *os.File
}
@@ -19,22 +26,29 @@ func NewJsonPrinter() *JsonPrinter {
return &JsonPrinter{}
}
func (jsonPrinter *JsonPrinter) SetWriter(outputFile string) {
jsonPrinter.writer = printer.GetWriter(outputFile)
func (jp *JsonPrinter) SetWriter(outputFile string) {
if strings.TrimSpace(outputFile) == "" {
outputFile = jsonOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != jsonOutputExt {
outputFile = outputFile + jsonOutputExt
}
jp.writer = printer.GetWriter(outputFile)
}
func (jsonPrinter *JsonPrinter) Score(score float32) {
func (jp *JsonPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
}
func (jsonPrinter *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
func (jp *JsonPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
r, err := json.Marshal(FinalizeResults(opaSessionObj))
if err != nil {
logger.L().Fatal("failed to Marshal posture report object")
}
logOUtputFile(jsonPrinter.writer.Name())
if _, err := jsonPrinter.writer.Write(r); err != nil {
if _, err := jp.writer.Write(r); err != nil {
logger.L().Error("failed to write results", helpers.Error(err))
} else {
printer.LogOutputFile(jp.writer.Name())
}
}

View File

@@ -1,9 +1,10 @@
package v2
package printer
import (
"encoding/xml"
"fmt"
"os"
"path/filepath"
"sort"
"strings"
@@ -16,6 +17,11 @@ import (
"github.com/kubescape/opa-utils/shared"
)
const (
junitOutputFile = "report"
junitOutputExt = ".xml"
)
/*
riskScore
status
@@ -92,24 +98,31 @@ func NewJunitPrinter(verbose bool) *JunitPrinter {
}
}
func (junitPrinter *JunitPrinter) SetWriter(outputFile string) {
junitPrinter.writer = printer.GetWriter(outputFile)
func (jp *JunitPrinter) SetWriter(outputFile string) {
if strings.TrimSpace(outputFile) == "" {
outputFile = junitOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != junitOutputExt {
outputFile = outputFile + junitOutputExt
}
jp.writer = printer.GetWriter(outputFile)
}
func (junitPrinter *JunitPrinter) Score(score float32) {
func (jp *JunitPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
}
func (junitPrinter *JunitPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
func (jp *JunitPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
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())
if _, err := junitPrinter.writer.Write(postureReportStr); err != nil {
if _, err := jp.writer.Write(postureReportStr); err != nil {
logger.L().Error("failed to write results", helpers.Error(err))
} else {
printer.LogOutputFile(jp.writer.Name())
}
}

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
_ "embed"
@@ -39,22 +39,22 @@ func NewPdfPrinter() *PdfPrinter {
return &PdfPrinter{}
}
func (pdfPrinter *PdfPrinter) SetWriter(outputFile string) {
func (pp *PdfPrinter) SetWriter(outputFile string) {
// Ensure to have an available output file, otherwise create it.
if outputFile == "" {
if strings.TrimSpace(outputFile) == "" {
outputFile = pdfOutputFile
}
// Ensure to have the right file extension.
if filepath.Ext(strings.TrimSpace(outputFile)) != pdfOutputExt {
outputFile = outputFile + pdfOutputExt
}
pdfPrinter.writer = printer.GetWriter(outputFile)
pp.writer = printer.GetWriter(outputFile)
}
func (pdfPrinter *PdfPrinter) Score(score float32) {
func (pp *PdfPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall risk-score (0- Excellent, 100- All failed): %d\n", cautils.Float32ToInt(score))
}
func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap []infoStars) {
func (pp *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap []infoStars) {
emptyRowCounter := 1
for i := range infoMap {
if infoMap[i].info != "" {
@@ -75,16 +75,16 @@ func (pdfPrinter *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsumm
}
func (pdfPrinter *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls)
func (pp *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls)
infoToPrintInfo := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls)
m := pdf.NewMaroto(consts.Portrait, consts.A4)
pdfPrinter.printHeader(m)
pdfPrinter.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks())
pdfPrinter.printTable(m, &opaSessionObj.Report.SummaryDetails, sortedControlNames)
pdfPrinter.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
pdfPrinter.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfo)
pp.printHeader(m)
pp.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks())
pp.printTable(m, &opaSessionObj.Report.SummaryDetails, sortedControlIDs)
pp.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
pp.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfo)
// Extrat output buffer.
outBuff, err := m.Output()
@@ -93,14 +93,15 @@ func (pdfPrinter *PdfPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj)
return
}
logOUtputFile(pdfPrinter.writer.Name())
if _, err := pdfPrinter.writer.Write(outBuff.Bytes()); err != nil {
if _, err := pp.writer.Write(outBuff.Bytes()); err != nil {
logger.L().Error("failed to write results", helpers.Error(err))
} else {
printer.LogOutputFile(pp.writer.Name())
}
}
// Print Kubescape logo and report date.
func (pdfPrinter *PdfPrinter) printHeader(m pdf.Maroto) {
// printHeader prints the Kubescape logo and report date
func (pp *PdfPrinter) printHeader(m pdf.Maroto) {
// Retrieve current time (we need it for the report timestamp).
t := time.Now()
// Enconde PNG into Base64 to embed it into the pdf.
@@ -136,8 +137,8 @@ func (pdfPrinter *PdfPrinter) printHeader(m pdf.Maroto) {
m.Line(1)
}
// Print pdf frameworks after pdf header.
func (pdfPrinter *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsummary.IFrameworkSummary) {
// printFramework prints the PDF frameworks after the PDF header
func (pp *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsummary.IFrameworkSummary) {
m.Row(10, func() {
m.Text(frameworksScoresToString(frameworks), props.Text{
Align: consts.Center,
@@ -148,17 +149,17 @@ func (pdfPrinter *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsu
})
}
// Create pdf table
func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
// printTable creates the PDF table
func (pp *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
headers := getControlTableHeaders()
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
controls := make([][]string, len(sortedControlNames))
controls := make([][]string, len(sortedControlIDs))
for i := range controls {
controls[i] = make([]string, len(headers))
}
for i := len(sortedControlNames) - 1; i >= 0; i-- {
for _, c := range sortedControlNames[i] {
controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfoMap, true)
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
controls[i] = generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap, true)
}
}
@@ -186,8 +187,8 @@ func (pdfPrinter *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsum
m.Row(2, func() {})
}
// Add final results.
func (pdfPrinter *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
// printFinalResult adds the final results
func (pp *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
m.Row(_rowLen, func() {
m.Col(3, func() {
m.Text("Resource summary", props.Text{

View File

@@ -1,9 +1,11 @@
package v2
package printer
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"github.com/enescakir/emoji"
"github.com/kubescape/k8s-interface/workloadinterface"
@@ -16,6 +18,11 @@ import (
"github.com/olekukonko/tablewriter"
)
const (
prettyPrinterOutputFile = "report"
prettyPrinterOutputExt = ".txt"
)
type PrettyPrinter struct {
formatVersion string
viewType cautils.ViewTypes
@@ -31,79 +38,100 @@ func NewPrettyPrinter(verboseMode bool, formatVersion string, viewType cautils.V
}
}
func (prettyPrinter *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
fmt.Fprintf(prettyPrinter.writer, "\n"+getSeparator("^")+"\n")
func (pp *PrettyPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
fmt.Fprintf(pp.writer, "\n"+getSeparator("^")+"\n")
sortedControlNames := getSortedControlsNames(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls) // ListControls().All())
switch prettyPrinter.viewType {
switch pp.viewType {
case cautils.ControlViewType:
prettyPrinter.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlNames)
pp.printResults(&opaSessionObj.Report.SummaryDetails.Controls, opaSessionObj.AllResources, sortedControlIDs)
case cautils.ResourceViewType:
if prettyPrinter.verboseMode {
prettyPrinter.resourceTable(opaSessionObj)
if pp.verboseMode {
pp.resourceTable(opaSessionObj)
}
}
prettyPrinter.printSummaryTable(&opaSessionObj.Report.SummaryDetails, sortedControlNames)
pp.printSummaryTable(&opaSessionObj.Report.SummaryDetails, sortedControlIDs)
// When writing to Stdout, we arent really writing to an output file,
// so no need to print that we are
if pp.writer.Name() != os.Stdout.Name() {
printer.LogOutputFile(pp.writer.Name())
}
}
func (prettyPrinter *PrettyPrinter) SetWriter(outputFile string) {
prettyPrinter.writer = printer.GetWriter(outputFile)
func (pp *PrettyPrinter) SetWriter(outputFile string) {
// PrettyPrinter should accept Stdout at least by its full name (path)
// and follow the common behavior of outputting to a default filename
// otherwise
if outputFile == os.Stdout.Name() {
pp.writer = printer.GetWriter("")
return
}
if strings.TrimSpace(outputFile) == "" {
outputFile = prettyPrinterOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != junitOutputExt {
outputFile = outputFile + prettyPrinterOutputExt
}
pp.writer = printer.GetWriter(outputFile)
}
func (prettyPrinter *PrettyPrinter) Score(score float32) {
func (pp *PrettyPrinter) Score(score float32) {
}
func (prettyPrinter *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata, sortedControlNames [][]string) {
for i := len(sortedControlNames) - 1; i >= 0; i-- {
for _, c := range sortedControlNames[i] {
controlSummary := controls.GetControl(reportsummary.EControlCriteriaName, c) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
prettyPrinter.printTitle(controlSummary)
prettyPrinter.printResources(controlSummary, allResources)
prettyPrinter.printSummary(c, controlSummary)
func (pp *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata, sortedControlIDs [][]string) {
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
controlSummary := controls.GetControl(reportsummary.EControlCriteriaID, c) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
pp.printTitle(controlSummary)
pp.printResources(controlSummary, allResources)
pp.printSummary(c, controlSummary)
}
}
}
func (prettyPrinter *PrettyPrinter) printSummary(controlName string, controlSummary reportsummary.IControlSummary) {
func (pp *PrettyPrinter) printSummary(controlName string, controlSummary reportsummary.IControlSummary) {
if controlSummary.GetStatus().IsSkipped() {
return
}
cautils.SimpleDisplay(prettyPrinter.writer, "Summary - ")
cautils.SuccessDisplay(prettyPrinter.writer, "Passed:%v ", controlSummary.NumberOfResources().Passed())
cautils.WarningDisplay(prettyPrinter.writer, "Excluded:%v ", controlSummary.NumberOfResources().Excluded())
cautils.FailureDisplay(prettyPrinter.writer, "Failed:%v ", controlSummary.NumberOfResources().Failed())
cautils.InfoDisplay(prettyPrinter.writer, "Total:%v\n", controlSummary.NumberOfResources().All())
cautils.SimpleDisplay(pp.writer, "Summary - ")
cautils.SuccessDisplay(pp.writer, "Passed:%v ", controlSummary.NumberOfResources().Passed())
cautils.WarningDisplay(pp.writer, "Excluded:%v ", controlSummary.NumberOfResources().Excluded())
cautils.FailureDisplay(pp.writer, "Failed:%v ", controlSummary.NumberOfResources().Failed())
cautils.InfoDisplay(pp.writer, "Total:%v\n", controlSummary.NumberOfResources().All())
if controlSummary.GetStatus().IsFailed() {
cautils.DescriptionDisplay(prettyPrinter.writer, "Remediation: %v\n", controlSummary.GetRemediation())
cautils.DescriptionDisplay(pp.writer, "Remediation: %v\n", controlSummary.GetRemediation())
}
cautils.DescriptionDisplay(prettyPrinter.writer, "\n")
cautils.DescriptionDisplay(pp.writer, "\n")
}
func (prettyPrinter *PrettyPrinter) printTitle(controlSummary reportsummary.IControlSummary) {
cautils.InfoDisplay(prettyPrinter.writer, "[control: %s - %s] ", controlSummary.GetName(), cautils.GetControlLink(controlSummary.GetID()))
func (pp *PrettyPrinter) printTitle(controlSummary reportsummary.IControlSummary) {
cautils.InfoDisplay(pp.writer, "[control: %s - %s] ", controlSummary.GetName(), cautils.GetControlLink(controlSummary.GetID()))
switch controlSummary.GetStatus().Status() {
case apis.StatusSkipped:
cautils.InfoDisplay(prettyPrinter.writer, "skipped %v\n", emoji.ConfusedFace)
cautils.InfoDisplay(pp.writer, "skipped %v\n", emoji.ConfusedFace)
case apis.StatusFailed:
cautils.FailureDisplay(prettyPrinter.writer, "failed %v\n", emoji.SadButRelievedFace)
cautils.FailureDisplay(pp.writer, "failed %v\n", emoji.SadButRelievedFace)
case apis.StatusExcluded:
cautils.WarningDisplay(prettyPrinter.writer, "excluded %v\n", emoji.NeutralFace)
cautils.WarningDisplay(pp.writer, "excluded %v\n", emoji.NeutralFace)
case apis.StatusIrrelevant:
cautils.SuccessDisplay(prettyPrinter.writer, "irrelevant %v\n", emoji.ConfusedFace)
cautils.SuccessDisplay(pp.writer, "irrelevant %v\n", emoji.ConfusedFace)
case apis.StatusError:
cautils.WarningDisplay(prettyPrinter.writer, "error %v\n", emoji.ConfusedFace)
cautils.WarningDisplay(pp.writer, "error %v\n", emoji.ConfusedFace)
default:
cautils.SuccessDisplay(prettyPrinter.writer, "passed %v\n", emoji.ThumbsUp)
cautils.SuccessDisplay(pp.writer, "passed %v\n", emoji.ThumbsUp)
}
cautils.DescriptionDisplay(prettyPrinter.writer, "Description: %s\n", controlSummary.GetDescription())
cautils.DescriptionDisplay(pp.writer, "Description: %s\n", controlSummary.GetDescription())
if controlSummary.GetStatus().Info() != "" {
cautils.WarningDisplay(prettyPrinter.writer, "Reason: %v\n", controlSummary.GetStatus().Info())
cautils.WarningDisplay(pp.writer, "Reason: %v\n", controlSummary.GetStatus().Info())
}
}
func (prettyPrinter *PrettyPrinter) printResources(controlSummary reportsummary.IControlSummary, allResources map[string]workloadinterface.IMetadata) {
func (pp *PrettyPrinter) printResources(controlSummary reportsummary.IControlSummary, allResources map[string]workloadinterface.IMetadata) {
workloadsSummary := listResultSummary(controlSummary, allResources)
@@ -111,35 +139,35 @@ func (prettyPrinter *PrettyPrinter) printResources(controlSummary reportsummary.
excludedWorkloads := groupByNamespaceOrKind(workloadsSummary, workloadSummaryExclude)
var passedWorkloads map[string][]WorkloadSummary
if prettyPrinter.verboseMode {
if pp.verboseMode {
passedWorkloads = groupByNamespaceOrKind(workloadsSummary, workloadSummaryPassed)
}
if len(failedWorkloads) > 0 {
cautils.FailureDisplay(prettyPrinter.writer, "Failed:\n")
prettyPrinter.printGroupedResources(failedWorkloads)
cautils.FailureDisplay(pp.writer, "Failed:\n")
pp.printGroupedResources(failedWorkloads)
}
if len(excludedWorkloads) > 0 {
cautils.WarningDisplay(prettyPrinter.writer, "Excluded:\n")
prettyPrinter.printGroupedResources(excludedWorkloads)
cautils.WarningDisplay(pp.writer, "Excluded:\n")
pp.printGroupedResources(excludedWorkloads)
}
if len(passedWorkloads) > 0 {
cautils.SuccessDisplay(prettyPrinter.writer, "Passed:\n")
prettyPrinter.printGroupedResources(passedWorkloads)
cautils.SuccessDisplay(pp.writer, "Passed:\n")
pp.printGroupedResources(passedWorkloads)
}
}
func (prettyPrinter *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) {
func (pp *PrettyPrinter) printGroupedResources(workloads map[string][]WorkloadSummary) {
indent := " "
for title, rsc := range workloads {
prettyPrinter.printGroupedResource(indent, title, rsc)
pp.printGroupedResource(indent, title, rsc)
}
}
func (prettyPrinter *PrettyPrinter) printGroupedResource(indent string, title string, rsc []WorkloadSummary) {
func (pp *PrettyPrinter) printGroupedResource(indent string, title string, rsc []WorkloadSummary) {
preIndent := indent
if title != "" {
cautils.SimpleDisplay(prettyPrinter.writer, "%s%s\n", indent, title)
cautils.SimpleDisplay(pp.writer, "%s%s\n", indent, title)
indent += indent
}
@@ -151,7 +179,7 @@ func (prettyPrinter *PrettyPrinter) printGroupedResource(indent string, title st
sort.Strings(resources)
for i := range resources {
cautils.SimpleDisplay(prettyPrinter.writer, resources[i]+"\n")
cautils.SimpleDisplay(pp.writer, resources[i]+"\n")
}
indent = preIndent
@@ -185,33 +213,33 @@ func generateFooter(summaryDetails *reportsummary.SummaryDetails) []string {
return row
}
func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlNames [][]string) {
func (pp *PrettyPrinter) printSummaryTable(summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
if summaryDetails.NumberOfControls().All() == 0 {
fmt.Fprintf(prettyPrinter.writer, "\nKubescape did not scan any of the resources, make sure you are scanning valid kubernetes manifests (Deployments, Pods, etc.)\n")
fmt.Fprintf(pp.writer, "\nKubescape did not scan any of the resources, make sure you are scanning valid kubernetes manifests (Deployments, Pods, etc.)\n")
return
}
cautils.InfoTextDisplay(prettyPrinter.writer, "\n"+controlCountersForSummary(summaryDetails.NumberOfControls())+"\n")
cautils.InfoTextDisplay(prettyPrinter.writer, renderSeverityCountersSummary(summaryDetails.GetResourcesSeverityCounters())+"\n\n")
cautils.InfoTextDisplay(pp.writer, "\n"+controlCountersForSummary(summaryDetails.NumberOfControls())+"\n")
cautils.InfoTextDisplay(pp.writer, renderSeverityCountersSummary(summaryDetails.GetResourcesSeverityCounters())+"\n\n")
// cautils.InfoTextDisplay(prettyPrinter.writer, "\n"+"Severities: SOME OTHER"+"\n\n")
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
summaryTable := tablewriter.NewWriter(pp.writer)
summaryTable.SetAutoWrapText(false)
summaryTable.SetHeader(getControlTableHeaders())
summaryTable.SetHeaderLine(true)
summaryTable.SetColumnAlignment(getColumnsAlignments())
printAll := prettyPrinter.verboseMode
printAll := pp.verboseMode
if summaryDetails.NumberOfResources().Failed() == 0 {
// if there are no failed controls, print the resource table and detailed information
printAll = true
}
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
for i := len(sortedControlNames) - 1; i >= 0; i-- {
for _, c := range sortedControlNames[i] {
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, c), infoToPrintInfo, printAll)
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
row := generateRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfo, printAll)
if len(row) > 0 {
summaryTable.Append(row)
}
@@ -223,16 +251,16 @@ func (prettyPrinter *PrettyPrinter) printSummaryTable(summaryDetails *reportsumm
summaryTable.Render()
// When scanning controls the framework list will be empty
cautils.InfoTextDisplay(prettyPrinter.writer, frameworksScoresToString(summaryDetails.ListFrameworks()))
cautils.InfoTextDisplay(pp.writer, frameworksScoresToString(summaryDetails.ListFrameworks()))
prettyPrinter.printInfo(infoToPrintInfo)
pp.printInfo(infoToPrintInfo)
}
func (prettyPrinter *PrettyPrinter) printInfo(infoToPrintInfo []infoStars) {
func (pp *PrettyPrinter) printInfo(infoToPrintInfo []infoStars) {
fmt.Println()
for i := range infoToPrintInfo {
cautils.InfoDisplay(prettyPrinter.writer, fmt.Sprintf("%s %s\n", infoToPrintInfo[i].stars, infoToPrintInfo[i].info))
cautils.InfoDisplay(pp.writer, fmt.Sprintf("%s %s\n", infoToPrintInfo[i].stars, infoToPrintInfo[i].info))
}
}

View File

@@ -1,3 +1,3 @@
package v2
package printer
var INDENT = " "

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"fmt"
@@ -24,15 +24,15 @@ func NewPrometheusPrinter(verboseMode bool) *PrometheusPrinter {
}
}
func (prometheusPrinter *PrometheusPrinter) SetWriter(outputFile string) {
prometheusPrinter.writer = printer.GetWriter(outputFile)
func (pp *PrometheusPrinter) SetWriter(outputFile string) {
pp.writer = printer.GetWriter(outputFile)
}
func (prometheusPrinter *PrometheusPrinter) Score(score float32) {
func (pp *PrometheusPrinter) Score(score float32) {
fmt.Printf("\n# Overall risk-score (0- Excellent, 100- All failed)\nkubescape_score %d\n", cautils.Float32ToInt(score))
}
func (printer *PrometheusPrinter) generatePrometheusFormat(
func (pp *PrometheusPrinter) generatePrometheusFormat(
resources map[string]workloadinterface.IMetadata,
results map[string]resourcesresults.Result,
summaryDetails *reportsummary.SummaryDetails) *Metrics {
@@ -44,12 +44,13 @@ func (printer *PrometheusPrinter) generatePrometheusFormat(
return m
}
func (printer *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
func (pp *PrometheusPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
metrics := printer.generatePrometheusFormat(opaSessionObj.AllResources, opaSessionObj.ResourcesResult, &opaSessionObj.Report.SummaryDetails)
metrics := pp.generatePrometheusFormat(opaSessionObj.AllResources, opaSessionObj.ResourcesResult, &opaSessionObj.Report.SummaryDetails)
logOUtputFile(printer.writer.Name())
if _, err := printer.writer.Write([]byte(metrics.String())); err != nil {
if _, err := pp.writer.Write([]byte(metrics.String())); err != nil {
logger.L().Error("failed to write results", helpers.Error(err))
} else {
printer.LogOutputFile(pp.writer.Name())
}
}

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"github.com/kubescape/k8s-interface/workloadinterface"

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"fmt"
@@ -77,7 +77,7 @@ func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl,
row[resourceColumnPath] = strings.Join(append(failedPathsToString(&controls[i]), fixPathsToString(&controls[i])...), "\n")
row[resourceColumnName] = controls[i].GetName()
if c := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaName, controls[i].GetName()); c != nil {
if c := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, controls[i].GetID()); c != nil {
row[resourceColumnSeverity] = getSeverityColumn(c)
}

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"fmt"
@@ -66,7 +66,7 @@ func (sp *SARIFPrinter) Score(score float32) {
}
func (sp *SARIFPrinter) SetWriter(outputFile string) {
if outputFile == "" {
if strings.TrimSpace(outputFile) == "" {
outputFile = sarifOutputFile
}
if filepath.Ext(strings.TrimSpace(outputFile)) != sarifOutputExt {
@@ -144,6 +144,8 @@ func (sp *SARIFPrinter) ActionPrint(opaSessionObj *cautils.OPASessionObj) {
report.AddRun(run)
report.PrettyWrite(sp.writer)
printer.LogOutputFile(sp.writer.Name())
}
func (sp *SARIFPrinter) resolveFixLocation(opaSessionObj *cautils.OPASessionObj, locationResolver *locationresolver.FixPathLocationResolver, ac *resourcesresults.ResourceAssociatedControl, resourceID string) locationresolver.Location {

View File

@@ -1,11 +1,11 @@
package v2
package printer
import "testing"
func Test_scoreToSeverityLevel(t *testing.T) {
tc := []struct {
Name string
ScoreFactor float32
ScoreFactor float32
ExpectedSARIFLevel sarifSeverityLevel
}{
{"Score factor 1.0 should map to 'note' SARIF level", 1.0, sarifSeverityLevelNote},

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"github.com/kubescape/kubescape/v2/core/cautils"

View File

@@ -1,4 +1,4 @@
package v2
package printer
import (
"github.com/kubescape/k8s-interface/k8sinterface"

View File

@@ -1,8 +1,6 @@
package v2
package printer
import (
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling"
@@ -83,10 +81,3 @@ func finalizeResources(results []resourcesresults.Result, allResources map[strin
}
return resources
}
func logOUtputFile(fileName string) {
if fileName != "/dev/stdout" && fileName != "/dev/stderr" {
logger.L().Success("Scan results saved", helpers.String("filename", fileName))
}
}

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"encoding/json"
@@ -85,10 +85,18 @@ func (report *ReportEventReceiver) SetClusterName(clusterName string) {
}
func (report *ReportEventReceiver) prepareReport(opaSessionObj *cautils.OPASessionObj) error {
// All scans whose target is not a cluster, currently their target is a file, which is what the backend expects
// (e.g. local-git, directory, etc)
// The backend for Kubescape expects scanning targets to be either
// Clusters or Files, not other types we support (GitLocal, Directory
// etc). So, to submit a compatible report to the backend, we have to
// override the scanning target, submit the report and then restore the
// original value.
originalScanningTarget := opaSessionObj.Metadata.ScanMetadata.ScanningTarget
if opaSessionObj.Metadata.ScanMetadata.ScanningTarget != reporthandlingv2.Cluster {
opaSessionObj.Metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
defer func() {
opaSessionObj.Metadata.ScanMetadata.ScanningTarget = originalScanningTarget
}()
}
report.initEventReceiverURL()
@@ -142,7 +150,7 @@ func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.Postur
// set result.RawResource
resourceID := v.GetResourceID()
if _, ok := allResources[resourceID]; !ok {
return fmt.Errorf("expected to find raw resource object for '%s'", resourceID)
continue
}
resource := reporthandling.NewResourceIMetadata(allResources[resourceID])
if r, ok := resourcesSource[resourceID]; ok {
@@ -260,7 +268,7 @@ func (report *ReportEventReceiver) addPathURL(urlObj *url.URL) {
if report.customerAdminEMail != "" || report.token == "" { // data has been submitted
switch report.submitContext {
case SubmitContextScan:
urlObj.Path = fmt.Sprintf("configuration-scanning/%s", report.clusterName)
urlObj.Path = fmt.Sprintf("config-scanning/%s", report.clusterName)
case SubmitContextRBAC:
urlObj.Path = "rbac-visualizer"
case SubmitContextRepository:

View File

@@ -1,10 +1,11 @@
package v2
package reporter
import (
"net/url"
"testing"
"github.com/kubescape/kubescape/v2/core/cautils"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/stretchr/testify/assert"
)
@@ -32,7 +33,7 @@ func TestReportEventReceiver_addPathURL(t *testing.T) {
want: &url.URL{
Scheme: "https",
Host: "localhost:8080",
Path: "configuration-scanning/test",
Path: "config-scanning/test",
},
},
}
@@ -58,7 +59,7 @@ func TestGetURL(t *testing.T) {
"",
SubmitContextScan,
)
assert.Equal(t, "https://cloud.armosec.io/configuration-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
assert.Equal(t, "https://cloud.armosec.io/config-scanning/test?utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
// Test rbac submit and registered url
@@ -106,3 +107,49 @@ func TestGetURL(t *testing.T) {
assert.Equal(t, "https://cloud.armosec.io/account/sign-up?customerGUID=1234&invitationToken=token&utm_campaign=Submit&utm_medium=CLI&utm_source=GitHub", reporter.GetURL())
}
}
func Test_prepareReportKeepsOriginalScanningTarget(t *testing.T) {
// prepareReport should keep the original scanning target it received, and not mutate it
testCases := []struct {
Name string
Want reporthandlingv2.ScanningTarget
}{
{"Cluster", reporthandlingv2.Cluster},
{"File", reporthandlingv2.File},
{"Repo", reporthandlingv2.Repo},
{"GitLocal", reporthandlingv2.GitLocal},
{"Directory", reporthandlingv2.Directory},
}
reporter := NewReportEventReceiver(
&cautils.ConfigObj{
AccountID: "1e3ae7c4-a8bb-4d7c-9bdf-eb86bc25e6bb",
Token: "token",
ClusterName: "test",
},
"",
SubmitContextScan,
)
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
want := tc.Want
opaSessionObj := &cautils.OPASessionObj{
Report: &reporthandlingv2.PostureReport{},
Metadata: &reporthandlingv2.Metadata{
ScanMetadata: reporthandlingv2.ScanMetadata{ScanningTarget: want},
},
}
reporter.prepareReport(opaSessionObj)
got := opaSessionObj.Metadata.ScanMetadata.ScanningTarget
if got != want {
t.Errorf("Scanning targets dont match after preparing report. Got: %v, want %v", got, want)
}
},
)
}
}

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"net/url"
@@ -45,8 +45,7 @@ func (report *ReportEventReceiver) setSubReport(opaSessionObj *cautils.OPASessio
if opaSessionObj.Metadata != nil {
reportObj.Metadata = *opaSessionObj.Metadata
if opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata != nil {
reportObj.ClusterCloudProvider = opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider // DEPRECATED
reportObj.Metadata.ClusterMetadata = *opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata
reportObj.ClusterCloudProvider = opaSessionObj.Metadata.ContextMetadata.ClusterContextMetadata.CloudProvider // DEPRECATED - left here as fallback
}
}
return reportObj

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"net/url"

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"net/url"

View File

@@ -1,4 +1,4 @@
package v2
package reporter
import (
"net/url"

View File

@@ -16,69 +16,82 @@ import (
type ResultsHandler struct {
reporterObj reporter.IReport
printerObj printer.IPrinter
printerObjs []printer.IPrinter
uiPrinter printer.IPrinter
scanData *cautils.OPASessionObj
}
func NewResultsHandler(reporterObj reporter.IReport, printerObj printer.IPrinter) *ResultsHandler {
func NewResultsHandler(reporterObj reporter.IReport, printerObjs []printer.IPrinter, uiPrinter printer.IPrinter) *ResultsHandler {
return &ResultsHandler{
reporterObj: reporterObj,
printerObj: printerObj,
printerObjs: printerObjs,
uiPrinter: uiPrinter,
}
}
// GetScore return scan risk-score
func (resultsHandler *ResultsHandler) GetRiskScore() float32 {
return resultsHandler.scanData.Report.SummaryDetails.Score
// GetScore returns the results risk score
func (rh *ResultsHandler) GetRiskScore() float32 {
return rh.scanData.Report.SummaryDetails.Score
}
// GetData get scan/action related data (policies, resources, results, etc.). Call ToJson function if you wish the json representation of the data
func (resultsHandler *ResultsHandler) GetData() *cautils.OPASessionObj {
return resultsHandler.scanData
// GetData returns scan/action related data (policies, resources, results, etc.)
//
// Call the ToJson() method if you want the JSON representation of the data
func (rh *ResultsHandler) GetData() *cautils.OPASessionObj {
return rh.scanData
}
// SetData set scan/action related data
func (resultsHandler *ResultsHandler) SetData(data *cautils.OPASessionObj) {
resultsHandler.scanData = data
// SetData sets the scan/action related data
func (rh *ResultsHandler) SetData(data *cautils.OPASessionObj) {
rh.scanData = data
}
// GetPrinter get printer object
func (resultsHandler *ResultsHandler) GetPrinter() printer.IPrinter {
return resultsHandler.printerObj
// GetPrinter returns all printers
func (rh *ResultsHandler) GetPrinters() []printer.IPrinter {
return rh.printerObjs
}
// GetReporter get reporter object
func (resultsHandler *ResultsHandler) GetReporter() reporter.IReport {
return resultsHandler.reporterObj
// GetReporter returns the reporter object
func (rh *ResultsHandler) GetReporter() reporter.IReport {
return rh.reporterObj
}
// ToJson return results in json format
func (resultsHandler *ResultsHandler) ToJson() ([]byte, error) {
return json.Marshal(printerv2.FinalizeResults(resultsHandler.scanData))
// ToJson returns the results in the JSON format
func (rh *ResultsHandler) ToJson() ([]byte, error) {
return json.Marshal(printerv2.FinalizeResults(rh.scanData))
}
// GetResults return results
func (resultsHandler *ResultsHandler) GetResults() *reporthandlingv2.PostureReport {
return printerv2.FinalizeResults(resultsHandler.scanData)
// GetResults returns the results
func (rh *ResultsHandler) GetResults() *reporthandlingv2.PostureReport {
return printerv2.FinalizeResults(rh.scanData)
}
// HandleResults handle the scan results according to the pre defined interfaces
func (resultsHandler *ResultsHandler) HandleResults() error {
// HandleResults handles all necessary actions for the scan results
func (rh *ResultsHandler) HandleResults() error {
// Display scan results in the UI first to give immediate value.
// First we output the results and then the score, so the
// score - a summary of the results—can always be seen at the end
// of output
rh.uiPrinter.ActionPrint(rh.scanData)
rh.uiPrinter.Score(rh.GetRiskScore())
resultsHandler.printerObj.ActionPrint(resultsHandler.scanData)
// Then print to output files
for _, printer := range rh.printerObjs {
printer.ActionPrint(rh.scanData)
printer.Score(rh.GetRiskScore())
}
if err := resultsHandler.reporterObj.Submit(resultsHandler.scanData); err != nil {
// We should submit only after printing results, so a user can see
// results at all times, even if submission fails
if err := rh.reporterObj.Submit(rh.scanData); err != nil {
return err
}
resultsHandler.printerObj.Score(resultsHandler.GetRiskScore())
resultsHandler.reporterObj.DisplayReportURL()
rh.reporterObj.DisplayReportURL()
return nil
}
// NewPrinter defined output format
// NewPrinter returns a new printer for a given format and configuration options
func NewPrinter(printFormat, formatVersion string, verboseMode bool, viewType cautils.ViewTypes) printer.IPrinter {
switch printFormat {

File diff suppressed because one or more lines are too long

4
go.mod
View File

@@ -14,10 +14,10 @@ require (
github.com/go-git/go-git/v5 v5.4.2
github.com/google/uuid v1.3.0
github.com/johnfercher/maroto v0.37.0
github.com/kubescape/go-git-url v0.0.17
github.com/kubescape/go-git-url v0.0.20
github.com/kubescape/go-logger v0.0.6
github.com/kubescape/k8s-interface v0.0.89
github.com/kubescape/opa-utils v0.0.204
github.com/kubescape/opa-utils v0.0.218
github.com/kubescape/rbac-utils v0.0.19
github.com/libgit2/git2go/v33 v33.0.9
github.com/mattn/go-isatty v0.0.14

10
go.sum
View File

@@ -134,7 +134,7 @@ github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg=
github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw=
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
github.com/alecthomas/repr v0.1.1 h1:87P60cSmareLAxMc4Hro0r2RBY4ROm0dYwkJNpS4pPs=
@@ -583,14 +583,14 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-git-url v0.0.17 h1:yBPmQzxIVa3vbFVjwTlrnxjGf1kTAWDeMh+kvMd/RZA=
github.com/kubescape/go-git-url v0.0.17/go.mod h1:a1rDC6M1VBMwTaDfrSwbVq84Zu71U+1qKqQmI1cA0lE=
github.com/kubescape/go-git-url v0.0.20 h1:oTtmF4c4Vmt0Og3Qbnjkz18sdu4ZdHubQlO6JsOXXsg=
github.com/kubescape/go-git-url v0.0.20/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM=
github.com/kubescape/go-logger v0.0.6 h1:ynhAmwrz0O7Jtqq1CdmCZUrKveji25hVP+B/FAb3QrA=
github.com/kubescape/go-logger v0.0.6/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.89 h1:OtlvZosHpjlbHfsilfQk2wRbuBnxwF0e+WZX6GbkfLU=
github.com/kubescape/k8s-interface v0.0.89/go.mod h1:pgFRs20mHiavf6+fFWY7h/f8HuKlwuZwirvjxiKJlu0=
github.com/kubescape/opa-utils v0.0.204 h1:9O9drjyzjOhI7Xi2S4Px0WKa66U5GFPQqeOLvhDqHnw=
github.com/kubescape/opa-utils v0.0.204/go.mod h1:rDC3PANuk8gU5lSDO/WPFTluypBQ+/6qiuZLye+slYg=
github.com/kubescape/opa-utils v0.0.218 h1:3YFloD8NYn0iKeheIaJAr7QynWQJsAjD2o4hlI3RFjE=
github.com/kubescape/opa-utils v0.0.218/go.mod h1:sNCabe+qZmZLSs/T76fPewEZnl5TSzGq4vhmPd1tP3o=
github.com/kubescape/rbac-utils v0.0.19 h1:7iydgVxlMLW15MgHORfMBMqNj9jHtFGACd744fdtrFs=
github.com/kubescape/rbac-utils v0.0.19/go.mod h1:t57AhSrjuNGQ+mpZWQM/hBzrCOeKBDHegFoVo4tbikQ=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=

View File

@@ -12,7 +12,7 @@ require (
github.com/gorilla/schema v1.2.0
github.com/kubescape/go-logger v0.0.6
github.com/kubescape/kubescape/v2 v2.0.0-00010101000000-000000000000
github.com/kubescape/opa-utils v0.0.204
github.com/kubescape/opa-utils v0.0.218
github.com/stretchr/testify v1.8.0
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
)
@@ -118,7 +118,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kubescape/go-git-url v0.0.17 // indirect
github.com/kubescape/go-git-url v0.0.20 // indirect
github.com/kubescape/k8s-interface v0.0.89 // indirect
github.com/kubescape/rbac-utils v0.0.19 // indirect
github.com/libgit2/git2go/v33 v33.0.9 // indirect

View File

@@ -134,7 +134,7 @@ github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg=
github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw=
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
github.com/alecthomas/repr v0.1.1 h1:87P60cSmareLAxMc4Hro0r2RBY4ROm0dYwkJNpS4pPs=
@@ -639,14 +639,14 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubescape/go-git-url v0.0.17 h1:yBPmQzxIVa3vbFVjwTlrnxjGf1kTAWDeMh+kvMd/RZA=
github.com/kubescape/go-git-url v0.0.17/go.mod h1:a1rDC6M1VBMwTaDfrSwbVq84Zu71U+1qKqQmI1cA0lE=
github.com/kubescape/go-git-url v0.0.20 h1:oTtmF4c4Vmt0Og3Qbnjkz18sdu4ZdHubQlO6JsOXXsg=
github.com/kubescape/go-git-url v0.0.20/go.mod h1:IbVT7Wsxlghsa+YxI5KOx4k9VQJaa3z0kTaQz5D3nKM=
github.com/kubescape/go-logger v0.0.6 h1:ynhAmwrz0O7Jtqq1CdmCZUrKveji25hVP+B/FAb3QrA=
github.com/kubescape/go-logger v0.0.6/go.mod h1:DnVWEvC90LFY1nNMaNo6nBVOcqkLMK3S0qzXP1fzRvI=
github.com/kubescape/k8s-interface v0.0.89 h1:OtlvZosHpjlbHfsilfQk2wRbuBnxwF0e+WZX6GbkfLU=
github.com/kubescape/k8s-interface v0.0.89/go.mod h1:pgFRs20mHiavf6+fFWY7h/f8HuKlwuZwirvjxiKJlu0=
github.com/kubescape/opa-utils v0.0.204 h1:9O9drjyzjOhI7Xi2S4Px0WKa66U5GFPQqeOLvhDqHnw=
github.com/kubescape/opa-utils v0.0.204/go.mod h1:rDC3PANuk8gU5lSDO/WPFTluypBQ+/6qiuZLye+slYg=
github.com/kubescape/opa-utils v0.0.218 h1:3YFloD8NYn0iKeheIaJAr7QynWQJsAjD2o4hlI3RFjE=
github.com/kubescape/opa-utils v0.0.218/go.mod h1:sNCabe+qZmZLSs/T76fPewEZnl5TSzGq4vhmPd1tP3o=
github.com/kubescape/rbac-utils v0.0.19 h1:7iydgVxlMLW15MgHORfMBMqNj9jHtFGACd744fdtrFs=
github.com/kubescape/rbac-utils v0.0.19/go.mod h1:t57AhSrjuNGQ+mpZWQM/hBzrCOeKBDHegFoVo4tbikQ=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=

View File

@@ -32,9 +32,9 @@ func TestToScanInfo(t *testing.T) {
assert.False(t, s.Submit)
assert.False(t, s.ScanAll)
assert.True(t, s.FrameworkScan)
assert.Equal(t, "nsa", s.PolicyIdentifier[0].Name)
assert.Equal(t, "nsa", s.PolicyIdentifier[0].Identifier)
assert.Equal(t, apisv1.KindFramework, s.PolicyIdentifier[0].Kind)
assert.Equal(t, "mitre", s.PolicyIdentifier[1].Name)
assert.Equal(t, "mitre", s.PolicyIdentifier[1].Identifier)
assert.Equal(t, apisv1.KindFramework, s.PolicyIdentifier[1].Kind)
}
{
@@ -49,7 +49,7 @@ func TestToScanInfo(t *testing.T) {
assert.Equal(t, "kube-system,kube-public", s.IncludeNamespaces)
assert.Equal(t, "", s.ExcludedNamespaces)
assert.Equal(t, 1, len(s.PolicyIdentifier))
assert.Equal(t, "c-0001", s.PolicyIdentifier[0].Name)
assert.Equal(t, "c-0001", s.PolicyIdentifier[0].Identifier)
assert.Equal(t, apisv1.KindControl, s.PolicyIdentifier[0].Kind)
}
{

Binary file not shown.

View File

@@ -66,6 +66,6 @@ echo -e "\033[0m"
$KUBESCAPE_EXEC version
echo
echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan --enable-host-scan --verbose"
echo -e "\033[35mUsage: $ $KUBESCAPE_EXEC scan --enable-host-scan"
echo -e "\033[0m"

View File

@@ -3,7 +3,6 @@ package main
import (
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v2/cmd"
)
func main() {

View File

@@ -21,7 +21,7 @@ def scan_control_id(kubescape_exec: str):
def scan_controls(kubescape_exec: str):
return smoke_utils.run_command(command=[kubescape_exec, "scan", "control", 'HostPath mount,Allow privilege escalation', all_files, "--enable-host-scan=false"])
return smoke_utils.run_command(command=[kubescape_exec, "scan", "control", 'C-0048,C-0016', all_files, "--enable-host-scan=false"])
def scan_framework(kubescape_exec: str):
@@ -48,10 +48,6 @@ def run(kubescape_exec: str):
# msg = scan_all(kubescape_exec=kubescape_exec)
# smoke_utils.assertion(msg)
print("Testing scan control name")
msg = scan_control_name(kubescape_exec=kubescape_exec)
smoke_utils.assertion(msg)
print("Testing scan control id")
msg = scan_control_id(kubescape_exec=kubescape_exec)
smoke_utils.assertion(msg)