1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00

fix: remove cli dead code (#7748)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-07-04 18:28:22 +02:00 committed by GitHub
parent d185e6f6a4
commit 7c553c4bd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 329 additions and 523 deletions

View file

@ -29,9 +29,11 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/log"
yaml1 "sigs.k8s.io/yaml"
"sigs.k8s.io/yaml"
)
const divider = "----------------------------------------------------------------------"
type SkippedInvalidPolicies struct {
skipped []string
invalid []string
@ -158,11 +160,17 @@ func Command() *cobra.Command {
}
}()
applyCommandConfig.PolicyPaths = policyPaths
rc, resources, skipInvalidPolicies, pvInfos, err := applyCommandConfig.applyCommandHelper()
rc, _, skipInvalidPolicies, responses, err := applyCommandConfig.applyCommandHelper()
if err != nil {
return err
}
PrintReportOrViolation(applyCommandConfig.PolicyReport, rc, applyCommandConfig.ResourcePaths, len(resources), skipInvalidPolicies, applyCommandConfig.Stdin, pvInfos, applyCommandConfig.warnExitCode, applyCommandConfig.warnNoPassed, applyCommandConfig.AuditWarn)
printSkippedAndInvalidPolicies(skipInvalidPolicies)
if applyCommandConfig.PolicyReport {
printReport(responses, applyCommandConfig.AuditWarn)
} else {
printViolations(rc)
}
exit(rc, applyCommandConfig.warnExitCode, applyCommandConfig.warnNoPassed)
return nil
},
}
@ -201,14 +209,34 @@ func (c *ApplyCommandConfig) applyCommandHelper() (*common.ResultCounts, []*unst
if len(c.ResourcePaths) == 0 && !c.Cluster {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.New("resource file(s) or cluster required")
}
store.SetLocal(true)
store.SetRegistryAccess(c.RegistryAccess)
if c.Cluster {
store.AllowApiCall(true)
mutateLogPathIsDir, err := checkMutateLogPath(c.MutateLogPath)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to create file/folder", err)
}
return nil, nil, skipInvalidPolicies, nil, 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)
// the truncation of files for the case when mutateLogPath is dir, is handled under pkg/kyverno/apply/common.go
if !mutateLogPathIsDir && c.MutateLogPath != "" {
c.MutateLogPath = filepath.Clean(c.MutateLogPath)
// Necessary for us to include the file via variable as it is part of the CLI.
_, err := os.OpenFile(c.MutateLogPath, os.O_TRUNC|os.O_WRONLY, 0o600) // #nosec G304
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to truncate the existing file at "+c.MutateLogPath, err)
}
return nil, nil, skipInvalidPolicies, nil, err
}
}
var userInfo v1beta1.RequestInfo
if c.UserInfoPath != "" {
userInfo, err = common.GetUserInfoFromPath(nil, c.UserInfoPath, false, "")
if err != nil {
fmt.Printf("Error: failed to load request info\nCause: %s\n", err)
osExit(1)
}
}
fs := memfs.New()
variables, globalValMap, valuesMap, namespaceSelectorMap, subresources, err := common.GetVariable(c.Variables, c.ValuesFile, nil, false, "")
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
@ -216,12 +244,17 @@ func (c *ApplyCommandConfig) applyCommandHelper() (*common.ResultCounts, []*unst
}
return nil, nil, skipInvalidPolicies, nil, err
}
openApiManager, err := openapi.NewManager(log.Log)
if err != nil {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to initialize openAPIController", err)
}
// init store
store.SetLocal(true)
store.SetRegistryAccess(c.RegistryAccess)
if c.Cluster {
store.AllowApiCall(true)
}
// init cluster client
var dClient dclient.Interface
if c.Cluster {
restConfig, err := config.CreateClientConfigWithContext(c.KubeConfig, c.Context)
@ -241,7 +274,8 @@ func (c *ApplyCommandConfig) applyCommandHelper() (*common.ResultCounts, []*unst
return nil, nil, skipInvalidPolicies, nil, err
}
}
// load policies
fs := memfs.New()
var policies []kyvernov1.PolicyInterface
var validatingAdmissionPolicies []v1alpha1.ValidatingAdmissionPolicy
@ -283,89 +317,26 @@ func (c *ApplyCommandConfig) applyCommandHelper() (*common.ResultCounts, []*unst
fmt.Printf("Error: failed to load policies\nCause: %s\n", err)
osExit(1)
}
mutateLogPathIsDir, err := checkMutateLogPath(c.MutateLogPath)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to create file/folder", err)
}
return nil, nil, skipInvalidPolicies, nil, 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)
// the truncation of files for the case when mutateLogPath is dir, is handled under pkg/kyverno/apply/common.go
if !mutateLogPathIsDir && c.MutateLogPath != "" {
c.MutateLogPath = filepath.Clean(c.MutateLogPath)
// Necessary for us to include the file via variable as it is part of the CLI.
_, err := os.OpenFile(c.MutateLogPath, os.O_TRUNC|os.O_WRONLY, 0o600) // #nosec G304
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to truncate the existing file at "+c.MutateLogPath, err)
}
return nil, nil, skipInvalidPolicies, nil, err
}
}
err = common.PrintMutatedPolicy(policies)
if err != nil {
return nil, nil, skipInvalidPolicies, nil, sanitizederror.NewWithError("failed to marshal mutated policy", err)
}
resources, err := common.GetResourceAccordingToResourcePath(fs, c.ResourcePaths, c.Cluster, policies, validatingAdmissionPolicies, dClient, c.Namespace, c.PolicyReport, false, "")
// load resources
resources, err := common.GetResourceAccordingToResourcePath(nil, c.ResourcePaths, c.Cluster, policies, validatingAdmissionPolicies, dClient, c.Namespace, c.PolicyReport, false, "")
if err != nil {
fmt.Printf("Error: failed to load resources\nCause: %s\n", err)
osExit(1)
}
if (len(resources) > 1 || len(policies) > 1) && c.Variables != nil {
return nil, resources, skipInvalidPolicies, nil, sanitizederror.NewWithError("currently `set` flag supports variable for single policy applied on single resource ", nil)
}
// get the user info as request info from a different file
var userInfo v1beta1.RequestInfo
if c.UserInfoPath != "" {
userInfo, err = common.GetUserInfoFromPath(fs, c.UserInfoPath, false, "")
if err != nil {
fmt.Printf("Error: failed to load request info\nCause: %s\n", err)
osExit(1)
}
}
// init variables
if len(variables) != 0 {
variables = common.SetInStoreContext(policies, variables)
}
var policyRulesCount, mutatedPolicyRulesCount int
for _, policy := range policies {
policyRulesCount += len(policy.GetSpec().Rules)
}
for _, policy := range policies {
mutatedPolicyRulesCount += len(policy.GetSpec().Rules)
}
msgPolicyRules := "1 policy rule"
if policyRulesCount > 1 {
msgPolicyRules = fmt.Sprintf("%d policy rules", policyRulesCount)
}
if mutatedPolicyRulesCount > policyRulesCount {
msgPolicyRules = fmt.Sprintf("%d policy rules", mutatedPolicyRulesCount)
}
msgResources := "1 resource"
if len(resources) > 1 {
msgResources = fmt.Sprintf("%d resources", len(resources))
}
if len(policies) > 0 && len(resources) > 0 {
if !c.Stdin {
if mutatedPolicyRulesCount > policyRulesCount {
fmt.Printf("\nauto-generated pod policies\nApplying %s to %s...\n", msgPolicyRules, msgResources)
} else {
fmt.Printf("\nApplying %s to %s...\n", msgPolicyRules, msgResources)
}
var policyRulesCount int
for _, policy := range policies {
policyRulesCount += len(autogen.ComputeRules(policy))
}
fmt.Printf("\nApplying %d policy rule(s) to %d resource(s)...\n", policyRulesCount, len(resources))
}
var rc common.ResultCounts
@ -494,32 +465,7 @@ func (c *ApplyCommandConfig) applyCommandHelper() (*common.ResultCounts, []*unst
return &rc, resources, skipInvalidPolicies, responses, nil
}
// checkMutateLogPath - checking path for printing mutated resource (-o flag)
func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err error) {
if mutateLogPath != "" {
spath := strings.Split(mutateLogPath, "/")
sfileName := strings.Split(spath[len(spath)-1], ".")
if sfileName[len(sfileName)-1] == "yml" || sfileName[len(sfileName)-1] == "yaml" {
mutateLogPathIsDir = false
} else {
mutateLogPathIsDir = true
}
err := createFileOrFolder(mutateLogPath, mutateLogPathIsDir)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return mutateLogPathIsDir, sanitizederror.NewWithError("failed to create file/folder.", err)
}
return mutateLogPathIsDir, err
}
}
return mutateLogPathIsDir, err
}
// PrintReportOrViolation - printing policy report/violations
func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skipInvalidPolicies SkippedInvalidPolicies, stdin bool, engineResponses []engineapi.EngineResponse, warnExitCode int, warnNoPassed bool, auditWarn bool) {
divider := "----------------------------------------------------------------------"
func printSkippedAndInvalidPolicies(skipInvalidPolicies SkippedInvalidPolicies) {
if len(skipInvalidPolicies.skipped) > 0 {
fmt.Println(divider)
fmt.Println("Policies Skipped (as required variables are not provided by the user):")
@ -536,26 +482,28 @@ func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resource
}
fmt.Println(divider)
}
}
if policyReport {
resps := buildPolicyReports(auditWarn, engineResponses...)
if len(resps) > 0 || resourcesLen == 0 {
func printReport(engineResponses []engineapi.EngineResponse, auditWarn bool) {
clustered, namespaced := buildPolicyReports(auditWarn, engineResponses...)
if len(clustered) > 0 || len(namespaced) > 0 {
fmt.Println(divider)
fmt.Println("POLICY REPORT:")
fmt.Println(divider)
report, _ := generateCLIRaw(resps)
yamlReport, _ := yaml1.Marshal(report)
report := mergeClusterReport(clustered, namespaced)
yamlReport, _ := yaml.Marshal(report)
fmt.Println(string(yamlReport))
} else {
fmt.Println(divider)
fmt.Println("POLICY REPORT: skip generating policy report (no validate policy found/resource skipped)")
}
} else {
if !stdin {
fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n", rc.Pass, rc.Fail, rc.Warn, rc.Error, rc.Skip)
}
}
}
func printViolations(rc *common.ResultCounts) {
fmt.Printf("\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n", rc.Pass, rc.Fail, rc.Warn, rc.Error, rc.Skip)
}
func exit(rc *common.ResultCounts, warnExitCode int, warnNoPassed bool) {
if rc.Fail > 0 || rc.Error > 0 {
osExit(1)
} else if rc.Warn > 0 && warnExitCode != 0 {
@ -564,50 +512,3 @@ func PrintReportOrViolation(policyReport bool, rc *common.ResultCounts, resource
osExit(warnExitCode)
}
}
// createFileOrFolder - creating file or folder according to path provided
func createFileOrFolder(mutateLogPath string, mutateLogPathIsDir bool) error {
mutateLogPath = filepath.Clean(mutateLogPath)
_, err := os.Stat(mutateLogPath)
if err != nil {
if os.IsNotExist(err) {
if !mutateLogPathIsDir {
// check the folder existence, then create the file
var folderPath string
s := strings.Split(mutateLogPath, "/")
if len(s) > 1 {
folderPath = mutateLogPath[:len(mutateLogPath)-len(s[len(s)-1])-1]
_, err := os.Stat(folderPath)
if os.IsNotExist(err) {
errDir := os.MkdirAll(folderPath, 0o750)
if errDir != nil {
return sanitizederror.NewWithError("failed to create directory", err)
}
}
}
mutateLogPath = filepath.Clean(mutateLogPath)
// Necessary for us to create the file via variable as it is part of the CLI.
file, err := os.OpenFile(mutateLogPath, os.O_RDONLY|os.O_CREATE, 0o600) // #nosec G304
if err != nil {
return sanitizederror.NewWithError("failed to create file", err)
}
err = file.Close()
if err != nil {
return sanitizederror.NewWithError("failed to close file", err)
}
} else {
errDir := os.MkdirAll(mutateLogPath, 0o750)
if errDir != nil {
return sanitizederror.NewWithError("failed to create directory", err)
}
}
} else {
return sanitizederror.NewWithError("failed to describe file", err)
}
}
return nil
}

View file

@ -212,15 +212,15 @@ func Test_Apply(t *testing.T) {
},
}
compareSummary := func(expected preport.PolicyReportSummary, actual map[string]interface{}, desc string) {
assert.Equal(t, actual[preport.StatusPass].(int64), int64(expected.Pass), desc)
assert.Equal(t, actual[preport.StatusFail].(int64), int64(expected.Fail), desc)
assert.Equal(t, actual[preport.StatusSkip].(int64), int64(expected.Skip), desc)
assert.Equal(t, actual[preport.StatusWarn].(int64), int64(expected.Warn), desc)
assert.Equal(t, actual[preport.StatusError].(int64), int64(expected.Error), desc)
compareSummary := func(expected preport.PolicyReportSummary, actual preport.PolicyReportSummary, desc string) {
assert.Equal(t, int64(actual.Pass), int64(expected.Pass), desc)
assert.Equal(t, int64(actual.Fail), int64(expected.Fail), desc)
assert.Equal(t, int64(actual.Skip), int64(expected.Skip), desc)
assert.Equal(t, int64(actual.Warn), int64(expected.Warn), desc)
assert.Equal(t, int64(actual.Error), int64(expected.Error), desc)
}
verifyTestcase := func(t *testing.T, tc *TestCase, compareSummary func(preport.PolicyReportSummary, map[string]interface{}, string)) {
verifyTestcase := func(t *testing.T, tc *TestCase, compareSummary func(preport.PolicyReportSummary, preport.PolicyReportSummary, string)) {
if tc.stdinFile != "" {
oldStdin := os.Stdin
input, err := os.OpenFile(tc.stdinFile, os.O_RDONLY, 0)
@ -242,10 +242,10 @@ func Test_Apply(t *testing.T) {
_, _, _, info, err := tc.config.applyCommandHelper()
assert.NilError(t, err, desc)
resps := buildPolicyReports(tc.config.AuditWarn, info...)
assert.Assert(t, len(resps) > 0, "policy reports should not be empty: %s", desc)
for i, resp := range resps {
compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}), desc)
clustered, _ := buildPolicyReports(tc.config.AuditWarn, info...)
assert.Assert(t, len(clustered) > 0, "policy reports should not be empty: %s", desc)
for i, resp := range clustered {
compareSummary(tc.expectedPolicyReports[i].Summary, resp.Summary, desc)
}
}

View file

@ -2,98 +2,33 @@ package apply
import (
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// generateCLIRaw merges all policy reports to a singe cluster policy report
func generateCLIRaw(reports []*unstructured.Unstructured) (*unstructured.Unstructured, error) {
for _, report := range reports {
if report.GetNamespace() != "" {
report.SetNamespace("")
func mergeClusterReport(
clustered []policyreportv1alpha2.ClusterPolicyReport,
namespaced []policyreportv1alpha2.PolicyReport,
) policyreportv1alpha2.ClusterPolicyReport {
var results []policyreportv1alpha2.PolicyReportResult
for _, report := range clustered {
results = append(results, report.Results...)
}
}
return mergeClusterReport(reports)
}
func mergeClusterReport(reports []*unstructured.Unstructured) (*unstructured.Unstructured, error) {
var resultsEntry []interface{}
res := &unstructured.Unstructured{}
res.SetName(clusterpolicyreport)
res.SetKind("ClusterPolicyReport")
res.SetAPIVersion(policyreportv1alpha2.SchemeGroupVersion.String())
for _, report := range reports {
for _, report := range namespaced {
if report.GetNamespace() != "" {
// skip namespace report
continue
}
mergeResults(report, &resultsEntry)
results = append(results, report.Results...)
}
if err := unstructured.SetNestedSlice(res.Object, resultsEntry, "results"); err != nil {
return nil, sanitizederror.NewWithError("failed to set results entry", err)
}
summary := updateSummary(resultsEntry)
if err := unstructured.SetNestedField(res.Object, summary, "summary"); err != nil {
return nil, sanitizederror.NewWithError("failed to set summary", err)
}
return res, nil
}
func mergeResults(report *unstructured.Unstructured, results *[]interface{}) {
entries, ok, err := unstructured.NestedSlice(report.UnstructuredContent(), "results")
if err != nil {
log.Log.V(3).Info("failed to get results entry", "report", report.GetName(), "error", err)
}
if ok {
*results = append(*results, entries...)
return policyreportv1alpha2.ClusterPolicyReport{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterPolicyReport",
APIVersion: policyreportv1alpha2.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: clusterpolicyreport,
},
Results: results,
Summary: reportutils.CalculateSummary(results),
}
}
func updateSummary(results []interface{}) map[string]interface{} {
summary := make(map[string]interface{})
status := []string{policyreportv1alpha2.StatusPass, policyreportv1alpha2.StatusFail, policyreportv1alpha2.StatusError, policyreportv1alpha2.StatusSkip, policyreportv1alpha2.StatusWarn}
for i := 0; i < 5; i++ {
if _, ok := summary[status[i]].(int64); !ok {
summary[status[i]] = int64(0)
}
}
for _, result := range results {
typedResult, ok := result.(map[string]interface{})
if !ok {
continue
}
switch typedResult["result"].(string) {
case policyreportv1alpha2.StatusPass:
pass, _ := summary[policyreportv1alpha2.StatusPass].(int64)
pass++
summary[policyreportv1alpha2.StatusPass] = pass
case policyreportv1alpha2.StatusFail:
fail, _ := summary[policyreportv1alpha2.StatusFail].(int64)
fail++
summary[policyreportv1alpha2.StatusFail] = fail
case policyreportv1alpha2.StatusWarn:
warn, _ := summary[policyreportv1alpha2.StatusWarn].(int64)
warn++
summary[policyreportv1alpha2.StatusWarn] = warn
case policyreportv1alpha2.StatusError:
e, _ := summary[policyreportv1alpha2.StatusError].(int64)
e++
summary[policyreportv1alpha2.StatusError] = e
case policyreportv1alpha2.StatusSkip:
skip, _ := summary[policyreportv1alpha2.StatusSkip].(int64)
skip++
summary[policyreportv1alpha2.StatusSkip] = skip
}
}
return summary
}

View file

@ -4,148 +4,127 @@ import (
"reflect"
"testing"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
report "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
"gotest.tools/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Test_mergeClusterReport(t *testing.T) {
reports := []*unstructured.Unstructured{
clustered := []policyreportv1alpha2.ClusterPolicyReport{
{
Object: map[string]interface{}{
"apiVersion": report.SchemeGroupVersion.String(),
"kind": "PolicyReport",
"metadata": map[string]interface{}{
"name": "ns-polr-1",
"namespace": "ns-polr",
TypeMeta: metav1.TypeMeta{
Kind: "ClusterPolicyReport",
APIVersion: report.SchemeGroupVersion.String(),
},
"results": []interface{}{
map[string]interface{}{
"policy": "ns-polr-1",
"result": report.StatusPass,
"resources": make([]interface{}, 10),
ObjectMeta: metav1.ObjectMeta{
Name: "cpolr-4",
},
Results: []policyreportv1alpha2.PolicyReportResult{
{
Policy: "cpolr-4",
Result: report.StatusFail,
},
},
},
{
Object: map[string]interface{}{
"apiVersion": report.SchemeGroupVersion.String(),
"kind": "PolicyReport",
"metadata": map[string]interface{}{
"name": "ns-polr-2",
},
"results": []interface{}{
map[string]interface{}{
"policy": "ns-polr-2",
"result": report.StatusPass,
"resources": make([]interface{}, 5),
},
},
TypeMeta: metav1.TypeMeta{
Kind: "ClusterPolicyReport",
APIVersion: report.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "cpolr-5",
},
Results: []policyreportv1alpha2.PolicyReportResult{
{
Object: map[string]interface{}{
"metadata": map[string]interface{}{
"name": "polr-3",
},
"results": []interface{}{
map[string]interface{}{
"policy": "polr-3",
"result": report.StatusPass,
"resources": make([]interface{}, 1),
},
},
},
},
{
Object: map[string]interface{}{
"apiVersion": report.SchemeGroupVersion.String(),
"kind": "ClusterPolicyReport",
"metadata": map[string]interface{}{
"name": "cpolr-4",
},
"results": []interface{}{
map[string]interface{}{
"policy": "cpolr-4",
"result": report.StatusFail,
},
},
},
},
{
Object: map[string]interface{}{
"apiVersion": report.SchemeGroupVersion.String(),
"kind": "ClusterPolicyReport",
"metadata": map[string]interface{}{
"name": "cpolr-5",
},
"results": []interface{}{
map[string]interface{}{
"policy": "cpolr-5",
"result": report.StatusFail,
},
Policy: "cpolr-5",
Result: report.StatusFail,
},
},
},
}
expectedResults := []interface{}{
map[string]interface{}{
"policy": "ns-polr-2",
"result": report.StatusPass,
"resources": make([]interface{}, 5),
namespaced := []policyreportv1alpha2.PolicyReport{
{
TypeMeta: metav1.TypeMeta{
Kind: "PolicyReport",
APIVersion: report.SchemeGroupVersion.String(),
},
map[string]interface{}{
"policy": "polr-3",
"result": report.StatusPass,
"resources": make([]interface{}, 1),
ObjectMeta: metav1.ObjectMeta{
Name: "ns-polr-1",
Namespace: "ns-polr",
},
Results: []policyreportv1alpha2.PolicyReportResult{
{
Policy: "ns-polr-1",
Result: report.StatusPass,
Resources: make([]corev1.ObjectReference, 10),
},
},
},
{
TypeMeta: metav1.TypeMeta{
Kind: "PolicyReport",
APIVersion: report.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "ns-polr-2",
},
Results: []policyreportv1alpha2.PolicyReportResult{
{
Policy: "ns-polr-2",
Result: report.StatusPass,
Resources: make([]corev1.ObjectReference, 5),
},
},
},
{
TypeMeta: metav1.TypeMeta{
Kind: "PolicyReport",
APIVersion: report.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "polr-3",
},
Results: []policyreportv1alpha2.PolicyReportResult{
{
Policy: "polr-3",
Result: report.StatusPass,
Resources: make([]corev1.ObjectReference, 1),
},
map[string]interface{}{
"policy": "cpolr-4",
"result": report.StatusFail,
},
map[string]interface{}{
"policy": "cpolr-5",
"result": report.StatusFail,
},
}
cpolr, err := mergeClusterReport(reports)
assert.NilError(t, err)
expectedResults := []policyreportv1alpha2.PolicyReportResult{
{
Policy: "cpolr-4",
Result: report.StatusFail,
},
{
Policy: "cpolr-5",
Result: report.StatusFail,
},
{
Policy: "ns-polr-2",
Result: report.StatusPass,
Resources: make([]corev1.ObjectReference, 5),
},
{
Policy: "polr-3",
Result: report.StatusPass,
Resources: make([]corev1.ObjectReference, 1),
},
}
assert.Assert(t, cpolr.GetAPIVersion() == report.SchemeGroupVersion.String(), cpolr.GetAPIVersion())
assert.Assert(t, cpolr.GetKind() == "ClusterPolicyReport", cpolr.GetKind())
cpolr := mergeClusterReport(clustered, namespaced)
entries, _, err := unstructured.NestedSlice(cpolr.UnstructuredContent(), "results")
assert.NilError(t, err)
assert.Assert(t, cpolr.APIVersion == report.SchemeGroupVersion.String(), cpolr.Kind)
assert.Assert(t, cpolr.Kind == "ClusterPolicyReport", cpolr.Kind)
assert.Assert(t, reflect.DeepEqual(entries, expectedResults), entries...)
assert.Assert(t, reflect.DeepEqual(cpolr.Results, expectedResults), cpolr.Results)
summary, _, err := unstructured.NestedMap(cpolr.UnstructuredContent(), "summary")
assert.NilError(t, err)
assert.Assert(t, summary[report.StatusPass].(int64) == 2, summary[report.StatusPass])
assert.Assert(t, summary[report.StatusFail].(int64) == 2, summary[report.StatusFail])
}
func Test_updateSummary(t *testing.T) {
results := []interface{}{
map[string]interface{}{
"result": report.StatusPass,
"resources": make([]interface{}, 5),
},
map[string]interface{}{
"result": report.StatusFail,
},
map[string]interface{}{
"result": report.StatusFail,
},
map[string]interface{}{
"result": report.StatusFail,
},
}
summary := updateSummary(results)
assert.Assert(t, summary[report.StatusPass].(int64) == 1, summary[report.StatusPass])
assert.Assert(t, summary[report.StatusFail].(int64) == 3, summary[report.StatusFail])
assert.Assert(t, cpolr.Summary.Pass == 2, cpolr.Summary.Pass)
assert.Assert(t, cpolr.Summary.Fail == 2, cpolr.Summary.Fail)
}

View file

@ -0,0 +1,78 @@
package apply
import (
"os"
"path/filepath"
"strings"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
)
// checkMutateLogPath - checking path for printing mutated resource (-o flag)
func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err error) {
if mutateLogPath != "" {
spath := strings.Split(mutateLogPath, "/")
sfileName := strings.Split(spath[len(spath)-1], ".")
if sfileName[len(sfileName)-1] == "yml" || sfileName[len(sfileName)-1] == "yaml" {
mutateLogPathIsDir = false
} else {
mutateLogPathIsDir = true
}
err := createFileOrFolder(mutateLogPath, mutateLogPathIsDir)
if err != nil {
if !sanitizederror.IsErrorSanitized(err) {
return mutateLogPathIsDir, sanitizederror.NewWithError("failed to create file/folder.", err)
}
return mutateLogPathIsDir, err
}
}
return mutateLogPathIsDir, err
}
// createFileOrFolder - creating file or folder according to path provided
func createFileOrFolder(mutateLogPath string, mutateLogPathIsDir bool) error {
mutateLogPath = filepath.Clean(mutateLogPath)
_, err := os.Stat(mutateLogPath)
if err != nil {
if os.IsNotExist(err) {
if !mutateLogPathIsDir {
// check the folder existence, then create the file
var folderPath string
s := strings.Split(mutateLogPath, "/")
if len(s) > 1 {
folderPath = mutateLogPath[:len(mutateLogPath)-len(s[len(s)-1])-1]
_, err := os.Stat(folderPath)
if os.IsNotExist(err) {
errDir := os.MkdirAll(folderPath, 0o750)
if errDir != nil {
return sanitizederror.NewWithError("failed to create directory", err)
}
}
}
mutateLogPath = filepath.Clean(mutateLogPath)
// Necessary for us to create the file via variable as it is part of the CLI.
file, err := os.OpenFile(mutateLogPath, os.O_RDONLY|os.O_CREATE, 0o600) // #nosec G304
if err != nil {
return sanitizederror.NewWithError("failed to create file", err)
}
err = file.Close()
if err != nil {
return sanitizederror.NewWithError("failed to close file", err)
}
} else {
errDir := os.MkdirAll(mutateLogPath, 0o750)
if errDir != nil {
return sanitizederror.NewWithError("failed to create directory", err)
}
}
} else {
return sanitizederror.NewWithError("failed to describe file", err)
}
}
return nil
}

View file

@ -1,7 +1,6 @@
package apply
import (
"encoding/json"
"fmt"
"strings"
"time"
@ -9,65 +8,47 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
reportutils "github.com/kyverno/kyverno/pkg/utils/report"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
const clusterpolicyreport = "clusterpolicyreport"
// resps is the engine responses generated for a single policy
func buildPolicyReports(auditWarn bool, engineResponses ...engineapi.EngineResponse) (res []*unstructured.Unstructured) {
var raw []byte
var err error
func buildPolicyReports(auditWarn bool, engineResponses ...engineapi.EngineResponse) ([]policyreportv1alpha2.ClusterPolicyReport, []policyreportv1alpha2.PolicyReport) {
var clustered []policyreportv1alpha2.ClusterPolicyReport
var namespaced []policyreportv1alpha2.PolicyReport
resultsMap := buildPolicyResults(auditWarn, engineResponses...)
for scope, result := range resultsMap {
if scope == clusterpolicyreport {
report := &policyreportv1alpha2.ClusterPolicyReport{
report := policyreportv1alpha2.ClusterPolicyReport{
TypeMeta: metav1.TypeMeta{
APIVersion: policyreportv1alpha2.SchemeGroupVersion.String(),
Kind: "ClusterPolicyReport",
},
Results: result,
Summary: calculateSummary(result),
Summary: reportutils.CalculateSummary(result),
}
report.SetName(scope)
if raw, err = json.Marshal(report); err != nil {
log.Log.V(3).Info("failed to serialize policy report", "name", report.Name, "scope", scope, "error", err)
}
clustered = append(clustered, report)
} else {
report := &policyreportv1alpha2.PolicyReport{
report := policyreportv1alpha2.PolicyReport{
TypeMeta: metav1.TypeMeta{
APIVersion: policyreportv1alpha2.SchemeGroupVersion.String(),
Kind: "PolicyReport",
},
Results: result,
Summary: calculateSummary(result),
Summary: reportutils.CalculateSummary(result),
}
ns := strings.ReplaceAll(scope, "policyreport-ns-", "")
report.SetName(scope)
report.SetNamespace(ns)
if raw, err = json.Marshal(report); err != nil {
log.Log.V(3).Info("failed to serialize policy report", "name", report.Name, "scope", scope, "error", err)
namespaced = append(namespaced, report)
}
}
reportUnstructured, err := kubeutils.BytesToUnstructured(raw)
if err != nil {
log.Log.V(3).Info("failed to convert policy report", "scope", scope, "error", err)
continue
}
res = append(res, reportUnstructured)
}
return
return clustered, namespaced
}
// buildPolicyResults returns a string-PolicyReportResult map
@ -150,21 +131,3 @@ func buildPolicyResults(auditWarn bool, engineResponses ...engineapi.EngineRespo
return results
}
func calculateSummary(results []policyreportv1alpha2.PolicyReportResult) (summary policyreportv1alpha2.PolicyReportSummary) {
for _, res := range results {
switch string(res.Result) {
case policyreportv1alpha2.StatusPass:
summary.Pass++
case policyreportv1alpha2.StatusFail:
summary.Fail++
case "warn":
summary.Warn++
case "error":
summary.Error++
case "skip":
summary.Skip++
}
}
return
}

View file

@ -8,7 +8,6 @@ import (
preport "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"gotest.tools/assert"
v1 "k8s.io/api/core/v1"
)
var rawPolicy = []byte(`
@ -102,25 +101,15 @@ func Test_buildPolicyReports(t *testing.T) {
),
)
reports := buildPolicyReports(false, er)
assert.Assert(t, len(reports) == 1, len(reports))
for _, report := range reports {
if report.GetNamespace() == "" {
clustered, namespaced := buildPolicyReports(false, er)
assert.Assert(t, len(clustered) == 1, len(clustered))
assert.Assert(t, len(namespaced) == 0, len(namespaced))
{
report := clustered[0]
assert.Assert(t, report.GetName() == clusterpolicyreport)
assert.Assert(t, report.GetKind() == "ClusterPolicyReport")
assert.Assert(t, len(report.UnstructuredContent()["results"].([]interface{})) == 2)
assert.Assert(t,
report.UnstructuredContent()["summary"].(map[string]interface{})[preport.StatusPass].(int64) == 1,
report.UnstructuredContent()["summary"].(map[string]interface{})[preport.StatusPass].(int64))
} else {
assert.Assert(t, report.GetName() == "policyreport-ns-default")
assert.Assert(t, report.GetKind() == "PolicyReport")
assert.Assert(t, len(report.UnstructuredContent()["results"].([]interface{})) == 2)
summary := report.UnstructuredContent()["summary"].(map[string]interface{})
assert.Assert(t, summary[preport.StatusPass].(int64) == 1, summary[preport.StatusPass].(int64))
}
assert.Assert(t, report.Kind == "ClusterPolicyReport")
assert.Assert(t, len(report.Results) == 2)
assert.Assert(t, report.Summary.Pass == 1, report.Summary.Pass)
}
}
@ -158,26 +147,3 @@ func Test_buildPolicyResults(t *testing.T) {
}
}
}
func Test_calculateSummary(t *testing.T) {
results := []preport.PolicyReportResult{
{
Resources: make([]v1.ObjectReference, 5),
Result: preport.PolicyResult(preport.StatusPass),
},
{Result: preport.PolicyResult(preport.StatusFail)},
{Result: preport.PolicyResult(preport.StatusFail)},
{Result: preport.PolicyResult(preport.StatusFail)},
{
Resources: make([]v1.ObjectReference, 1),
Result: preport.PolicyResult(preport.StatusPass)},
{
Resources: make([]v1.ObjectReference, 4),
Result: preport.PolicyResult(preport.StatusPass),
},
}
summary := calculateSummary(results)
assert.Assert(t, summary.Pass == 3)
assert.Assert(t, summary.Fail == 3)
}

View file

@ -166,11 +166,6 @@ func applyPoliciesFromPath(
}
policies = filteredPolicies
err = common.PrintMutatedPolicy(policies)
if err != nil {
return nil, nil, sanitizederror.NewWithError("failed to print mutated policy", err)
}
resources, err := common.GetResourceAccordingToResourcePath(fs, resourceFullPath, false, policies, validatingAdmissionPolicies, dClient, "", false, isGit, policyResourcePath)
if err != nil {
fmt.Printf("Error: failed to load resources\nCause: %s\n", err)

View file

@ -651,17 +651,6 @@ func processMutateEngineResponse(c ApplyPolicyConfig, mutateResponse *engineapi.
return nil
}
func PrintMutatedPolicy(mutatedPolicies []kyvernov1.PolicyInterface) error {
for _, policy := range mutatedPolicies {
p, err := json.Marshal(policy)
if err != nil {
return sanitizederror.NewWithError("failed to marsal mutated policy", err)
}
log.V(5).Info("mutated Policy:", string(p))
}
return nil
}
func CheckVariableForPolicy(valuesMap map[string]map[string]values.Resource, globalValMap map[string]string, policyName string, resourceName string, resourceKind string, variables map[string]string, kindOnwhichPolicyIsApplied map[string]struct{}, variable string) (map[string]interface{}, error) {
// get values from file for this policy resource combination
thisPolicyResourceValues := make(map[string]interface{})