Compare commits

..

4 Commits

Author SHA1 Message Date
dwertent
3f84ee3fcc update summary 2021-09-05 14:42:49 +03:00
dwertent
38103ac90b update screenshot 2021-09-05 14:39:13 +03:00
dwertent
13d27697e1 update readme 2021-09-05 14:33:32 +03:00
dwertent
942f356d19 support exceptions 2021-09-05 14:21:51 +03:00
21 changed files with 379 additions and 86 deletions

View File

@@ -37,6 +37,9 @@ If you wish to scan all namespaces in your cluster, remove the `--exclude-namesp
| `-t`/`--fail-threshold` | `0` (do not fail) | fail command (return exit code 1) if result bellow threshold| `0` -> `100` |
| `-f`/`--format` | `pretty-printer` | Output format | `pretty-printer`/`json`/`junit` |
| `-o`/`--output` | print to stdout | Save scan result in file |
| `--use-from` | | Load local framework object from specified path. If not used will download latest |
| `--use-default` | `false` | Load local framework object from default path. If not used will download latest | `true`/`false` |
| `--exceptions` | | Path to an [exceptions obj](examples/exceptions.json) |
## Usage & Examples
@@ -53,24 +56,29 @@ kubescape scan framework nsa *.yaml
```
* Scan `yaml`/`json` files from url <img src="docs/new-feature.svg">
* Scan `yaml`/`json` files from url
```
kubescape scan framework nsa https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
```
* Output in `json` format <img src="docs/new-feature.svg">
* Output in `json` format
```
kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --format json --output results.json
```
* Output in `junit xml` format <img src="docs/new-feature.svg">
* Output in `junit xml` format
```
kubescape scan framework nsa --exclude-namespaces kube-system,kube-public --format junit --output results.xml
```
* Scan with exceptions, objects with exceptions will be presented as `warning` and not `fail` <img src="docs/new-feature.svg">
```
kubescape scan framework nsa --exceptions examples/exceptions.json
```
### Helm Support
* Render the helm chart using [`helm template`](https://helm.sh/docs/helm/helm_template/) and pass to stdout <img src="docs/new-feature.svg">
* Render the helm chart using [`helm template`](https://helm.sh/docs/helm/helm_template/) and pass to stdout
```
helm template [NAME] [CHART] [flags] --dry-run | kubescape scan framework nsa -
```

View File

@@ -21,6 +21,7 @@ func IsSilent() bool {
}
var FailureDisplay = color.New(color.Bold, color.FgHiRed).FprintfFunc()
var WarningDisplay = color.New(color.Bold, color.FgCyan).FprintfFunc()
var FailureTextDisplay = color.New(color.Faint, color.FgHiRed).FprintfFunc()
var InfoDisplay = color.New(color.Bold, color.FgHiYellow).FprintfFunc()
var InfoTextDisplay = color.New(color.Faint, color.FgHiYellow).FprintfFunc()

View File

@@ -16,18 +16,17 @@ import (
// Armo API for downloading policies
type ArmoAPI struct {
httpClient *http.Client
hostURL string
baseURL string
}
func NewArmoAPI() *ArmoAPI {
return &ArmoAPI{
httpClient: &http.Client{},
hostURL: "https://dashbe.eustage2.cyberarmorsoft.com",
baseURL: "https://dashbe.auprod1.cyberarmorsoft.com",
}
}
func (armoAPI *ArmoAPI) GetFramework(name string) (*opapolicy.Framework, error) {
armoAPI.setURL(name)
respStr, err := HttpGetter(armoAPI.httpClient, armoAPI.hostURL)
respStr, err := HttpGetter(armoAPI.httpClient, armoAPI.getFrameworkURL(name))
if err != nil {
return nil, err
}
@@ -41,15 +40,37 @@ func (armoAPI *ArmoAPI) GetFramework(name string) (*opapolicy.Framework, error)
return framework, err
}
func (armoAPI *ArmoAPI) setURL(frameworkName string) {
func (armoAPI *ArmoAPI) getFrameworkURL(frameworkName string) string {
requestURI := "v1/armoFrameworks"
requestURI += fmt.Sprintf("?customerGUID=%s", "11111111-1111-1111-1111-111111111111")
requestURI += fmt.Sprintf("&frameworkName=%s", strings.ToUpper(frameworkName))
requestURI += "&getRules=true"
armoAPI.hostURL = urlEncoder(fmt.Sprintf("%s/%s", armoAPI.hostURL, requestURI))
return urlEncoder(fmt.Sprintf("%s/%s", armoAPI.baseURL, requestURI))
}
func (armoAPI *ArmoAPI) GetExceptions(scope, customerName, namespace string) ([]armotypes.PostureExceptionPolicy, error) {
return []armotypes.PostureExceptionPolicy{}, nil
func (armoAPI *ArmoAPI) GetExceptions(customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
exceptions := []armotypes.PostureExceptionPolicy{}
if customerGUID == "" {
return exceptions, nil
}
respStr, err := HttpGetter(armoAPI.httpClient, armoAPI.getExceptionsURL(customerGUID, clusterName))
if err != nil {
return nil, err
}
if err = JSONDecoder(respStr).Decode(&exceptions); err != nil {
return nil, err
}
return exceptions, nil
}
func (armoAPI *ArmoAPI) getExceptionsURL(customerGUID, clusterName string) string {
requestURI := "api/v1/armoPostureExceptions"
requestURI += fmt.Sprintf("?customerGUID=%s", customerGUID)
if clusterName != "" {
requestURI += fmt.Sprintf("&clusterName=%s", clusterName)
}
return urlEncoder(fmt.Sprintf("%s/%s", armoAPI.baseURL, requestURI))
}

View File

@@ -27,7 +27,7 @@ func NewDownloadReleasedPolicy() *DownloadReleasedPolicy {
}
}
func (drp *DownloadReleasedPolicy) GetExceptions(policyType, customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
func (drp *DownloadReleasedPolicy) GetExceptions(customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
return []armotypes.PostureExceptionPolicy{}, nil
}

View File

@@ -7,6 +7,6 @@ import (
type IPolicyGetter interface {
GetFramework(name string) (*opapolicy.Framework, error)
GetExceptions(policyType, customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error)
GetExceptions(customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error)
// GetScores(scope, customerName, namespace string) ([]armotypes.PostureExceptionPolicy, error)
}

View File

@@ -41,6 +41,14 @@ func (lp *LoadPolicy) GetFramework(frameworkName string) (*opapolicy.Framework,
return framework, err
}
func (lp *LoadPolicy) GetExceptions(policyType, customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
return []armotypes.PostureExceptionPolicy{}, nil
func (lp *LoadPolicy) GetExceptions(customerGUID, clusterName string) ([]armotypes.PostureExceptionPolicy, error) {
exception := []armotypes.PostureExceptionPolicy{}
f, err := ioutil.ReadFile(lp.filePath)
if err != nil {
return nil, err
}
err = json.Unmarshal(f, &exception)
return exception, err
}

23
cautils/jsonutils.go Normal file
View File

@@ -0,0 +1,23 @@
package cautils
import (
"bytes"
"encoding/json"
)
const (
empty = ""
tab = " "
)
func PrettyJson(data interface{}) ([]byte, error) {
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent(empty, tab)
err := encoder.Encode(data)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}

View File

@@ -53,13 +53,26 @@ func (ruleReport *RuleReport) GetRuleStatus() (string, []RuleResponse, []RuleRes
func (controlReport *ControlReport) GetNumberOfResources() int {
sum := 0
for i := range controlReport.RuleReports {
if controlReport.RuleReports[i].ListInputResources != nil {
sum += len(controlReport.RuleReports[i].ListInputResources)
}
sum += controlReport.RuleReports[i].GetNumberOfResources()
}
return sum
}
func (controlReport *ControlReport) GetNumberOfFailedResources() int {
sum := 0
for i := range controlReport.RuleReports {
sum += controlReport.RuleReports[i].GetNumberOfFailedResources()
}
return sum
}
func (controlReport *ControlReport) GetNumberOfWarningResources() int {
sum := 0
for i := range controlReport.RuleReports {
sum += controlReport.RuleReports[i].GetNumberOfWarningResources()
}
return sum
}
func (controlReport *ControlReport) ListControlsInputKinds() []string {
listControlsInputKinds := []string{}
for i := range controlReport.RuleReports {
@@ -100,3 +113,27 @@ func (controlReport *ControlReport) Failed() bool {
}
return false
}
func (ruleReport *RuleReport) GetNumberOfResources() int {
return len(ruleReport.ListInputResources)
}
func (ruleReport *RuleReport) GetNumberOfFailedResources() int {
sum := 0
for i := range ruleReport.RuleResponses {
if ruleReport.RuleResponses[i].GetSingleResultStatus() == "failed" {
sum += 1
}
}
return sum
}
func (ruleReport *RuleReport) GetNumberOfWarningResources() int {
sum := 0
for i := range ruleReport.RuleResponses {
if ruleReport.RuleResponses[i].GetSingleResultStatus() == "warning" {
sum += 1
}
}
return sum
}

View File

@@ -27,7 +27,6 @@ type Getters struct {
}
func (scanInfo *ScanInfo) Init() {
// scanInfo.setSilentMode()
scanInfo.setUseFrom()
scanInfo.setUseExceptions()
scanInfo.setOutputFile()
@@ -58,16 +57,7 @@ func (scanInfo *ScanInfo) setGetter() {
// load from file
scanInfo.PolicyGetter = getter.NewLoadPolicy(scanInfo.UseFrom)
} else {
scanInfo.PolicyGetter = getter.NewArmoAPI()
}
}
func (scanInfo *ScanInfo) setSilentMode() {
if scanInfo.Format == "json" || scanInfo.Format == "junit" {
scanInfo.Silent = true
}
if scanInfo.Output != "" {
scanInfo.Silent = true
scanInfo.PolicyGetter = getter.NewDownloadReleasedPolicy()
}
}

View File

@@ -14,7 +14,9 @@ import (
"github.com/armosec/kubescape/cautils/opapolicy"
"github.com/armosec/kubescape/opaprocessor"
"github.com/armosec/kubescape/policyhandler"
"github.com/armosec/kubescape/printer"
"github.com/armosec/kubescape/resultshandling"
"github.com/armosec/kubescape/resultshandling/printer"
"github.com/armosec/kubescape/resultshandling/reporter"
"github.com/spf13/cobra"
)
@@ -121,11 +123,12 @@ func CliSetup() error {
// processor setup - rego run
go func() {
reporterObj := opaprocessor.NewOPAProcessorHandler(&processNotification, &reportResults)
reporterObj.ProcessRulesListenner()
opaprocessorObj := opaprocessor.NewOPAProcessorHandler(&processNotification, &reportResults)
opaprocessorObj.ProcessRulesListenner()
}()
p := printer.NewPrinter(&reportResults, scanInfo.Format, scanInfo.Output)
score := p.ActionPrint()
resultsHandling := resultshandling.NewResultsHandler(&reportResults, reporter.NewReportEventReceiver(), printer.NewPrinter(scanInfo.Format, scanInfo.Output))
score := resultsHandling.HandleResults()
adjustedFailThreshold := float32(scanInfo.FailThreshold) / 100
if score < adjustedFailThreshold {

BIN
docs/summary.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

After

Width:  |  Height:  |  Size: 65 KiB

34
examples/exceptions.json Normal file
View File

@@ -0,0 +1,34 @@
[
{
"name": "ignore-kube-namespaces",
"policyType": "postureExceptionPolicy",
"actions": [
"alertOnly"
],
"resources": [
{
"designatorType": "Attributes",
"attributes": {
"namespace": "kube-system"
}
},
{
"designatorType": "Attributes",
"attributes": {
"namespace": "kube-public"
}
},
{
"designatorType": "Attributes",
"attributes": {
"namespace": "kube-node-lease"
}
}
],
"posturePolicies": [
{
"frameworkName": "NSA"
}
]
}
]

View File

@@ -41,7 +41,7 @@ func (policyHandler *PolicyHandler) getFrameworkPolicies(policyName string) (*op
return nil, nil, err
}
receivedException, err := policyHandler.getters.ExceptionsGetter.GetExceptions("", "", "")
receivedException, err := policyHandler.getters.ExceptionsGetter.GetExceptions("", "")
if err != nil {
return receivedFramework, nil, err
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/k8sinterface"
"github.com/armosec/kubescape/cautils/opapolicy"
"github.com/enescakir/emoji"
@@ -27,19 +26,17 @@ const (
)
type Printer struct {
opaSessionObj *chan *cautils.OPASessionObj
writer *os.File
summary Summary
sortedControlNames []string
printerType string
}
func NewPrinter(opaSessionObj *chan *cautils.OPASessionObj, printerType, outputFile string) *Printer {
func NewPrinter(printerType, outputFile string) *Printer {
return &Printer{
opaSessionObj: opaSessionObj,
summary: NewSummary(),
printerType: printerType,
writer: getWriter(outputFile),
summary: NewSummary(),
writer: getWriter(outputFile),
printerType: printerType,
}
}
@@ -63,45 +60,39 @@ func calculatePostureScore(postureReport *opapolicy.PostureReport) float32 {
return (float32(totalResources) - float32(totalFailed)) / float32(totalResources)
}
func (printer *Printer) ActionPrint() float32 {
func (printer *Printer) ActionPrint(opaSessionObj *cautils.OPASessionObj) float32 {
var score float32
for {
opaSessionObj := <-*printer.opaSessionObj
if printer.printerType == PrettyPrinter {
printer.SummarySetup(opaSessionObj.PostureReport)
printer.PrintResults()
printer.PrintSummaryTable()
} else if printer.printerType == JsonPrinter {
postureReportStr, err := json.Marshal(opaSessionObj.PostureReport.FrameworkReports[0])
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
printer.writer.Write(postureReportStr)
} else if printer.printerType == JunitResultPrinter {
junitResult, err := convertPostureReportToJunitResult(opaSessionObj.PostureReport)
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
postureReportStr, err := xml.Marshal(junitResult)
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
printer.writer.Write(postureReportStr)
} else if !cautils.IsSilent() {
fmt.Println("unknown output printer")
if printer.printerType == PrettyPrinter {
printer.SummarySetup(opaSessionObj.PostureReport)
printer.PrintResults()
printer.PrintSummaryTable()
} else if printer.printerType == JsonPrinter {
postureReportStr, err := json.Marshal(opaSessionObj.PostureReport.FrameworkReports[0])
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
score = calculatePostureScore(opaSessionObj.PostureReport)
if !k8sinterface.RunningIncluster {
break
printer.writer.Write(postureReportStr)
} else if printer.printerType == JunitResultPrinter {
junitResult, err := convertPostureReportToJunitResult(opaSessionObj.PostureReport)
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
postureReportStr, err := xml.Marshal(junitResult)
if err != nil {
fmt.Println("Failed to convert posture report object!")
os.Exit(1)
}
printer.writer.Write(postureReportStr)
} else if !cautils.IsSilent() {
fmt.Println("unknown output printer")
os.Exit(1)
}
score = calculatePostureScore(opaSessionObj.PostureReport)
return score
}
@@ -116,7 +107,8 @@ func (printer *Printer) SummarySetup(postureReport *opapolicy.PostureReport) {
printer.summary[cr.Name] = ControlSummary{
TotalResources: cr.GetNumberOfResources(),
TotalFailed: len(workloadsSummary),
TotalFailed: cr.GetNumberOfFailedResources(),
TotalWarnign: cr.GetNumberOfWarningResources(),
WorkloadSummary: mapResources,
Description: cr.Description,
Remediation: cr.Remediation,
@@ -125,9 +117,7 @@ func (printer *Printer) SummarySetup(postureReport *opapolicy.PostureReport) {
}
}
printer.sortedControlNames = printer.getSortedControlsNames()
}
func (printer *Printer) PrintResults() {
for i := 0; i < len(printer.sortedControlNames); i++ {
controlSummary := printer.summary[printer.sortedControlNames[i]]
@@ -144,6 +134,7 @@ func (printer *Printer) PrintResults() {
func (printer *Printer) printSummary(controlName string, controlSummary *ControlSummary) {
cautils.SimpleDisplay(printer.writer, "Summary - ")
cautils.SuccessDisplay(printer.writer, "Passed:%v ", controlSummary.TotalResources-controlSummary.TotalFailed)
cautils.WarningDisplay(printer.writer, "Warning:%v ", controlSummary.TotalWarnign)
cautils.FailureDisplay(printer.writer, "Failed:%v ", controlSummary.TotalFailed)
cautils.InfoDisplay(printer.writer, "Total:%v\n", controlSummary.TotalResources)
if controlSummary.TotalFailed > 0 {
@@ -157,10 +148,12 @@ func (printer *Printer) printTitle(controlName string, controlSummary *ControlSu
cautils.InfoDisplay(printer.writer, "[control: %s] ", controlName)
if controlSummary.TotalResources == 0 && len(controlSummary.ListInputKinds) > 0 {
cautils.InfoDisplay(printer.writer, "resources not found %v\n", emoji.ConfusedFace)
} else if controlSummary.TotalFailed == 0 {
cautils.SuccessDisplay(printer.writer, "passed %v\n", emoji.ThumbsUp)
} else {
} else if controlSummary.TotalFailed != 0 {
cautils.FailureDisplay(printer.writer, "failed %v\n", emoji.SadButRelievedFace)
} else if controlSummary.TotalWarnign != 0 {
cautils.WarningDisplay(printer.writer, "warning %v\n", emoji.NeutralFace)
} else {
cautils.SuccessDisplay(printer.writer, "passed %v\n", emoji.ThumbsUp)
}
cautils.DescriptionDisplay(printer.writer, "Description: %s\n", controlSummary.Description)
@@ -197,7 +190,7 @@ func generateRow(control string, cs ControlSummary) []string {
}
func generateHeader() []string {
return []string{"Control Name", "Failed Resources", "All Resources", "% success"}
return []string{"Control Name", "Failed Resources", "Warning Resources", "All Resources", "% success"}
}
func percentage(big, small int) int {
@@ -209,11 +202,12 @@ func percentage(big, small int) int {
}
return int(float64(float64(big-small)/float64(big)) * 100)
}
func generateFooter(numControlers, sumFailed, sumTotal int) []string {
func generateFooter(numControlers, sumFailed, sumWarning, sumTotal int) []string {
// Control name | # failed resources | all resources | % success
row := []string{}
row = append(row, fmt.Sprintf("%d", numControlers))
row = append(row, fmt.Sprintf("%d", sumFailed))
row = append(row, fmt.Sprintf("%d", sumWarning))
row = append(row, fmt.Sprintf("%d", sumTotal))
if sumTotal != 0 {
row = append(row, fmt.Sprintf("%d%s", percentage(sumTotal, sumFailed), "%"))
@@ -230,14 +224,16 @@ func (printer *Printer) PrintSummaryTable() {
summaryTable.SetAlignment(tablewriter.ALIGN_LEFT)
sumTotal := 0
sumFailed := 0
sumWarning := 0
for i := 0; i < len(printer.sortedControlNames); i++ {
controlSummary := printer.summary[printer.sortedControlNames[i]]
summaryTable.Append(generateRow(printer.sortedControlNames[i], controlSummary))
sumFailed += controlSummary.TotalFailed
sumWarning += controlSummary.TotalWarnign
sumTotal += controlSummary.TotalResources
}
summaryTable.SetFooter(generateFooter(len(printer.summary), sumFailed, sumTotal))
summaryTable.SetFooter(generateFooter(len(printer.summary), sumFailed, sumWarning, sumTotal))
summaryTable.Render()
}

View File

@@ -2,6 +2,8 @@ package printer
import (
"fmt"
"github.com/armosec/kubescape/cautils/armotypes"
)
type Summary map[string]ControlSummary
@@ -13,6 +15,7 @@ func NewSummary() Summary {
type ControlSummary struct {
TotalResources int
TotalFailed int
TotalWarnign int
Description string
Remediation string
ListInputKinds []string
@@ -24,11 +27,13 @@ type WorkloadSummary struct {
Name string
Namespace string
Group string
Exception *armotypes.PostureExceptionPolicy
}
func (controlSummary *ControlSummary) ToSlice() []string {
s := []string{}
s = append(s, fmt.Sprintf("%d", controlSummary.TotalFailed))
s = append(s, fmt.Sprintf("%d", controlSummary.TotalWarnign))
s = append(s, fmt.Sprintf("%d", controlSummary.TotalResources))
return s
}

View File

@@ -34,6 +34,7 @@ func listResultSummary(ruleReports []opapolicy.RuleReport) []WorkloadSummary {
// add resource only once
for i := range resource {
resource[i].Exception = ruleReport.Exception
if ok := track[resource[i].ToString()]; !ok {
track[resource[i].ToString()] = true
workloadsSummary = append(workloadsSummary, resource[i])
@@ -51,6 +52,7 @@ func ruleResultSummary(obj opapolicy.AlertObject) ([]WorkloadSummary, error) {
if err != nil {
return resource, err
}
resource = append(resource, *r)
}

View File

@@ -0,0 +1,56 @@
package reporter
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/cautils/opapolicy"
)
type ReportEventReceiver struct {
httpClient http.Client
host url.URL
}
func NewReportEventReceiver() *ReportEventReceiver {
hostURL := initEventReceiverURL()
return &ReportEventReceiver{
httpClient: http.Client{},
host: *hostURL,
}
}
func (report *ReportEventReceiver) ActionSendReportListenner(opaSessionObj *cautils.OPASessionObj) {
if cautils.CustomerGUID == "" {
return
}
if err := report.Send(opaSessionObj.PostureReport); err != nil {
fmt.Println(err)
}
}
func (report *ReportEventReceiver) Send(postureReport *opapolicy.PostureReport) error {
reqBody, err := json.Marshal(*postureReport)
if err != nil {
return fmt.Errorf("in 'Send' failed to json.Marshal, reason: %v", err)
}
host := hostToString(&report.host, postureReport.ReportID)
req, err := http.NewRequest("POST", host, bytes.NewReader(reqBody))
if err != nil {
return fmt.Errorf("in 'Send', http.NewRequest failed, host: %s, reason: %v", host, err)
}
res, err := report.httpClient.Do(req)
if err != nil {
return fmt.Errorf("httpClient.Do failed: %v", err)
}
msg, err := httpRespToString(res)
if err != nil {
return fmt.Errorf("%s, %v:%s", host, err, msg)
}
return err
}

View File

@@ -0,0 +1,57 @@
package reporter
import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/armosec/kubescape/cautils"
"github.com/gofrs/uuid"
)
// HTTPRespToString parses the body as string and checks the HTTP status code, it closes the body reader at the end
func httpRespToString(resp *http.Response) (string, error) {
if resp == nil || resp.Body == nil {
return "", nil
}
strBuilder := strings.Builder{}
defer resp.Body.Close()
if resp.ContentLength > 0 {
strBuilder.Grow(int(resp.ContentLength))
}
_, err := io.Copy(&strBuilder, resp.Body)
if err != nil {
return strBuilder.String(), err
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err = fmt.Errorf("response status: %d. Content: %s", resp.StatusCode, strBuilder.String())
}
return strBuilder.String(), err
}
func initEventReceiverURL() *url.URL {
urlObj := url.URL{}
urlObj.Scheme = "https"
urlObj.Host = "report.euprod1.cyberarmorsoft.com"
urlObj.Path = "/k8s/postureReport"
q := urlObj.Query()
q.Add("customerGUID", uuid.FromStringOrNil(cautils.CustomerGUID).String())
q.Add("clusterName", cautils.ClusterName)
urlObj.RawQuery = q.Encode()
return &urlObj
}
func hostToString(host *url.URL, reportID string) string {
q := host.Query()
if reportID != "" {
q.Add("reportID", reportID) // TODO - do we add the reportID?
}
host.RawQuery = q.Encode()
return host.String()
}

View File

@@ -0,0 +1,20 @@
package reporter
import (
"net/url"
"testing"
)
func TestHostToString(t *testing.T) {
host := url.URL{
Scheme: "https",
Host: "report.eudev3.cyberarmorsoft.com",
Path: "k8srestapi/v1/postureReport",
RawQuery: "cluster=openrasty_seal-7fvz&customerGUID=5d817063-096f-4d91-b39b-8665240080af",
}
expectedHost := "https://report.eudev3.cyberarmorsoft.com/k8srestapi/v1/postureReport?cluster=openrasty_seal-7fvz&customerGUID=5d817063-096f-4d91-b39b-8665240080af&reportID=ffdd2a00-4dc8-4bf3-b97a-a6d4fd198a41"
receivedHost := hostToString(&host, "ffdd2a00-4dc8-4bf3-b97a-a6d4fd198a41")
if receivedHost != expectedHost {
t.Errorf("%s != %s", receivedHost, expectedHost)
}
}

View File

@@ -0,0 +1,32 @@
package resultshandling
import (
"github.com/armosec/kubescape/cautils"
"github.com/armosec/kubescape/resultshandling/printer"
"github.com/armosec/kubescape/resultshandling/reporter"
)
type ResultsHandler struct {
opaSessionObj *chan *cautils.OPASessionObj
reporterObj *reporter.ReportEventReceiver
printerObj *printer.Printer
}
func NewResultsHandler(opaSessionObj *chan *cautils.OPASessionObj, reporterObj *reporter.ReportEventReceiver, printerObj *printer.Printer) *ResultsHandler {
return &ResultsHandler{
opaSessionObj: opaSessionObj,
reporterObj: reporterObj,
printerObj: printerObj,
}
}
func (resultsHandler *ResultsHandler) HandleResults() float32 {
opaSessionObj := <-*resultsHandler.opaSessionObj
resultsHandler.reporterObj.ActionSendReportListenner(opaSessionObj)
score := resultsHandler.printerObj.ActionPrint(opaSessionObj)
return score
}