From 3f1997c0e81f102248e5915995ce3c247208e65b Mon Sep 17 00:00:00 2001
From: Prateek Pandey <prateek.pandey@nirmata.com>
Date: Thu, 21 Jul 2022 14:31:42 +0530
Subject: [PATCH] fix split policyreport name with background scan (#4237)

- fix split policyreport name with background scan
- fix the label selector initialising
- refactor the generatePolicyName func

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>
---
 cmd/initContainer/main.go                |  8 +-
 cmd/kyverno/main.go                      |  5 +-
 pkg/policy/report.go                     | 98 +++++++++++++++++-------
 pkg/policyreport/builder.go              | 13 +++-
 pkg/policyreport/changerequestcreator.go | 18 ++---
 pkg/policyreport/reportcontroller.go     | 52 ++++---------
 pkg/policyreport/reportrequest.go        |  3 +-
 pkg/toggle/toggle.go                     | 29 ++++++-
 8 files changed, 140 insertions(+), 86 deletions(-)

diff --git a/cmd/initContainer/main.go b/cmd/initContainer/main.go
index ecb1ec5060..d01254a18f 100644
--- a/cmd/initContainer/main.go
+++ b/cmd/initContainer/main.go
@@ -340,6 +340,8 @@ func removePolicyReport(client dclient.Interface, kind string) error {
 	return nil
 }
 
+// Deprecated: New ClusterPolicyReports already has required labels, will be removed in
+// 1.8.0 version
 func addClusterPolicyReportSelectorLabel(client dclient.Interface) {
 	logger := log.Log.WithName("addClusterPolicyReportSelectorLabel")
 
@@ -350,12 +352,14 @@ func addClusterPolicyReportSelectorLabel(client dclient.Interface) {
 	}
 
 	for _, cpolr := range cpolrs.Items {
-		if cpolr.GetName() == policyreport.GeneratePolicyReportName("") {
+		if cpolr.GetName() == policyreport.GeneratePolicyReportName("", "") {
 			addSelectorLabel(client, cpolr.GetAPIVersion(), cpolr.GetKind(), "", cpolr.GetName())
 		}
 	}
 }
 
+// Deprecated: New PolicyReports already has required labels, will be removed in
+// 1.8.0 version
 func addPolicyReportSelectorLabel(client dclient.Interface) {
 	logger := log.Log.WithName("addPolicyReportSelectorLabel")
 
@@ -366,7 +370,7 @@ func addPolicyReportSelectorLabel(client dclient.Interface) {
 	}
 
 	for _, polr := range polrs.Items {
-		if polr.GetName() == policyreport.GeneratePolicyReportName(polr.GetNamespace()) {
+		if polr.GetName() == policyreport.GeneratePolicyReportName(polr.GetNamespace(), "") {
 			addSelectorLabel(client, polr.GetAPIVersion(), polr.GetKind(), polr.GetNamespace(), polr.GetName())
 		}
 	}
diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go
index 701bfc2668..8a4cf60dbe 100644
--- a/cmd/kyverno/main.go
+++ b/cmd/kyverno/main.go
@@ -75,7 +75,6 @@ var (
 	clientRateLimitQPS           float64
 	clientRateLimitBurst         int
 	changeRequestLimit           int
-	splitPolicyReport            bool
 	webhookRegistrationTimeout   time.Duration
 	setupLog                     = log.Log.WithName("setup")
 )
@@ -105,7 +104,7 @@ func main() {
 	flag.Func(toggle.AutogenInternalsFlagName, toggle.AutogenInternalsDescription, toggle.AutogenInternalsFlag)
 	flag.DurationVar(&webhookRegistrationTimeout, "webhookRegistrationTimeout", 120*time.Second, "Timeout for webhook registration, e.g., 30s, 1m, 5m.")
 	flag.IntVar(&changeRequestLimit, "maxReportChangeRequests", 1000, "Maximum pending report change requests per namespace or for the cluster-wide policy report.")
-	flag.BoolVar(&splitPolicyReport, "splitPolicyReport", false, "Set the flag to 'true', to enable the split-up PolicyReports per policy.")
+	flag.Func(toggle.SplitPolicyReportFlagName, "Set the flag to 'true', to enable the split-up PolicyReports per policy.", toggle.SplitPolicyReportFlag)
 	if err := flag.Set("v", "2"); err != nil {
 		setupLog.Error(err, "failed to set log level")
 		os.Exit(1)
@@ -216,7 +215,6 @@ func main() {
 		kyvernoV1.ClusterPolicies(),
 		kyvernoV1.Policies(),
 		changeRequestLimit,
-		splitPolicyReport,
 		log.Log.WithName("ReportChangeRequestGenerator"),
 	)
 
@@ -229,7 +227,6 @@ func main() {
 		kyvernoV1alpha2.ClusterReportChangeRequests(),
 		kubeInformer.Core().V1().Namespaces(),
 		reportReqGen.CleanupChangeRequest,
-		splitPolicyReport,
 		log.Log.WithName("PolicyReportGenerator"),
 	)
 	if err != nil {
diff --git a/pkg/policy/report.go b/pkg/policy/report.go
index 8fb7ab0670..b738dde13f 100644
--- a/pkg/policy/report.go
+++ b/pkg/policy/report.go
@@ -15,6 +15,7 @@ import (
 	"github.com/kyverno/kyverno/pkg/engine/response"
 	"github.com/kyverno/kyverno/pkg/event"
 	"github.com/kyverno/kyverno/pkg/policyreport"
+	"github.com/kyverno/kyverno/pkg/toggle"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 )
@@ -95,9 +96,9 @@ func (pc *PolicyController) forceReconciliation(reconcileCh <-chan bool, cleanup
 			changeRequestMapperNamespace[ns] = false
 
 			if err := pc.policyReportEraser.EraseResultEntries(eraseResultEntries, info.Namespace); err != nil {
-				logger.Error(err, "failed to erase result entries for the report", "report", policyreport.GeneratePolicyReportName(ns))
+				logger.Error(err, "failed to erase result entries for the report", "report", policyreport.GeneratePolicyReportName(ns, ""))
 			} else {
-				logger.V(3).Info("wiped out result entries for the report", "report", policyreport.GeneratePolicyReportName(ns))
+				logger.V(3).Info("wiped out result entries for the report", "report", policyreport.GeneratePolicyReportName(ns, ""))
 			}
 
 			if info.MapperInactive {
@@ -113,22 +114,19 @@ func (pc *PolicyController) forceReconciliation(reconcileCh <-chan bool, cleanup
 	}
 }
 
-func cleanupReportChangeRequests(pclient kyvernoclient.Interface, rcrLister kyvernov1alpha2listers.ReportChangeRequestLister, crcrLister kyvernov1alpha2listers.ClusterReportChangeRequestLister, labels map[string]string) error {
+func cleanupReportChangeRequests(pclient kyvernoclient.Interface, rcrLister kyvernov1alpha2listers.ReportChangeRequestLister, crcrLister kyvernov1alpha2listers.ClusterReportChangeRequestLister, nslabels map[string]string) error {
 	var errors []string
-
 	var gracePeriod int64 = 0
 	deleteOptions := metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod}
 
-	selector := &metav1.LabelSelector{
-		MatchLabels: labels,
-	}
+	selector := labels.SelectorFromSet(labels.Set(nslabels))
 
-	err := pclient.KyvernoV1alpha2().ClusterReportChangeRequests().DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(selector)})
+	err := pclient.KyvernoV1alpha2().ClusterReportChangeRequests().DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{LabelSelector: selector.String()})
 	if err != nil {
 		errors = append(errors, err.Error())
 	}
 
-	err = pclient.KyvernoV1alpha2().ReportChangeRequests(config.KyvernoNamespace()).DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{LabelSelector: metav1.FormatLabelSelector(selector)})
+	err = pclient.KyvernoV1alpha2().ReportChangeRequests(config.KyvernoNamespace()).DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{LabelSelector: selector.String()})
 	if err != nil {
 		errors = append(errors, err.Error())
 	}
@@ -150,31 +148,37 @@ func eraseResultEntries(pclient kyvernoclient.Interface, reportLister policyrepo
 	var polrName string
 
 	if ns != nil {
-		polrName = policyreport.GeneratePolicyReportName(*ns)
-		if polrName != "" {
-			polr, err := reportLister.PolicyReports(*ns).Get(polrName)
+		if toggle.SplitPolicyReport() {
+			err = eraseSplitResultEntries(pclient, ns, selector)
 			if err != nil {
-				return fmt.Errorf("failed to erase results entries for PolicyReport %s: %v", polrName, err)
-			}
-
-			polr.Results = []v1alpha2.PolicyReportResult{}
-			polr.Summary = v1alpha2.PolicyReportSummary{}
-			if _, err = pclient.Wgpolicyk8sV1alpha2().PolicyReports(polr.GetNamespace()).Update(context.TODO(), polr, metav1.UpdateOptions{}); err != nil {
-				errors = append(errors, fmt.Sprintf("%s/%s/%s: %v", polr.Kind, polr.Namespace, polr.Name, err))
+				errors = append(errors, fmt.Sprintf("%v", err))
 			}
 		} else {
-			cpolr, err := clusterReportLister.Get(polrName)
-			if err != nil {
-				errors = append(errors, err.Error())
-			}
+			polrName = policyreport.GeneratePolicyReportName(*ns, "")
+			if polrName != "" {
+				polr, err := reportLister.PolicyReports(*ns).Get(polrName)
+				if err != nil {
+					return fmt.Errorf("failed to erase results entries for PolicyReport %s: %v", polrName, err)
+				}
 
-			cpolr.Results = []v1alpha2.PolicyReportResult{}
-			cpolr.Summary = v1alpha2.PolicyReportSummary{}
-			if _, err = pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Update(context.TODO(), cpolr, metav1.UpdateOptions{}); err != nil {
-				return fmt.Errorf("failed to erase results entries for ClusterPolicyReport %s: %v", polrName, err)
+				polr.Results = []v1alpha2.PolicyReportResult{}
+				polr.Summary = v1alpha2.PolicyReportSummary{}
+				if _, err = pclient.Wgpolicyk8sV1alpha2().PolicyReports(polr.GetNamespace()).Update(context.TODO(), polr, metav1.UpdateOptions{}); err != nil {
+					errors = append(errors, fmt.Sprintf("%s/%s/%s: %v", polr.Kind, polr.Namespace, polr.Name, err))
+				}
+			} else {
+				cpolr, err := clusterReportLister.Get(policyreport.GeneratePolicyReportName(*ns, ""))
+				if err != nil {
+					errors = append(errors, err.Error())
+				}
+
+				cpolr.Results = []v1alpha2.PolicyReportResult{}
+				cpolr.Summary = v1alpha2.PolicyReportSummary{}
+				if _, err = pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Update(context.TODO(), cpolr, metav1.UpdateOptions{}); err != nil {
+					return fmt.Errorf("failed to erase results entries for ClusterPolicyReport %s: %v", polrName, err)
+				}
 			}
 		}
-
 		if len(errors) == 0 {
 			return nil
 		}
@@ -213,6 +217,44 @@ func eraseResultEntries(pclient kyvernoclient.Interface, reportLister policyrepo
 	return fmt.Errorf("failed to erase results entries %v", strings.Join(errors, ";"))
 }
 
+func eraseSplitResultEntries(pclient kyvernoclient.Interface, ns *string, selector labels.Selector) error {
+	var errors []string
+
+	if ns != nil {
+		if *ns != "" {
+			polrs, err := pclient.Wgpolicyk8sV1alpha2().PolicyReports(*ns).List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()})
+			if err != nil {
+				return fmt.Errorf("failed to list PolicyReports for given namespace %s : %v", *ns, err)
+			}
+			for _, polr := range polrs.Items {
+				polr := polr
+				polr.Results = []v1alpha2.PolicyReportResult{}
+				polr.Summary = v1alpha2.PolicyReportSummary{}
+				if _, err := pclient.Wgpolicyk8sV1alpha2().PolicyReports(polr.GetNamespace()).Update(context.TODO(), &polr, metav1.UpdateOptions{}); err != nil {
+					errors = append(errors, fmt.Sprintf("%s/%s/%s: %v", polr.Kind, polr.Namespace, polr.Name, err))
+				}
+			}
+		} else {
+			cpolrs, err := pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()})
+			if err != nil {
+				return fmt.Errorf("failed to list ClusterPolicyReports : %v", err)
+			}
+			for _, cpolr := range cpolrs.Items {
+				cpolr := cpolr
+				cpolr.Results = []v1alpha2.PolicyReportResult{}
+				cpolr.Summary = v1alpha2.PolicyReportSummary{}
+				if _, err := pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Update(context.TODO(), &cpolr, metav1.UpdateOptions{}); err != nil {
+					errors = append(errors, fmt.Sprintf("%s/%s/%s: %v", cpolr.Kind, cpolr.Namespace, cpolr.Name, err))
+				}
+			}
+		}
+		if len(errors) == 0 {
+			return nil
+		}
+	}
+	return fmt.Errorf("failed to erase results entries for split reports in namespace %s: %v", *ns, strings.Join(errors, ";"))
+}
+
 func (pc *PolicyController) requeuePolicies() {
 	logger := pc.log.WithName("requeuePolicies")
 	if cpols, err := pc.pLister.List(labels.Everything()); err == nil {
diff --git a/pkg/policyreport/builder.go b/pkg/policyreport/builder.go
index b1da866e6d..3534701232 100644
--- a/pkg/policyreport/builder.go
+++ b/pkg/policyreport/builder.go
@@ -14,6 +14,7 @@ import (
 	"github.com/kyverno/kyverno/pkg/config"
 	"github.com/kyverno/kyverno/pkg/engine"
 	"github.com/kyverno/kyverno/pkg/engine/response"
+	"github.com/kyverno/kyverno/pkg/toggle"
 	"github.com/kyverno/kyverno/pkg/version"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -44,12 +45,20 @@ const (
 	SourceValue = "Kyverno"
 )
 
-func GeneratePolicyReportName(ns string) string {
+func GeneratePolicyReportName(ns, policyName string) string {
 	if ns == "" {
+		if toggle.SplitPolicyReport() {
+			return TrimmedName(clusterpolicyreport + "-" + policyName)
+		}
 		return clusterpolicyreport
 	}
 
-	name := fmt.Sprintf("polr-ns-%s", ns)
+	var name string
+	if toggle.SplitPolicyReport() {
+		name = fmt.Sprintf("polr-ns-%s-%s", ns, policyName)
+	} else {
+		name = fmt.Sprintf("polr-ns-%s", ns)
+	}
 	if len(name) > 63 {
 		return name[:63]
 	}
diff --git a/pkg/policyreport/changerequestcreator.go b/pkg/policyreport/changerequestcreator.go
index 9caad97ad8..d4f8f9b9db 100644
--- a/pkg/policyreport/changerequestcreator.go
+++ b/pkg/policyreport/changerequestcreator.go
@@ -11,6 +11,7 @@ import (
 	"github.com/go-logr/logr"
 	kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
 	"github.com/kyverno/kyverno/pkg/config"
+	"github.com/kyverno/kyverno/pkg/toggle"
 	"github.com/patrickmn/go-cache"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -44,15 +45,14 @@ type changeRequestCreator struct {
 	log logr.Logger
 }
 
-func newChangeRequestCreator(client kyvernoclient.Interface, tickerInterval time.Duration, splitPolicyReport bool, log logr.Logger) creator {
+func newChangeRequestCreator(client kyvernoclient.Interface, tickerInterval time.Duration, log logr.Logger) creator {
 	return &changeRequestCreator{
-		client:            client,
-		RCRCache:          cache.New(0, 24*time.Hour),
-		CRCRCache:         cache.New(0, 24*time.Hour),
-		queue:             []string{},
-		tickerInterval:    tickerInterval,
-		splitPolicyReport: splitPolicyReport,
-		log:               log,
+		client:         client,
+		RCRCache:       cache.New(0, 24*time.Hour),
+		CRCRCache:      cache.New(0, 24*time.Hour),
+		queue:          []string{},
+		tickerInterval: tickerInterval,
+		log:            log,
 	}
 }
 
@@ -114,7 +114,7 @@ func (c *changeRequestCreator) run(stopChan <-chan struct{}) {
 	ticker := time.NewTicker(c.tickerInterval)
 	defer ticker.Stop()
 
-	if c.splitPolicyReport {
+	if toggle.SplitPolicyReport() {
 		err := CleanupPolicyReport(c.client)
 		if err != nil {
 			c.log.Error(err, "failed to delete old reports")
diff --git a/pkg/policyreport/reportcontroller.go b/pkg/policyreport/reportcontroller.go
index 3234eb32bd..08ef98a1ae 100644
--- a/pkg/policyreport/reportcontroller.go
+++ b/pkg/policyreport/reportcontroller.go
@@ -17,6 +17,7 @@ import (
 	policyreportv1alpha2listers "github.com/kyverno/kyverno/pkg/client/listers/policyreport/v1alpha2"
 	"github.com/kyverno/kyverno/pkg/config"
 	"github.com/kyverno/kyverno/pkg/dclient"
+	"github.com/kyverno/kyverno/pkg/toggle"
 	kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
 	"github.com/kyverno/kyverno/pkg/version"
 	corev1 "k8s.io/api/core/v1"
@@ -67,8 +68,6 @@ type ReportGenerator struct {
 	reportChangeRequestLister        kyvernov1alpha2listers.ReportChangeRequestLister
 	clusterReportChangeRequestLister kyvernov1alpha2listers.ClusterReportChangeRequestLister
 	nsLister                         corev1listers.NamespaceLister
-	// splitPolicyReport enable/disable the PolicyReport split-up per policy feature
-	splitPolicyReport bool
 
 	informersSynced []cache.InformerSynced
 
@@ -93,7 +92,6 @@ func NewReportGenerator(
 	clusterReportReqInformer kyvernov1alpha2informers.ClusterReportChangeRequestInformer,
 	namespace corev1informers.NamespaceInformer,
 	cleanupChangeRequest chan<- ReconcileInfo,
-	splitPolicyReport bool,
 	log logr.Logger,
 ) (*ReportGenerator, error) {
 	gen := &ReportGenerator{
@@ -104,7 +102,6 @@ func NewReportGenerator(
 		reportReqInformer:        reportReqInformer,
 		clusterReportReqInformer: clusterReportReqInformer,
 		queue:                    workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), prWorkQueueName),
-		splitPolicyReport:        splitPolicyReport,
 		ReconcileCh:              make(chan bool, 10),
 		cleanupChangeRequest:     cleanupChangeRequest,
 		log:                      log,
@@ -137,7 +134,7 @@ func (g *ReportGenerator) generateCacheKey(changeRequest interface{}) string {
 		if ns == "" {
 			ns = "default"
 		}
-		if g.splitPolicyReport {
+		if toggle.SplitPolicyReport() {
 			policy = label[policyLabel]
 			return strings.Join([]string{ns, policy}, "/")
 		} else {
@@ -150,7 +147,7 @@ func (g *ReportGenerator) generateCacheKey(changeRequest interface{}) string {
 		if rule != "" || policy != "" {
 			return strings.Join([]string{deletedPolicyKey, policy, rule}, "/")
 		}
-		if g.splitPolicyReport {
+		if toggle.SplitPolicyReport() {
 			policy = label[policyLabel]
 			return strings.Join([]string{"", policy}, "/")
 		} else {
@@ -344,7 +341,7 @@ func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{
 		return g.removePolicyEntryFromReport(policy, rule)
 	}
 	var namespace, policyName string
-	if g.splitPolicyReport {
+	if toggle.SplitPolicyReport() {
 		namespace = strings.Split(key, "/")[0]
 		policyName = strings.Split(key, "/")[1]
 	} else {
@@ -355,7 +352,7 @@ func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{
 		return aggregatedRequests, fmt.Errorf("failed to aggregate reportChangeRequest results %v", err)
 	}
 
-	if g.splitPolicyReport {
+	if toggle.SplitPolicyReport() {
 		deleteResources := getDeletedResources(aggregatedRequests)
 		if len(deleteResources) != 0 {
 			for _, dr := range deleteResources {
@@ -367,11 +364,7 @@ func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{
 	}
 
 	var report *policyreportv1alpha2.PolicyReport
-	if g.splitPolicyReport {
-		report, err = g.reportLister.PolicyReports(namespace).Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
-	} else {
-		report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
-	}
+	report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace, policyName))
 	if err == nil {
 		if val, ok := report.GetLabels()[inactiveLabelKey]; ok && val == inactiveLabelVal {
 			g.log.Info("got resourceExhausted error, please opt-in via \"splitPolicyReport\" to generate report per policy")
@@ -423,11 +416,7 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace, policyName string,
 			return nil, nil
 		}
 
-		if g.splitPolicyReport {
-			report, err = g.reportLister.PolicyReports(namespace).Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
-		} else {
-			report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
-		}
+		report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace, policyName))
 		if err != nil {
 			if apierrors.IsNotFound(err) && new != nil {
 				polr, err := convertToPolr(new)
@@ -447,12 +436,7 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace, policyName string,
 			return nil, fmt.Errorf("unable to get policyReport: %v", err)
 		}
 	} else {
-
-		if g.splitPolicyReport {
-			report, err = g.clusterReportLister.Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
-		} else {
-			report, err = g.clusterReportLister.Get(GeneratePolicyReportName(namespace))
-		}
+		report, err = g.clusterReportLister.Get(GeneratePolicyReportName(namespace, policyName))
 		if err != nil {
 			if apierrors.IsNotFound(err) {
 				if new != nil {
@@ -514,7 +498,7 @@ func (g *ReportGenerator) removeFromClusterPolicyReport(policyName, ruleName str
 			if ruleName != "" && result.Rule == ruleName && result.Policy == policyName {
 				continue
 			} else if ruleName == "" && result.Policy == policyName {
-				if g.splitPolicyReport {
+				if toggle.SplitPolicyReport() {
 					if err := g.pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Delete(context.TODO(), cpolr.GetName(), metav1.DeleteOptions{}); err != nil {
 						if apierrors.IsNotFound(err) {
 							return nil
@@ -566,7 +550,7 @@ func (g *ReportGenerator) removeFromPolicyReport(policyName, ruleName string) er
 			if ruleName != "" && result.Rule == ruleName && result.Policy == policyName {
 				continue
 			} else if ruleName == "" && result.Policy == policyName {
-				if g.splitPolicyReport {
+				if toggle.SplitPolicyReport() {
 					if err := g.pclient.Wgpolicyk8sV1alpha2().PolicyReports(r.GetNamespace()).Delete(context.TODO(), r.GetName(), metav1.DeleteOptions{}); err != nil {
 						if apierrors.IsNotFound(err) {
 							return nil
@@ -607,7 +591,7 @@ func (g *ReportGenerator) aggregateReports(namespace, policyName string) (
 
 	selector := labels.NewSelector()
 	if namespace == "" {
-		if g.splitPolicyReport {
+		if toggle.SplitPolicyReport() {
 			selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, policyLabel: TrimmedName(policyName)}))
 		} else {
 			selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion}))
@@ -633,7 +617,7 @@ func (g *ReportGenerator) aggregateReports(namespace, policyName string) (
 			ns.SetDeletionTimestamp(&now)
 		}
 
-		if g.splitPolicyReport {
+		if toggle.SplitPolicyReport() {
 			selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, ResourceLabelNamespace: namespace, policyLabel: TrimmedName(policyName)}))
 		} else {
 			selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, ResourceLabelNamespace: namespace}))
@@ -733,20 +717,12 @@ func (g *ReportGenerator) setReport(reportUnstructured *unstructured.Unstructure
 	}
 
 	if ns == nil {
-		if g.splitPolicyReport {
-			reportUnstructured.SetName(TrimmedName(GeneratePolicyReportName("") + "-" + policyname))
-		} else {
-			reportUnstructured.SetName(GeneratePolicyReportName(""))
-		}
+		reportUnstructured.SetName(GeneratePolicyReportName("", policyname))
 		reportUnstructured.SetKind("ClusterPolicyReport")
 		return
 	}
 
-	if g.splitPolicyReport {
-		reportUnstructured.SetName(TrimmedName(GeneratePolicyReportName(ns.GetName()) + "-" + policyname))
-	} else {
-		reportUnstructured.SetName(GeneratePolicyReportName(ns.GetName()))
-	}
+	reportUnstructured.SetName(GeneratePolicyReportName(ns.GetName(), policyname))
 	reportUnstructured.SetNamespace(ns.GetName())
 	reportUnstructured.SetKind("PolicyReport")
 }
diff --git a/pkg/policyreport/reportrequest.go b/pkg/policyreport/reportrequest.go
index f9dbd79a3a..42ac552edd 100644
--- a/pkg/policyreport/reportrequest.go
+++ b/pkg/policyreport/reportrequest.go
@@ -70,7 +70,6 @@ func NewReportChangeRequestGenerator(client kyvernoclient.Interface,
 	cpolInformer kyvernov1informers.ClusterPolicyInformer,
 	polInformer kyvernov1informers.PolicyInformer,
 	changeRequestLimit int,
-	splitPolicyReport bool,
 	log logr.Logger,
 ) *Generator {
 	gen := Generator{
@@ -84,7 +83,7 @@ func NewReportChangeRequestGenerator(client kyvernoclient.Interface,
 		dataStore:                        newDataStore(),
 		changeRequestLimit:               changeRequestLimit,
 		CleanupChangeRequest:             make(chan ReconcileInfo, 10),
-		requestCreator:                   newChangeRequestCreator(client, 3*time.Second, splitPolicyReport, log.WithName("requestCreator")),
+		requestCreator:                   newChangeRequestCreator(client, 3*time.Second, log.WithName("requestCreator")),
 		log:                              log,
 	}
 
diff --git a/pkg/toggle/toggle.go b/pkg/toggle/toggle.go
index 7e76bccb37..0caa7fed5b 100644
--- a/pkg/toggle/toggle.go
+++ b/pkg/toggle/toggle.go
@@ -10,9 +10,17 @@ const (
 	AutogenInternalsDescription = "Enables autogen internal policies. When this is 'true' policy rules should not be mutated."
 	AutogenInternalsEnvVar      = "FLAG_AUTOGEN_INTERNALS"
 	DefaultAutogenInternals     = false
+
+	// split policy report ...
+	SplitPolicyReportFlagName = "splitPolicyReport"
+	SplitPolicyReportEnvVar   = "FLAG_SPLIT_POLICY_REPORT"
+	DefaultSplitPolicyReport  = false
 )
 
-var autogenInternals *bool
+var (
+	autogenInternals  *bool
+	splitPolicyReport *bool
+)
 
 func getBool(in string) (*bool, error) {
 	if in == "" {
@@ -43,3 +51,22 @@ func AutogenInternals() bool {
 	}
 	return DefaultAutogenInternals
 }
+
+func SplitPolicyReportFlag(in string) error {
+	if value, err := getBool(in); err != nil {
+		return err
+	} else {
+		splitPolicyReport = value
+		return nil
+	}
+}
+
+func SplitPolicyReport() bool {
+	if splitPolicyReport != nil {
+		return *splitPolicyReport
+	}
+	if value, err := getBool(os.Getenv(SplitPolicyReportEnvVar)); err == nil && value != nil {
+		return *value
+	}
+	return DefaultSplitPolicyReport
+}