diff --git a/cmd/background-controller/main.go b/cmd/background-controller/main.go index c5b986095d..69759dfa99 100644 --- a/cmd/background-controller/main.go +++ b/cmd/background-controller/main.go @@ -213,7 +213,8 @@ func main() { ) engine := engine.NewEngine( configuration, - engine.LegacyContextLoaderFactory(rclient, configMapResolver), + dClient, + engine.LegacyContextLoaderFactory(dClient, rclient, configMapResolver), // TODO: do we need exceptions here ? nil, ) diff --git a/cmd/cli/kubectl-kyverno/utils/common/common.go b/cmd/cli/kubectl-kyverno/utils/common/common.go index 7a2eb57c75..9480f01d59 100644 --- a/cmd/cli/kubectl-kyverno/utils/common/common.go +++ b/cmd/cli/kubectl-kyverno/utils/common/common.go @@ -476,7 +476,8 @@ OuterLoop: } eng := engine.NewEngine( cfg, - engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil), + c.Client, + engine.LegacyContextLoaderFactory(c.Client, registryclient.NewOrDie(), nil), nil, ) policyContext := engine.NewPolicyContextWithJsonContext(ctx). @@ -484,7 +485,6 @@ OuterLoop: WithNewResource(*updatedResource). WithNamespaceLabels(namespaceLabels). WithAdmissionInfo(c.UserInfo). - WithClient(c.Client). WithSubresourcesInPolicy(subresources) mutateResponse := eng.Mutate( @@ -1080,7 +1080,8 @@ func initializeMockController(objects []runtime.Object) (*generate.GenerateContr client.SetDiscovery(dclient.NewFakeDiscoveryClient(nil)) c := generate.NewGenerateControllerWithOnlyClient(client, engine.NewEngine( config.NewDefaultConfiguration(), - engine.LegacyContextLoaderFactory(nil, nil), + client, + engine.LegacyContextLoaderFactory(client, nil, nil), nil, )) return c, nil diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index 137f6118e2..f5d7c77f25 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -366,7 +366,8 @@ func main() { } eng := engine.NewEngine( configuration, - engine.LegacyContextLoaderFactory(rclient, configMapResolver), + dClient, + engine.LegacyContextLoaderFactory(dClient, rclient, configMapResolver), exceptionsLister, ) // create non leader controllers diff --git a/cmd/reports-controller/main.go b/cmd/reports-controller/main.go index 93fdb51e1f..75493be2ea 100644 --- a/cmd/reports-controller/main.go +++ b/cmd/reports-controller/main.go @@ -314,7 +314,8 @@ func main() { go eventGenerator.Run(ctx, 3) eng := engine.NewEngine( configuration, - engine.LegacyContextLoaderFactory(rclient, configMapResolver), + dClient, + engine.LegacyContextLoaderFactory(dClient, rclient, configMapResolver), exceptionsLister, ) // setup leader election diff --git a/pkg/background/common/context.go b/pkg/background/common/context.go index c34e91a20c..a317c25497 100644 --- a/pkg/background/common/context.go +++ b/pkg/background/common/context.go @@ -81,8 +81,7 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe WithNewResource(*trigger). WithOldResource(old). WithAdmissionInfo(ur.Spec.Context.UserRequestInfo). - WithNamespaceLabels(namespaceLabels). - WithClient(dclient) + WithNamespaceLabels(namespaceLabels) return policyContext, false, nil } diff --git a/pkg/controllers/report/utils/scanner.go b/pkg/controllers/report/utils/scanner.go index 6cd033beb7..238acb7807 100644 --- a/pkg/controllers/report/utils/scanner.go +++ b/pkg/controllers/report/utils/scanner.go @@ -92,7 +92,6 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un policyCtx := engine.NewPolicyContextWithJsonContext(enginectx). WithNewResource(resource). WithPolicy(policy). - WithClient(s.client). WithNamespaceLabels(nsLabels) return s.engine.Validate(ctx, policyCtx), nil } @@ -114,7 +113,6 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst policyCtx := engine.NewPolicyContextWithJsonContext(enginectx). WithNewResource(resource). WithPolicy(policy). - WithClient(s.client). WithNamespaceLabels(nsLabels) response, _ := s.engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx) if len(response.PolicyResponse.Rules) > 0 { diff --git a/pkg/engine/api/contextloader.go b/pkg/engine/api/contextloader.go index c654f298bc..ed99fbe452 100644 --- a/pkg/engine/api/contextloader.go +++ b/pkg/engine/api/contextloader.go @@ -7,8 +7,10 @@ import ( enginecontext "github.com/kyverno/kyverno/pkg/engine/context" ) +// ContextLoaderFactory provides a ContextLoader given a policy context and rule name type ContextLoaderFactory = func(pContext PolicyContext, ruleName string) ContextLoader +// ContextLoader abstracts the mechanics to load context entries in the underlying json context type ContextLoader interface { Load(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error } diff --git a/pkg/engine/api/engine.go b/pkg/engine/api/engine.go index 4e4cc489ef..e969f5b1de 100644 --- a/pkg/engine/api/engine.go +++ b/pkg/engine/api/engine.go @@ -4,19 +4,10 @@ import ( "context" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" - kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" "github.com/kyverno/kyverno/pkg/registryclient" - "k8s.io/apimachinery/pkg/labels" ) -type NamespacedResourceSelector[T any] interface { - // List selects resources based on label selector. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []T, err error) -} - -type PolicyExceptionSelector = NamespacedResourceSelector[*kyvernov2alpha1.PolicyException] - +// Engine is the main interface to run policies against resources type Engine interface { // Validate applies validation rules from policy on the resource Validate( diff --git a/pkg/engine/api/policycontext.go b/pkg/engine/api/policycontext.go index 331848be55..a3446260e9 100644 --- a/pkg/engine/api/policycontext.go +++ b/pkg/engine/api/policycontext.go @@ -3,7 +3,6 @@ package api import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" - "github.com/kyverno/kyverno/pkg/clients/dclient" enginecontext "github.com/kyverno/kyverno/pkg/engine/context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -31,6 +30,5 @@ type PolicyContext interface { SetElement(element unstructured.Unstructured) JSONContext() enginecontext.Interface - Client() dclient.Interface Copy() PolicyContext } diff --git a/pkg/engine/api/selector.go b/pkg/engine/api/selector.go new file mode 100644 index 0000000000..90053c5bbb --- /dev/null +++ b/pkg/engine/api/selector.go @@ -0,0 +1,17 @@ +package api + +import ( + kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1" + "k8s.io/apimachinery/pkg/labels" +) + +// NamespacedResourceSelector is an abstract interface used to list namespaced resources given a label selector +// Any implementation might exist, cache based, file based, client based etc... +type NamespacedResourceSelector[T any] interface { + // List selects resources based on label selector. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []T, err error) +} + +// PolicyExceptionSelector is an abstract interface used to resolve poliicy exceptions +type PolicyExceptionSelector = NamespacedResourceSelector[*kyvernov2alpha1.PolicyException] diff --git a/pkg/engine/background.go b/pkg/engine/background.go index ba90090c7e..19c5dc5888 100644 --- a/pkg/engine/background.go +++ b/pkg/engine/background.go @@ -84,7 +84,7 @@ func (e *engine) filterRule( logger := logging.WithName("exception") kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...) - subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext) + subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(e.client, kindsInPolicy, policyContext) // check if there is a corresponding policy exception ruleResp := hasPolicyExceptions(logger, e.exceptionSelector, policyContext, &rule, subresourceGVKToAPIResource, e.configuration) diff --git a/pkg/engine/common.go b/pkg/engine/common.go index 32ad0bc771..1b88644676 100644 --- a/pkg/engine/common.go +++ b/pkg/engine/common.go @@ -3,13 +3,14 @@ package engine import ( "strings" + "github.com/kyverno/kyverno/pkg/clients/dclient" engineapi "github.com/kyverno/kyverno/pkg/engine/api" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // GetSubresourceGVKToAPIResourceMap returns a map of subresource GVK to APIResource. This is used to determine if a resource is a subresource. -func GetSubresourceGVKToAPIResourceMap(kindsInPolicy []string, ctx engineapi.PolicyContext) map[string]*metav1.APIResource { +func GetSubresourceGVKToAPIResourceMap(client dclient.Interface, kindsInPolicy []string, ctx engineapi.PolicyContext) map[string]*metav1.APIResource { subresourceGVKToAPIResource := make(map[string]*metav1.APIResource) for _, gvk := range kindsInPolicy { gv, k := kubeutils.GetKindFromGVK(gvk) @@ -50,9 +51,9 @@ func GetSubresourceGVKToAPIResourceMap(kindsInPolicy []string, ctx engineapi.Pol } } } - } else if ctx.Client() != nil { + } else if client != nil { // find the resource from API client - apiResource, _, _, err := ctx.Client().Discovery().FindResource(gv, k) + apiResource, _, _, err := client.Discovery().FindResource(gv, k) if err == nil { if kubeutils.IsSubresource(apiResource.Name) { subresourceGVKToAPIResource[gvk] = apiResource diff --git a/pkg/engine/common_test.go b/pkg/engine/common_test.go index 2d5291a0ad..2c50a962db 100644 --- a/pkg/engine/common_test.go +++ b/pkg/engine/common_test.go @@ -51,7 +51,7 @@ func Test_GetSubresourceGVKToAPIResourceMap(t *testing.T) { kindsInPolicy := []string{"Pod", "Eviction", "Pod/status", "Pod/eviction"} - subresourceGVKToAPIResourceMap := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext) + subresourceGVKToAPIResourceMap := GetSubresourceGVKToAPIResourceMap(nil, kindsInPolicy, policyContext) podStatusResourceFromMap := subresourceGVKToAPIResourceMap["Pod/status"] assert.Equal(t, podStatusResourceFromMap.Name, podStatusAPIResource.Name) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index a15808ffc0..6562c5c478 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -4,6 +4,7 @@ import ( "context" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" + "github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/config" engineapi "github.com/kyverno/kyverno/pkg/engine/api" "github.com/kyverno/kyverno/pkg/registryclient" @@ -11,17 +12,20 @@ import ( type engine struct { configuration config.Configuration + client dclient.Interface contextLoader engineapi.ContextLoaderFactory exceptionSelector engineapi.PolicyExceptionSelector } func NewEngine( configuration config.Configuration, + client dclient.Interface, contextLoader engineapi.ContextLoaderFactory, exceptionSelector engineapi.PolicyExceptionSelector, ) engineapi.Engine { return &engine{ configuration: configuration, + client: client, contextLoader: contextLoader, exceptionSelector: exceptionSelector, } diff --git a/pkg/engine/imageVerify.go b/pkg/engine/imageVerify.go index 241842645d..c940134116 100644 --- a/pkg/engine/imageVerify.go +++ b/pkg/engine/imageVerify.go @@ -70,7 +70,7 @@ func (e *engine) verifyAndPatchImages( } kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...) - subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext) + subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(e.client, kindsInPolicy, policyContext) if !matches(logger, rule, policyContext, subresourceGVKToAPIResource, e.configuration) { return diff --git a/pkg/engine/imageVerify_test.go b/pkg/engine/imageVerify_test.go index 1be96519c7..3a9cc48550 100644 --- a/pkg/engine/imageVerify_test.go +++ b/pkg/engine/imageVerify_test.go @@ -169,7 +169,8 @@ func testVerifyAndPatchImages( ) (*engineapi.EngineResponse, *engineapi.ImageVerificationMetadata) { e := NewEngine( cfg, - LegacyContextLoaderFactory(rclient, cmResolver), + nil, + LegacyContextLoaderFactory(nil, rclient, cmResolver), nil, ) return e.VerifyAndPatchImages( diff --git a/pkg/engine/jsonContext.go b/pkg/engine/jsonContext.go index 230b93c6ad..076341243c 100644 --- a/pkg/engine/jsonContext.go +++ b/pkg/engine/jsonContext.go @@ -19,6 +19,7 @@ import ( ) func LegacyContextLoaderFactory( + client dclient.Interface, rclient registryclient.Client, cmResolver engineapi.ConfigmapResolver, ) engineapi.ContextLoaderFactory { @@ -29,7 +30,7 @@ func LegacyContextLoaderFactory( logger: logging.WithName("MockContextLoaderFactory"), policyName: policy.GetName(), ruleName: ruleName, - client: pContext.Client(), + client: client, rclient: rclient, cmResolver: cmResolver, } @@ -38,7 +39,7 @@ func LegacyContextLoaderFactory( return func(pContext engineapi.PolicyContext, ruleName string) engineapi.ContextLoader { return &contextLoader{ logger: logging.WithName("LegacyContextLoaderFactory"), - client: pContext.Client(), + client: client, rclient: rclient, cmResolver: cmResolver, } diff --git a/pkg/engine/k8smanifest.go b/pkg/engine/k8smanifest.go index 941679c6ce..cc1216275d 100644 --- a/pkg/engine/k8smanifest.go +++ b/pkg/engine/k8smanifest.go @@ -35,16 +35,26 @@ const ( //go:embed resources/default-config.yaml var defaultConfigBytes []byte -func processYAMLValidationRule(log logr.Logger, ctx engineapi.PolicyContext, rule *kyvernov1.Rule) *engineapi.RuleResponse { +func processYAMLValidationRule( + client dclient.Interface, + log logr.Logger, + ctx engineapi.PolicyContext, + rule *kyvernov1.Rule, +) *engineapi.RuleResponse { if isDeleteRequest(ctx) { return nil } - ruleResp := handleVerifyManifest(ctx, rule, log) + ruleResp := handleVerifyManifest(client, ctx, rule, log) return ruleResp } -func handleVerifyManifest(ctx engineapi.PolicyContext, rule *kyvernov1.Rule, logger logr.Logger) *engineapi.RuleResponse { - verified, reason, err := verifyManifest(ctx, *rule.Validation.Manifests, logger) +func handleVerifyManifest( + client dclient.Interface, + ctx engineapi.PolicyContext, + rule *kyvernov1.Rule, + logger logr.Logger, +) *engineapi.RuleResponse { + verified, reason, err := verifyManifest(client, ctx, *rule.Validation.Manifests, logger) if err != nil { logger.V(3).Info("verifyManifest return err", "error", err.Error()) return internal.RuleError(rule, engineapi.Validation, "error occurred during manifest verification", err) @@ -56,7 +66,12 @@ func handleVerifyManifest(ctx engineapi.PolicyContext, rule *kyvernov1.Rule, log return internal.RuleResponse(*rule, engineapi.Validation, reason, engineapi.RuleStatusPass) } -func verifyManifest(policyContext engineapi.PolicyContext, verifyRule kyvernov1.Manifests, logger logr.Logger) (bool, string, error) { +func verifyManifest( + client dclient.Interface, + policyContext engineapi.PolicyContext, + verifyRule kyvernov1.Manifests, + logger logr.Logger, +) (bool, string, error) { // load AdmissionRequest request, err := policyContext.JSONContext().Query("request") if err != nil { @@ -106,7 +121,7 @@ func verifyManifest(policyContext engineapi.PolicyContext, verifyRule kyvernov1. } if !vo.DisableDryRun { // check if kyverno can 'create' dryrun resource - ok, err := checkDryRunPermission(policyContext.Client(), adreq.Kind.Kind, vo.DryRunNamespace) + ok, err := checkDryRunPermission(client, adreq.Kind.Kind, vo.DryRunNamespace) if err != nil { logger.V(1).Info("failed to check permissions to 'create' resource. disabled DryRun option.", "dryrun namespace", vo.DryRunNamespace, "kind", adreq.Kind.Kind, "error", err.Error()) vo.DisableDryRun = true diff --git a/pkg/engine/k8smanifest_test.go b/pkg/engine/k8smanifest_test.go index 5cb6a2ed5e..1cd80ae403 100644 --- a/pkg/engine/k8smanifest_test.go +++ b/pkg/engine/k8smanifest_test.go @@ -628,7 +628,7 @@ func Test_VerifyManifest_SignedYAML(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) assert.NilError(t, err) assert.Equal(t, verified, true) } @@ -650,7 +650,7 @@ func Test_VerifyManifest_UnsignedYAML(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) assert.NilError(t, err) assert.Equal(t, verified, false) } @@ -672,7 +672,7 @@ func Test_VerifyManifest_InvalidYAML(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) assert.NilError(t, err) assert.Equal(t, verified, false) } @@ -699,7 +699,7 @@ func Test_VerifyManifest_MustAll_InvalidYAML(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) errMsg := `.attestors[0].entries[1].keys: failed to verify signature: verification failed for 1 signature. all trials: ["[publickey 1/1] [signature 1/1] error: cosign.VerifyBlobCmd() returned an error: invalid signature when validating ASN.1 encoded signature"]` assert.Error(t, err, errMsg) assert.Equal(t, verified, false) @@ -732,7 +732,7 @@ func Test_VerifyManifest_MustAll_ValidYAML(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) assert.NilError(t, err) assert.Equal(t, verified, true) } @@ -761,7 +761,7 @@ func Test_VerifyManifest_AtLeastOne(t *testing.T) { }, }) logger := logr.Discard() - verified, _, err := verifyManifest(policyContext, verifyRule, logger) + verified, _, err := verifyManifest(nil, policyContext, verifyRule, logger) assert.NilError(t, err) assert.Equal(t, verified, true) } diff --git a/pkg/engine/loadtargets.go b/pkg/engine/loadtargets.go index 14efad7e3e..cb1ffad3cd 100644 --- a/pkg/engine/loadtargets.go +++ b/pkg/engine/loadtargets.go @@ -7,6 +7,7 @@ import ( "github.com/go-logr/logr" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/clients/dclient" engineapi "github.com/kyverno/kyverno/pkg/engine/api" "github.com/kyverno/kyverno/pkg/engine/variables" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" @@ -24,7 +25,12 @@ type resourceInfo struct { parentResourceGVR metav1.GroupVersionResource } -func loadTargets(targets []kyvernov1.ResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) ([]resourceInfo, error) { +func loadTargets( + client dclient.Interface, + targets []kyvernov1.ResourceSpec, + ctx engineapi.PolicyContext, + logger logr.Logger, +) ([]resourceInfo, error) { var targetObjects []resourceInfo var errors []error @@ -35,7 +41,7 @@ func loadTargets(targets []kyvernov1.ResourceSpec, ctx engineapi.PolicyContext, continue } - objs, err := getTargets(spec, ctx) + objs, err := getTargets(client, spec, ctx) if err != nil { errors = append(errors, err) continue @@ -76,7 +82,11 @@ func resolveSpec(i int, target kyvernov1.ResourceSpec, ctx engineapi.PolicyConte }, nil } -func getTargets(target kyvernov1.ResourceSpec, ctx engineapi.PolicyContext) ([]resourceInfo, error) { +func getTargets( + client dclient.Interface, + target kyvernov1.ResourceSpec, + ctx engineapi.PolicyContext, +) ([]resourceInfo, error) { var targetObjects []resourceInfo namespace := target.Namespace name := target.Name @@ -86,7 +96,6 @@ func getTargets(target kyvernov1.ResourceSpec, ctx engineapi.PolicyContext) ([]r if policy.IsNamespaced() { namespace = policy.GetNamespace() } - client := ctx.Client() apiResource, parentAPIResource, _, err := client.Discovery().FindResource(target.APIVersion, target.Kind) if err != nil { return nil, err diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 3040d8150a..27492801fe 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -67,7 +67,7 @@ func (e *engine) mutate( } kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...) - subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext) + subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(e.client, kindsInPolicy, policyContext) if err = MatchesResourceDescription(subresourceGVKToAPIResource, matchedResource, rule, policyContext.AdmissionInfo(), excludeResource, policyContext.NamespaceLabels(), policyContext.Policy().GetNamespace(), policyContext.SubResource()); err != nil { logger.V(4).Info("rule not matched", "reason", err.Error()) skippedRules = append(skippedRules, rule.Name) @@ -104,7 +104,7 @@ func (e *engine) mutate( ruleCopy := rule.DeepCopy() var patchedResources []resourceInfo if !policyContext.AdmissionOperation() && rule.IsMutateExisting() { - targets, err := loadTargets(ruleCopy.Mutation.Targets, policyContext, logger) + targets, err := loadTargets(e.client, ruleCopy.Mutation.Targets, policyContext, logger) if err != nil { rr := internal.RuleResponse(rule, engineapi.Mutation, err.Error(), engineapi.RuleStatusError) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *rr) diff --git a/pkg/engine/mutation_test.go b/pkg/engine/mutation_test.go index 14080858b0..bc95120338 100644 --- a/pkg/engine/mutation_test.go +++ b/pkg/engine/mutation_test.go @@ -9,6 +9,7 @@ import ( kyverno "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store" + "github.com/kyverno/kyverno/pkg/clients/dclient" client "github.com/kyverno/kyverno/pkg/clients/dclient" engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginecontext "github.com/kyverno/kyverno/pkg/engine/context" @@ -22,12 +23,14 @@ import ( func testMutate( ctx context.Context, + client dclient.Interface, rclient registryclient.Client, pContext *PolicyContext, ) *engineapi.EngineResponse { e := NewEngine( cfg, - LegacyContextLoaderFactory(rclient, nil), + client, + LegacyContextLoaderFactory(client, rclient, nil), nil, ) return e.Mutate( @@ -111,7 +114,7 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) { jsonContext: ctx, newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) t.Log(string(expectedPatch)) assert.Equal(t, len(er.PolicyResponse.Rules), 1) @@ -185,7 +188,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) { jsonContext: ctx, newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path")) } @@ -278,7 +281,7 @@ func Test_variableSubstitutionCLI(t *testing.T) { newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1) t.Log(string(expectedPatch)) @@ -387,7 +390,7 @@ func Test_chained_rules(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers") assert.NilError(t, err) assert.Equal(t, containers[0].(map[string]interface{})["image"], "otherregistry.corp.com/foo/bash:5.0") @@ -475,7 +478,7 @@ func Test_precondition(t *testing.T) { newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) t.Log(string(expectedPatch)) t.Log(string(er.PolicyResponse.Rules[0].Patches[0])) if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) { @@ -572,7 +575,7 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) { newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) t.Log(string(expectedPatch)) t.Log(string(er.PolicyResponse.Rules[0].Patches[0])) if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) { @@ -666,7 +669,7 @@ func Test_foreach(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass) @@ -773,7 +776,7 @@ func Test_foreach_element_mutation(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass) @@ -899,7 +902,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass) @@ -1049,7 +1052,7 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) *eng err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) return er } @@ -1594,18 +1597,18 @@ func Test_mutate_existing_resources(t *testing.T) { assert.NilError(t, err) policyContext = &PolicyContext{ - client: dclient, policy: &policy, jsonContext: ctx, newResource: *trigger, } - } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) - for _, rr := range er.PolicyResponse.Rules { - for i, p := range rr.Patches { - assert.Equal(t, test.patches[i], string(p), "test %s failed:\nGot %s\nExpected: %s", test.name, rr.Patches[i], test.patches[i]) - assert.Equal(t, rr.Status, engineapi.RuleStatusPass, rr.Status) + er := testMutate(context.TODO(), dclient, registryclient.NewOrDie(), policyContext) + + for _, rr := range er.PolicyResponse.Rules { + for i, p := range rr.Patches { + assert.Equal(t, test.patches[i], string(p), "test %s failed:\nGot %s\nExpected: %s", test.name, rr.Patches[i], test.patches[i]) + assert.Equal(t, rr.Status, engineapi.RuleStatusPass, rr.Status) + } } } } @@ -1708,7 +1711,7 @@ func Test_RuleSelectorMutate(t *testing.T) { newResource: *resourceUnstructured, } - er := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 2) assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1) assert.Equal(t, len(er.PolicyResponse.Rules[1].Patches), 1) @@ -1723,7 +1726,7 @@ func Test_RuleSelectorMutate(t *testing.T) { applyOne := kyverno.ApplyOne policyContext.policy.GetSpec().ApplyRules = &applyOne - er = testMutate(context.TODO(), registryclient.NewOrDie(), policyContext) + er = testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1) @@ -2090,7 +2093,7 @@ func Test_SpecialCharacters(t *testing.T) { } // Mutate and make sure that we got the expected amount of rules. - patches := testMutate(context.TODO(), registryclient.NewOrDie(), policyContext).GetPatches() + patches := testMutate(context.TODO(), nil, registryclient.NewOrDie(), policyContext).GetPatches() if !reflect.DeepEqual(patches, tt.want) { t.Errorf("Mutate() got patches %s, expected %s", patches, tt.want) } diff --git a/pkg/engine/policyContext.go b/pkg/engine/policyContext.go index 134c9cf4f0..a9b96c5fdb 100644 --- a/pkg/engine/policyContext.go +++ b/pkg/engine/policyContext.go @@ -5,7 +5,6 @@ import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" - "github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/config" engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginectx "github.com/kyverno/kyverno/pkg/engine/context" @@ -42,9 +41,6 @@ type PolicyContext struct { // and `requestResource: {group:"apps", version:"v1beta1", resource:"deployments"}` (indicating the resource of the original API request). requestResource metav1.GroupVersionResource - // Dynamic client - used for api lookups - client dclient.Interface - // jsonContext is the variable context jsonContext enginectx.Interface @@ -113,10 +109,6 @@ func (c *PolicyContext) JSONContext() enginectx.Interface { return c.jsonContext } -func (c *PolicyContext) Client() dclient.Interface { - return c.client -} - func (c PolicyContext) Copy() engineapi.PolicyContext { return c.copy() } @@ -163,12 +155,6 @@ func (c *PolicyContext) WithResources(newResource unstructured.Unstructured, old return c.WithNewResource(newResource).WithOldResource(oldResource) } -func (c *PolicyContext) WithClient(client dclient.Interface) *PolicyContext { - copy := c.copy() - copy.client = client - return copy -} - func (c *PolicyContext) withAdmissionOperation(admissionOperation bool) *PolicyContext { copy := c.copy() copy.admissionOperation = admissionOperation @@ -207,7 +193,6 @@ func NewPolicyContextFromAdmissionRequest( request *admissionv1.AdmissionRequest, admissionInfo kyvernov1beta1.RequestInfo, configuration config.Configuration, - client dclient.Interface, ) (*PolicyContext, error) { ctx, err := newVariablesContext(request, &admissionInfo) if err != nil { @@ -225,7 +210,6 @@ func NewPolicyContextFromAdmissionRequest( WithNewResource(newResource). WithOldResource(oldResource). WithAdmissionInfo(admissionInfo). - WithClient(client). withAdmissionOperation(true). WithRequestResource(*requestResource). WithSubresource(request.SubResource) diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index c0f4b7f6d7..89cf778b7a 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -87,7 +87,7 @@ func (e *engine) validateResource( } log = log.WithValues("rule", rule.Name) kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...) - subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, enginectx) + subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(e.client, kindsInPolicy, enginectx) if !matches(log, rule, enginectx, subresourceGVKToAPIResource, e.configuration) { return nil @@ -104,7 +104,7 @@ func (e *engine) validateResource( } else if hasValidateImage { return e.processImageValidationRule(ctx, log, enginectx, rule) } else if hasYAMLSignatureVerify { - return processYAMLValidationRule(log, enginectx, rule) + return processYAMLValidationRule(e.client, log, enginectx, rule) } return nil }, diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go index a683e734dd..296c9fe9cf 100644 --- a/pkg/engine/validation_test.go +++ b/pkg/engine/validation_test.go @@ -22,7 +22,8 @@ import ( func testValidate(ctx context.Context, rclient registryclient.Client, pContext *PolicyContext, cfg config.Configuration) *engineapi.EngineResponse { e := NewEngine( cfg, - LegacyContextLoaderFactory(rclient, nil), + nil, + LegacyContextLoaderFactory(nil, rclient, nil), nil, ) return e.Validate( diff --git a/pkg/testrunner/scenario.go b/pkg/testrunner/scenario.go index 68ae386295..57eba27421 100644 --- a/pkg/testrunner/scenario.go +++ b/pkg/testrunner/scenario.go @@ -148,7 +148,8 @@ func runTestCase(t *testing.T, tc TestCase) bool { policyContext := engine.NewPolicyContext().WithPolicy(policy).WithNewResource(*resource) eng := engine.NewEngine( config.NewDefaultConfiguration(), - engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil), + nil, + engine.LegacyContextLoaderFactory(nil, registryclient.NewOrDie(), nil), nil, ) er := eng.Mutate( @@ -183,7 +184,7 @@ func runTestCase(t *testing.T, tc TestCase) bool { if err := createNamespace(client, resource); err != nil { t.Error(err) } else { - policyContext := policyContext.WithClient(client) + // policyContext := policyContext.WithClient(client) er = eng.ApplyBackgroundChecks( policyContext, diff --git a/pkg/webhooks/resource/fake.go b/pkg/webhooks/resource/fake.go index 16c8df1c72..f5335b678c 100644 --- a/pkg/webhooks/resource/fake.go +++ b/pkg/webhooks/resource/fake.go @@ -58,7 +58,8 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoclient, urLister), engine: engine.NewEngine( configuration, - engine.LegacyContextLoaderFactory(rclient, configMapResolver), + dclient, + engine.LegacyContextLoaderFactory(dclient, rclient, configMapResolver), peLister, ), } diff --git a/pkg/webhooks/resource/validation_test.go b/pkg/webhooks/resource/validation_test.go index 5614d453af..91e2084f9b 100644 --- a/pkg/webhooks/resource/validation_test.go +++ b/pkg/webhooks/resource/validation_test.go @@ -1051,7 +1051,8 @@ func TestValidate_failure_action_overrides(t *testing.T) { eng := engine.NewEngine( config.NewDefaultConfiguration(), - engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil), + nil, + engine.LegacyContextLoaderFactory(nil, registryclient.NewOrDie(), nil), nil, ) for i, tc := range testcases { @@ -1128,7 +1129,8 @@ func Test_RuleSelector(t *testing.T) { eng := engine.NewEngine( config.NewDefaultConfiguration(), - engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil), + nil, + engine.LegacyContextLoaderFactory(nil, registryclient.NewOrDie(), nil), nil, ) resp := eng.Validate( diff --git a/pkg/webhooks/utils/policy_context_builder.go b/pkg/webhooks/utils/policy_context_builder.go index 712052715f..ee7bed49e4 100644 --- a/pkg/webhooks/utils/policy_context_builder.go +++ b/pkg/webhooks/utils/policy_context_builder.go @@ -18,7 +18,6 @@ type PolicyContextBuilder interface { type policyContextBuilder struct { configuration config.Configuration - client dclient.Interface rbLister rbacv1listers.RoleBindingLister crbLister rbacv1listers.ClusterRoleBindingLister } @@ -31,7 +30,6 @@ func NewPolicyContextBuilder( ) PolicyContextBuilder { return &policyContextBuilder{ configuration: configuration, - client: client, rbLister: rbLister, crbLister: crbLister, } @@ -47,5 +45,5 @@ func (b *policyContextBuilder) Build(request *admissionv1.AdmissionRequest) (*en userRequestInfo.Roles = roles userRequestInfo.ClusterRoles = clusterRoles } - return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, b.configuration, b.client) + return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, b.configuration) }