diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index bbcbbe7d..a1a4f3e1 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -6,15 +6,14 @@ labels: ''
assignees: ''
---
+**Is your feature request related to a problem? Please describe.**
+ > A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+**Describe the solution you'd like.**
+ > A clear and concise description of what you want to happen.
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
+**Describe alternatives you've considered.**
+ > A clear and concise description of any alternative solutions or features you've considered.
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
+**Additional context.**
+ > Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index b2d8493c..3e3ec6b2 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,11 +2,15 @@
## Screenshots - If Any (Optional)
-## Issue ticket number and link
+## This PR fixes:
+
+* Resolved #
## Checklist before requesting a review
+
+
- [ ] My code follows the style guidelines of this project
-- [ ] I have commented my code, particularly in hard-to-understand areas
+- [ ] I have commented on my code, particularly in hard-to-understand areas
- [ ] I have performed a self-review of my code
- [ ] If it is a core feature, I have added thorough tests.
- [ ] New and existing unit tests pass locally with my changes
diff --git a/.github/workflows/close-typos-issues.yaml b/.github/workflows/close-typos-issues.yaml
index 46b3275b..e12c3fb4 100644
--- a/.github/workflows/close-typos-issues.yaml
+++ b/.github/workflows/close-typos-issues.yaml
@@ -3,16 +3,21 @@ on:
types: [opened, labeled]
jobs:
- build:
- if: ${{ github.event.label.name == 'typo' }}
+ open_PR_message:
+ if: github.event.label.name == 'typo'
runs-on: ubuntu-latest
+ steps:
+ - uses: ben-z/actions-comment-on-issue@1.0.2
+ with:
+ message: "Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+
+
auto_close_issues:
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v3
- - name: Automatically close typo issues
- uses: lucasbento/auto-close-issues@v1.0.2
+ - uses: lee-dohm/close-matching-issues@v2
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- issue-close-message: "@${issue.user.login}: Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
+ query: 'label:typo'
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/community.yml b/.github/workflows/community.yml
new file mode 100644
index 00000000..1d88e1bc
--- /dev/null
+++ b/.github/workflows/community.yml
@@ -0,0 +1,22 @@
+on:
+ fork:
+ issues:
+ types: [opened]
+ issue_comment:
+ types: [created]
+ pull_request_target:
+ types: [opened]
+ pull_request_review_comment:
+ types: [created]
+
+jobs:
+ welcome:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v1
+ - uses: EddieHubCommunity/gh-action-community/src/welcome@main
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ issue-message: '
Hey, Welcome to this repo, Congratulations on opening your issue. Keep Contributing to Kubescape
'
+ pr-message: '
Hey, Welcome to this repo, Congratulations on opening your Pull Request. Keep Contributing to Kubescape
'
+ footer: '
We''ll try to review and add you work as soon as possible and a maintainer will get back to you soon!
'
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 297639fc..a31c2504 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,13 +3,13 @@
First, it is awesome that you are considering contributing to Kubescape! Contributing is important and fun and we welcome your efforts.
When contributing, we categorize contributions into two:
-* Small code changes or fixes, whose scope are limited to a single or two files
-* Complex features and improvements, whose are not limited
+* Small code changes or fixes, whose scope is limited to a single or two files
+* Complex features and improvements, that are not limited
If you have a small change, feel free to fire up a Pull Request.
When planning a bigger change, please first discuss the change you wish to make via issue,
-email, or any other method with the owners of this repository before making a change. Most likely your changes or features are great, but sometimes we might be already going to this direction (or the exact opposite ;-) ) and we don't want to waste your time.
+email, or any other method with the owners of this repository before making a change. Most likely your changes or features are great, but sometimes we might be already going in this direction (or the exact opposite ;-) ) and we don't want to waste your time.
Please note we have a code of conduct, please follow it in all your interactions with the project.
@@ -27,7 +27,7 @@ Please note we have a code of conduct, please follow it in all your interactions
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
+contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
diff --git a/README.md b/README.md
index 4deb6bd6..d6950498 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,12 @@
-
+
+
+
+
+---
[](https://github.com/kubescape/kubescape/actions/workflows/build.yaml)
[](https://goreportcard.com/report/github.com/kubescape/kubescape)
+[](https://gitpod.io/#https://github.com/kubescape/kubescape)
:sunglasses: [Want to contribute?](#being-a-part-of-the-team) :innocent:
@@ -46,19 +51,18 @@ kubescape scan --submit --enable-host-scan --verbose
-### Click [👍](https://github.com/kubescape/kubescape/stargazers) if you want us to continue to develop and improve Kubescape 😀
+### Please [star ⭐](https://github.com/kubescape/kubescape/stargazers) the repo if you want us to continue developing and improving Kubescape 😀
-
# Being a part of the team
We invite you to our team! We are excited about this project and want to return the love we get.
-Want to contribute? Want to discuss something? Have an issue?
+[Want to contribute?](https://github.com/kubescape/kubescape/blob/master/CONTRIBUTING.md) Want to discuss something? Have an issue? Please make sure that you follow our [Code Of Conduct](https://github.com/kubescape/kubescape/blob/master/CODE_OF_CONDUCT.md) .
* Feel free to pick a task from the [issues](https://github.com/kubescape/kubescape/issues?q=is%3Aissue+is%3Aopen+label%3A%22open+for+contribution%22), [roadmap](docs/roadmap.md) or suggest a feature of your own. [Contact us](MAINTAINERS.md) directly for more information :)
-* Open an issue, we are trying to respond within 48 hours
+* [Open an issue](https://github.com/kubescape/kubescape/issues/new/choose) , we are trying to respond within 48 hours
* [Join us](https://discord.com/invite/WKZRaCtBxN) in the discussion on our discord server!
[](https://discord.com/invite/WKZRaCtBxN)
@@ -80,7 +84,9 @@ Want to contribute? Want to discuss something? Have an issue?
* [Scan Kubescape on an air-gapped environment (offline support)](https://youtu.be/IGXL9s37smM)
* [Managing exceptions in the Kubescape SaaS version](https://youtu.be/OzpvxGmCR80)
* [Configure and run customized frameworks](https://youtu.be/12Sanq_rEhs)
-* Customize control configurations. [Kubescape CLI](https://youtu.be/955psg6TVu4), [Kubescape SaaS](https://youtu.be/lIMVSVhH33o)
+* Customize control configurations:
+ - [Kubescape CLI](https://youtu.be/955psg6TVu4)
+ - [Kubescape SaaS](https://youtu.be/lIMVSVhH33o)
## Install on Windows
@@ -187,12 +193,12 @@ kubescape scan --include-namespaces development,staging,production
kubescape scan --exclude-namespaces kube-system,kube-public
```
-#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI) Submit the results in case the directory is a git repo. [docs](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
+#### Scan local `yaml`/`json` files before deploying. [Take a look at the demonstration](https://youtu.be/Ox6DaR7_4ZI). Submit the results in case the directory is a git repo. [docs](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
```
kubescape scan *.yaml --submit
```
-#### Scan kubernetes manifest files from a git repository [and submit the results](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
+#### Scan Kubernetes manifest files from a git repository [and submit the results](https://hub.armosec.io/docs/repository-scanning?utm_source=github&utm_medium=repository)
```
kubescape scan https://github.com/kubescape/kubescape --submit
```
@@ -261,7 +267,7 @@ kubescape scan --use-artifacts-from path/to/local/dir
You can also download a single artifact and scan with the `--use-from` flag
-1. Download and save in file, if file name is not specified, will save in `~/.kubescape/.json`
+1. Download and save in a file, if the file name is not specified, will save in `~/.kubescape/.json`
```
kubescape download framework nsa --output /path/nsa.json
```
diff --git a/build.py b/build.py
index a1ad193b..f9ed0380 100644
--- a/build.py
+++ b/build.py
@@ -25,7 +25,7 @@ def get_build_dir():
def get_package_name():
package_name = "kubescape"
- # if platform.system() == "Windows": package_name += ".exe"
+ if platform.system() == "Windows": package_name += ".exe"
return package_name
diff --git a/build/Dockerfile b/build/Dockerfile
index 542bc210..d626ec3b 100644
--- a/build/Dockerfile
+++ b/build/Dockerfile
@@ -20,7 +20,6 @@ WORKDIR /work
ADD . .
# install libgit2
-WORKDIR /work
RUN rm -rf git2go && make libgit2
# build kubescape server
@@ -34,16 +33,16 @@ RUN python build.py
RUN /work/build/ubuntu-latest/kubescape download artifacts -o /work/artifacts
-FROM alpine
+FROM alpine:3.16.2
RUN addgroup -S armo && adduser -S armo -G armo
-RUN mkdir /home/armo/.kubescape
COPY --from=builder /work/artifacts/ /home/armo/.kubescape
RUN chown -R armo:armo /home/armo/.kubescape
USER armo
+
WORKDIR /home/armo
COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/ksserver
diff --git a/cmd/completion/completion.go b/cmd/completion/completion.go
index 0fe36c1c..3a7ac1a5 100644
--- a/cmd/completion/completion.go
+++ b/cmd/completion/completion.go
@@ -43,7 +43,3 @@ func GetCompletionCmd() *cobra.Command {
}
return completionCmd
}
-
-// func init() {
-// rootCmd.AddCommand(completionCmd)
-// }
diff --git a/cmd/root.go b/cmd/root.go
index a94c5f5e..c4d0da28 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -63,6 +63,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.PersistentFlags().StringVarP(&rootInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/")))
rootCmd.PersistentFlags().StringVar(&rootInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.DisableColor, "disable-color", "", false, "Disable Color output for logging")
+ rootCmd.PersistentFlags().BoolVarP(&rootInfo.EnableColor, "enable-color", "", false, "Force enable Color output for logging")
cobra.OnInitialize(initLogger, initLoggerLevel, initEnvironment, initCacheDir)
diff --git a/cmd/rootutils.go b/cmd/rootutils.go
index cf6e533f..3b0140df 100644
--- a/cmd/rootutils.go
+++ b/cmd/rootutils.go
@@ -16,6 +16,7 @@ const envFlagUsage = "Send report results to specific URL. Format: 1 {
if len(args[1:]) == 0 || args[1] != "-" {
- scanInfo.InputPatterns = []string{args[1]}
+ scanInfo.InputPatterns = args[1:]
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
diff --git a/cmd/scan/framework.go b/cmd/scan/framework.go
index 5a50b628..602c52ca 100644
--- a/cmd/scan/framework.go
+++ b/cmd/scan/framework.go
@@ -80,7 +80,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
if len(args) > 1 {
if len(args[1:]) == 0 || args[1] != "-" {
- scanInfo.InputPatterns = []string{args[1]}
+ scanInfo.InputPatterns = args[1:]
} else { // store stdin to file - do NOT move to separate function !!
tempFile, err := os.CreateTemp(".", "tmp-kubescape*.yaml")
if err != nil {
diff --git a/core/cautils/customerloader.go b/core/cautils/customerloader.go
index a7bbb0e9..4016cbeb 100644
--- a/core/cautils/customerloader.go
+++ b/core/cautils/customerloader.go
@@ -182,11 +182,11 @@ TODO - supprot:
KS_CACHE // path to cached files
*/
type ClusterConfig struct {
+ backendAPI getter.IBackend
k8s *k8sinterface.KubernetesApi
+ configObj *ConfigObj
configMapName string
configMapNamespace string
- backendAPI getter.IBackend
- configObj *ConfigObj
}
func NewClusterConfig(k8s *k8sinterface.KubernetesApi, backendAPI getter.IBackend, credentials *Credentials, clusterName string) *ClusterConfig {
diff --git a/core/cautils/datastructures.go b/core/cautils/datastructures.go
index 39946da8..733ca8d7 100644
--- a/core/cautils/datastructures.go
+++ b/core/cautils/datastructures.go
@@ -5,6 +5,7 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/reporthandling"
apis "github.com/kubescape/opa-utils/reporthandling/apis"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
@@ -14,15 +15,16 @@ type K8SResources map[string][]string
type KSResources map[string][]string
type OPASessionObj struct {
- K8SResources *K8SResources // input k8s objects
- ArmoResource *KSResources // input ARMO objects
- Policies []reporthandling.Framework // list of frameworks to scan
- AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[]
- ResourcesResult map[string]resourcesresults.Result // resources scan results, map[]
- ResourceSource map[string]reporthandling.Source // resources sources, map[]
- Report *reporthandlingv2.PostureReport // scan results v2 - Remove
- Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
- RegoInputData RegoInputData // input passed to rgo for scanning. map[][]
+ K8SResources *K8SResources // input k8s objects
+ ArmoResource *KSResources // input ARMO objects
+ Policies []reporthandling.Framework // list of frameworks to scan
+ AllResources map[string]workloadinterface.IMetadata // all scanned resources, map[]
+ ResourcesResult map[string]resourcesresults.Result // resources scan results, map[]
+ ResourceSource map[string]reporthandling.Source // resources sources, map[]
+ ResourcesPrioritized map[string]prioritization.PrioritizedResource // resources prioritization information, map[]
+ Report *reporthandlingv2.PostureReport // scan results v2 - Remove
+ Exceptions []armotypes.PostureExceptionPolicy // list of exceptions to apply on scan results
+ RegoInputData RegoInputData // input passed to rgo for scanning. map[][]
Metadata *reporthandlingv2.Metadata
InfoMap map[string]apis.StatusInfo // Map errors of resources to StatusInfo
ResourceToControlsMap map[string][]string // map[] = []
@@ -36,6 +38,7 @@ func NewOPASessionObj(frameworks []reporthandling.Framework, k8sResources *K8SRe
K8SResources: k8sResources,
AllResources: make(map[string]workloadinterface.IMetadata),
ResourcesResult: make(map[string]resourcesresults.Result),
+ ResourcesPrioritized: make(map[string]prioritization.PrioritizedResource),
InfoMap: make(map[string]apis.StatusInfo),
ResourceToControlsMap: make(map[string][]string),
ResourceSource: make(map[string]reporthandling.Source),
@@ -63,11 +66,12 @@ func (sessionObj *OPASessionObj) SetNumberOfWorkerNodes(n int) {
func NewOPASessionObjMock() *OPASessionObj {
return &OPASessionObj{
- Policies: nil,
- K8SResources: nil,
- AllResources: make(map[string]workloadinterface.IMetadata),
- ResourcesResult: make(map[string]resourcesresults.Result),
- Report: &reporthandlingv2.PostureReport{},
+ Policies: nil,
+ K8SResources: nil,
+ AllResources: make(map[string]workloadinterface.IMetadata),
+ ResourcesResult: make(map[string]resourcesresults.Result),
+ ResourcesPrioritized: make(map[string]prioritization.PrioritizedResource),
+ Report: &reporthandlingv2.PostureReport{},
Metadata: &reporthandlingv2.Metadata{
ScanMetadata: reporthandlingv2.ScanMetadata{
ScanningTarget: 0,
@@ -94,6 +98,6 @@ type RegoInputData struct {
}
type Policies struct {
- Frameworks []string
Controls map[string]reporthandling.Control // map[]
+ Frameworks []string
}
diff --git a/core/cautils/fileutils.go b/core/cautils/fileutils.go
index 6d1fbc60..4a03e928 100644
--- a/core/cautils/fileutils.go
+++ b/core/cautils/fileutils.go
@@ -47,7 +47,7 @@ func LoadResourcesFromHelmCharts(basePath string) (map[string][]workloadinterfac
if err == nil {
wls, errs := chart.GetWorkloadsWithDefaultValues()
if len(errs) > 0 {
- logger.L().Error(fmt.Sprintf("Rendering of Helm chart template failed: %v", errs))
+ logger.L().Error(fmt.Sprintf("Rendering of Helm chart template '%s', failed: %v", chart.GetName(), errs))
continue
}
@@ -190,8 +190,10 @@ func readYamlFile(yamlFile []byte) ([]workloadinterface.IMetadata, error) {
}
if obj, ok := j.(map[string]interface{}); ok {
if o := objectsenvelopes.NewObject(obj); o != nil {
- if o.GetKind() == "List" {
- yamlObjs = append(yamlObjs, handleListObject(o)...)
+ if o.GetObjectType() == workloadinterface.TypeListWorkloads {
+ if list := workloadinterface.NewListWorkloadsObj(o.GetObject()); list != nil {
+ yamlObjs = append(yamlObjs, list.GetItems()...)
+ }
} else {
yamlObjs = append(yamlObjs, o)
}
@@ -323,20 +325,3 @@ func GetFileFormat(filePath string) FileFormat {
return FileFormat(filePath)
}
}
-
-// handleListObject handle a List manifest
-func handleListObject(obj workloadinterface.IMetadata) []workloadinterface.IMetadata {
- yamlObjs := []workloadinterface.IMetadata{}
- if i, ok := workloadinterface.InspectMap(obj.GetObject(), "items"); ok && i != nil {
- if items, ok := i.([]interface{}); ok && items != nil {
- for item := range items {
- if m, ok := items[item].(map[string]interface{}); ok && m != nil {
- if o := objectsenvelopes.NewObject(m); o != nil {
- yamlObjs = append(yamlObjs, o)
- }
- }
- }
- }
- }
- return yamlObjs
-}
diff --git a/core/cautils/getter/datastructures.go b/core/cautils/getter/datastructures.go
index 47a06626..d30abb1c 100644
--- a/core/cautils/getter/datastructures.go
+++ b/core/cautils/getter/datastructures.go
@@ -8,8 +8,8 @@ type FeLoginData struct {
type FeLoginResponse struct {
Token string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
- ExpiresIn int32 `json:"expiresIn"`
Expires string `json:"expires"`
+ ExpiresIn int32 `json:"expiresIn"`
}
type KSCloudSelectCustomer struct {
diff --git a/core/cautils/getter/kscloudapi.go b/core/cautils/getter/kscloudapi.go
index 676b5129..437ffa06 100644
--- a/core/cautils/getter/kscloudapi.go
+++ b/core/cautils/getter/kscloudapi.go
@@ -42,8 +42,8 @@ type KSCloudAPI struct {
accountID string
clientID string
secretKey string
- feToken FeLoginResponse
authCookie string
+ feToken FeLoginResponse
loggedIn bool
}
diff --git a/core/cautils/reportv2tov1.go b/core/cautils/reportv2tov1.go
index 7d202391..23859d6d 100644
--- a/core/cautils/reportv2tov1.go
+++ b/core/cautils/reportv2tov1.go
@@ -56,7 +56,9 @@ func controlReportV2ToV1(opaSessionObj *OPASessionObj, frameworkName string, con
rulesv1 := map[string]reporthandling.RuleReport{}
- for _, resourceID := range crv2.ListResourcesIDs().All() {
+ iter := crv2.ListResourcesIDs().All()
+ for iter.HasNext() {
+ resourceID := iter.Next()
if result, ok := opaSessionObj.ResourcesResult[resourceID]; ok {
for _, rulev2 := range result.ListRulesOfControl(crv2.GetID(), "") {
diff --git a/core/cautils/rootinfo.go b/core/cautils/rootinfo.go
index 5b2c8a69..333f474d 100644
--- a/core/cautils/rootinfo.go
+++ b/core/cautils/rootinfo.go
@@ -5,6 +5,7 @@ type RootInfo struct {
LoggerName string // logger name ("pretty"/"zap"/"none")
CacheDir string // cached dir
DisableColor bool // Disable Color
+ EnableColor bool // Force enable Color
KSCloudBEURLs string // Kubescape Cloud URL
KSCloudBEURLsDep string // Kubescape Cloud URL
diff --git a/core/core/scan.go b/core/core/scan.go
index 3eac8071..1af6a847 100644
--- a/core/core/scan.go
+++ b/core/core/scan.go
@@ -15,6 +15,7 @@ import (
"github.com/kubescape/kubescape/v2/core/pkg/opaprocessor"
"github.com/kubescape/kubescape/v2/core/pkg/policyhandler"
"github.com/kubescape/kubescape/v2/core/pkg/resourcehandler"
+ "github.com/kubescape/kubescape/v2/core/pkg/resourcesprioritization"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/printer"
"github.com/kubescape/kubescape/v2/core/pkg/resultshandling/reporter"
@@ -152,6 +153,12 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
return resultsHandling, fmt.Errorf("%w", err)
}
+ // ======================== prioritization ===================
+ priotizationHandler := resourcesprioritization.NewResourcesPrioritizationHandler(true)
+ if err := priotizationHandler.PrioritizeResources(scanData); err != nil {
+ return resultsHandling, fmt.Errorf("%w", err)
+ }
+
// ========================= results handling =====================
resultsHandling.SetData(scanData)
diff --git a/core/pkg/hostsensorutils/hostsensor.yaml b/core/pkg/hostsensorutils/hostsensor.yaml
index b2aea6e0..16f368c2 100644
--- a/core/pkg/hostsensorutils/hostsensor.yaml
+++ b/core/pkg/hostsensorutils/hostsensor.yaml
@@ -33,7 +33,7 @@ spec:
effect: NoSchedule
containers:
- name: host-sensor
- image: quay.io/armosec/kube-host-sensor:latest
+ image: quay.io/kubescape/host-scanner:latest
securityContext:
privileged: true
readOnlyRootFilesystem: true
diff --git a/core/pkg/opaprocessor/processorhandler.go b/core/pkg/opaprocessor/processorhandler.go
index f7fcbd01..7d9ddab4 100644
--- a/core/pkg/opaprocessor/processorhandler.go
+++ b/core/pkg/opaprocessor/processorhandler.go
@@ -122,7 +122,7 @@ func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[s
// ruleResults := make(map[string][]resourcesresults.ResourceAssociatedRule)
for i := range control.Rules {
- resourceAssociatedRule, err := opap.processRule(&control.Rules[i])
+ resourceAssociatedRule, err := opap.processRule(&control.Rules[i], control.FixedInput)
if err != nil {
logger.L().Error(err.Error())
continue
@@ -150,10 +150,15 @@ func (opap *OPAProcessor) processControl(control *reporthandling.Control) (map[s
return resourcesAssociatedControl, errs
}
-func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule) (map[string]*resourcesresults.ResourceAssociatedRule, error) {
+func (opap *OPAProcessor) processRule(rule *reporthandling.PolicyRule, fixedControlInputs map[string][]string) (map[string]*resourcesresults.ResourceAssociatedRule, error) {
postureControlInputs := opap.regoDependenciesData.GetFilteredPostureControlInputs(rule.ConfigInputs) // get store
+ // Merge configurable control input and fixed control input
+ for k, v := range fixedControlInputs {
+ postureControlInputs[k] = v
+ }
+
inputResources, err := reporthandling.RegoResourcesAggregator(rule, getAllSupportedObjects(opap.K8SResources, opap.ArmoResource, opap.AllResources, rule))
if err != nil {
return nil, fmt.Errorf("error getting aggregated k8sObjects: %s", err.Error())
diff --git a/core/pkg/opaprocessor/processorhandler_test.go b/core/pkg/opaprocessor/processorhandler_test.go
index 65099d17..c592e528 100644
--- a/core/pkg/opaprocessor/processorhandler_test.go
+++ b/core/pkg/opaprocessor/processorhandler_test.go
@@ -42,7 +42,7 @@ func TestProcessResourcesResult(t *testing.T) {
assert.Equal(t, 1, len(opaSessionObj.ResourcesResult))
res := opaSessionObj.ResourcesResult[deployment.GetID()]
- assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
+ assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Failed()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsFailed())
@@ -51,8 +51,8 @@ func TestProcessResourcesResult(t *testing.T) {
opap.updateResults()
res = opaSessionObj.ResourcesResult[deployment.GetID()]
- assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
- assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
+ assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
+ assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Failed()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsFailed())
@@ -67,13 +67,13 @@ func TestProcessResourcesResult(t *testing.T) {
assert.Equal(t, 0, summaryDetails.NumberOfResources().Passed())
// test resource listing
- assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().All()))
+ assert.Equal(t, 1, summaryDetails.ListResourcesIDs().All().Len())
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().Failed()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Excluded()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Passed()))
// test control listing
- assert.Equal(t, len(res.ListControlsIDs(nil).All()), summaryDetails.NumberOfControls().All())
+ assert.Equal(t, res.ListControlsIDs(nil).All().Len(), summaryDetails.NumberOfControls().All())
assert.Equal(t, len(res.ListControlsIDs(nil).Passed()), summaryDetails.NumberOfControls().Passed())
assert.Equal(t, len(res.ListControlsIDs(nil).Failed()), summaryDetails.NumberOfControls().Failed())
assert.Equal(t, len(res.ListControlsIDs(nil).Excluded()), summaryDetails.NumberOfControls().Excluded())
@@ -83,7 +83,7 @@ func TestProcessResourcesResult(t *testing.T) {
opap.updateResults()
res = opaSessionObj.ResourcesResult[deployment.GetID()]
- assert.Equal(t, 2, len(res.ListControlsIDs(nil).All()))
+ assert.Equal(t, 2, res.ListControlsIDs(nil).All().Len())
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Excluded()))
assert.Equal(t, 1, len(res.ListControlsIDs(nil).Passed()))
assert.True(t, res.GetStatus(nil).IsExcluded())
@@ -93,7 +93,7 @@ func TestProcessResourcesResult(t *testing.T) {
// test resource listing
summaryDetails = opaSessionObj.Report.SummaryDetails
- assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().All()))
+ assert.Equal(t, 1, summaryDetails.ListResourcesIDs().All().Len())
assert.Equal(t, 1, len(summaryDetails.ListResourcesIDs().Failed()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Excluded()))
assert.Equal(t, 0, len(summaryDetails.ListResourcesIDs().Passed()))
diff --git a/core/pkg/resourcehandler/filesloader.go b/core/pkg/resourcehandler/filesloader.go
index 44ec7a8d..d1a63a24 100644
--- a/core/pkg/resourcehandler/filesloader.go
+++ b/core/pkg/resourcehandler/filesloader.go
@@ -37,19 +37,62 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
// map resources based on framework required resources: map["/group/version/kind"][]
k8sResources := setK8sResourceMap(sessionObj.Policies)
allResources := map[string]workloadinterface.IMetadata{}
- workloadIDToSource := make(map[string]reporthandling.Source, 0)
ksResources := &cautils.KSResources{}
- workloads := []workloadinterface.IMetadata{}
-
if len(fileHandler.inputPatterns) == 0 {
return nil, nil, nil, fmt.Errorf("missing input")
}
- path := fileHandler.inputPatterns[0]
+
+ logger.L().Info("Accessing local objects")
+ cautils.StartSpinner()
+
+ for path := range fileHandler.inputPatterns {
+ workloadIDToSource, workloads, err := getResourcesFromPath(fileHandler.inputPatterns[path])
+ if err != nil {
+ return nil, allResources, nil, err
+ }
+ if len(workloads) == 0 {
+ logger.L().Debug("path ignored because contains only a non-kubernetes file", helpers.String("path", fileHandler.inputPatterns[path]))
+ }
+
+ for k, v := range workloadIDToSource {
+ sessionObj.ResourceSource[k] = v
+ }
+
+ // map all resources: map["/apiVersion/version/kind"][]
+ mappedResources := mapResources(workloads)
+
+ // save only relevant resources
+ for i := range mappedResources {
+ if _, ok := (*k8sResources)[i]; ok {
+ ids := []string{}
+ for j := range mappedResources[i] {
+ ids = append(ids, mappedResources[i][j].GetID())
+ allResources[mappedResources[i][j].GetID()] = mappedResources[i][j]
+ }
+ (*k8sResources)[i] = append((*k8sResources)[i], ids...)
+ }
+ }
+
+ }
+
+ if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, ksResources); err != nil {
+ logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
+ }
+
+ cautils.StopSpinner()
+ logger.L().Success("Done accessing local objects")
+
+ return k8sResources, allResources, ksResources, nil
+}
+
+func getResourcesFromPath(path string) (map[string]reporthandling.Source, []workloadinterface.IMetadata, error) {
+ workloadIDToSource := make(map[string]reporthandling.Source, 0)
+ workloads := []workloadinterface.IMetadata{}
clonedRepo, err := cloneGitRepo(&path)
if err != nil {
- return nil, allResources, nil, err
+ return nil, nil, err
}
if clonedRepo != "" {
defer os.RemoveAll(clonedRepo)
@@ -63,9 +106,6 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
}
// load resource from local file system
- logger.L().Info("Accessing local objects")
- cautils.StartSpinner()
-
sourceToWorkloads := cautils.LoadResourcesFromFiles(path, repoRoot)
// update workloads and workloadIDToSource
@@ -156,37 +196,7 @@ func (fileHandler *FileResourceHandler) GetResources(sessionObj *cautils.OPASess
logger.L().Debug("helm templates found in local storage", helpers.Int("helmTemplates", len(helmSourceToWorkloads)), helpers.Int("workloads", len(workloads)))
}
- // addCommitData(fileHandler.inputPatterns[0], workloadIDToSource)
-
- if len(workloads) == 0 {
- return nil, allResources, nil, fmt.Errorf("empty list of workloads - no workloads found")
- }
-
- sessionObj.ResourceSource = workloadIDToSource
-
- // map all resources: map["/apiVersion/version/kind"][]
- mappedResources := mapResources(workloads)
-
- // save only relevant resources
- for i := range mappedResources {
- if _, ok := (*k8sResources)[i]; ok {
- ids := []string{}
- for j := range mappedResources[i] {
- ids = append(ids, mappedResources[i][j].GetID())
- allResources[mappedResources[i][j].GetID()] = mappedResources[i][j]
- }
- (*k8sResources)[i] = ids
- }
- }
-
- if err := fileHandler.registryAdaptors.collectImagesVulnerabilities(k8sResources, allResources, ksResources); err != nil {
- logger.L().Warning("failed to collect images vulnerabilities", helpers.Error(err))
- }
-
- cautils.StopSpinner()
- logger.L().Success("Accessed to local objects")
-
- return k8sResources, allResources, ksResources, nil
+ return workloadIDToSource, workloads, nil
}
func (fileHandler *FileResourceHandler) GetClusterAPIServerInfo() *version.Info {
diff --git a/core/pkg/resourcehandler/filesloaderutils.go b/core/pkg/resourcehandler/filesloaderutils.go
index 7f9ec407..bfd8eb97 100644
--- a/core/pkg/resourcehandler/filesloaderutils.go
+++ b/core/pkg/resourcehandler/filesloaderutils.go
@@ -18,7 +18,7 @@ func cloneGitRepo(path *string) (string, error) {
var clonedDir string
// Clone git repository if needed
- gitURL, err := giturl.NewGitURL(*path)
+ gitURL, err := giturl.NewGitAPI(*path)
if err == nil {
logger.L().Info("cloning", helpers.String("repository url", gitURL.GetURL().String()))
cautils.StartSpinner()
diff --git a/core/pkg/resourcehandler/k8sresources_test.go b/core/pkg/resourcehandler/k8sresources_test.go
index 00025f4d..b8dfd17e 100644
--- a/core/pkg/resourcehandler/k8sresources_test.go
+++ b/core/pkg/resourcehandler/k8sresources_test.go
@@ -238,8 +238,8 @@ func TestIsMasterNodeTaints(t *testing.T) {
},
{
"names": [
- "quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
- "quay.io/armosec/kube-host-sensor:latest"
+ "quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
+ "quay.io/kubescape/host-scanner:latest"
],
"sizeBytes": 11796788
},
@@ -503,8 +503,8 @@ func TestIsMasterNodeTaints(t *testing.T) {
},
{
"names": [
- "quay.io/armosec/kube-host-sensor@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
- "quay.io/armosec/kube-host-sensor:latest"
+ "quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
+ "quay.io/kubescape/host-scanner:latest"
],
"sizeBytes": 11796788
},
diff --git a/core/pkg/resourcehandler/remotegitutils.go b/core/pkg/resourcehandler/remotegitutils.go
index 47a45d09..1dc4922b 100644
--- a/core/pkg/resourcehandler/remotegitutils.go
+++ b/core/pkg/resourcehandler/remotegitutils.go
@@ -1,16 +1,45 @@
package resourcehandler
import (
+ "errors"
"fmt"
+ nethttp "net/http"
"os"
giturl "github.com/armosec/go-git-url"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
+ "github.com/go-git/go-git/v5/plumbing/transport"
+ "github.com/go-git/go-git/v5/plumbing/transport/http"
)
+// To Check if the given repository is Public(No Authentication needed), send a HTTP GET request to the URL
+// If response code is 200, the repository is Public.
+func isGitRepoPublic(URL string) bool {
+ resp, err := nethttp.Get(URL)
+
+ if err != nil {
+ return false
+ }
+ // if the status code is 200, our get request is successful.
+ // It only happens when the repository is public.
+ if resp.StatusCode == 200 {
+ return true
+ }
+
+ return false
+}
+
+// Check if the GITHUB_TOKEN is present
+func isGitTokenPresent(gitURL giturl.IGitAPI) bool {
+ if token := gitURL.GetToken(); token == "" {
+ return false
+ }
+ return true
+}
+
// cloneRepo clones a repository to a local temporary directory and returns the directory
-func cloneRepo(gitURL giturl.IGitURL) (string, error) {
+func cloneRepo(gitURL giturl.IGitAPI) (string, error) {
// Create temp directory
tmpDir, err := os.MkdirTemp("", "")
@@ -18,9 +47,31 @@ func cloneRepo(gitURL giturl.IGitURL) (string, error) {
return "", fmt.Errorf("failed to create temporary directory: %w", err)
}
- // Clone option
+ // Get the URL to clone
cloneURL := gitURL.GetHttpCloneURL()
- cloneOpts := git.CloneOptions{URL: cloneURL}
+
+ isGitRepoPublic := isGitRepoPublic(cloneURL)
+
+ // Declare the authentication variable required for cloneOptions
+ var auth transport.AuthMethod
+
+ if isGitRepoPublic {
+ // No authentication needed if repository is public
+ auth = nil
+ } else {
+
+ // Return Error if the GITHUB_TOKEN is not present
+ if isGitTokenPresent := isGitTokenPresent(gitURL); !isGitTokenPresent {
+ return "", fmt.Errorf("%w", errors.New("GITHUB_TOKEN is not present"))
+ }
+ auth = &http.BasicAuth{
+ Username: "anything Except Empty String",
+ Password: gitURL.GetToken(),
+ }
+ }
+
+ // Clone option
+ cloneOpts := git.CloneOptions{URL: cloneURL, Auth: auth}
if gitURL.GetBranchName() != "" {
cloneOpts.ReferenceName = plumbing.NewBranchReferenceName(gitURL.GetBranchName())
cloneOpts.SingleBranch = true
diff --git a/core/pkg/resourcesprioritization/prioritizationhandler.go b/core/pkg/resourcesprioritization/prioritizationhandler.go
new file mode 100644
index 00000000..3441ad7f
--- /dev/null
+++ b/core/pkg/resourcesprioritization/prioritizationhandler.go
@@ -0,0 +1,91 @@
+package resourcesprioritization
+
+import (
+ "fmt"
+
+ "github.com/kubescape/k8s-interface/workloadinterface"
+ "github.com/kubescape/kubescape/v2/core/cautils"
+ "github.com/kubescape/opa-utils/reporthandling/apis"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
+)
+
+type ResourcesPrioritizationHandler struct {
+ skipZeroScores bool
+}
+
+func NewResourcesPrioritizationHandler(skipZeroScore bool) *ResourcesPrioritizationHandler {
+ return &ResourcesPrioritizationHandler{
+ skipZeroScores: skipZeroScore,
+ }
+}
+
+func (handler *ResourcesPrioritizationHandler) PrioritizeResources(sessionObj *cautils.OPASessionObj) error {
+ for resourceId, result := range sessionObj.ResourcesResult {
+ resourcePriorityVector := []prioritization.ControlsVector{}
+ resource, exist := sessionObj.AllResources[resourceId]
+ if !exist {
+ return fmt.Errorf("expected to find resource id '%s' in scanned resources map", resourceId)
+ }
+
+ workload := workloadinterface.NewWorkloadObj(resource.GetObject())
+
+ if workload != nil && handler.isSupportedKind(workload) {
+ for _, resourceAssociatedControl := range result.ListControls() {
+ if !resourceAssociatedControl.GetStatus(nil).IsFailed() {
+ continue
+ }
+
+ controlSummary := sessionObj.Report.SummaryDetails.Controls.GetControl("ID", resourceAssociatedControl.ControlID)
+ if controlSummary == nil {
+ return fmt.Errorf("expected to find control id '%s' in summary details", resourceAssociatedControl.ControlID)
+ }
+
+ controlScoreFactor := controlSummary.GetScoreFactor()
+ replicaCount := float64(workload.GetReplicas())
+
+ cVector := prioritization.NewControlsVector()
+ cVector.AddControl(prioritization.PriorityVectorControl{
+ ControlID: resourceAssociatedControl.ControlID,
+ Category: "",
+ })
+
+ cVector.SetSeverity(apis.ControlSeverityToInt(controlScoreFactor))
+ cVector.SetScore(float64(controlScoreFactor) + (replicaCount / 10))
+ resourcePriorityVector = append(resourcePriorityVector, *cVector)
+ }
+ }
+
+ prioritizedResource := prioritization.PrioritizedResource{
+ ResourceID: resourceId,
+ PriorityVector: resourcePriorityVector,
+ }
+
+ prioritizedResource.SetSeverity(prioritizedResource.CalculateSeverity())
+ prioritizedResource.SetScore(prioritizedResource.CalculateScore())
+
+ if handler.skipZeroScores && prioritizedResource.GetScore() == 0 {
+ continue
+ }
+
+ sessionObj.ResourcesPrioritized[resourceId] = prioritizedResource
+ }
+
+ return nil
+}
+
+func (handler *ResourcesPrioritizationHandler) isSupportedKind(obj workloadinterface.IMetadata) bool {
+ if obj != nil {
+ switch obj.GetKind() {
+ case "Deployment",
+ "Pod",
+ "ReplicaSet",
+ "Node",
+ "DaemonSet",
+ "StatefulSet",
+ "Job",
+ "CronJob":
+ return true
+ }
+ }
+ return false
+}
diff --git a/core/pkg/resourcesprioritization/prioritizationhandler_test.go b/core/pkg/resourcesprioritization/prioritizationhandler_test.go
new file mode 100644
index 00000000..36d1d8d9
--- /dev/null
+++ b/core/pkg/resourcesprioritization/prioritizationhandler_test.go
@@ -0,0 +1,150 @@
+package resourcesprioritization
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/kubescape/k8s-interface/workloadinterface"
+ "github.com/kubescape/kubescape/v2/core/cautils"
+ "github.com/kubescape/opa-utils/reporthandling/apis"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
+ "github.com/stretchr/testify/assert"
+)
+
+func OPASessionObjMock(mockResults map[string]resourcesresults.Result, mockControlsSummary map[string]reportsummary.ControlSummary, mockAllResources map[string]workloadinterface.IMetadata) *cautils.OPASessionObj {
+ mock := cautils.NewOPASessionObjMock()
+ mock.Report.SummaryDetails.Controls = mockControlsSummary
+ mock.ResourcesResult = mockResults
+ mock.AllResources = mockAllResources
+ return mock
+}
+
+func WorkloadMockWithKind(kind string) workloadinterface.IMetadata {
+ mock := workloadinterface.NewWorkloadMock(nil)
+ mock.SetKind(kind)
+ return mock
+}
+
+func DeploymentWorkloadMock(replicas int) workloadinterface.IMetadata {
+ var deploymentMock = fmt.Sprintf(`{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"privileged-deployment","labels":{"app":"nginx"}},"spec":{"replicas":%v,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"name":"nginx","image":"nginx:1.18.0","ports":[{"containerPort":80}],"securityContext":{"privileged":true}}]}}}}`, replicas)
+ w, _ := workloadinterface.NewWorkload([]byte(deploymentMock))
+ return w
+}
+
+func ResourceAssociatedControlMock(controlID string, status apis.ScanningStatus) resourcesresults.ResourceAssociatedControl {
+ return resourcesresults.ResourceAssociatedControl{
+ ControlID: controlID,
+ ResourceAssociatedRules: []resourcesresults.ResourceAssociatedRule{
+ {Name: "Test", Status: status},
+ },
+ }
+}
+
+func TestResourcesPrioritizationHandler_PrioritizeResources(t *testing.T) {
+ tests := []struct {
+ name string
+ results map[string]resourcesresults.Result
+ controls map[string]reportsummary.ControlSummary
+ resources map[string]workloadinterface.IMetadata
+ expectedScores map[string]float64
+ expectedSeverity map[string]int
+ expectedControlsInVector map[string][]string
+ }{
+ {
+ name: "non-empty report",
+ results: map[string]resourcesresults.Result{
+ "resource1": {
+ AssociatedControls: []resourcesresults.ResourceAssociatedControl{
+ ResourceAssociatedControlMock("C-001", apis.StatusFailed),
+ ResourceAssociatedControlMock("C-002", apis.StatusFailed),
+ },
+ },
+ "resource2": {
+ AssociatedControls: []resourcesresults.ResourceAssociatedControl{
+ ResourceAssociatedControlMock("C-001", apis.StatusFailed),
+ ResourceAssociatedControlMock("C-002", apis.StatusFailed),
+ ResourceAssociatedControlMock("C-003", apis.StatusPassed),
+ },
+ },
+ "resource3": {
+ AssociatedControls: []resourcesresults.ResourceAssociatedControl{
+ ResourceAssociatedControlMock("C-001", apis.StatusPassed),
+ ResourceAssociatedControlMock("C-002", apis.StatusPassed),
+ ResourceAssociatedControlMock("C-003", apis.StatusFailed),
+ },
+ },
+ },
+ controls: map[string]reportsummary.ControlSummary{
+ "C-001": {
+ ControlID: "C-001",
+ ScoreFactor: 3,
+ },
+ "C-002": {
+ ControlID: "C-002",
+ ScoreFactor: 4,
+ },
+ "C-003": {
+ ControlID: "C-003",
+ ScoreFactor: 10,
+ },
+ },
+ resources: map[string]workloadinterface.IMetadata{
+ "resource1": DeploymentWorkloadMock(20),
+ "resource2": DeploymentWorkloadMock(1),
+ "resource3": DeploymentWorkloadMock(1),
+ },
+ expectedScores: map[string]float64{
+ "resource1": float64(11),
+ "resource2": float64(7.199999999999999),
+ "resource3": float64(10.1),
+ },
+ expectedSeverity: map[string]int{
+ "resource1": apis.SeverityMedium,
+ "resource2": apis.SeverityMedium,
+ "resource3": apis.SeverityCritical,
+ },
+ expectedControlsInVector: map[string][]string{
+ "resource1": {"C-001", "C-002"},
+ "resource2": {"C-001", "C-002"},
+ "resource3": {"C-003"},
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ handler := &ResourcesPrioritizationHandler{
+ skipZeroScores: false,
+ }
+ sessionObj := OPASessionObjMock(tt.results, tt.controls, tt.resources)
+ err := handler.PrioritizeResources(sessionObj)
+ assert.NoError(t, err, "expected to have no errors in PrioritizeResources()")
+
+ assert.Equalf(t, len(tt.results), len(sessionObj.ResourcesPrioritized), "expected prioritized resources to be not empty")
+ for rId, resource := range sessionObj.ResourcesPrioritized {
+ expectedScore := tt.expectedScores[rId]
+ assert.Equalf(t, expectedScore, resource.GetScore(), "expected score of resourceID '%s' to be '%v', got '%v'", rId, expectedScore, resource.GetScore())
+
+ expectedSeverity := tt.expectedSeverity[rId]
+ assert.Equalf(t, expectedSeverity, resource.GetSeverity(), "expected severity of resourceID '%s' to be '%v', got '%v'", rId, expectedSeverity, resource.GetSeverity())
+
+ expectedControlIDs := tt.expectedControlsInVector[rId]
+ assert.ElementsMatchf(t, expectedControlIDs, resource.ListControlsIDs(), "expected controls of resourceID '%s' to be '%v', got '%v'", rId, expectedControlIDs, resource.ListControlsIDs())
+ }
+ })
+ }
+}
+
+func TestResourcesPrioritizationHandler_isSupportedKind(t *testing.T) {
+ handler := &ResourcesPrioritizationHandler{}
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Deployment")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Pod")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Node")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("DaemonSet")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("StatefulSet")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("Job")))
+ assert.True(t, handler.isSupportedKind(WorkloadMockWithKind("CronJob")))
+ assert.False(t, handler.isSupportedKind(nil))
+ assert.False(t, handler.isSupportedKind(WorkloadMockWithKind("ConfigMap")))
+ assert.False(t, handler.isSupportedKind(WorkloadMockWithKind("ServiceAccount")))
+}
diff --git a/core/pkg/resultshandling/printer/v2/junit.go b/core/pkg/resultshandling/printer/v2/junit.go
index e73df0ad..a7a53d57 100644
--- a/core/pkg/resultshandling/printer/v2/junit.go
+++ b/core/pkg/resultshandling/printer/v2/junit.go
@@ -155,7 +155,9 @@ func listTestsSuite(results *cautils.OPASessionObj) []JUnitTestSuite {
func testsCases(results *cautils.OPASessionObj, controls reportsummary.IControlsSummaries, classname string) []JUnitTestCase {
var testCases []JUnitTestCase
- for _, cID := range controls.ListControlsIDs().All() {
+ iter := controls.ListControlsIDs().All()
+ for iter.HasNext() {
+ cID := iter.Next()
testCase := JUnitTestCase{}
control := results.Report.SummaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, cID)
diff --git a/core/pkg/resultshandling/printer/v2/prettyprinter.go b/core/pkg/resultshandling/printer/v2/prettyprinter.go
index 80e0cccf..5cee44fc 100644
--- a/core/pkg/resultshandling/printer/v2/prettyprinter.go
+++ b/core/pkg/resultshandling/printer/v2/prettyprinter.go
@@ -261,7 +261,7 @@ func controlCountersForSummary(counters reportsummary.ICounters) string {
}
func controlCountersForResource(l *helpersv1.AllLists) string {
- return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", len(l.All()), len(l.Failed()), len(l.Excluded()))
+ return fmt.Sprintf("Controls: %d (Failed: %d, Excluded: %d)", l.All().Len(), len(l.Failed()), len(l.Excluded()))
}
func getSeparator(sep string) string {
s := ""
diff --git a/core/pkg/resultshandling/printer/v2/utils.go b/core/pkg/resultshandling/printer/v2/utils.go
index 78f20594..e14c93e3 100644
--- a/core/pkg/resultshandling/printer/v2/utils.go
+++ b/core/pkg/resultshandling/printer/v2/utils.go
@@ -6,6 +6,7 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/opa-utils/reporthandling"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
@@ -24,16 +25,21 @@ func FinalizeResults(data *cautils.OPASessionObj) *reporthandlingv2.PostureRepor
}
report.Results = make([]resourcesresults.Result, len(data.ResourcesResult))
- finalizeResults(report.Results, data.ResourcesResult)
+ finalizeResults(report.Results, data.ResourcesResult, data.ResourcesPrioritized)
report.Resources = finalizeResources(report.Results, data.AllResources, data.ResourceSource)
return &report
}
-func finalizeResults(results []resourcesresults.Result, resourcesResult map[string]resourcesresults.Result) {
+func finalizeResults(results []resourcesresults.Result, resourcesResult map[string]resourcesresults.Result, prioritizedResources map[string]prioritization.PrioritizedResource) {
index := 0
for resourceID := range resourcesResult {
results[index] = resourcesResult[resourceID]
+
+ // Add prioritization information to the result
+ if v, exist := prioritizedResources[resourceID]; exist {
+ results[index].PrioritizedResource = v
+ }
index++
}
}
diff --git a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
index 00a0d5de..8f8da4f5 100644
--- a/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
+++ b/core/pkg/resultshandling/reporter/v2/reporteventreceiver.go
@@ -14,6 +14,7 @@ import (
"github.com/kubescape/kubescape/v2/core/cautils"
"github.com/kubescape/kubescape/v2/core/cautils/getter"
"github.com/kubescape/opa-utils/reporthandling"
+ "github.com/kubescape/opa-utils/reporthandling/results/v1/prioritization"
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
@@ -124,17 +125,36 @@ func (report *ReportEventReceiver) sendResources(host string, opaSessionObj *cau
counter := 0
reportCounter := 0
- if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, opaSessionObj.ResourceSource, &counter, &reportCounter, host); err != nil {
+
+ if err := report.setResources(splittedPostureReport, opaSessionObj.AllResources, opaSessionObj.ResourceSource, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
return err
}
- if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, &counter, &reportCounter, host); err != nil {
+
+ if err := report.setResults(splittedPostureReport, opaSessionObj.ResourcesResult, opaSessionObj.AllResources, opaSessionObj.ResourceSource, opaSessionObj.ResourcesPrioritized, &counter, &reportCounter, host); err != nil {
return err
}
return report.sendReport(host, splittedPostureReport, reportCounter, true)
}
-func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
+
+func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.PostureReport, results map[string]resourcesresults.Result, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, prioritizedResources map[string]prioritization.PrioritizedResource, counter, reportCounter *int, host string) error {
for _, v := range results {
+ // set result.RawResource
+ resourceID := v.GetResourceID()
+ if _, ok := allResources[resourceID]; !ok {
+ return fmt.Errorf("expected to find raw resource object for '%s'", resourceID)
+ }
+ resource := reporthandling.NewResourceIMetadata(allResources[resourceID])
+ if r, ok := resourcesSource[resourceID]; ok {
+ resource.SetSource(&r)
+ }
+ v.RawResource = *resource
+
+ // set result.PrioritizedResource
+ if _, ok := prioritizedResources[resourceID]; ok {
+ v.PrioritizedResource = prioritizedResources[resourceID]
+ }
+
r, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("failed to unmarshal resource '%s', reason: %v", v.GetResourceID(), err)
@@ -162,8 +182,13 @@ func (report *ReportEventReceiver) setResults(reportObj *reporthandlingv2.Postur
return nil
}
-func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, counter, reportCounter *int, host string) error {
+func (report *ReportEventReceiver) setResources(reportObj *reporthandlingv2.PostureReport, allResources map[string]workloadinterface.IMetadata, resourcesSource map[string]reporthandling.Source, results map[string]resourcesresults.Result, counter, reportCounter *int, host string) error {
for resourceID, v := range allResources {
+ // process only resources which have no result because these resources will be sent on the result object
+ if _, hasResult := results[resourceID]; hasResult {
+ continue
+ }
+
resource := reporthandling.NewResourceIMetadata(v)
if r, ok := resourcesSource[resourceID]; ok {
resource.SetSource(&r)
diff --git a/docs/index.html b/docs/index.html
index add13cd3..16518447 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -15,10 +15,10 @@
-
+
-