Repository: datreeio/datree
Pull request #367 (2022-01-05 14:07:00)

feat: improve output structure for non-interactive modes
This PR solves issue #116 .

The updated output structure for non-interactive options is provided by @eyarz and can be seen [here](https://www.jsonschemavalidator.net/s/vrvKDXaN). I have provided some working examples below -

Edit:
New output:

![datree_structured_output](https://user-images.githubusercontent.com/75240995/148897768-73242abe-8a92-410b-8ede-d542d5d9c5bd.png)

![datree_json_output](https://user-images.githubusercontent.com/75240995/148897840-56fc9825-8833-4769-aa8f-886199ae6719.png)




Patch:
diff --git a/bl/evaluation/evaluator.go b/bl/evaluation/evaluator.go
index 1cb8659..07a9984 100644
--- a/bl/evaluation/evaluator.go
+++ b/bl/evaluation/evaluator.go
@@ -27,6 +27,10 @@ func New(c CLIClient) *Evaluator {
 
 type FileNameRuleMapper map[string]map[int]*Rule
 
+type ResultType struct {
+	EvaluationResults               *EvaluationResults
+	NonInteractiveEvaluationResults *NonInteractiveEvaluationResults
+}
 type EvaluationResults struct {
 	FileNameRuleMapper FileNameRuleMapper
 	Summary            struct {
@@ -78,22 +82,62 @@ func (e *Evaluator) UpdateFailedK8sValidation(invalidFiles []*validation.Invalid
 	return err
 }
 
-func (e *Evaluator) Evaluate(filesConfigurations []*extractor.FileConfigurations, evaluationId int) (*EvaluationResults, error) {
+func (e *Evaluator) Evaluate(filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, isInteractiveMode bool) (ResultType, error) {
 
 	if len(filesConfigurations) == 0 {
-		return &EvaluationResults{}, nil
+		return ResultType{}, nil
 	}
 
 	res, err := e.cliClient.RequestEvaluation(&cliClient.EvaluationRequest{
-		EvaluationId: evaluationId,
+		EvaluationId: evaluationResponse.EvaluationId,
 		Files:        filesConfigurations,
 	})
 	if err != nil {
-		return nil, err
+		return ResultType{}, err
+	}
+	resultType := ResultType{}
+	resultType.EvaluationResults = e.formatEvaluationResults(res.Results, len(filesConfigurations))
+	if !isInteractiveMode {
+		resultType.NonInteractiveEvaluationResults = e.formatNonInteractiveEvaluationResults(resultType.EvaluationResults, res.Results, evaluationResponse.PolicyName, evaluationResponse.RulesCount)
+	}
+	return resultType, nil
+}
+
+// This method creates a NonInteractiveEvaluationResults structure
+// from EvaluationResults.
+func (e *Evaluator) formatNonInteractiveEvaluationResults(evaluationResults *EvaluationResults, listEvaluationResult []*cliClient.EvaluationResult, policyName string, totalRulesInPolicy int) *NonInteractiveEvaluationResults {
+	fileNameRuleMapper := evaluationResults.FileNameRuleMapper
+	ruleMapper := make(map[int]string)
+	for _, result := range listEvaluationResult {
+		ruleId := getRuleId(result)
+		ruleMapper[ruleId] = result.Rule.Identifier
+	}
+	nonInteractiveEvaluationResults := NonInteractiveEvaluationResults{}
+
+	for fileName, rules := range fileNameRuleMapper {
+		formattedEvaluationResults := FormattedEvaluationResults{}
+		formattedEvaluationResults.FileName = fileName
+
+		for _, rule := range rules {
+			ruleResult := RuleResult{Identifier: ruleMapper[rule.ID], Name: rule.Name, MessageOnFailure: rule.FailSuggestion, OccurrencesDetails: rule.OccurrencesDetails}
+			formattedEvaluationResults.RuleResults = append(
+				formattedEvaluationResults.RuleResults,
+				&ruleResult,
+			)
+		}
+		nonInteractiveEvaluationResults.FormattedEvaluationResults = append(
+			nonInteractiveEvaluationResults.FormattedEvaluationResults,
+			&formattedEvaluationResults,
+		)
+	}
+	nonInteractiveEvaluationResults.PolicySummary = PolicySummary{
+		PolicyName:         policyName,
+		TotalRulesInPolicy: totalRulesInPolicy,
+		TotalRulesFailed:   evaluationResults.Summary.TotalFailedRules,
+		TotalPassedCount:   evaluationResults.Summary.TotalPassedCount,
 	}
 
-	results := e.formatEvaluationResults(res.Results, len(filesConfigurations))
-	return results, nil
+	return &nonInteractiveEvaluationResults
 }
 
 func (e *Evaluator) formatEvaluationResults(evaluationResults []*cliClient.EvaluationResult, filesCount int) *EvaluationResults {
diff --git a/bl/evaluation/non_interactive_evaluator_types.go b/bl/evaluation/non_interactive_evaluator_types.go
new file mode 100644
index 0000000..d4c4b0e
--- /dev/null
+++ b/bl/evaluation/non_interactive_evaluator_types.go
@@ -0,0 +1,45 @@
+package evaluation
+
+import (
+	"github.com/datreeio/datree/bl/validation"
+)
+
+type FormattedOutput struct {
+	PolicyValidationResults []*FormattedEvaluationResults   `yaml:"policyValidationResults" json:"policyValidationResults"`
+	PolicySummary           PolicySummary                   `yaml:"policySummary" json:"policySummary"`
+	EvaluationSummary       NonInteractiveEvaluationSummary `yaml:"evaluationSummary" json:"evaluationSummary"`
+	YamlValidationResults   []*validation.InvalidYamlFile   `yaml:"yamlValidationResults" json:"yamlValidationResults"`
+	K8sValidationResults    []*validation.InvalidK8sFile    `yaml:"k8sValidationResults" json:"k8sValidationResults"`
+}
+
+type NonInteractiveEvaluationResults struct {
+	FormattedEvaluationResults []*FormattedEvaluationResults
+	PolicySummary              PolicySummary
+}
+
+type FormattedEvaluationResults struct {
+	FileName    string        `yaml:"fileName" json:"fileName"`
+	RuleResults []*RuleResult `yaml:"ruleResults" json:"ruleResults"`
+}
+
+type RuleResult struct {
+	Identifier         string              `json:"identifier"`
+	Name               string              `json:"name"`
+	MessageOnFailure   string              `yaml:"messageOnFailure" json:"messageOnFailure"`
+	OccurrencesDetails []OccurrenceDetails `yaml:"occurrencesDetails" json:"occurrencesDetails"`
+}
+
+type NonInteractiveEvaluationSummary struct {
+	ConfigsCount                int `yaml:"configsCount" json:"configsCount"`
+	FilesCount                  int `yaml:"filesCount" json:"filesCount"`
+	PassedYamlValidationCount   int `yaml:"passedYamlValidationCount" json:"passedYamlValidationCount"`
+	PassedK8sValidationCount    int `yaml:"passedK8sValidationCount" json:"passedK8sValidationCount"`
+	PassedPolicyValidationCount int `yaml:"passedPolicyValidationCount" json:"passedPolicyValidationCount"`
+}
+
+type PolicySummary struct {
+	PolicyName         string `yaml:"policyName" json:"policyName"`
+	TotalRulesInPolicy int    `yaml:"totalRulesInPolicy" json:"totalRulesInPolicy"`
+	TotalRulesFailed   int    `yaml:"totalRulesFailed"  json:"totalRulesFailed"`
+	TotalPassedCount   int    `yaml:"totalPassedCount"  json:"totalPassedCount"`
+}
diff --git a/bl/evaluation/printer.go b/bl/evaluation/printer.go
index fb0b0d8..f5e2be3 100644
--- a/bl/evaluation/printer.go
+++ b/bl/evaluation/printer.go
@@ -21,23 +21,35 @@ type Printer interface {
 	PrintEvaluationSummary(summary printer.EvaluationSummary, k8sVersion string)
 }
 
-type FormattedOutput struct {
-	EvaluationResults *EvaluationResults
-	EvaluationSummary printer.EvaluationSummary
-	InvalidYamlFiles  []*validation.InvalidYamlFile
-	InvalidK8sFiles   []*validation.InvalidK8sFile
-}
+func PrintResults(results ResultType, invalidYamlFiles []*validation.InvalidYamlFile, invalidK8sFiles []*validation.InvalidK8sFile, evaluationSummary printer.EvaluationSummary, loginURL string, outputFormat string, printer Printer, k8sVersion string, policyName string) error {
+	if outputFormat == "json" || outputFormat == "yaml" || outputFormat == "xml" {
+		nonInteractiveEvaluationResults := results.NonInteractiveEvaluationResults
+		if nonInteractiveEvaluationResults == nil {
+			return fmt.Errorf("results not found")
+		}
+		formattedOutput := FormattedOutput{
+			PolicyValidationResults: nonInteractiveEvaluationResults.FormattedEvaluationResults,
+			PolicySummary:           nonInteractiveEvaluationResults.PolicySummary,
+			EvaluationSummary: NonInteractiveEvaluationSummary{
+				ConfigsCount:                evaluationSummary.ConfigsCount,
+				FilesCount:                  evaluationSummary.FilesCount,
+				PassedYamlValidationCount:   evaluationSummary.PassedYamlValidationCount,
+				PassedK8sValidationCount:    evaluationSummary.PassedK8sValidationCount,
+				PassedPolicyValidationCount: evaluationSummary.PassedPolicyCheckCount,
+			},
+			YamlValidationResults: invalidYamlFiles,
+			K8sValidationResults:  invalidK8sFiles,
+		}
 
-func PrintResults(results *EvaluationResults, invalidYamlFiles []*validation.InvalidYamlFile, invalidK8sFiles []*validation.InvalidK8sFile, evaluationSummary printer.EvaluationSummary, loginURL string, outputFormat string, printer Printer, k8sVersion string, policyName string) error {
-	switch {
-	case outputFormat == "json":
-		return jsonOutput(&FormattedOutput{EvaluationResults: results, EvaluationSummary: evaluationSummary, InvalidYamlFiles: invalidYamlFiles, InvalidK8sFiles: invalidK8sFiles})
-	case outputFormat == "yaml":
-		return yamlOutput(&FormattedOutput{EvaluationResults: results, EvaluationSummary: evaluationSummary, InvalidYamlFiles: invalidYamlFiles, InvalidK8sFiles: invalidK8sFiles})
-	case outputFormat == "xml":
-		return xmlOutput(&FormattedOutput{EvaluationResults: results, EvaluationSummary: evaluationSummary, InvalidYamlFiles: invalidYamlFiles, InvalidK8sFiles: invalidK8sFiles})
-	default:
-		return textOutput(results, invalidYamlFiles, invalidK8sFiles, evaluationSummary, loginURL, printer, k8sVersion, policyName)
+		if outputFormat == "json" {
+			return jsonOutput(&formattedOutput)
+		} else if outputFormat == "yaml" {
+			return yamlOutput(&formattedOutput)
+		} else {
+			return xmlOutput(&formattedOutput)
+		}
+	} else {
+		return textOutput(results.EvaluationResults, invalidYamlFiles, invalidK8sFiles, evaluationSummary, loginURL, printer, k8sVersion, policyName)
 	}
 }
 
diff --git a/bl/evaluation/rule.go b/bl/evaluation/rule.go
index 8807f1f..f6a3bcf 100644
--- a/bl/evaluation/rule.go
+++ b/bl/evaluation/rule.go
@@ -12,6 +12,6 @@ func (rp *Rule) GetCount() int {
 }
 
 type OccurrenceDetails struct {
-	MetadataName string
-	Kind         string
+	MetadataName string `yaml:"metadataName" json:"metadataName"`
+	Kind         string `json:"kind"`
 }
diff --git a/bl/validation/k8sValidator.go b/bl/validation/k8sValidator.go
index 233e23f..e1075ad 100644
--- a/bl/validation/k8sValidator.go
+++ b/bl/validation/k8sValidator.go
@@ -23,8 +23,8 @@ func New() *K8sValidator {
 }
 
 type InvalidFile struct {
-	Path             string
-	ValidationErrors []error
+	Path             string  `json:"path"`
+	ValidationErrors []error `yaml:"errors" json:"errors" xml:"Errors"`
 }
 type InvalidYamlFile InvalidFile
 


Test patch:
diff --git a/bl/evaluation/evaluator_test.go b/bl/evaluation/evaluator_test.go
index c08d795..89a1fb1 100644
--- a/bl/evaluation/evaluator_test.go
+++ b/bl/evaluation/evaluator_test.go
@@ -107,12 +107,12 @@ func TestEvaluate(t *testing.T) {
 			}
 
 			// TODO: define and check the rest of the values
-			results, _ := evaluator.Evaluate(tt.args.validFilesConfigurations, tt.args.evaluationId)
+			results, _ := evaluator.Evaluate(tt.args.validFilesConfigurations, tt.args.response, tt.args.isInteractiveMode)
 
 			if tt.expected.isRequestEvaluationCalled {
 				mockedCliClient.AssertCalled(t, "RequestEvaluation", mock.Anything)
-				assert.Equal(t, tt.expected.response.Summary, results.Summary)
-				assert.Equal(t, tt.expected.response.FileNameRuleMapper, results.FileNameRuleMapper)
+				assert.Equal(t, tt.expected.response.EvaluationResults.Summary, results.EvaluationResults.Summary)
+				assert.Equal(t, tt.expected.response.EvaluationResults.FileNameRuleMapper, results.EvaluationResults.FileNameRuleMapper)
 			} else {
 				mockedCliClient.AssertNotCalled(t, "RequestEvaluation")
 			}
@@ -122,13 +122,14 @@ func TestEvaluate(t *testing.T) {
 
 type evaluateArgs struct {
 	validFilesConfigurations []*extractor.FileConfigurations
-	evaluationId             int
 	osInfo                   *OSInfo
+	isInteractiveMode        bool
 	rulesCount               int
+	response                 *cliClient.CreateEvaluationResponse
 }
 
 type evaluateExpected struct {
-	response                  *EvaluationResults
+	response                  ResultType
 	err                       error
 	isRequestEvaluationCalled bool
 	isCreateEvaluationCalled  bool
@@ -149,12 +150,17 @@ func request_evaluation_all_valid() *evaluateTestCase {
 		name: "should request validation without invalid files",
 		args: &evaluateArgs{
 			validFilesConfigurations: newFilesConfigurations(validFilePath),
-			evaluationId:             1,
+			response: &cliClient.CreateEvaluationResponse{
+				EvaluationId: 1,
+				PolicyName:   "Default",
+				RulesCount:   21,
+			},
 			osInfo: &OSInfo{
 				OS:              "darwin",
 				PlatformVersion: "1.2.3",
 				KernelVersion:   "4.5.6",
 			},
+			isInteractiveMode: true,
 		},
 		mock: &evaluatorMock{
 			cliClient: &cliClientMockTestCase{
@@ -188,16 +194,18 @@ func request_evaluation_all_valid() *evaluateTestCase {
 			},
 		},
 		expected: &evaluateExpected{
-			response: &EvaluationResults{
-				FileNameRuleMapper: make(map[string]map[int]*Rule),
-				Summary: struct {
-					TotalFailedRules int
-					FilesCount       int
-					TotalPassedCount int
-				}{
-					TotalFailedRules: 0,
-					FilesCount:       1,
-					TotalPassedCount: 1,
+			response: ResultType{
+				EvaluationResults: &EvaluationResults{
+					FileNameRuleMapper: make(map[string]map[int]*Rule),
+					Summary: struct {
+						TotalFailedRules int
+						FilesCount       int
+						TotalPassedCount int
+					}{
+						TotalFailedRules: 0,
+						FilesCount:       1,
+						TotalPassedCount: 1,
+					},
 				},
 			},
 			err:                       nil,
@@ -211,12 +219,17 @@ func request_evaluation_all_invalid() *evaluateTestCase {
 		name: "should not request validation if there are no valid files",
 		args: &evaluateArgs{
 			validFilesConfigurations: []*extractor.FileConfigurations{},
-			evaluationId:             1,
+			response: &cliClient.CreateEvaluationResponse{
+				EvaluationId: 1,
+				PolicyName:   "Default",
+				RulesCount:   21,
+			},
 			osInfo: &OSInfo{
 				OS:              "darwin",
 				PlatformVersion: "1.2.3",
 				KernelVersion:   "4.5.6",
 			},
+			isInteractiveMode: true,
 		},
 		mock: &evaluatorMock{
 			cliClient: &cliClientMockTestCase{
@@ -250,16 +263,18 @@ func request_evaluation_all_invalid() *evaluateTestCase {
 			},
 		},
 		expected: &evaluateExpected{
-			response: &EvaluationResults{
-				FileNameRuleMapper: make(map[string]map[int]*Rule),
-				Summary: struct {
-					TotalFailedRules int
-					FilesCount       int
-					TotalPassedCount int
-				}{
-					TotalFailedRules: 0,
-					FilesCount:       1,
-					TotalPassedCount: 0,
+			response: ResultType{
+				EvaluationResults: &EvaluationResults{
+					FileNameRuleMapper: make(map[string]map[int]*Rule),
+					Summary: struct {
+						TotalFailedRules int
+						FilesCount       int
+						TotalPassedCount int
+					}{
+						TotalFailedRules: 0,
+						FilesCount:       1,
+						TotalPassedCount: 0,
+					},
 				},
 			},
 			err:                       nil,
diff --git a/bl/evaluation/printer_test.go b/bl/evaluation/printer_test.go
index 43cb018..ec9a4f9 100644
--- a/bl/evaluation/printer_test.go
+++ b/bl/evaluation/printer_test.go
@@ -31,7 +31,7 @@ func (c *mockPrinter) PrintEvaluationSummary(summary printer.EvaluationSummary,
 }
 
 type printResultsTestCaseArgs struct {
-	results           *EvaluationResults
+	results           ResultType
 	invalidYamlFiles  []*validation.InvalidYamlFile
 	invalidK8sFiles   []*validation.InvalidK8sFile
 	evaluationSummary printer.EvaluationSummary
@@ -76,7 +76,7 @@ func TestPrintResults(t *testing.T) {
 				mockedPrinter.AssertNotCalled(t, "PrintWarnings")
 			} else {
 				pwd, _ := os.Getwd()
-				warnings, _ := parseToPrinterWarnings(tt.args.results, tt.args.invalidYamlFiles, tt.args.invalidK8sFiles, pwd, "1.18.0")
+				warnings, _ := parseToPrinterWarnings(tt.args.results.EvaluationResults, tt.args.invalidYamlFiles, tt.args.invalidK8sFiles, pwd, "1.18.0")
 				mockedPrinter.AssertCalled(t, "PrintWarnings", warnings)
 			}
 		})
@@ -127,75 +127,76 @@ func readOutput(outputFormat string, formattedOutput FormattedOutput) string {
 }
 
 func createFormattedOutput() FormattedOutput {
-	evaluationResults := &EvaluationResults{
-		Summary: struct {
-			TotalFailedRules int
-			FilesCount       int
-			TotalPassedCount int
-		}{
-			TotalFailedRules: 4,
-			FilesCount:       1,
-			TotalPassedCount: 0,
+	evaluationResults := &NonInteractiveEvaluationResults{
+		PolicySummary: PolicySummary{
+			PolicyName:         "Default",
+			TotalRulesInPolicy: 21,
+			TotalRulesFailed:   4,
+			TotalPassedCount:   0,
 		},
-		FileNameRuleMapper: FileNameRuleMapper{"File1": map[int]*Rule{
-			1: &Rule{
-				ID:             1,
-				Name:           "Ensure each container image has a pinned (tag) version",
-				FailSuggestion: "Incorrect value for key `image` - specify an image version to avoid unpleasant \"version surprises\" in the future",
-				OccurrencesDetails: []OccurrenceDetails{{
-					MetadataName: "rss-site",
-					Kind:         "Deployment",
-				}},
-			},
-			4: &Rule{
-				ID:             4,
-				Name:           "Ensure each container has a configured memory limit",
-				FailSuggestion: "Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization",
-				OccurrencesDetails: []OccurrenceDetails{{
-					MetadataName: "rss-site",
-					Kind:         "Deployment",
-				}},
-			},
-			9: &Rule{
-				ID:             9,
-				Name:           "Ensure workload has valid label values",
-				FailSuggestion: "Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it",
-				OccurrencesDetails: []OccurrenceDetails{{
-					MetadataName: "rss-site",
-					Kind:         "Deployment",
-				}},
-			},
-			11: &Rule{
-				ID:             11,
-				Name:           "Ensure each container has a configured liveness probe",
-				FailSuggestion: "Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks",
-				OccurrencesDetails: []OccurrenceDetails{{
-					MetadataName: "rss-site",
-					Kind:         "Deployment",
-				}},
+		FormattedEvaluationResults: []*FormattedEvaluationResults{
+			{
+				FileName: "File1",
+				RuleResults: []*RuleResult{
+					{
+						Identifier:       "CONTAINERS_MISSING_IMAGE_VALUE_VERSION",
+						Name:             "Ensure each container image has a pinned (tag) version",
+						MessageOnFailure: "Incorrect value for key `image` - specify an image version to avoid unpleasant \"version surprises\" in the future",
+						OccurrencesDetails: []OccurrenceDetails{{
+							MetadataName: "rss-site",
+							Kind:         "Deployment",
+						}},
+					},
+					{
+						Identifier:       "CONTAINERS_MISSING_MEMORY_LIMIT_KEY",
+						Name:             "Ensure each container has a configured memory limit",
+						MessageOnFailure: "Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization",
+						OccurrencesDetails: []OccurrenceDetails{{
+							MetadataName: "rss-site",
+							Kind:         "Deployment",
+						}},
+					},
+					{
+						Identifier:       "WORKLOAD_INVALID_LABELS_VALUE",
+						Name:             "Ensure workload has valid label values",
+						MessageOnFailure: "Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it",
+						OccurrencesDetails: []OccurrenceDetails{{
+							MetadataName: "rss-site",
+							Kind:         "Deployment",
+						}},
+					},
+					{
+						Identifier:       "CONTAINERS_MISSING_LIVENESSPROBE_KEY",
+						Name:             "Ensure each container has a configured liveness probe",
+						MessageOnFailure: "Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks",
+						OccurrencesDetails: []OccurrenceDetails{{
+							MetadataName: "rss-site",
+							Kind:         "Deployment",
+						}},
+					},
+				},
 			},
-		}},
+		},
 	}
 
-	evaluationSummary := &printer.EvaluationSummary{
-		ConfigsCount:              1,
-		RulesCount:                21,
-		FilesCount:                1,
-		PassedYamlValidationCount: 1,
-		PassedK8sValidationCount:  1,
-		PassedPolicyCheckCount:    0,
-	}
 	return FormattedOutput{
-		EvaluationResults: evaluationResults,
-		EvaluationSummary: *evaluationSummary,
+		PolicyValidationResults: evaluationResults.FormattedEvaluationResults,
+		PolicySummary:           evaluationResults.PolicySummary,
+		EvaluationSummary: NonInteractiveEvaluationSummary{
+			ConfigsCount:                1,
+			FilesCount:                  1,
+			PassedYamlValidationCount:   1,
+			PassedK8sValidationCount:    1,
+			PassedPolicyValidationCount: 0,
+		},
 	}
 }
 
 func getExpectedOutputs() expectedOutputs {
 	return expectedOutputs{
-		json: "{\"EvaluationResults\":{\"FileNameRuleMapper\":{\"File1\":{\"1\":{\"ID\":1,\"Name\":\"Ensure each container image has a pinned (tag) version\",\"FailSuggestion\":\"Incorrect value for key `image` - specify an image version to avoid unpleasant \\\"version surprises\\\" in the future\",\"OccurrencesDetails\":[{\"MetadataName\":\"rss-site\",\"Kind\":\"Deployment\"}]},\"11\":{\"ID\":11,\"Name\":\"Ensure each container has a configured liveness probe\",\"FailSuggestion\":\"Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks\",\"OccurrencesDetails\":[{\"MetadataName\":\"rss-site\",\"Kind\":\"Deployment\"}]},\"4\":{\"ID\":4,\"Name\":\"Ensure each container has a configured memory limit\",\"FailSuggestion\":\"Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization\",\"OccurrencesDetails\":[{\"MetadataName\":\"rss-site\",\"Kind\":\"Deployment\"}]},\"9\":{\"ID\":9,\"Name\":\"Ensure workload has valid label values\",\"FailSuggestion\":\"Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it\",\"OccurrencesDetails\":[{\"MetadataName\":\"rss-site\",\"Kind\":\"Deployment\"}]}}},\"Summary\":{\"TotalFailedRules\":4,\"FilesCount\":1,\"TotalPassedCount\":0}},\"EvaluationSummary\":{\"ConfigsCount\":1,\"RulesCount\":21,\"FilesCount\":1,\"PassedYamlValidationCount\":1,\"PassedK8sValidationCount\":1,\"PassedPolicyCheckCount\":0},\"InvalidYamlFiles\":null,\"InvalidK8sFiles\":null}\n",
-		yaml: "evaluationresults:\n  filenamerulemapper:\n    File1:\n      1:\n        id: 1\n        name: Ensure each container image has a pinned (tag) version\n        failsuggestion: Incorrect value for key `image` - specify an image version\n          to avoid unpleasant \"version surprises\" in the future\n        occurrencesdetails:\n        - metadataname: rss-site\n          kind: Deployment\n      4:\n        id: 4\n        name: Ensure each container has a configured memory limit\n        failsuggestion: Missing property object `limits.memory` - value should be\n          within the accepted boundaries recommended by the organization\n        occurrencesdetails:\n        - metadataname: rss-site\n          kind: Deployment\n      9:\n        id: 9\n        name: Ensure workload has valid label values\n        failsuggestion: Incorrect value for key(s) under `labels` - the vales syntax\n          is not valid so the Kubernetes engine will not accept it\n        occurrencesdetails:\n        - metadataname: rss-site\n          kind: Deployment\n      11:\n        id: 11\n        name: Ensure each container has a configured liveness probe\n        failsuggestion: Missing property object `livenessProbe` - add a properly configured\n          livenessProbe to catch possible deadlocks\n        occurrencesdetails:\n        - metadataname: rss-site\n          kind: Deployment\n  summary:\n    totalfailedrules: 4\n    filescount: 1\n    totalpassedcount: 0\nevaluationsummary:\n  configscount: 1\n  rulescount: 21\n  filescount: 1\n  passedyamlvalidationcount: 1\n  passedk8svalidationcount: 1\n  passedpolicycheckcount: 0\ninvalidyamlfiles: []\ninvalidk8sfiles: []\n\n",
-		xml:  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FormattedOutput>\n\t<EvaluationResults>\n\t\t<FileNameRuleMapper>\n\t\t\t<File filename=\"File1\">\n\t\t\t\t<Rule>\n\t\t\t\t\t<ID>1</ID>\n\t\t\t\t\t<Name>Ensure each container image has a pinned (tag) version</Name>\n\t\t\t\t\t<FailSuggestion>Incorrect value for key `image` - specify an image version to avoid unpleasant &#34;version surprises&#34; in the future</FailSuggestion>\n\t\t\t\t\t<OccurrencesDetails>\n\t\t\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t\t\t</OccurrencesDetails>\n\t\t\t\t</Rule>\n\t\t\t</File>\n\t\t\t<File filename=\"File1\">\n\t\t\t\t<Rule>\n\t\t\t\t\t<ID>4</ID>\n\t\t\t\t\t<Name>Ensure each container has a configured memory limit</Name>\n\t\t\t\t\t<FailSuggestion>Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization</FailSuggestion>\n\t\t\t\t\t<OccurrencesDetails>\n\t\t\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t\t\t</OccurrencesDetails>\n\t\t\t\t</Rule>\n\t\t\t</File>\n\t\t\t<File filename=\"File1\">\n\t\t\t\t<Rule>\n\t\t\t\t\t<ID>9</ID>\n\t\t\t\t\t<Name>Ensure workload has valid label values</Name>\n\t\t\t\t\t<FailSuggestion>Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it</FailSuggestion>\n\t\t\t\t\t<OccurrencesDetails>\n\t\t\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t\t\t</OccurrencesDetails>\n\t\t\t\t</Rule>\n\t\t\t</File>\n\t\t\t<File filename=\"File1\">\n\t\t\t\t<Rule>\n\t\t\t\t\t<ID>11</ID>\n\t\t\t\t\t<Name>Ensure each container has a configured liveness probe</Name>\n\t\t\t\t\t<FailSuggestion>Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks</FailSuggestion>\n\t\t\t\t\t<OccurrencesDetails>\n\t\t\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t\t\t</OccurrencesDetails>\n\t\t\t\t</Rule>\n\t\t\t</File>\n\t\t</FileNameRuleMapper>\n\t\t<Summary>\n\t\t\t<TotalFailedRules>4</TotalFailedRules>\n\t\t\t<FilesCount>1</FilesCount>\n\t\t\t<TotalPassedCount>0</TotalPassedCount>\n\t\t</Summary>\n\t</EvaluationResults>\n\t<EvaluationSummary>\n\t\t<ConfigsCount>1</ConfigsCount>\n\t\t<RulesCount>21</RulesCount>\n\t\t<FilesCount>1</FilesCount>\n\t\t<PassedYamlValidationCount>1</PassedYamlValidationCount>\n\t\t<PassedK8sValidationCount>1</PassedK8sValidationCount>\n\t\t<PassedPolicyCheckCount>0</PassedPolicyCheckCount>\n\t</EvaluationSummary>\n</FormattedOutput>\n",
+		json: "{\"policyValidationResults\":[{\"fileName\":\"File1\",\"ruleResults\":[{\"identifier\":\"CONTAINERS_MISSING_IMAGE_VALUE_VERSION\",\"name\":\"Ensure each container image has a pinned (tag) version\",\"messageOnFailure\":\"Incorrect value for key `image` - specify an image version to avoid unpleasant \\\"version surprises\\\" in the future\",\"occurrencesDetails\":[{\"metadataName\":\"rss-site\",\"kind\":\"Deployment\"}]},{\"identifier\":\"CONTAINERS_MISSING_MEMORY_LIMIT_KEY\",\"name\":\"Ensure each container has a configured memory limit\",\"messageOnFailure\":\"Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization\",\"occurrencesDetails\":[{\"metadataName\":\"rss-site\",\"kind\":\"Deployment\"}]},{\"identifier\":\"WORKLOAD_INVALID_LABELS_VALUE\",\"name\":\"Ensure workload has valid label values\",\"messageOnFailure\":\"Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it\",\"occurrencesDetails\":[{\"metadataName\":\"rss-site\",\"kind\":\"Deployment\"}]},{\"identifier\":\"CONTAINERS_MISSING_LIVENESSPROBE_KEY\",\"name\":\"Ensure each container has a configured liveness probe\",\"messageOnFailure\":\"Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks\",\"occurrencesDetails\":[{\"metadataName\":\"rss-site\",\"kind\":\"Deployment\"}]}]}],\"policySummary\":{\"policyName\":\"Default\",\"totalRulesInPolicy\":21,\"totalRulesFailed\":4,\"totalPassedCount\":0},\"evaluationSummary\":{\"configsCount\":1,\"filesCount\":1,\"passedYamlValidationCount\":1,\"passedK8sValidationCount\":1,\"passedPolicyValidationCount\":0},\"yamlValidationResults\":null,\"k8sValidationResults\":null}\n",
+		yaml: "policyValidationResults:\n- fileName: File1\n  ruleResults:\n  - identifier: CONTAINERS_MISSING_IMAGE_VALUE_VERSION\n    name: Ensure each container image has a pinned (tag) version\n    messageOnFailure: Incorrect value for key `image` - specify an image version to\n      avoid unpleasant \"version surprises\" in the future\n    occurrencesDetails:\n    - metadataName: rss-site\n      kind: Deployment\n  - identifier: CONTAINERS_MISSING_MEMORY_LIMIT_KEY\n    name: Ensure each container has a configured memory limit\n    messageOnFailure: Missing property object `limits.memory` - value should be within\n      the accepted boundaries recommended by the organization\n    occurrencesDetails:\n    - metadataName: rss-site\n      kind: Deployment\n  - identifier: WORKLOAD_INVALID_LABELS_VALUE\n    name: Ensure workload has valid label values\n    messageOnFailure: Incorrect value for key(s) under `labels` - the vales syntax\n      is not valid so the Kubernetes engine will not accept it\n    occurrencesDetails:\n    - metadataName: rss-site\n      kind: Deployment\n  - identifier: CONTAINERS_MISSING_LIVENESSPROBE_KEY\n    name: Ensure each container has a configured liveness probe\n    messageOnFailure: Missing property object `livenessProbe` - add a properly configured\n      livenessProbe to catch possible deadlocks\n    occurrencesDetails:\n    - metadataName: rss-site\n      kind: Deployment\npolicySummary:\n  policyName: Default\n  totalRulesInPolicy: 21\n  totalRulesFailed: 4\n  totalPassedCount: 0\nevaluationSummary:\n  configsCount: 1\n  filesCount: 1\n  passedYamlValidationCount: 1\n  passedK8sValidationCount: 1\n  passedPolicyValidationCount: 0\nyamlValidationResults: []\nk8sValidationResults: []\n\n",
+		xml:  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FormattedOutput>\n\t<PolicyValidationResults>\n\t\t<FileName>File1</FileName>\n\t\t<RuleResults>\n\t\t\t<Identifier>CONTAINERS_MISSING_IMAGE_VALUE_VERSION</Identifier>\n\t\t\t<Name>Ensure each container image has a pinned (tag) version</Name>\n\t\t\t<MessageOnFailure>Incorrect value for key `image` - specify an image version to avoid unpleasant &#34;version surprises&#34; in the future</MessageOnFailure>\n\t\t\t<OccurrencesDetails>\n\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t</OccurrencesDetails>\n\t\t</RuleResults>\n\t\t<RuleResults>\n\t\t\t<Identifier>CONTAINERS_MISSING_MEMORY_LIMIT_KEY</Identifier>\n\t\t\t<Name>Ensure each container has a configured memory limit</Name>\n\t\t\t<MessageOnFailure>Missing property object `limits.memory` - value should be within the accepted boundaries recommended by the organization</MessageOnFailure>\n\t\t\t<OccurrencesDetails>\n\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t</OccurrencesDetails>\n\t\t</RuleResults>\n\t\t<RuleResults>\n\t\t\t<Identifier>WORKLOAD_INVALID_LABELS_VALUE</Identifier>\n\t\t\t<Name>Ensure workload has valid label values</Name>\n\t\t\t<MessageOnFailure>Incorrect value for key(s) under `labels` - the vales syntax is not valid so the Kubernetes engine will not accept it</MessageOnFailure>\n\t\t\t<OccurrencesDetails>\n\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t</OccurrencesDetails>\n\t\t</RuleResults>\n\t\t<RuleResults>\n\t\t\t<Identifier>CONTAINERS_MISSING_LIVENESSPROBE_KEY</Identifier>\n\t\t\t<Name>Ensure each container has a configured liveness probe</Name>\n\t\t\t<MessageOnFailure>Missing property object `livenessProbe` - add a properly configured livenessProbe to catch possible deadlocks</MessageOnFailure>\n\t\t\t<OccurrencesDetails>\n\t\t\t\t<MetadataName>rss-site</MetadataName>\n\t\t\t\t<Kind>Deployment</Kind>\n\t\t\t</OccurrencesDetails>\n\t\t</RuleResults>\n\t</PolicyValidationResults>\n\t<PolicySummary>\n\t\t<PolicyName>Default</PolicyName>\n\t\t<TotalRulesInPolicy>21</TotalRulesInPolicy>\n\t\t<TotalRulesFailed>4</TotalRulesFailed>\n\t\t<TotalPassedCount>0</TotalPassedCount>\n\t</PolicySummary>\n\t<EvaluationSummary>\n\t\t<ConfigsCount>1</ConfigsCount>\n\t\t<FilesCount>1</FilesCount>\n\t\t<PassedYamlValidationCount>1</PassedYamlValidationCount>\n\t\t<PassedK8sValidationCount>1</PassedK8sValidationCount>\n\t\t<PassedPolicyValidationCount>0</PassedPolicyValidationCount>\n\t</EvaluationSummary>\n</FormattedOutput>\n",
 	}
 }
 
@@ -203,16 +204,27 @@ func print_resultst(outputFormat string) *printResultsTestCase {
 	return &printResultsTestCase{
 		name: "Print Results Text",
 		args: &printResultsTestCaseArgs{
-			results: &EvaluationResults{
-				FileNameRuleMapper: map[string]map[int]*Rule{},
-				Summary: struct {
-					TotalFailedRules int
-					FilesCount       int
-					TotalPassedCount int
-				}{
-					TotalFailedRules: 0,
-					FilesCount:       0,
-					TotalPassedCount: 0,
+			results: ResultType{
+				EvaluationResults: &EvaluationResults{
+					FileNameRuleMapper: map[string]map[int]*Rule{},
+					Summary: struct {
+						TotalFailedRules int
+						FilesCount       int
+						TotalPassedCount int
+					}{
+						TotalFailedRules: 0,
+						FilesCount:       0,
+						TotalPassedCount: 0,
+					},
+				},
+				NonInteractiveEvaluationResults: &NonInteractiveEvaluationResults{
+					PolicySummary: PolicySummary{
+						PolicyName:         "Default",
+						TotalRulesInPolicy: 0,
+						TotalRulesFailed:   0,
+						TotalPassedCount:   0,
+					},
+					FormattedEvaluationResults: []*FormattedEvaluationResults{},
 				},
 			},
 			invalidYamlFiles:  []*validation.InvalidYamlFile{},
diff --git a/cmd/test/main.go b/cmd/test/main.go
index c02b989..06ef389 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -21,7 +21,7 @@ import (
 )
 
 type Evaluator interface {
-	Evaluate(filesConfigurationsChan []*extractor.FileConfigurations, evaluationId int) (*evaluation.EvaluationResults, error)
+	Evaluate(filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, isInteractiveMode bool) (evaluation.ResultType, error)
 	CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string) (*cliClient.CreateEvaluationResponse, error)
 	UpdateFailedYamlValidation(invalidFiles []*validation.InvalidYamlFile, evaluationId int, stopEvaluation bool) error
 	UpdateFailedK8sValidation(invalidFiles []*validation.InvalidK8sFile, evaluationId int, stopEvaluation bool) error
@@ -207,8 +207,8 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 	}
 
 	passedPolicyCheckCount := 0
-	if results != nil {
-		passedPolicyCheckCount = results.Summary.TotalPassedCount
+	if results.EvaluationResults != nil {
+		passedPolicyCheckCount = results.EvaluationResults.Summary.TotalPassedCount
 	}
 
 	passedYamlValidationCount := filesPathsLen - validationManager.InvalidYamlFilesCount()
@@ -243,14 +243,14 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 
 	if err != nil {
 		invocationFailedErr = err
-	} else if validationManager.InvalidYamlFilesCount() > 0 || validationManager.InvalidK8sFilesCount() > 0 || results.Summary.TotalFailedRules > 0 {
+	} else if validationManager.InvalidYamlFilesCount() > 0 || validationManager.InvalidK8sFilesCount() > 0 || results.EvaluationResults.Summary.TotalFailedRules > 0 {
 		invocationFailedErr = fmt.Errorf("")
 	}
 
 	return invocationFailedErr
 }
 
-func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFlags, cliId string) (*ValidationManager, *cliClient.CreateEvaluationResponse, *evaluation.EvaluationResults, error) {
+func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFlags, cliId string) (*ValidationManager, *cliClient.CreateEvaluationResponse, evaluation.ResultType, error) {
 	isInteractiveMode := (flags.Output != "json") && (flags.Output != "yaml") && (flags.Output != "xml")
 
 	if isInteractiveMode {
@@ -281,7 +281,7 @@ func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFla
 
 	createEvaluationResponse, err := ctx.Evaluator.CreateEvaluation(cliId, ctx.CliVersion, flags.K8sVersion, flags.PolicyName)
 	if err != nil {
-		return validationManager, nil, nil, err
+		return validationManager, nil, evaluation.ResultType{}, err
 	}
 
 	ctx.K8sValidator.InitClient(createEvaluationResponse.K8sVersion, flags.IgnoreMissingSchemas, flags.SchemaLocations)
@@ -304,7 +304,7 @@ func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFla
 	if validationManager.InvalidYamlFilesCount() > 0 {
 		err = ctx.Evaluator.UpdateFailedYamlValidation(validationManager.InvalidYamlFiles(), createEvaluationResponse.EvaluationId, noValidYamlFiles)
 		if err != nil {
-			return validationManager, createEvaluationResponse, nil, err
+			return validationManager, createEvaluationResponse, evaluation.ResultType{}, err
 		}
 	}
 
@@ -316,17 +316,13 @@ func evaluate(ctx *TestCommandContext, filesPaths []string, flags TestCommandFla
 	if validationManager.InvalidK8sFilesCount() > 0 {
 		err = ctx.Evaluator.UpdateFailedK8sValidation(validationManager.InvalidK8sFiles(), createEvaluationResponse.EvaluationId, noValidK8sFiles)
 		if err != nil {
-			return validationManager, createEvaluationResponse, nil, err
+			return validationManager, createEvaluationResponse, evaluation.ResultType{}, err
 		}
 	}
 
 	validationManager.AggregateValidK8sFiles(validK8sFilesConfigurationsChan)
 
-	results, err := ctx.Evaluator.Evaluate(validationManager.ValidK8sFilesConfigurations(), createEvaluationResponse.EvaluationId)
+	results, err := ctx.Evaluator.Evaluate(validationManager.ValidK8sFilesConfigurations(), createEvaluationResponse, isInteractiveMode)
 
-	if err != nil {
-		return validationManager, createEvaluationResponse, nil, err
-	}
-
-	return validationManager, createEvaluationResponse, results, nil
+	return validationManager, createEvaluationResponse, results, err
 }
diff --git a/cmd/test/main_test.go b/cmd/test/main_test.go
index b18046c..35a7d14 100644
--- a/cmd/test/main_test.go
+++ b/cmd/test/main_test.go
@@ -18,9 +18,9 @@ type mockEvaluator struct {
 	mock.Mock
 }
 
-func (m *mockEvaluator) Evaluate(filesConfigurationsChan []*extractor.FileConfigurations, evaluationId int) (*evaluation.EvaluationResults, error) {
-	args := m.Called(filesConfigurationsChan, evaluationId)
-	return args.Get(0).(*evaluation.EvaluationResults), args.Error(1)
+func (m *mockEvaluator) Evaluate(filesConfigurationsChan []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, isInteractiveMode bool) (evaluation.ResultType, error) {
+	args := m.Called(filesConfigurationsChan, evaluationResponse, isInteractiveMode)
+	return args.Get(0).(evaluation.ResultType), args.Error(1)
 }
 
 func (m *mockEvaluator) CreateEvaluation(cliId string, cliVersion string, k8sVersion string, policyName string) (*cliClient.CreateEvaluationResponse, error) {
@@ -123,8 +123,10 @@ func (lc *LocalConfigMock) GetLocalConfiguration() (*localConfig.ConfigContent,
 
 func TestTestCommand(t *testing.T) {
 	evaluationId := 444
+	evaluationResponse := cliClient.CreateEvaluationResponse{EvaluationId: evaluationId, K8sVersion: "1.18.0", RulesCount: 21, PolicyName: "Default"}
+	resultType := evaluation.ResultType{}
 
-	evaluationResults := &evaluation.EvaluationResults{
+	resultType.EvaluationResults = &evaluation.EvaluationResults{
 		FileNameRuleMapper: map[string]map[int]*evaluation.Rule{}, Summary: struct {
 			TotalFailedRules int
 			FilesCount       int
@@ -133,7 +135,7 @@ func TestTestCommand(t *testing.T) {
 	}
 
 	mockedEvaluator := &mockEvaluator{}
-	mockedEvaluator.On("Evaluate", mock.Anything, mock.Anything, mock.Anything).Return(evaluationResults, nil)
+	mockedEvaluator.On("Evaluate", mock.Anything, mock.Anything, mock.Anything).Return(resultType, nil)
 	mockedEvaluator.On("CreateEvaluation", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&cliClient.CreateEvaluationResponse{EvaluationId: evaluationId, K8sVersion: "1.18.0", RulesCount: 21}, nil)
 	mockedEvaluator.On("UpdateFailedYamlValidation", mock.Anything, mock.Anything, mock.Anything).Return(nil)
 	mockedEvaluator.On("UpdateFailedK8sValidation", mock.Anything, mock.Anything, mock.Anything).Return(nil)
@@ -175,41 +177,41 @@ func TestTestCommand(t *testing.T) {
 		Reader:       readerMock,
 	}
 
-	test_testCommand_no_flags(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, evaluationId, ctx)
-	test_testCommand_json_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, evaluationId, ctx)
-	test_testCommand_yaml_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, evaluationId, ctx)
-	test_testCommand_xml_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, evaluationId, ctx)
+	test_testCommand_no_flags(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, &evaluationResponse, ctx)
+	test_testCommand_json_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, &evaluationResponse, ctx)
+	test_testCommand_yaml_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, &evaluationResponse, ctx)
+	test_testCommand_xml_output(t, mockedEvaluator, k8sValidatorMock, filesConfigurations, &evaluationResponse, ctx)
 
 	test_testCommand_only_k8s_files(t, k8sValidatorMock, filesConfigurations, evaluationId, ctx)
 }
 
-func test_testCommand_no_flags(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationId int, ctx *TestCommandContext) {
+func test_testCommand_no_flags(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, ctx *TestCommandContext) {
 	test(ctx, []string{"8/*"}, TestCommandFlags{K8sVersion: "1.18.0", Output: "", PolicyName: "Default"})
 
 	k8sValidator.AssertCalled(t, "ValidateResources", mock.Anything, 100)
 	evaluator.AssertCalled(t, "CreateEvaluation", "134kh", "", "1.18.0", "Default")
-	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, evaluationId)
+	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, mock.Anything, mock.Anything)
 }
 
-func test_testCommand_json_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationId int, ctx *TestCommandContext) {
+func test_testCommand_json_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, ctx *TestCommandContext) {
 	test(ctx, []string{"8/*"}, TestCommandFlags{Output: "json"})
 
 	k8sValidator.AssertCalled(t, "ValidateResources", mock.Anything, 100)
-	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, evaluationId)
+	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, mock.Anything, mock.Anything)
 }
 
-func test_testCommand_yaml_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationId int, ctx *TestCommandContext) {
+func test_testCommand_yaml_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, ctx *TestCommandContext) {
 	test(ctx, []string{"8/*"}, TestCommandFlags{Output: "yaml"})
 
 	k8sValidator.AssertCalled(t, "ValidateResources", mock.Anything, 100)
-	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, evaluationId)
+	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, mock.Anything, mock.Anything)
 }
 
-func test_testCommand_xml_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationId int, ctx *TestCommandContext) {
+func test_testCommand_xml_output(t *testing.T, evaluator *mockEvaluator, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationResponse *cliClient.CreateEvaluationResponse, ctx *TestCommandContext) {
 	test(ctx, []string{"8/*"}, TestCommandFlags{Output: "xml"})
 
 	k8sValidator.AssertCalled(t, "ValidateResources", mock.Anything, 100)
-	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, evaluationId)
+	evaluator.AssertCalled(t, "Evaluate", filesConfigurations, mock.Anything, mock.Anything)
 }
 
 func test_testCommand_only_k8s_files(t *testing.T, k8sValidator *K8sValidatorMock, filesConfigurations []*extractor.FileConfigurations, evaluationId int, ctx *TestCommandContext) {