mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
added different logic for policy report in CLI
Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>
This commit is contained in:
parent
1e6b4bdcee
commit
868537f04d
7 changed files with 106 additions and 68 deletions
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/pkg/kyverno/store"
|
"github.com/kyverno/kyverno/pkg/kyverno/store"
|
||||||
"github.com/kyverno/kyverno/pkg/openapi"
|
"github.com/kyverno/kyverno/pkg/openapi"
|
||||||
policy2 "github.com/kyverno/kyverno/pkg/policy"
|
policy2 "github.com/kyverno/kyverno/pkg/policy"
|
||||||
|
"github.com/kyverno/kyverno/pkg/policyreport"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
|
@ -121,12 +122,12 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
validateEngineResponses, rc, resources, skippedPolicies, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths, stdin)
|
validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths, stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
printReportOrViolation(policyReport, validateEngineResponses, rc, resourcePaths, len(resources), skippedPolicies, stdin)
|
printReportOrViolation(policyReport, validateEngineResponses, rc, resourcePaths, len(resources), skippedPolicies, stdin, pvInfos)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -144,48 +145,48 @@ func Command() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
|
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
|
||||||
variablesString string, valuesFile string, namespace string, policyPaths []string, stdin bool) (validateEngineResponses []*response.EngineResponse, rc *common.ResultCounts, resources []*unstructured.Unstructured, skippedPolicies []string, err error) {
|
variablesString string, valuesFile string, namespace string, policyPaths []string, stdin bool) (validateEngineResponses []*response.EngineResponse, rc *common.ResultCounts, resources []*unstructured.Unstructured, skippedPolicies []string, pvInfos []policyreport.Info, err error) {
|
||||||
|
|
||||||
store.SetMock(true)
|
store.SetMock(true)
|
||||||
kubernetesConfig := genericclioptions.NewConfigFlags(true)
|
kubernetesConfig := genericclioptions.NewConfigFlags(true)
|
||||||
fs := memfs.New()
|
fs := memfs.New()
|
||||||
|
|
||||||
if valuesFile != "" && variablesString != "" {
|
if valuesFile != "" && variablesString != "" {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("pass the values either using set flag or values_file flag", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
variables, valuesMap, namespaceSelectorMap, err := common.GetVariable(variablesString, valuesFile, fs, false, "")
|
variables, valuesMap, namespaceSelectorMap, err := common.GetVariable(variablesString, valuesFile, fs, false, "")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizederror.IsErrorSanitized(err) {
|
if !sanitizederror.IsErrorSanitized(err) {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to decode yaml", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to decode yaml", err)
|
||||||
}
|
}
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, err
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
openAPIController, err := openapi.NewOpenAPIController()
|
openAPIController, err := openapi.NewOpenAPIController()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to initialize openAPIController", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to initialize openAPIController", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var dClient *client.Client
|
var dClient *client.Client
|
||||||
if cluster {
|
if cluster {
|
||||||
restConfig, err := kubernetesConfig.ToRESTConfig()
|
restConfig, err := kubernetesConfig.ToRESTConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, err
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err
|
||||||
}
|
}
|
||||||
dClient, err = client.NewClient(restConfig, 15*time.Minute, make(chan struct{}), log.Log)
|
dClient, err = client.NewClient(restConfig, 15*time.Minute, make(chan struct{}), log.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, err
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(policyPaths) == 0 {
|
if len(policyPaths) == 0 {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Sprintf("require policy"), err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Sprintf("require policy"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(policyPaths) > 0 && policyPaths[0] == "-") && len(resourcePaths) > 0 && resourcePaths[0] == "-" {
|
if (len(policyPaths) > 0 && policyPaths[0] == "-") && len(resourcePaths) > 0 && resourcePaths[0] == "-" {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("a stdin pipe can be used for either policies or resources, not both", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("a stdin pipe can be used for either policies or resources, not both", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
policies, err := common.GetPoliciesFromPaths(fs, policyPaths, false, "")
|
policies, err := common.GetPoliciesFromPaths(fs, policyPaths, false, "")
|
||||||
|
@ -195,15 +196,15 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resourcePaths) == 0 && !cluster {
|
if len(resourcePaths) == 0 && !cluster {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Sprintf("resource file(s) or cluster required"), err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Sprintf("resource file(s) or cluster required"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutateLogPathIsDir, err := checkMutateLogPath(mutateLogPath)
|
mutateLogPathIsDir, err := checkMutateLogPath(mutateLogPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizederror.IsErrorSanitized(err) {
|
if !sanitizederror.IsErrorSanitized(err) {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to create file/folder", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to create file/folder", err)
|
||||||
}
|
}
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, err
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty the previous contents of the file just in case if the file already existed before with some content(so as to perform overwrites)
|
// empty the previous contents of the file just in case if the file already existed before with some content(so as to perform overwrites)
|
||||||
|
@ -212,23 +213,23 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
|
||||||
_, err := os.OpenFile(mutateLogPath, os.O_TRUNC|os.O_WRONLY, 0644)
|
_, err := os.OpenFile(mutateLogPath, os.O_TRUNC|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizederror.IsErrorSanitized(err) {
|
if !sanitizederror.IsErrorSanitized(err) {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to truncate the existing file at "+mutateLogPath, err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to truncate the existing file at "+mutateLogPath, err)
|
||||||
}
|
}
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, err
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutatedPolicies, err := common.MutatePolices(policies)
|
mutatedPolicies, err := common.MutatePolices(policies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !sanitizederror.IsErrorSanitized(err) {
|
if !sanitizederror.IsErrorSanitized(err) {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to mutate policy", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to mutate policy", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, policy := range mutatedPolicies {
|
for _, policy := range mutatedPolicies {
|
||||||
p, err := json.Marshal(policy)
|
p, err := json.Marshal(policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("failed to marsal mutated policy", err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("failed to marsal mutated policy", err)
|
||||||
}
|
}
|
||||||
log.Log.V(5).Info("mutated Policy:", string(p))
|
log.Log.V(5).Info("mutated Policy:", string(p))
|
||||||
|
|
||||||
|
@ -241,7 +242,7 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(resources) > 1 || len(mutatedPolicies) > 1) && variablesString != "" {
|
if (len(resources) > 1 || len(mutatedPolicies) > 1) && variablesString != "" {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError("currently `set` flag supports variable for single policy applied on single resource ", nil)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError("currently `set` flag supports variable for single policy applied on single resource ", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if variablesString != "" {
|
if variablesString != "" {
|
||||||
|
@ -311,20 +312,21 @@ func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool,
|
||||||
// skipping the variable check for non matching kind
|
// skipping the variable check for non matching kind
|
||||||
if _, ok := kindOnwhichPolicyIsApplied[resource.GetKind()]; ok {
|
if _, ok := kindOnwhichPolicyIsApplied[resource.GetKind()]; ok {
|
||||||
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
|
if len(variable) > 0 && len(thisPolicyResourceValues) == 0 && len(store.GetContext().Policies) == 0 {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.Name, resource.GetName()), err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Sprintf("policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag", policy.Name, resource.GetName()), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateErs, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin, rc)
|
validateErs, info, err := common.ApplyPolicyOnResource(policy, resource, mutateLogPath, mutateLogPathIsDir, thisPolicyResourceValues, policyReport, namespaceSelectorMap, stdin, rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
|
||||||
}
|
}
|
||||||
|
pvInfos = append(pvInfos, info)
|
||||||
|
|
||||||
validateEngineResponses = append(validateEngineResponses, validateErs)
|
validateEngineResponses = append(validateEngineResponses, validateErs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateEngineResponses, rc, resources, skippedPolicies, nil
|
return validateEngineResponses, rc, resources, skippedPolicies, pvInfos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkMutateLogPath - checking path for printing mutated resource (-o flag)
|
// checkMutateLogPath - checking path for printing mutated resource (-o flag)
|
||||||
|
@ -350,7 +352,7 @@ func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// printReportOrViolation - printing policy report/violations
|
// printReportOrViolation - printing policy report/violations
|
||||||
func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []string, stdin bool) {
|
func printReportOrViolation(policyReport bool, validateEngineResponses []*response.EngineResponse, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skippedPolicies []string, stdin bool, pvInfos []policyreport.Info) {
|
||||||
if len(skippedPolicies) > 0 {
|
if len(skippedPolicies) > 0 {
|
||||||
fmt.Println("----------------------------------------------------------------------\nPolicies Skipped(as required variables are not provided by the users):")
|
fmt.Println("----------------------------------------------------------------------\nPolicies Skipped(as required variables are not provided by the users):")
|
||||||
for i, policyName := range skippedPolicies {
|
for i, policyName := range skippedPolicies {
|
||||||
|
@ -361,7 +363,7 @@ func printReportOrViolation(policyReport bool, validateEngineResponses []*respon
|
||||||
|
|
||||||
if policyReport {
|
if policyReport {
|
||||||
os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport)
|
os.Setenv("POLICY-TYPE", pkgCommon.PolicyReport)
|
||||||
resps := buildPolicyReports(validateEngineResponses)
|
resps := buildPolicyReports(validateEngineResponses, pvInfos)
|
||||||
if len(resps) > 0 || resourcesLen == 0 {
|
if len(resps) > 0 || resourcesLen == 0 {
|
||||||
fmt.Println("\n----------------------------------------------------------------------\nPOLICY REPORT:\n----------------------------------------------------------------------")
|
fmt.Println("\n----------------------------------------------------------------------\nPOLICY REPORT:\n----------------------------------------------------------------------")
|
||||||
report, _ := generateCLIRaw(resps)
|
report, _ := generateCLIRaw(resps)
|
||||||
|
|
|
@ -56,8 +56,8 @@ func Test_Apply(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testcases {
|
for _, tc := range testcases {
|
||||||
validateEngineResponses, _, _, _, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths, false)
|
validateEngineResponses, _, _, _, info, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths, false)
|
||||||
resps := buildPolicyReports(validateEngineResponses)
|
resps := buildPolicyReports(validateEngineResponses, info)
|
||||||
for i, resp := range resps {
|
for i, resp := range resps {
|
||||||
compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}))
|
compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,11 @@ import (
|
||||||
const clusterpolicyreport = "clusterpolicyreport"
|
const clusterpolicyreport = "clusterpolicyreport"
|
||||||
|
|
||||||
// resps is the engine responses generated for a single policy
|
// resps is the engine responses generated for a single policy
|
||||||
func buildPolicyReports(resps []*response.EngineResponse) (res []*unstructured.Unstructured) {
|
func buildPolicyReports(resps []*response.EngineResponse, pvInfos []policyreport.Info) (res []*unstructured.Unstructured) {
|
||||||
var raw []byte
|
var raw []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
resultsMap := buildPolicyResults(resps)
|
resultsMap := buildPolicyResults(resps, pvInfos)
|
||||||
for scope, result := range resultsMap {
|
for scope, result := range resultsMap {
|
||||||
if scope == clusterpolicyreport {
|
if scope == clusterpolicyreport {
|
||||||
report := &report.ClusterPolicyReport{
|
report := &report.ClusterPolicyReport{
|
||||||
|
@ -74,9 +74,8 @@ func buildPolicyReports(resps []*response.EngineResponse) (res []*unstructured.U
|
||||||
|
|
||||||
// buildPolicyResults returns a string-PolicyReportResult map
|
// buildPolicyResults returns a string-PolicyReportResult map
|
||||||
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>"
|
// the key of the map is one of "clusterpolicyreport", "policyreport-ns-<namespace>"
|
||||||
func buildPolicyResults(resps []*response.EngineResponse) map[string][]*report.PolicyReportResult {
|
func buildPolicyResults(resps []*response.EngineResponse, infos []policyreport.Info) map[string][]*report.PolicyReportResult {
|
||||||
results := make(map[string][]*report.PolicyReportResult)
|
results := make(map[string][]*report.PolicyReportResult)
|
||||||
infos := policyreport.GeneratePRsFromEngineResponse(resps, log.Log)
|
|
||||||
now := metav1.Timestamp{Seconds: time.Now().Unix()}
|
now := metav1.Timestamp{Seconds: time.Now().Unix()}
|
||||||
|
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
|
|
|
@ -72,7 +72,7 @@ var engineResponses = []*response.EngineResponse{
|
||||||
|
|
||||||
func Test_buildPolicyReports(t *testing.T) {
|
func Test_buildPolicyReports(t *testing.T) {
|
||||||
os.Setenv("POLICY-TYPE", common.PolicyReport)
|
os.Setenv("POLICY-TYPE", common.PolicyReport)
|
||||||
reports := buildPolicyReports(engineResponses)
|
reports := buildPolicyReports(engineResponses, nil)
|
||||||
assert.Assert(t, len(reports) == 2, len(reports))
|
assert.Assert(t, len(reports) == 2, len(reports))
|
||||||
|
|
||||||
for _, report := range reports {
|
for _, report := range reports {
|
||||||
|
@ -97,7 +97,7 @@ func Test_buildPolicyReports(t *testing.T) {
|
||||||
func Test_buildPolicyResults(t *testing.T) {
|
func Test_buildPolicyResults(t *testing.T) {
|
||||||
os.Setenv("POLICY-TYPE", common.PolicyReport)
|
os.Setenv("POLICY-TYPE", common.PolicyReport)
|
||||||
|
|
||||||
results := buildPolicyResults(engineResponses)
|
results := buildPolicyResults(engineResponses, nil)
|
||||||
assert.Assert(t, len(results[clusterpolicyreport]) == 2, len(results[clusterpolicyreport]))
|
assert.Assert(t, len(results[clusterpolicyreport]) == 2, len(results[clusterpolicyreport]))
|
||||||
assert.Assert(t, len(results["policyreport-ns-policy1-namespace"]) == 2, len(results["policyreport-ns-policy1-namespace"]))
|
assert.Assert(t, len(results["policyreport-ns-policy1-namespace"]) == 2, len(results["policyreport-ns-policy1-namespace"]))
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||||
|
report "github.com/kyverno/kyverno/pkg/api/policyreport/v1alpha2"
|
||||||
pkgcommon "github.com/kyverno/kyverno/pkg/common"
|
pkgcommon "github.com/kyverno/kyverno/pkg/common"
|
||||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||||
"github.com/kyverno/kyverno/pkg/engine"
|
"github.com/kyverno/kyverno/pkg/engine"
|
||||||
|
@ -25,6 +26,7 @@ import (
|
||||||
sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
|
sanitizederror "github.com/kyverno/kyverno/pkg/kyverno/sanitizedError"
|
||||||
"github.com/kyverno/kyverno/pkg/kyverno/store"
|
"github.com/kyverno/kyverno/pkg/kyverno/store"
|
||||||
"github.com/kyverno/kyverno/pkg/policymutation"
|
"github.com/kyverno/kyverno/pkg/policymutation"
|
||||||
|
"github.com/kyverno/kyverno/pkg/policyreport"
|
||||||
"github.com/kyverno/kyverno/pkg/utils"
|
"github.com/kyverno/kyverno/pkg/utils"
|
||||||
ut "github.com/kyverno/kyverno/pkg/utils"
|
ut "github.com/kyverno/kyverno/pkg/utils"
|
||||||
yamlv2 "gopkg.in/yaml.v2"
|
yamlv2 "gopkg.in/yaml.v2"
|
||||||
|
@ -514,7 +516,7 @@ func MutatePolices(policies []*v1.ClusterPolicy) ([]*v1.ClusterPolicy, error) {
|
||||||
|
|
||||||
// ApplyPolicyOnResource - function to apply policy on resource
|
// ApplyPolicyOnResource - function to apply policy on resource
|
||||||
func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
|
func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured,
|
||||||
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool, rc *ResultCounts) (*response.EngineResponse, error) {
|
mutateLogPath string, mutateLogPathIsDir bool, variables map[string]string, policyReport bool, namespaceSelectorMap map[string]map[string]string, stdin bool, rc *ResultCounts) (*response.EngineResponse, policyreport.Info, error) {
|
||||||
|
|
||||||
operationIsDelete := false
|
operationIsDelete := false
|
||||||
|
|
||||||
|
@ -539,7 +541,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
|
||||||
resourceNamespace := resource.GetNamespace()
|
resourceNamespace := resource.GetNamespace()
|
||||||
namespaceLabels = namespaceSelectorMap[resource.GetNamespace()]
|
namespaceLabels = namespaceSelectorMap[resource.GetNamespace()]
|
||||||
if resourceNamespace != "default" && len(namespaceLabels) < 1 {
|
if resourceNamespace != "default" && len(namespaceLabels) < 1 {
|
||||||
return &response.EngineResponse{}, sanitizederror.NewWithError(fmt.Sprintf("failed to get namesapce labels for resource %s. use --values-file flag to pass the namespace labels", resource.GetName()), nil)
|
return &response.EngineResponse{}, policyreport.Info{}, sanitizederror.NewWithError(fmt.Sprintf("failed to get namesapce labels for resource %s. use --values-file flag to pass the namespace labels", resource.GetName()), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +581,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
|
||||||
if len(mutateResponse.PolicyResponse.Rules) > 0 {
|
if len(mutateResponse.PolicyResponse.Rules) > 0 {
|
||||||
yamlEncodedResource, err := yamlv2.Marshal(mutateResponse.PatchedResource.Object)
|
yamlEncodedResource, err := yamlv2.Marshal(mutateResponse.PatchedResource.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &response.EngineResponse{}, sanitizederror.NewWithError("failed to marshal", err)
|
return &response.EngineResponse{}, policyreport.Info{}, sanitizederror.NewWithError("failed to marshal", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mutateLogPath == "" {
|
if mutateLogPath == "" {
|
||||||
|
@ -594,7 +596,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
|
||||||
} else {
|
} else {
|
||||||
err := PrintMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
|
err := PrintMutatedOutput(mutateLogPath, mutateLogPathIsDir, string(yamlEncodedResource), resource.GetName()+"-mutated")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &response.EngineResponse{}, sanitizederror.NewWithError("failed to print mutated result", err)
|
return &response.EngineResponse{}, policyreport.Info{}, sanitizederror.NewWithError("failed to print mutated result", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.")
|
fmt.Printf("\n\nMutation:\nMutation has been applied successfully. Check the files.")
|
||||||
}
|
}
|
||||||
|
@ -612,34 +614,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
|
||||||
|
|
||||||
policyCtx := &engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, JSONContext: ctx, NamespaceLabels: namespaceLabels}
|
policyCtx := &engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, JSONContext: ctx, NamespaceLabels: namespaceLabels}
|
||||||
validateResponse := engine.Validate(policyCtx)
|
validateResponse := engine.Validate(policyCtx)
|
||||||
printCount := 0
|
info := checkValidateEngineResponse(policy, validateResponse, resPath, rc)
|
||||||
if !policyReport {
|
|
||||||
for _, policyRule := range policy.Spec.Rules {
|
|
||||||
ruleFoundInEngineResponse := false
|
|
||||||
|
|
||||||
for i, valResponseRule := range validateResponse.PolicyResponse.Rules {
|
|
||||||
if policyRule.Name == valResponseRule.Name {
|
|
||||||
ruleFoundInEngineResponse = true
|
|
||||||
if valResponseRule.Success {
|
|
||||||
rc.Pass++
|
|
||||||
} else {
|
|
||||||
if printCount < 1 {
|
|
||||||
fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath)
|
|
||||||
printCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%d. %s: %s \n", i+1, valResponseRule.Name, valResponseRule.Message)
|
|
||||||
rc.Fail++
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ruleFoundInEngineResponse {
|
|
||||||
rc.Skip++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var policyHasGenerate bool
|
var policyHasGenerate bool
|
||||||
for _, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
|
@ -673,7 +648,7 @@ func ApplyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateResponse, nil
|
return validateResponse, info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintMutatedOutput - function to print output in provided file or directory
|
// PrintMutatedOutput - function to print output in provided file or directory
|
||||||
|
@ -798,3 +773,65 @@ func GetResourceAccordingToResourcePath(fs billy.Filesystem, resourcePaths []str
|
||||||
}
|
}
|
||||||
return resources, err
|
return resources, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkValidateEngineResponse(policy *v1.ClusterPolicy, validateResponse *response.EngineResponse, resPath string, rc *ResultCounts) policyreport.Info {
|
||||||
|
var violatedRules []v1.ViolatedRule
|
||||||
|
printCount := 0
|
||||||
|
for _, policyRule := range policy.Spec.Rules {
|
||||||
|
ruleFoundInEngineResponse := false
|
||||||
|
|
||||||
|
for i, valResponseRule := range validateResponse.PolicyResponse.Rules {
|
||||||
|
if policyRule.Name == valResponseRule.Name {
|
||||||
|
ruleFoundInEngineResponse = true
|
||||||
|
vrule := v1.ViolatedRule{
|
||||||
|
Name: valResponseRule.Name,
|
||||||
|
Type: valResponseRule.Type,
|
||||||
|
Message: valResponseRule.Message,
|
||||||
|
}
|
||||||
|
|
||||||
|
if valResponseRule.Success {
|
||||||
|
rc.Pass++
|
||||||
|
vrule.Check = report.StatusPass
|
||||||
|
} else {
|
||||||
|
if printCount < 1 {
|
||||||
|
fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath)
|
||||||
|
printCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%d. %s: %s \n", i+1, valResponseRule.Name, valResponseRule.Message)
|
||||||
|
rc.Fail++
|
||||||
|
vrule.Check = report.StatusFail
|
||||||
|
}
|
||||||
|
violatedRules = append(violatedRules, vrule)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ruleFoundInEngineResponse {
|
||||||
|
rc.Skip++
|
||||||
|
vruleSkip := v1.ViolatedRule{
|
||||||
|
Name: policyRule.Name,
|
||||||
|
Type: "Validation",
|
||||||
|
Message: policyRule.Validation.Message,
|
||||||
|
Check: report.StatusSkip,
|
||||||
|
}
|
||||||
|
violatedRules = append(violatedRules, vruleSkip)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return buildPVInfo(validateResponse, violatedRules)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPVInfo(er *response.EngineResponse, violatedRules []v1.ViolatedRule) policyreport.Info {
|
||||||
|
info := policyreport.Info{
|
||||||
|
PolicyName: er.PolicyResponse.Policy.Name,
|
||||||
|
Namespace: er.PatchedResource.GetNamespace(),
|
||||||
|
Results: []policyreport.EngineResponseResult{
|
||||||
|
{
|
||||||
|
Resource: er.GetResourceSpec(),
|
||||||
|
Rules: violatedRules,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ func Test_NamespaceSelector(t *testing.T) {
|
||||||
for _, tc := range testcases {
|
for _, tc := range testcases {
|
||||||
policyArray, _ := ut.GetPolicy(tc.policy)
|
policyArray, _ := ut.GetPolicy(tc.policy)
|
||||||
resourceArray, _ := GetResource(tc.resource)
|
resourceArray, _ := GetResource(tc.resource)
|
||||||
validateErs, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, nil)
|
validateErs, _, _ := ApplyPolicyOnResource(policyArray[0], resourceArray[0], "", false, nil, false, tc.namespaceSelectorMap, false, nil)
|
||||||
assert.Assert(t, tc.success == validateErs.IsSuccessful())
|
assert.Assert(t, tc.success == validateErs.IsSuccessful())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,7 +394,7 @@ func applyPoliciesFromPath(fs billy.Filesystem, policyBytes []byte, valuesFile s
|
||||||
return sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
|
return sanitizederror.NewWithError(fmt.Sprintf("policy %s have variables. pass the values for the variables using set/values_file flag", policy.Name), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateErs, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false, nil)
|
validateErs, _, err := common.ApplyPolicyOnResource(policy, resource, "", false, thisPolicyResourceValues, true, namespaceSelectorMap, false, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
|
return sanitizederror.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue