From ff728d5f2b01980a35ba2a83d5812a06c1332bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= Date: Fri, 9 Dec 2022 14:45:11 +0100 Subject: [PATCH] feat: propagate context through engine (#5639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: propagate context through engine Signed-off-by: Charles-Edouard Brétéché * feat: propagate context through engine Signed-off-by: Charles-Edouard Brétéché * feat: propagate context through engine Signed-off-by: Charles-Edouard Brétéché * feat: propagate context through engine Signed-off-by: Charles-Edouard Brétéché Signed-off-by: Charles-Edouard Brétéché --- .../kubectl-kyverno/utils/common/common.go | 6 +- cmd/kyverno/main.go | 14 +-- pkg/background/generate/generate.go | 2 +- pkg/background/mutate/mutate.go | 2 +- .../report/background/controller.go | 4 +- pkg/controllers/report/utils/scanner.go | 44 +++---- pkg/cosign/cosign.go | 22 ++-- pkg/cosign/cosign_test.go | 7 +- pkg/engine/background.go | 3 +- pkg/engine/imageVerify.go | 61 ++++++---- pkg/engine/imageVerifyValidate.go | 17 +-- pkg/engine/imageVerify_test.go | 45 +++---- pkg/engine/jsonContext.go | 74 ++++++------ pkg/engine/mutation.go | 39 +++--- pkg/engine/mutation_test.go | 28 ++--- pkg/engine/validation.go | 79 ++++++------ pkg/engine/validation_test.go | 113 +++++++++--------- pkg/policy/apply.go | 13 +- pkg/testrunner/scenario.go | 4 +- .../resource/generation/generation.go | 47 ++++---- pkg/webhooks/resource/generation/utils.go | 24 ++-- pkg/webhooks/resource/handlers.go | 14 +-- .../resource/imageverification/handler.go | 22 ++-- pkg/webhooks/resource/mutation/mutation.go | 28 ++--- pkg/webhooks/resource/updaterequest.go | 10 +- pkg/webhooks/resource/utils.go | 13 +- .../resource/validation/validation.go | 29 +++-- pkg/webhooks/resource/validation_test.go | 6 +- pkg/webhooks/updaterequest/fake.go | 4 +- pkg/webhooks/updaterequest/generator.go | 14 +-- 30 files changed, 420 insertions(+), 368 deletions(-) diff --git a/cmd/cli/kubectl-kyverno/utils/common/common.go b/cmd/cli/kubectl-kyverno/utils/common/common.go index 5f6f991dff..b16e6b4ca5 100644 --- a/cmd/cli/kubectl-kyverno/utils/common/common.go +++ b/cmd/cli/kubectl-kyverno/utils/common/common.go @@ -458,7 +458,7 @@ OuterLoop: WithAdmissionInfo(c.UserInfo). WithClient(c.Client) - mutateResponse := engine.Mutate(registryclient.NewOrDie(), policyContext) + mutateResponse := engine.Mutate(context.Background(), registryclient.NewOrDie(), policyContext) if mutateResponse != nil { engineResponses = append(engineResponses, mutateResponse) } @@ -482,7 +482,7 @@ OuterLoop: var info Info var validateResponse *response.EngineResponse if policyHasValidate { - validateResponse = engine.Validate(registryclient.NewOrDie(), policyContext) + validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext) info = ProcessValidateEngineResponse(c.Policy, validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn) } @@ -490,7 +490,7 @@ OuterLoop: engineResponses = append(engineResponses, validateResponse) } - verifyImageResponse, _ := engine.VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext) if verifyImageResponse != nil && !verifyImageResponse.IsEmpty() { engineResponses = append(engineResponses, verifyImageResponse) info = ProcessValidateEngineResponse(c.Policy, verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn) diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index aca9741e8a..0066425d7b 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -62,17 +62,15 @@ const ( resyncPeriod = 15 * time.Minute ) -func setupRegistryClient(logger logr.Logger, lister corev1listers.SecretNamespaceLister, imagePullSecrets string, allowInsecureRegistry bool) (registryclient.Client, error) { +func setupRegistryClient(ctx context.Context, logger logr.Logger, lister corev1listers.SecretNamespaceLister, imagePullSecrets string, allowInsecureRegistry bool) (registryclient.Client, error) { logger = logger.WithName("registry-client") logger.Info("setup registry client...", "secrets", imagePullSecrets, "insecure", allowInsecureRegistry) - var registryOptions []registryclient.Option + registryOptions := []registryclient.Option{ + registryclient.WithTracing(), + } secrets := strings.Split(imagePullSecrets, ",") if imagePullSecrets != "" && len(secrets) > 0 { - registryOptions = append(registryOptions, registryclient.WithKeychainPullSecrets( - context.TODO(), - lister, - secrets..., - )) + registryOptions = append(registryOptions, registryclient.WithKeychainPullSecrets(ctx, lister, secrets...)) } if allowInsecureRegistry { registryOptions = append(registryOptions, registryclient.WithAllowInsecureRegistry()) @@ -415,7 +413,7 @@ func main() { } secretLister := kubeKyvernoInformer.Core().V1().Secrets().Lister().Secrets(config.KyvernoNamespace()) // setup registry client - rclient, err := setupRegistryClient(logger, secretLister, imagePullSecrets, allowInsecureRegistry) + rclient, err := setupRegistryClient(signalCtx, logger, secretLister, imagePullSecrets, allowInsecureRegistry) if err != nil { logger.Error(err, "failed to setup registry client") os.Exit(1) diff --git a/pkg/background/generate/generate.go b/pkg/background/generate/generate.go index 9d3acb353c..401ade590e 100644 --- a/pkg/background/generate/generate.go +++ b/pkg/background/generate/generate.go @@ -345,7 +345,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext } // add configmap json data to context - if err := engine.LoadContext(log, c.rclient, rule.Context, policyContext, rule.Name); err != nil { + if err := engine.LoadContext(context.TODO(), log, c.rclient, rule.Context, policyContext, rule.Name); err != nil { log.Error(err, "cannot add configmaps to context") return nil, processExisting, err } diff --git a/pkg/background/mutate/mutate.go b/pkg/background/mutate/mutate.go index a7debc720b..b35707d211 100644 --- a/pkg/background/mutate/mutate.go +++ b/pkg/background/mutate/mutate.go @@ -93,7 +93,7 @@ func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e continue } - er := engine.Mutate(c.rclient, policyContext) + er := engine.Mutate(context.TODO(), c.rclient, policyContext) for _, r := range er.PolicyResponse.Rules { patched := r.PatchedTarget switch r.Status { diff --git a/pkg/controllers/report/background/controller.go b/pkg/controllers/report/background/controller.go index 29a712d21b..6abf48653e 100644 --- a/pkg/controllers/report/background/controller.go +++ b/pkg/controllers/report/background/controller.go @@ -241,7 +241,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s nsLabels = ns.GetLabels() } var responses []*response.EngineResponse - for _, result := range scanner.ScanResource(*resource, nsLabels, backgroundPolicies...) { + for _, result := range scanner.ScanResource(ctx, *resource, nsLabels, backgroundPolicies...) { if result.Error != nil { logger.Error(result.Error, "failed to apply policy") } else { @@ -321,7 +321,7 @@ func (c *controller) updateReport(ctx context.Context, meta metav1.Object, gvk s } nsLabels = ns.GetLabels() } - for _, result := range scanner.ScanResource(*resource, nsLabels, toCreate...) { + for _, result := range scanner.ScanResource(ctx, *resource, nsLabels, toCreate...) { if result.Error != nil { return result.Error } else { diff --git a/pkg/controllers/report/utils/scanner.go b/pkg/controllers/report/utils/scanner.go index 368284a344..d66b3d2f4e 100644 --- a/pkg/controllers/report/utils/scanner.go +++ b/pkg/controllers/report/utils/scanner.go @@ -1,11 +1,13 @@ package utils import ( + "context" + "github.com/go-logr/logr" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/engine" - "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/registryclient" "go.uber.org/multierr" @@ -25,7 +27,7 @@ type ScanResult struct { } type Scanner interface { - ScanResource(unstructured.Unstructured, map[string]string, ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult + ScanResource(context.Context, unstructured.Unstructured, map[string]string, ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult } func NewScanner(logger logr.Logger, client dclient.Interface, rclient registryclient.Client, excludeGroupRole ...string) Scanner { @@ -37,18 +39,18 @@ func NewScanner(logger logr.Logger, client dclient.Interface, rclient registrycl } } -func (s *scanner) ScanResource(resource unstructured.Unstructured, nsLabels map[string]string, policies ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult { +func (s *scanner) ScanResource(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policies ...kyvernov1.PolicyInterface) map[kyvernov1.PolicyInterface]ScanResult { results := map[kyvernov1.PolicyInterface]ScanResult{} for _, policy := range policies { var errors []error - response, err := s.validateResource(resource, nsLabels, policy) + response, err := s.validateResource(ctx, resource, nsLabels, policy) if err != nil { s.logger.Error(err, "failed to scan resource") errors = append(errors, err) } spec := policy.GetSpec() if spec.HasVerifyImages() { - ivResponse, err := s.validateImages(resource, nsLabels, policy) + ivResponse, err := s.validateImages(ctx, resource, nsLabels, policy) if err != nil { s.logger.Error(err, "failed to scan images") errors = append(errors, err) @@ -64,50 +66,50 @@ func (s *scanner) ScanResource(resource unstructured.Unstructured, nsLabels map[ return results } -func (s *scanner) validateResource(resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) { - ctx := context.NewContext() - if err := ctx.AddResource(resource.Object); err != nil { +func (s *scanner) validateResource(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) { + enginectx := enginecontext.NewContext() + if err := enginectx.AddResource(resource.Object); err != nil { return nil, err } - if err := ctx.AddNamespace(resource.GetNamespace()); err != nil { + if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil { return nil, err } - if err := ctx.AddImageInfos(&resource); err != nil { + if err := enginectx.AddImageInfos(&resource); err != nil { return nil, err } - if err := ctx.AddOperation("CREATE"); err != nil { + if err := enginectx.AddOperation("CREATE"); err != nil { return nil, err } - policyCtx := engine.NewPolicyContextWithJsonContext(ctx). + policyCtx := engine.NewPolicyContextWithJsonContext(enginectx). WithNewResource(resource). WithPolicy(policy). WithClient(s.client). WithNamespaceLabels(nsLabels). WithExcludeGroupRole(s.excludeGroupRole...) - return engine.Validate(s.rclient, policyCtx), nil + return engine.Validate(ctx, s.rclient, policyCtx), nil } -func (s *scanner) validateImages(resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) { - ctx := context.NewContext() - if err := ctx.AddResource(resource.Object); err != nil { +func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*response.EngineResponse, error) { + enginectx := enginecontext.NewContext() + if err := enginectx.AddResource(resource.Object); err != nil { return nil, err } - if err := ctx.AddNamespace(resource.GetNamespace()); err != nil { + if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil { return nil, err } - if err := ctx.AddImageInfos(&resource); err != nil { + if err := enginectx.AddImageInfos(&resource); err != nil { return nil, err } - if err := ctx.AddOperation("CREATE"); err != nil { + if err := enginectx.AddOperation("CREATE"); err != nil { return nil, err } - policyCtx := engine.NewPolicyContextWithJsonContext(ctx). + policyCtx := engine.NewPolicyContextWithJsonContext(enginectx). WithNewResource(resource). WithPolicy(policy). WithClient(s.client). WithNamespaceLabels(nsLabels). WithExcludeGroupRole(s.excludeGroupRole...) - response, _ := engine.VerifyAndPatchImages(s.rclient, policyCtx) + response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx) if len(response.PolicyResponse.Rules) > 0 { s.logger.Info("validateImages", "policy", policy, "response", response) } diff --git a/pkg/cosign/cosign.go b/pkg/cosign/cosign.go index cde692ba86..f0947ca5cf 100644 --- a/pkg/cosign/cosign.go +++ b/pkg/cosign/cosign.go @@ -59,13 +59,13 @@ type Response struct { type CosignError struct{} // VerifySignature verifies that the image has the expected signatures -func VerifySignature(rclient registryclient.Client, opts Options) (*Response, error) { +func VerifySignature(ctx context.Context, rclient registryclient.Client, opts Options) (*Response, error) { ref, err := name.ParseReference(opts.ImageRef) if err != nil { return nil, fmt.Errorf("failed to parse image %s", opts.ImageRef) } - cosignOpts, err := buildCosignOptions(rclient, opts) + cosignOpts, err := buildCosignOptions(ctx, rclient, opts) if err != nil { return nil, err } @@ -75,7 +75,7 @@ func VerifySignature(rclient registryclient.Client, opts Options) (*Response, er bundleVerified bool ) - tracing.DoInSpan(context.Background(), "cosign", "verify_image_signatures", func(ctx context.Context) { + tracing.DoInSpan(ctx, "cosign", "verify_image_signatures", func(ctx context.Context) { signatures, bundleVerified, err = client.VerifyImageSignatures(ctx, ref, cosignOpts) }) @@ -110,7 +110,7 @@ func VerifySignature(rclient registryclient.Client, opts Options) (*Response, er return &Response{Digest: digest}, nil } -func buildCosignOptions(rclient registryclient.Client, opts Options) (*cosign.CheckOpts, error) { +func buildCosignOptions(ctx context.Context, rclient registryclient.Client, opts Options) (*cosign.CheckOpts, error) { var remoteOpts []remote.Option var err error signatureAlgorithmMap := map[string]crypto.Hash{ @@ -119,11 +119,11 @@ func buildCosignOptions(rclient registryclient.Client, opts Options) (*cosign.Ch "sha512": crypto.SHA512, } ro := options.RegistryOptions{} - remoteOpts, err = ro.ClientOpts(context.Background()) + remoteOpts, err = ro.ClientOpts(ctx) if err != nil { return nil, errors.Wrap(err, "constructing client options") } - remoteOpts = append(remoteOpts, rclient.BuildRemoteOption(context.TODO())) + remoteOpts = append(remoteOpts, rclient.BuildRemoteOption(ctx)) cosignOpts := &cosign.CheckOpts{ Annotations: map[string]interface{}{}, RegistryClientOpts: remoteOpts, @@ -151,7 +151,7 @@ func buildCosignOptions(rclient registryclient.Client, opts Options) (*cosign.Ch } } else { // this supports Kubernetes secrets and KMS - cosignOpts.SigVerifier, err = sigs.PublicKeyFromKeyRef(context.Background(), opts.Key) + cosignOpts.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, opts.Key) if err != nil { return nil, errors.Wrapf(err, "failed to load public key from %s", opts.Key) } @@ -254,8 +254,8 @@ func loadCertChain(pem []byte) ([]*x509.Certificate, error) { // FetchAttestations retrieves signed attestations and decodes them into in-toto statements // https://github.com/in-toto/attestation/blob/main/spec/README.md#statement -func FetchAttestations(rclient registryclient.Client, opts Options) (*Response, error) { - cosignOpts, err := buildCosignOptions(rclient, opts) +func FetchAttestations(ctx context.Context, rclient registryclient.Client, opts Options) (*Response, error) { + cosignOpts, err := buildCosignOptions(ctx, rclient, opts) if err != nil { return nil, err } @@ -268,8 +268,8 @@ func FetchAttestations(rclient registryclient.Client, opts Options) (*Response, var signatures []oci.Signature var bundleVerified bool - tracing.DoInSpan(context.Background(), "cosign_operations", "verify_image_signatures", func(ctx context.Context) { - signatures, bundleVerified, err = client.VerifyImageAttestations(context.Background(), ref, cosignOpts) + tracing.DoInSpan(ctx, "cosign_operations", "verify_image_signatures", func(ctx context.Context) { + signatures, bundleVerified, err = client.VerifyImageAttestations(ctx, ref, cosignOpts) }) if err != nil { diff --git a/pkg/cosign/cosign_test.go b/pkg/cosign/cosign_test.go index e3967fca20..ac9cc1aed7 100644 --- a/pkg/cosign/cosign_test.go +++ b/pkg/cosign/cosign_test.go @@ -1,6 +1,7 @@ package cosign import ( + "context" "crypto/x509" "fmt" "io" @@ -80,15 +81,15 @@ func TestCosignKeyless(t *testing.T) { client, err := registryclient.New() assert.NilError(t, err) - _, err = VerifySignature(client, opts) + _, err = VerifySignature(context.TODO(), client, opts) assert.ErrorContains(t, err, "subject mismatch: expected jim, received jim@nirmata.com") opts.Subject = "jim@nirmata.com" - _, err = VerifySignature(client, opts) + _, err = VerifySignature(context.TODO(), client, opts) assert.ErrorContains(t, err, "issuer mismatch: expected https://github.com/, received https://github.com/login/oauth") opts.Issuer = "https://github.com/login/oauth" - _, err = VerifySignature(client, opts) + _, err = VerifySignature(context.TODO(), client, opts) assert.NilError(t, err) } diff --git a/pkg/engine/background.go b/pkg/engine/background.go index 74b6b95159..fa3b2e3741 100644 --- a/pkg/engine/background.go +++ b/pkg/engine/background.go @@ -1,6 +1,7 @@ package engine import ( + "context" "time" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" @@ -109,7 +110,7 @@ func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContex policyContext.jsonContext.Checkpoint() defer policyContext.jsonContext.Restore() - if err = LoadContext(logger, rclient, rule.Context, policyContext, rule.Name); err != nil { + if err = LoadContext(context.TODO(), logger, rclient, rule.Context, policyContext, rule.Name); err != nil { logger.V(4).Info("cannot add external data to the context", "reason", err.Error()) return nil } diff --git a/pkg/engine/imageVerify.go b/pkg/engine/imageVerify.go index dfc4679b06..6ea9793b7b 100644 --- a/pkg/engine/imageVerify.go +++ b/pkg/engine/imageVerify.go @@ -63,7 +63,11 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) ( return matchingImages, imageRefs, nil } -func VerifyAndPatchImages(rclient registryclient.Client, policyContext *PolicyContext) (*response.EngineResponse, *ImageVerificationMetadata) { +func VerifyAndPatchImages( + ctx context.Context, + rclient registryclient.Client, + policyContext *PolicyContext, +) (*response.EngineResponse, *ImageVerificationMetadata) { resp := &response.EngineResponse{} policy := policyContext.policy @@ -112,7 +116,7 @@ func VerifyAndPatchImages(rclient registryclient.Client, policyContext *PolicyCo } policyContext.jsonContext.Restore() - if err := LoadContext(logger, rclient, rule.Context, policyContext, rule.Name); err != nil { + if err := LoadContext(ctx, logger, rclient, rule.Context, policyContext, rule.Name); err != nil { appendResponse(resp, rule, fmt.Sprintf("failed to load context: %s", err.Error()), response.RuleStatusError) continue } @@ -133,7 +137,7 @@ func VerifyAndPatchImages(rclient registryclient.Client, policyContext *PolicyCo } for _, imageVerify := range ruleCopy.VerifyImages { - iv.verify(imageVerify, ruleImages) + iv.verify(ctx, imageVerify, ruleImages) } if applyRules == kyvernov1.ApplyOne && resp.PolicyResponse.RulesAppliedCount > 0 { @@ -182,7 +186,7 @@ type imageVerifier struct { // verify applies policy rules to each matching image. The policy rule results and annotation patches are // added to tme imageVerifier `resp` and `ivm` fields. -func (iv *imageVerifier) verify(imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo) { +func (iv *imageVerifier) verify(ctx context.Context, imageVerify kyvernov1.ImageVerification, matchedImageInfos []apiutils.ImageInfo) { // for backward compatibility imageVerify = *imageVerify.Convert() @@ -211,10 +215,10 @@ func (iv *imageVerifier) verify(imageVerify kyvernov1.ImageVerification, matched continue } - ruleResp, digest := iv.verifyImage(imageVerify, imageInfo) + ruleResp, digest := iv.verifyImage(ctx, imageVerify, imageInfo) if imageVerify.MutateDigest { - patch, retrievedDigest, err := iv.handleMutateDigest(digest, imageInfo) + patch, retrievedDigest, err := iv.handleMutateDigest(ctx, digest, imageInfo) if err != nil { ruleResp = ruleError(iv.rule, response.ImageVerify, "failed to update digest", err) } else if patch != nil { @@ -240,13 +244,13 @@ func (iv *imageVerifier) verify(imageVerify kyvernov1.ImageVerification, matched } } -func (iv *imageVerifier) handleMutateDigest(digest string, imageInfo apiutils.ImageInfo) ([]byte, string, error) { +func (iv *imageVerifier) handleMutateDigest(ctx context.Context, digest string, imageInfo apiutils.ImageInfo) ([]byte, string, error) { if imageInfo.Digest != "" { return nil, "", nil } if digest == "" { - desc, err := iv.rclient.FetchImageDescriptor(context.TODO(), imageInfo.String()) + desc, err := iv.rclient.FetchImageDescriptor(ctx, imageInfo.String()) if err != nil { return nil, "", err } @@ -290,7 +294,11 @@ func imageMatches(image string, imagePatterns []string) bool { return false } -func (iv *imageVerifier) verifyImage(imageVerify kyvernov1.ImageVerification, imageInfo apiutils.ImageInfo) (*response.RuleResponse, string) { +func (iv *imageVerifier) verifyImage( + ctx context.Context, + imageVerify kyvernov1.ImageVerification, + imageInfo apiutils.ImageInfo, +) (*response.RuleResponse, string) { if len(imageVerify.Attestors) <= 0 && len(imageVerify.Attestations) <= 0 { return nil, "" } @@ -306,17 +314,21 @@ func (iv *imageVerifier) verifyImage(imageVerify kyvernov1.ImageVerification, im } if len(imageVerify.Attestors) > 0 { - ruleResp, _, _ := iv.verifyAttestors(imageVerify.Attestors, imageVerify, imageInfo, "") + ruleResp, _, _ := iv.verifyAttestors(ctx, imageVerify.Attestors, imageVerify, imageInfo, "") if ruleResp.Status != response.RuleStatusPass { return ruleResp, "" } } - return iv.verifyAttestations(imageVerify, imageInfo) + return iv.verifyAttestations(ctx, imageVerify, imageInfo) } -func (iv *imageVerifier) verifyAttestors(attestors []kyvernov1.AttestorSet, imageVerify kyvernov1.ImageVerification, - imageInfo apiutils.ImageInfo, predicateType string, +func (iv *imageVerifier) verifyAttestors( + ctx context.Context, + attestors []kyvernov1.AttestorSet, + imageVerify kyvernov1.ImageVerification, + imageInfo apiutils.ImageInfo, + predicateType string, ) (*response.RuleResponse, *cosign.Response, []kyvernov1.AttestorSet) { var cosignResponse *cosign.Response var newAttestors []kyvernov1.AttestorSet @@ -326,7 +338,7 @@ func (iv *imageVerifier) verifyAttestors(attestors []kyvernov1.AttestorSet, imag var err error path := fmt.Sprintf(".attestors[%d]", i) iv.logger.V(4).Info("verifying attestors", "path", path) - cosignResponse, err = iv.verifyAttestorSet(attestorSet, imageVerify, imageInfo, path, predicateType) + cosignResponse, err = iv.verifyAttestorSet(ctx, attestorSet, imageVerify, imageInfo, path, predicateType) if err != nil { iv.logger.Error(err, "failed to verify image") msg := fmt.Sprintf("failed to verify image %s: %s", image, err.Error()) @@ -350,7 +362,11 @@ func (iv *imageVerifier) verifyAttestors(attestors []kyvernov1.AttestorSet, imag return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusPass, nil), cosignResponse, newAttestors } -func (iv *imageVerifier) verifyAttestations(imageVerify kyvernov1.ImageVerification, imageInfo apiutils.ImageInfo) (*response.RuleResponse, string) { +func (iv *imageVerifier) verifyAttestations( + ctx context.Context, + imageVerify kyvernov1.ImageVerification, + imageInfo apiutils.ImageInfo, +) (*response.RuleResponse, string) { image := imageInfo.String() for i, attestation := range imageVerify.Attestations { var attestationError error @@ -375,7 +391,7 @@ func (iv *imageVerifier) verifyAttestations(imageVerify kyvernov1.ImageVerificat for _, a := range entries { entryPath := fmt.Sprintf("%s.entries[%d]", attestorPath, i) opts, subPath := iv.buildOptionsAndPath(a, imageVerify, image, attestation) - cosignResp, err := cosign.FetchAttestations(iv.rclient, *opts) + cosignResp, err := cosign.FetchAttestations(ctx, iv.rclient, *opts) if err != nil { iv.logger.Error(err, "failed to fetch attestations") msg := fmt.Sprintf("failed to fetch attestations %s: %s", image, err.Error()) @@ -410,8 +426,13 @@ func (iv *imageVerifier) verifyAttestations(imageVerify kyvernov1.ImageVerificat return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusPass, nil), "" } -func (iv *imageVerifier) verifyAttestorSet(attestorSet kyvernov1.AttestorSet, imageVerify kyvernov1.ImageVerification, - imageInfo apiutils.ImageInfo, path, predicateType string, +func (iv *imageVerifier) verifyAttestorSet( + ctx context.Context, + attestorSet kyvernov1.AttestorSet, + imageVerify kyvernov1.ImageVerification, + imageInfo apiutils.ImageInfo, + path string, + predicateType string, ) (*cosign.Response, error) { var errorList []error verifiedCount := 0 @@ -431,11 +452,11 @@ func (iv *imageVerifier) verifyAttestorSet(attestorSet kyvernov1.AttestorSet, im entryError = errors.Wrapf(err, "failed to unmarshal nested attestor %s", attestorPath) } else { attestorPath += ".attestor" - cosignResp, entryError = iv.verifyAttestorSet(*nestedAttestorSet, imageVerify, imageInfo, attestorPath, predicateType) + cosignResp, entryError = iv.verifyAttestorSet(ctx, *nestedAttestorSet, imageVerify, imageInfo, attestorPath, predicateType) } } else { opts, subPath := iv.buildOptionsAndPath(a, imageVerify, image, kyvernov1.Attestation{PredicateType: predicateType}) - cosignResp, entryError = cosign.VerifySignature(iv.rclient, *opts) + cosignResp, entryError = cosign.VerifySignature(ctx, iv.rclient, *opts) if entryError != nil { entryError = errors.Wrapf(entryError, attestorPath+subPath) } diff --git a/pkg/engine/imageVerifyValidate.go b/pkg/engine/imageVerifyValidate.go index 940d48115f..830eb4cb8b 100644 --- a/pkg/engine/imageVerifyValidate.go +++ b/pkg/engine/imageVerifyValidate.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "reflect" @@ -14,20 +15,20 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -func processImageValidationRule(log logr.Logger, rclient registryclient.Client, ctx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse { - if isDeleteRequest(ctx) { +func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse { + if isDeleteRequest(enginectx) { return nil } log = log.WithValues("rule", rule.Name) - matchingImages, _, err := extractMatchingImages(ctx, rule) + matchingImages, _, err := extractMatchingImages(enginectx, rule) if err != nil { return ruleResponse(*rule, response.Validation, err.Error(), response.RuleStatusError, nil) } if len(matchingImages) == 0 { return ruleResponse(*rule, response.Validation, "image verified", response.RuleStatusSkip, nil) } - if err := LoadContext(log, rclient, rule.Context, ctx, rule.Name); err != nil { + if err := LoadContext(ctx, log, rclient, rule.Context, enginectx, rule.Name); err != nil { if _, ok := err.(gojmespath.NotFoundError); ok { log.V(3).Info("failed to load context", "reason", err.Error()) } else { @@ -37,13 +38,13 @@ func processImageValidationRule(log logr.Logger, rclient registryclient.Client, return ruleError(rule, response.Validation, "failed to load context", err) } - preconditionsPassed, err := checkPreconditions(log, ctx, rule.RawAnyAllConditions) + preconditionsPassed, err := checkPreconditions(log, enginectx, rule.RawAnyAllConditions) if err != nil { return ruleError(rule, response.Validation, "failed to evaluate preconditions", err) } if !preconditionsPassed { - if ctx.policy.GetSpec().ValidationFailureAction.Audit() { + if enginectx.policy.GetSpec().ValidationFailureAction.Audit() { return nil } @@ -52,7 +53,7 @@ func processImageValidationRule(log logr.Logger, rclient registryclient.Client, for _, v := range rule.VerifyImages { imageVerify := v.Convert() - for _, infoMap := range ctx.jsonContext.ImageInfo() { + for _, infoMap := range enginectx.jsonContext.ImageInfo() { for name, imageInfo := range infoMap { image := imageInfo.String() log = log.WithValues("rule", rule.Name) @@ -63,7 +64,7 @@ func processImageValidationRule(log logr.Logger, rclient registryclient.Client, } log.V(4).Info("validating image", "image", image) - if err := validateImage(ctx, imageVerify, name, imageInfo, log); err != nil { + if err := validateImage(enginectx, imageVerify, name, imageInfo, log); err != nil { return ruleResponse(*rule, response.ImageVerify, err.Error(), response.RuleStatusFail, nil) } } diff --git a/pkg/engine/imageVerify_test.go b/pkg/engine/imageVerify_test.go index 887b587a2d..183c553d75 100644 --- a/pkg/engine/imageVerify_test.go +++ b/pkg/engine/imageVerify_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "encoding/json" "fmt" "strings" @@ -13,7 +14,7 @@ import ( kyverno "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/cosign" - "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/context/resolvers" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" @@ -150,7 +151,7 @@ func Test_CosignMockAttest(t *testing.T) { err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads) assert.NilError(t, err) - er, ivm := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass, fmt.Sprintf("expected: %v, got: %v, failure: %v", @@ -164,7 +165,7 @@ func Test_CosignMockAttest_fail(t *testing.T) { err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads) assert.NilError(t, err) - er, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail) } @@ -178,8 +179,8 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po resourceUnstructured, err := utils.ConvertToUnstructured([]byte(resource)) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, []byte(resource)) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, []byte(resource)) assert.NilError(t, err) policyContext := &PolicyContext{ @@ -192,7 +193,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po oldResourceUnstructured, err := utils.ConvertToUnstructured([]byte(oldResource)) assert.NilError(t, err) - err = context.AddOldResource(ctx, []byte(oldResource)) + err = enginecontext.AddOldResource(ctx, []byte(oldResource)) assert.NilError(t, err) policyContext.oldResource = *oldResourceUnstructured @@ -412,7 +413,7 @@ var testOtherKey = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD func Test_ConfigMapMissingSuccess(t *testing.T) { policyContext := buildContext(t, testConfigMapMissing, testConfigMapMissingResource, "") cosign.ClearMock() - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusSkip, err.PolicyResponse.Rules[0].Message) } @@ -424,7 +425,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) { assert.NilError(t, err) policyContext.informerCacheResolvers = resolver cosign.ClearMock() - resp, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(resp.PolicyResponse.Rules), 1) assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusError, resp.PolicyResponse.Rules[0].Message) } @@ -432,7 +433,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) { func Test_SignatureGoodSigned(t *testing.T) { policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "") cosign.ClearMock() - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass, err.PolicyResponse.Rules[0].Message) } @@ -441,7 +442,7 @@ func Test_SignatureUnsigned(t *testing.T) { cosign.ClearMock() unsigned := strings.Replace(testSampleResource, ":signed", ":unsigned", -1) policyContext := buildContext(t, testSampleSingleKeyPolicy, unsigned, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail, err.PolicyResponse.Rules[0].Message) } @@ -450,7 +451,7 @@ func Test_SignatureWrongKey(t *testing.T) { cosign.ClearMock() otherKey := strings.Replace(testSampleResource, ":signed", ":signed-by-someone-else", -1) policyContext := buildContext(t, testSampleSingleKeyPolicy, otherKey, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail, err.PolicyResponse.Rules[0].Message) } @@ -461,7 +462,7 @@ func Test_SignaturesMultiKey(t *testing.T) { policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1) policy = strings.Replace(policy, "COUNT", "0", -1) policyContext := buildContext(t, policy, testSampleResource, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass, err.PolicyResponse.Rules[0].Message) } @@ -471,7 +472,7 @@ func Test_SignaturesMultiKeyFail(t *testing.T) { policy := strings.Replace(testSampleMultipleKeyPolicy, "KEY1", testVerifyImageKey, -1) policy = strings.Replace(policy, "COUNT", "0", -1) policyContext := buildContext(t, policy, testSampleResource, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail, err.PolicyResponse.Rules[0].Message) } @@ -482,7 +483,7 @@ func Test_SignaturesMultiKeyOneGoodKey(t *testing.T) { policy = strings.Replace(policy, "KEY2", testOtherKey, -1) policy = strings.Replace(policy, "COUNT", "1", -1) policyContext := buildContext(t, policy, testSampleResource, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass, err.PolicyResponse.Rules[0].Message) } @@ -493,7 +494,7 @@ func Test_SignaturesMultiKeyZeroGoodKey(t *testing.T) { policy = strings.Replace(policy, "KEY2", testOtherKey, -1) policy = strings.Replace(policy, "COUNT", "1", -1) policyContext := buildContext(t, policy, testSampleResource, "") - resp, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(resp.PolicyResponse.Rules), 1) assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[0].Message) } @@ -509,14 +510,14 @@ func Test_RuleSelectorImageVerify(t *testing.T) { applyAll := kyverno.ApplyAll spec.ApplyRules = &applyAll - resp, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(resp.PolicyResponse.Rules), 2) assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message) assert.Equal(t, resp.PolicyResponse.Rules[1].Status, response.RuleStatusFail, resp.PolicyResponse.Rules[1].Message) applyOne := kyverno.ApplyOne spec.ApplyRules = &applyOne - resp, _ = VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(resp.PolicyResponse.Rules), 1) assert.Equal(t, resp.PolicyResponse.Rules[0].Status, response.RuleStatusPass, resp.PolicyResponse.Rules[0].Message) } @@ -620,7 +621,7 @@ func Test_NestedAttestors(t *testing.T) { policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1) policy = strings.Replace(policy, "COUNT", "0", -1) policyContext := buildContext(t, policy, testSampleResource, "") - err, _ := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -628,7 +629,7 @@ func Test_NestedAttestors(t *testing.T) { policy = strings.Replace(policy, "KEY2", testOtherKey, -1) policy = strings.Replace(policy, "COUNT", "0", -1) policyContext = buildContext(t, policy, testSampleResource, "") - err, _ = VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusFail) @@ -636,7 +637,7 @@ func Test_NestedAttestors(t *testing.T) { policy = strings.Replace(policy, "KEY2", testOtherKey, -1) policy = strings.Replace(policy, "COUNT", "1", -1) policyContext = buildContext(t, policy, testSampleResource, "") - err, _ = VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(err.PolicyResponse.Rules), 1) assert.Equal(t, err.PolicyResponse.Rules[0].Status, response.RuleStatusPass) } @@ -729,7 +730,7 @@ func Test_MarkImageVerified(t *testing.T) { err := cosign.SetMock(image, attestationPayloads) assert.NilError(t, err) - engineResponse, verifiedImages := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Assert(t, engineResponse != nil) assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1) assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -822,7 +823,7 @@ func Test_ParsePEMDelimited(t *testing.T) { err := cosign.SetMock(image, signaturePayloads) assert.NilError(t, err) - engineResponse, verifiedImages := VerifyAndPatchImages(registryclient.NewOrDie(), policyContext) + engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Assert(t, engineResponse != nil) assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1) assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, response.RuleStatusPass) diff --git a/pkg/engine/jsonContext.go b/pkg/engine/jsonContext.go index bea96ca7b4..f74bbf6799 100644 --- a/pkg/engine/jsonContext.go +++ b/pkg/engine/jsonContext.go @@ -14,18 +14,18 @@ import ( ) // LoadContext - Fetches and adds external data to the Context. -func LoadContext(logger logr.Logger, rclient registryclient.Client, contextEntries []kyvernov1.ContextEntry, ctx *PolicyContext, ruleName string) error { +func LoadContext(ctx context.Context, logger logr.Logger, rclient registryclient.Client, contextEntries []kyvernov1.ContextEntry, enginectx *PolicyContext, ruleName string) error { if len(contextEntries) == 0 { return nil } - policyName := ctx.policy.GetName() + policyName := enginectx.policy.GetName() if store.GetMock() { rule := store.GetPolicyRuleFromContext(policyName, ruleName) if rule != nil && len(rule.Values) > 0 { variables := rule.Values for key, value := range variables { - if err := ctx.jsonContext.AddVariable(key, value); err != nil { + if err := enginectx.jsonContext.AddVariable(key, value); err != nil { return err } } @@ -37,15 +37,15 @@ func LoadContext(logger logr.Logger, rclient registryclient.Client, contextEntri for _, entry := range contextEntries { if entry.ImageRegistry != nil && hasRegistryAccess { rclient := store.GetRegistryClient() - if err := loadImageData(rclient, logger, entry, ctx); err != nil { + if err := loadImageData(ctx, rclient, logger, entry, enginectx); err != nil { return err } } else if entry.Variable != nil { - if err := loadVariable(logger, entry, ctx); err != nil { + if err := loadVariable(logger, entry, enginectx); err != nil { return err } } else if entry.APICall != nil && store.IsAllowApiCall() { - if err := loadAPIData(logger, entry, ctx); err != nil { + if err := loadAPIData(ctx, logger, entry, enginectx); err != nil { return err } } @@ -53,7 +53,7 @@ func LoadContext(logger logr.Logger, rclient registryclient.Client, contextEntri if rule != nil && len(rule.ForeachValues) > 0 { for key, value := range rule.ForeachValues { - if err := ctx.jsonContext.AddVariable(key, value[store.ForeachElement]); err != nil { + if err := enginectx.jsonContext.AddVariable(key, value[store.ForeachElement]); err != nil { return err } } @@ -61,19 +61,19 @@ func LoadContext(logger logr.Logger, rclient registryclient.Client, contextEntri } else { for _, entry := range contextEntries { if entry.ConfigMap != nil { - if err := loadConfigMap(logger, entry, ctx); err != nil { + if err := loadConfigMap(ctx, logger, entry, enginectx); err != nil { return err } } else if entry.APICall != nil { - if err := loadAPIData(logger, entry, ctx); err != nil { + if err := loadAPIData(ctx, logger, entry, enginectx); err != nil { return err } } else if entry.ImageRegistry != nil { - if err := loadImageData(rclient, logger, entry, ctx); err != nil { + if err := loadImageData(ctx, rclient, logger, entry, enginectx); err != nil { return err } } else if entry.Variable != nil { - if err := loadVariable(logger, entry, ctx); err != nil { + if err := loadVariable(logger, entry, enginectx); err != nil { return err } } @@ -141,8 +141,8 @@ func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyC } } -func loadImageData(rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) error { - imageData, err := fetchImageData(rclient, logger, entry, ctx) +func loadImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error { + imageData, err := fetchImageData(ctx, rclient, logger, entry, enginectx) if err != nil { return err } @@ -150,14 +150,14 @@ func loadImageData(rclient registryclient.Client, logger logr.Logger, entry kyve if err != nil { return err } - if err := ctx.jsonContext.AddContextEntry(entry.Name, jsonBytes); err != nil { + if err := enginectx.jsonContext.AddContextEntry(entry.Name, jsonBytes); err != nil { return fmt.Errorf("failed to add resource data to context: contextEntry: %v, error: %v", entry, err) } return nil } -func fetchImageData(rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) (interface{}, error) { - ref, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.ImageRegistry.Reference) +func fetchImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) (interface{}, error) { + ref, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ImageRegistry.Reference) if err != nil { return nil, fmt.Errorf("ailed to substitute variables in context entry %s %s: %v", entry.Name, entry.ImageRegistry.Reference, err) } @@ -165,11 +165,11 @@ func fetchImageData(rclient registryclient.Client, logger logr.Logger, entry kyv if !ok { return nil, fmt.Errorf("invalid image reference %s, image reference must be a string", ref) } - path, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.ImageRegistry.JMESPath) + path, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ImageRegistry.JMESPath) if err != nil { return nil, fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.ImageRegistry.JMESPath, err) } - imageData, err := fetchImageDataMap(rclient, refString) + imageData, err := fetchImageDataMap(ctx, rclient, refString) if err != nil { return nil, err } @@ -183,8 +183,8 @@ func fetchImageData(rclient registryclient.Client, logger logr.Logger, entry kyv } // FetchImageDataMap fetches image information from the remote registry. -func fetchImageDataMap(rclient registryclient.Client, ref string) (interface{}, error) { - desc, err := rclient.FetchImageDescriptor(context.TODO(), ref) +func fetchImageDataMap(ctx context.Context, rclient registryclient.Client, ref string) (interface{}, error) { + desc, err := rclient.FetchImageDescriptor(ctx, ref) if err != nil { return nil, err } @@ -237,14 +237,14 @@ func fetchImageDataMap(rclient registryclient.Client, ref string) (interface{}, return untyped, nil } -func loadAPIData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) error { - jsonData, err := fetchAPIData(logger, entry, ctx) +func loadAPIData(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error { + jsonData, err := fetchAPIData(ctx, logger, entry, enginectx) if err != nil { return err } if entry.APICall.JMESPath == "" { - err = ctx.jsonContext.AddContextEntry(entry.Name, jsonData) + err = enginectx.jsonContext.AddContextEntry(entry.Name, jsonData) if err != nil { return fmt.Errorf("failed to add resource data to context: contextEntry: %v, error: %v", entry, err) } @@ -252,7 +252,7 @@ func loadAPIData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCo return nil } - path, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.APICall.JMESPath) + path, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.APICall.JMESPath) if err != nil { return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.APICall.JMESPath, err) } @@ -267,7 +267,7 @@ func loadAPIData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCo return fmt.Errorf("failed to marshall data %v for context entry %v: %v", contextData, entry, err) } - err = ctx.jsonContext.AddContextEntry(entry.Name, contextData) + err = enginectx.jsonContext.AddContextEntry(entry.Name, contextData) if err != nil { return fmt.Errorf("failed to add JMESPath (%s) results to context, error: %v", entry.APICall.JMESPath, err) } @@ -294,19 +294,19 @@ func applyJMESPathJSON(jmesPath string, jsonData []byte) (interface{}, error) { return applyJMESPath(jmesPath, data) } -func fetchAPIData(log logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) ([]byte, error) { +func fetchAPIData(ctx context.Context, log logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) ([]byte, error) { if entry.APICall == nil { return nil, fmt.Errorf("missing APICall in context entry %s %v", entry.Name, entry.APICall) } - path, err := variables.SubstituteAll(log, ctx.jsonContext, entry.APICall.URLPath) + path, err := variables.SubstituteAll(log, enginectx.jsonContext, entry.APICall.URLPath) if err != nil { return nil, fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.APICall.URLPath, err) } pathStr := path.(string) - jsonData, err := getResource(ctx, pathStr) + jsonData, err := getResource(ctx, enginectx, pathStr) if err != nil { return nil, fmt.Errorf("failed to get resource with raw url\n: %s: %v", pathStr, err) } @@ -314,17 +314,17 @@ func fetchAPIData(log logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCont return jsonData, nil } -func getResource(ctx *PolicyContext, p string) ([]byte, error) { - return ctx.client.RawAbsPath(context.TODO(), p) +func getResource(ctx context.Context, enginectx *PolicyContext, p string) ([]byte, error) { + return enginectx.client.RawAbsPath(ctx, p) } -func loadConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) error { - data, err := fetchConfigMap(logger, entry, ctx) +func loadConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error { + data, err := fetchConfigMap(ctx, logger, entry, enginectx) if err != nil { return fmt.Errorf("failed to retrieve config map for context entry %s: %v", entry.Name, err) } - err = ctx.jsonContext.AddContextEntry(entry.Name, data) + err = enginectx.jsonContext.AddContextEntry(entry.Name, data) if err != nil { return fmt.Errorf("failed to add config map for context entry %s: %v", entry.Name, err) } @@ -332,15 +332,15 @@ func loadConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Policy return nil } -func fetchConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) ([]byte, error) { +func fetchConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) ([]byte, error) { contextData := make(map[string]interface{}) - name, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.ConfigMap.Name) + name, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ConfigMap.Name) if err != nil { return nil, fmt.Errorf("failed to substitute variables in context %s configMap.name %s: %v", entry.Name, entry.ConfigMap.Name, err) } - namespace, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.ConfigMap.Namespace) + namespace, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ConfigMap.Namespace) if err != nil { return nil, fmt.Errorf("failed to substitute variables in context %s configMap.namespace %s: %v", entry.Name, entry.ConfigMap.Namespace, err) } @@ -349,7 +349,7 @@ func fetchConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Polic namespace = "default" } - obj, err := ctx.informerCacheResolvers.Get(context.TODO(), namespace.(string), name.(string)) + obj, err := enginectx.informerCacheResolvers.Get(ctx, namespace.(string), name.(string)) if err != nil { return nil, fmt.Errorf("failed to get configmap %s/%s : %v", namespace, name, err) } diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 6f94dbbfc0..e8e2c3cc2f 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -1,6 +1,7 @@ package engine import ( + "context" "fmt" "reflect" "time" @@ -18,14 +19,14 @@ import ( ) // Mutate performs mutation. Overlay first and then mutation patches -func Mutate(rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) { +func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) { startTime := time.Now() policy := policyContext.policy resp = &response.EngineResponse{ Policy: policy, } matchedResource := policyContext.newResource - ctx := policyContext.jsonContext + enginectx := policyContext.jsonContext var skippedRules []string logger := logging.WithName("EngineMutate").WithValues("policy", policy.GetName(), "kind", matchedResource.GetKind(), @@ -63,14 +64,14 @@ func Mutate(rclient registryclient.Client, policyContext *PolicyContext) (resp * resource, err := policyContext.jsonContext.Query("request.object") policyContext.jsonContext.Reset() if err == nil && resource != nil { - if err := ctx.AddResource(resource.(map[string]interface{})); err != nil { + if err := enginectx.AddResource(resource.(map[string]interface{})); err != nil { logger.Error(err, "unable to update resource object") } } else { logger.Error(err, "failed to query resource object") } - if err := LoadContext(logger, rclient, rule.Context, policyContext, rule.Name); err != nil { + if err := LoadContext(ctx, logger, rclient, rule.Context, policyContext, rule.Name); err != nil { if _, ok := err.(gojmespath.NotFoundError); ok { logger.V(3).Info("failed to load context", "reason", err.Error()) } else { @@ -109,7 +110,7 @@ func Mutate(rclient registryclient.Client, policyContext *PolicyContext) (resp * logger.V(4).Info("apply rule to resource", "rule", rule.Name, "resource namespace", patchedResource.GetNamespace(), "resource name", patchedResource.GetName()) var ruleResp *response.RuleResponse if rule.Mutation.ForEachMutation != nil { - ruleResp, patchedResource = mutateForEach(rclient, ruleCopy, policyContext, patchedResource, logger) + ruleResp, patchedResource = mutateForEach(ctx, rclient, ruleCopy, policyContext, patchedResource, logger) } else { ruleResp, patchedResource = mutateResource(ruleCopy, policyContext, patchedResource, logger) } @@ -159,7 +160,7 @@ func mutateResource(rule *kyvernov1.Rule, ctx *PolicyContext, resource unstructu return ruleResp, mutateResp.PatchedResource } -func mutateForEach(rclient registryclient.Client, rule *kyvernov1.Rule, ctx *PolicyContext, resource unstructured.Unstructured, logger logr.Logger) (*response.RuleResponse, unstructured.Unstructured) { +func mutateForEach(ctx context.Context, rclient registryclient.Client, rule *kyvernov1.Rule, enginectx *PolicyContext, resource unstructured.Unstructured, logger logr.Logger) (*response.RuleResponse, unstructured.Unstructured) { foreachList := rule.Mutation.ForEachMutation if foreachList == nil { return nil, resource @@ -170,12 +171,12 @@ func mutateForEach(rclient registryclient.Client, rule *kyvernov1.Rule, ctx *Pol allPatches := make([][]byte, 0) for _, foreach := range foreachList { - if err := LoadContext(logger, rclient, rule.Context, ctx, rule.Name); err != nil { + if err := LoadContext(ctx, logger, rclient, rule.Context, enginectx, rule.Name); err != nil { logger.Error(err, "failed to load context") return ruleError(rule, response.Mutation, "failed to load context", err), resource } - preconditionsPassed, err := checkPreconditions(logger, ctx, rule.GetAnyAllConditions()) + preconditionsPassed, err := checkPreconditions(logger, enginectx, rule.GetAnyAllConditions()) if err != nil { return ruleError(rule, response.Mutation, "failed to evaluate preconditions", err), resource } @@ -184,13 +185,13 @@ func mutateForEach(rclient registryclient.Client, rule *kyvernov1.Rule, ctx *Pol return ruleResponse(*rule, response.Mutation, "preconditions not met", response.RuleStatusSkip, &patchedResource), resource } - elements, err := evaluateList(foreach.List, ctx.jsonContext) + elements, err := evaluateList(foreach.List, enginectx.jsonContext) if err != nil { msg := fmt.Sprintf("failed to evaluate list %s", foreach.List) return ruleError(rule, response.Mutation, msg, err), resource } - mutateResp := mutateElements(rclient, rule.Name, foreach, ctx, elements, patchedResource, logger) + mutateResp := mutateElements(ctx, rclient, rule.Name, foreach, enginectx, elements, patchedResource, logger) if mutateResp.Status == response.RuleStatusError { logger.Error(err, "failed to mutate elements") return buildRuleResponse(rule, mutateResp, nil), resource @@ -214,9 +215,9 @@ func mutateForEach(rclient registryclient.Client, rule *kyvernov1.Rule, ctx *Pol return r, patchedResource } -func mutateElements(rclient registryclient.Client, name string, foreach kyvernov1.ForEachMutation, ctx *PolicyContext, elements []interface{}, resource unstructured.Unstructured, logger logr.Logger) *mutate.Response { - ctx.jsonContext.Checkpoint() - defer ctx.jsonContext.Restore() +func mutateElements(ctx context.Context, rclient registryclient.Client, name string, foreach kyvernov1.ForEachMutation, enginectx *PolicyContext, elements []interface{}, resource unstructured.Unstructured, logger logr.Logger) *mutate.Response { + enginectx.jsonContext.Checkpoint() + defer enginectx.jsonContext.Restore() patchedResource := resource var allPatches [][]byte @@ -228,19 +229,19 @@ func mutateElements(rclient registryclient.Client, name string, foreach kyvernov if e == nil { continue } - ctx.jsonContext.Reset() - ctx := ctx.Copy() + enginectx.jsonContext.Reset() + enginectx := enginectx.Copy() store.SetForeachElement(i) falseVar := false - if err := addElementToContext(ctx, e, i, &falseVar); err != nil { + if err := addElementToContext(enginectx, e, i, &falseVar); err != nil { return mutateError(err, fmt.Sprintf("failed to add element to mutate.foreach[%d].context", i)) } - if err := LoadContext(logger, rclient, foreach.Context, ctx, name); err != nil { + if err := LoadContext(ctx, logger, rclient, foreach.Context, enginectx, name); err != nil { return mutateError(err, fmt.Sprintf("failed to load to mutate.foreach[%d].context", i)) } - preconditionsPassed, err := checkPreconditions(logger, ctx, foreach.AnyAllConditions) + preconditionsPassed, err := checkPreconditions(logger, enginectx, foreach.AnyAllConditions) if err != nil { return mutateError(err, fmt.Sprintf("failed to evaluate mutate.foreach[%d].preconditions", i)) } @@ -250,7 +251,7 @@ func mutateElements(rclient registryclient.Client, name string, foreach kyvernov continue } - mutateResp := mutate.ForEach(name, foreach, ctx.jsonContext, patchedResource, logger) + mutateResp := mutate.ForEach(name, foreach, enginectx.jsonContext, patchedResource, logger) if mutateResp.Status == response.RuleStatusFail || mutateResp.Status == response.RuleStatusError { return mutateResp } diff --git a/pkg/engine/mutation_test.go b/pkg/engine/mutation_test.go index ec39af0517..454b0d34c0 100644 --- a/pkg/engine/mutation_test.go +++ b/pkg/engine/mutation_test.go @@ -94,7 +94,7 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) { policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) t.Log(string(expectedPatch)) assert.Equal(t, len(er.PolicyResponse.Rules), 1) @@ -167,7 +167,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) { policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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")) } @@ -264,7 +264,7 @@ func Test_variableSubstitutionCLI(t *testing.T) { newResource: *resourceUnstructured, } - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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)) @@ -373,7 +373,7 @@ func Test_chained_rules(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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") @@ -461,7 +461,7 @@ func Test_precondition(t *testing.T) { newResource: *resourceUnstructured, } - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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]) { @@ -558,7 +558,7 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) { newResource: *resourceUnstructured, } - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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]) { @@ -652,7 +652,7 @@ func Test_foreach(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -759,7 +759,7 @@ func Test_foreach_element_mutation(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -885,7 +885,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -1012,7 +1012,7 @@ func Test_foreach_order_mutation_(t *testing.T) { err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx) assert.NilError(t, err) - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusPass) @@ -1458,7 +1458,7 @@ func Test_mutate_existing_resources(t *testing.T) { newResource: *trigger, } } - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) for _, rr := range er.PolicyResponse.Rules { for i, p := range rr.Patches { @@ -1566,7 +1566,7 @@ func Test_RuleSelectorMutate(t *testing.T) { newResource: *resourceUnstructured, } - er := Mutate(registryclient.NewOrDie(), policyContext) + er := Mutate(context.TODO(), 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) @@ -1581,7 +1581,7 @@ func Test_RuleSelectorMutate(t *testing.T) { applyOne := kyverno.ApplyOne policyContext.policy.GetSpec().ApplyRules = &applyOne - er = Mutate(registryclient.NewOrDie(), policyContext) + er = Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1) @@ -1948,7 +1948,7 @@ func Test_SpecialCharacters(t *testing.T) { } // Mutate and make sure that we got the expected amount of rules. - patches := Mutate(registryclient.NewOrDie(), policyContext).GetPatches() + patches := Mutate(context.TODO(), 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/validation.go b/pkg/engine/validation.go index c2902c2ec8..2d857b02a0 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -1,6 +1,7 @@ package engine import ( + "context" "encoding/json" "fmt" "reflect" @@ -13,7 +14,7 @@ import ( "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store" "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/engine/common" - "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/validate" "github.com/kyverno/kyverno/pkg/engine/variables" @@ -31,7 +32,7 @@ import ( ) // Validate applies validation rules from policy on the resource -func Validate(rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) { +func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext) (resp *response.EngineResponse) { resp = &response.EngineResponse{} startTime := time.Now() @@ -42,7 +43,7 @@ func Validate(rclient registryclient.Client, policyContext *PolicyContext) (resp logger.V(4).Info("finished policy processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount) }() - resp = validateResource(logger, rclient, policyContext) + resp = validateResource(ctx, logger, rclient, policyContext) return } @@ -89,22 +90,22 @@ func buildResponse(ctx *PolicyContext, resp *response.EngineResponse, startTime resp.PolicyResponse.PolicyExecutionTimestamp = startTime.Unix() } -func validateResource(log logr.Logger, rclient registryclient.Client, ctx *PolicyContext) *response.EngineResponse { +func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext) *response.EngineResponse { resp := &response.EngineResponse{} - ctx.jsonContext.Checkpoint() - defer ctx.jsonContext.Restore() + enginectx.jsonContext.Checkpoint() + defer enginectx.jsonContext.Restore() - rules := autogen.ComputeRules(ctx.policy) + rules := autogen.ComputeRules(enginectx.policy) matchCount := 0 - applyRules := ctx.policy.GetSpec().GetApplyRules() + applyRules := enginectx.policy.GetSpec().GetApplyRules() - if ctx.policy.IsNamespaced() { - polNs := ctx.policy.GetNamespace() - if ctx.newResource.Object != nil && (ctx.newResource.GetNamespace() != polNs || ctx.newResource.GetNamespace() == "") { + if enginectx.policy.IsNamespaced() { + polNs := enginectx.policy.GetNamespace() + if enginectx.newResource.Object != nil && (enginectx.newResource.GetNamespace() != polNs || enginectx.newResource.GetNamespace() == "") { return resp } - if ctx.oldResource.Object != nil && (ctx.oldResource.GetNamespace() != polNs || ctx.oldResource.GetNamespace() == "") { + if enginectx.oldResource.Object != nil && (enginectx.oldResource.GetNamespace() != polNs || enginectx.oldResource.GetNamespace() == "") { return resp } } @@ -119,21 +120,21 @@ func validateResource(log logr.Logger, rclient registryclient.Client, ctx *Polic } log = log.WithValues("rule", rule.Name) - if !matches(log, rule, ctx) { + if !matches(log, rule, enginectx) { continue } log.V(3).Info("processing validation rule", "matchCount", matchCount, "applyRules", applyRules) - ctx.jsonContext.Reset() + enginectx.jsonContext.Reset() startTime := time.Now() var ruleResp *response.RuleResponse if hasValidate && !hasYAMLSignatureVerify { - ruleResp = processValidationRule(log, rclient, ctx, rule) + ruleResp = processValidationRule(ctx, log, rclient, enginectx, rule) } else if hasValidateImage { - ruleResp = processImageValidationRule(log, rclient, ctx, rule) + ruleResp = processImageValidationRule(ctx, log, rclient, enginectx, rule) } else if hasYAMLSignatureVerify { - ruleResp = processYAMLValidationRule(log, ctx, rule) + ruleResp = processYAMLValidationRule(log, enginectx, rule) } if ruleResp != nil { @@ -147,29 +148,29 @@ func validateResource(log logr.Logger, rclient registryclient.Client, ctx *Polic return resp } -func validateOldObject(log logr.Logger, rclient registryclient.Client, ctx *PolicyContext, rule *kyvernov1.Rule) (*response.RuleResponse, error) { - ctxCopy := ctx.Copy() +func validateOldObject(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule) (*response.RuleResponse, error) { + ctxCopy := enginectx.Copy() ctxCopy.newResource = *ctxCopy.oldResource.DeepCopy() ctxCopy.oldResource = unstructured.Unstructured{} - if err := context.ReplaceResource(ctxCopy.jsonContext, ctxCopy.newResource.Object); err != nil { + if err := enginecontext.ReplaceResource(ctxCopy.jsonContext, ctxCopy.newResource.Object); err != nil { return nil, errors.Wrapf(err, "failed to replace object in the JSON context") } - if err := context.ReplaceOldResource(ctxCopy.jsonContext, ctxCopy.oldResource.Object); err != nil { + if err := enginecontext.ReplaceOldResource(ctxCopy.jsonContext, ctxCopy.oldResource.Object); err != nil { return nil, errors.Wrapf(err, "failed to replace old object in the JSON context") } - return processValidationRule(log, rclient, ctxCopy, rule), nil + return processValidationRule(ctx, log, rclient, ctxCopy, rule), nil } -func processValidationRule(log logr.Logger, rclient registryclient.Client, ctx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse { - v := newValidator(log, rclient, ctx, rule) +func processValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule) *response.RuleResponse { + v := newValidator(log, rclient, enginectx, rule) if rule.Validation.ForEachValidation != nil { - return v.validateForEach() + return v.validateForEach(ctx) } - return v.validate() + return v.validate(ctx) } func addRuleResponse(log logr.Logger, resp *response.EngineResponse, ruleResp *response.RuleResponse, startTime time.Time) { @@ -235,8 +236,8 @@ func newForeachValidator(log logr.Logger, rclient registryclient.Client, foreach } } -func (v *validator) validate() *response.RuleResponse { - if err := v.loadContext(); err != nil { +func (v *validator) validate(ctx context.Context) *response.RuleResponse { + if err := v.loadContext(ctx); err != nil { return ruleError(v.rule, response.Validation, "failed to load context", err) } @@ -260,7 +261,7 @@ func (v *validator) validate() *response.RuleResponse { ruleResponse := v.validateResourceWithRule() if isUpdateRequest(v.ctx) { - priorResp, err := validateOldObject(v.log, v.rclient, v.ctx, v.rule) + priorResp, err := validateOldObject(ctx, v.log, v.rclient, v.ctx, v.rule) if err != nil { return ruleError(v.rule, response.Validation, "failed to validate old object", err) } @@ -285,8 +286,8 @@ func (v *validator) validate() *response.RuleResponse { return nil } -func (v *validator) validateForEach() *response.RuleResponse { - if err := v.loadContext(); err != nil { +func (v *validator) validateForEach(ctx context.Context) *response.RuleResponse { + if err := v.loadContext(ctx); err != nil { return ruleError(v.rule, response.Validation, "failed to load context", err) } @@ -309,7 +310,7 @@ func (v *validator) validateForEach() *response.RuleResponse { v.log.V(2).Info("failed to evaluate list", "list", foreach.List, "error", err.Error()) continue } - resp, count := v.validateElements(foreach, elements, foreach.ElementScope) + resp, count := v.validateElements(ctx, foreach, elements, foreach.ElementScope) if resp.Status != response.RuleStatusPass { return resp } @@ -324,7 +325,7 @@ func (v *validator) validateForEach() *response.RuleResponse { return ruleResponse(*v.rule, response.Validation, "rule passed", response.RuleStatusPass, nil) } -func (v *validator) validateElements(foreach kyvernov1.ForEachValidation, elements []interface{}, elementScope *bool) (*response.RuleResponse, int) { +func (v *validator) validateElements(ctx context.Context, foreach kyvernov1.ForEachValidation, elements []interface{}, elementScope *bool) (*response.RuleResponse, int) { v.ctx.jsonContext.Checkpoint() defer v.ctx.jsonContext.Restore() applyCount := 0 @@ -336,14 +337,14 @@ func (v *validator) validateElements(foreach kyvernov1.ForEachValidation, elemen store.SetForeachElement(i) v.ctx.jsonContext.Reset() - ctx := v.ctx.Copy() - if err := addElementToContext(ctx, e, i, elementScope); err != nil { + enginectx := v.ctx.Copy() + if err := addElementToContext(enginectx, e, i, elementScope); err != nil { v.log.Error(err, "failed to add element to context") return ruleError(v.rule, response.Validation, "failed to process foreach", err), applyCount } - foreachValidator := newForeachValidator(v.log, v.rclient, foreach, v.rule, ctx) - r := foreachValidator.validate() + foreachValidator := newForeachValidator(v.log, v.rclient, foreach, v.rule, enginectx) + r := foreachValidator.validate(ctx) if r == nil { v.log.V(2).Info("skip rule due to empty result") continue @@ -401,8 +402,8 @@ func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex int, el return nil } -func (v *validator) loadContext() error { - if err := LoadContext(v.log, v.rclient, v.contextEntries, v.ctx, v.rule.Name); err != nil { +func (v *validator) loadContext(ctx context.Context) error { + if err := LoadContext(ctx, v.log, v.rclient, v.contextEntries, v.ctx, v.rule.Name); err != nil { if _, ok := err.(gojmespath.NotFoundError); ok { v.log.V(3).Info("failed to load context", "reason", err.Error()) } else { diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go index ea46946b11..99c4dacf4a 100644 --- a/pkg/engine/validation_test.go +++ b/pkg/engine/validation_test.go @@ -1,6 +1,7 @@ package engine import ( + "context" "encoding/json" "strings" "testing" @@ -8,7 +9,7 @@ import ( kyverno "github.com/kyverno/kyverno/api/kyverno/v1" urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store" - "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" "github.com/kyverno/kyverno/pkg/registryclient" @@ -132,7 +133,7 @@ func TestValidate_image_tag_fail(t *testing.T) { "validation error: imagePullPolicy 'Always' required with tag 'latest'. rule validate-latest failed at path /spec/containers/0/imagePullPolicy/", } - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) for index, r := range er.PolicyResponse.Rules { assert.Equal(t, r.Message, msgs[index]) } @@ -232,7 +233,7 @@ func TestValidate_image_tag_pass(t *testing.T) { "validation rule 'validate-tag' passed.", "validation rule 'validate-latest' passed.", } - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) for index, r := range er.PolicyResponse.Rules { assert.Equal(t, r.Message, msgs[index]) } @@ -306,7 +307,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) assert.Assert(t, !er.IsSuccessful()) msgs := []string{"validation error: A namespace is required. rule check-default-namespace[0] failed at path /metadata/namespace/ rule check-default-namespace[1] failed at path /metadata/namespace/"} @@ -389,7 +390,7 @@ func TestValidate_host_network_port(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation error: Host network and port are not allowed. rule validate-host-network-port failed at path /spec/containers/0/ports/0/hostPort/"} for index, r := range er.PolicyResponse.Rules { @@ -479,7 +480,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'validate-host-path' passed."} for index, r := range er.PolicyResponse.Rules { @@ -567,7 +568,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) { assert.NilError(t, err) resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation error: Host path '/var/lib/' is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/path/"} for index, r := range er.PolicyResponse.Rules { @@ -637,7 +638,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod rule 2' passed."} for index, r := range er.PolicyResponse.Rules { @@ -710,7 +711,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod rule 2' passed."} for index, r := range er.PolicyResponse.Rules { @@ -784,7 +785,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod rule 2' passed."} for index, r := range er.PolicyResponse.Rules { @@ -864,7 +865,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod rule 2' passed."} for index, r := range er.PolicyResponse.Rules { @@ -938,7 +939,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation error: pod: validate run as non root user. rule pod rule 2 failed at path /spec/securityContext/runAsNonRoot/"} for index, r := range er.PolicyResponse.Rules { @@ -1013,7 +1014,7 @@ func TestValidate_AnchorList_pass(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod image rule' passed."} for index, r := range er.PolicyResponse.Rules { @@ -1088,7 +1089,7 @@ func TestValidate_AnchorList_fail(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) assert.Assert(t, !er.IsSuccessful()) } @@ -1158,7 +1159,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) assert.Assert(t, !er.IsSuccessful()) } @@ -1228,7 +1229,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'pod image rule' passed."} for index, r := range er.PolicyResponse.Rules { @@ -1316,7 +1317,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation error: Host path is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/"} for index, r := range er.PolicyResponse.Rules { @@ -1403,7 +1404,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) msgs := []string{"validation rule 'validate-host-path' passed."} for index, r := range er.PolicyResponse.Rules { @@ -1471,15 +1472,15 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError) @@ -1564,15 +1565,15 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError) @@ -1625,15 +1626,15 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail) assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation error: rule not-operator-with-variable-should-alway-fail-validation failed at path /spec/content/") } @@ -1716,15 +1717,15 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, len(er.PolicyResponse.Rules), 1) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError) @@ -1809,15 +1810,15 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail) assert.Equal(t, er.PolicyResponse.Rules[0].Message, @@ -1914,15 +1915,15 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing. resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail) assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.") } @@ -1967,15 +1968,15 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(test.resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, test.resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, test.resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) for i, rule := range er.PolicyResponse.Rules { assert.Equal(t, er.PolicyResponse.Rules[i].Status, test.expectedResults[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedResults[i].String(), er.PolicyResponse.Rules[i].Status.String()) @@ -2112,7 +2113,7 @@ func executeTest(t *testing.T, test testCase) { t.Fatal(err) } - ctx := context.NewContext() + ctx := enginecontext.NewContext() err = ctx.AddRequest(request) if err != nil { t.Fatal(err) @@ -2141,7 +2142,7 @@ func executeTest(t *testing.T, test testCase) { jsonContext: ctx, } - resp := Validate(registryclient.NewOrDie(), pc) + resp := Validate(context.TODO(), registryclient.NewOrDie(), pc) if resp.IsSuccessful() && test.requestDenied { t.Errorf("Testcase has failed, policy: %v", policy.Name) } @@ -2240,7 +2241,7 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) { msgs := []string{ "restrict pod counts to be no more than 10 on node minikube", } - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) for index, r := range er.PolicyResponse.Rules { assert.Equal(t, r.Message, msgs[index]) } @@ -2322,14 +2323,14 @@ func Test_EmptyStringInDenyCondition(t *testing.T) { err := json.Unmarshal(policyRaw, &policy) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}) assert.Assert(t, !er.IsSuccessful()) } @@ -2411,14 +2412,14 @@ func Test_StringInDenyCondition(t *testing.T) { err := json.Unmarshal(policyRaw, &policy) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}) assert.Assert(t, er.IsSuccessful()) } @@ -2997,15 +2998,15 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string, resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContext := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - er := Validate(registryclient.NewOrDie(), policyContext) + er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext) assert.Equal(t, er.PolicyResponse.Rules[0].Status, status) if msg != "" { @@ -3061,15 +3062,15 @@ func Test_delete_ignore_pattern(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw) assert.NilError(t, err) - ctx := context.NewContext() - err = context.AddResource(ctx, resourceRaw) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, resourceRaw) assert.NilError(t, err) policyContextCreate := &PolicyContext{ policy: &policy, jsonContext: ctx, newResource: *resourceUnstructured} - engineResponseCreate := Validate(registryclient.NewOrDie(), policyContextCreate) + engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate) assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1) assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, response.RuleStatusFail) @@ -3077,7 +3078,7 @@ func Test_delete_ignore_pattern(t *testing.T) { policy: &policy, jsonContext: ctx, oldResource: *resourceUnstructured} - engineResponseDelete := Validate(registryclient.NewOrDie(), policyContextDelete) + engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete) assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0) } @@ -3136,7 +3137,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) { resourceUnstructured, err := utils.ConvertToUnstructured(tc.rawResource) assert.NilError(t, err) - er := Validate(registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()}) + er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}) if tc.expectedFailed { assert.Assert(t, er.IsFailed()) } else if tc.expectedSkipped { diff --git a/pkg/policy/apply.go b/pkg/policy/apply.go index 346f173a9d..e898329eb8 100644 --- a/pkg/policy/apply.go +++ b/pkg/policy/apply.go @@ -1,6 +1,7 @@ package policy import ( + "context" "fmt" "reflect" "strings" @@ -11,7 +12,7 @@ import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/clients/dclient" "github.com/kyverno/kyverno/pkg/engine" - "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/registryclient" jsonutils "github.com/kyverno/kyverno/pkg/utils/json" @@ -43,8 +44,8 @@ func applyPolicy( var engineResponseMutation, engineResponseValidation *response.EngineResponse var err error - ctx := context.NewContext() - err = context.AddResource(ctx, transformResource(resource)) + ctx := enginecontext.NewContext() + err = enginecontext.AddResource(ctx, transformResource(resource)) if err != nil { logger.Error(err, "failed to add transform resource to ctx") } @@ -74,7 +75,7 @@ func applyPolicy( WithClient(client). WithExcludeGroupRole(excludeGroupRole...) - engineResponseValidation = engine.Validate(rclient, policyCtx) + engineResponseValidation = engine.Validate(context.TODO(), rclient, policyCtx) engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation)) return engineResponses @@ -84,7 +85,7 @@ func mutation( policy kyvernov1.PolicyInterface, resource unstructured.Unstructured, log logr.Logger, - jsonContext context.Interface, + jsonContext enginecontext.Interface, rclient registryclient.Client, namespaceLabels map[string]string, ) (*response.EngineResponse, error) { @@ -93,7 +94,7 @@ func mutation( WithNamespaceLabels(namespaceLabels). WithNewResource(resource) - engineResponse := engine.Mutate(rclient, policyContext) + engineResponse := engine.Mutate(context.TODO(), rclient, policyContext) if !engineResponse.IsSuccessful() { log.V(4).Info("failed to apply mutation rules; reporting them") return engineResponse, nil diff --git a/pkg/testrunner/scenario.go b/pkg/testrunner/scenario.go index 22e442b6e8..41ae1222bc 100644 --- a/pkg/testrunner/scenario.go +++ b/pkg/testrunner/scenario.go @@ -146,7 +146,7 @@ func runTestCase(t *testing.T, tc TestCase) bool { policyContext := engine.NewPolicyContext().WithPolicy(policy).WithNewResource(*resource) - er := engine.Mutate(registryclient.NewOrDie(), policyContext) + er := engine.Mutate(context.TODO(), registryclient.NewOrDie(), policyContext) t.Log("---Mutation---") validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource) validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse) @@ -158,7 +158,7 @@ func runTestCase(t *testing.T, tc TestCase) bool { policyContext = policyContext.WithNewResource(*resource) - er = engine.Validate(registryclient.NewOrDie(), policyContext) + er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext) t.Log("---Validation---") validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse) diff --git a/pkg/webhooks/resource/generation/generation.go b/pkg/webhooks/resource/generation/generation.go index 215f774ba0..4eeae428f9 100644 --- a/pkg/webhooks/resource/generation/generation.go +++ b/pkg/webhooks/resource/generation/generation.go @@ -32,14 +32,8 @@ import ( type GenerationHandler interface { // TODO: why do we need to expose that ? - HandleUpdatesForGenerateRules(*admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface) - Handle( - metrics.MetricsConfigManager, - *admissionv1.AdmissionRequest, - []kyvernov1.PolicyInterface, - *engine.PolicyContext, - time.Time, - ) + HandleUpdatesForGenerateRules(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface) + Handle(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext, time.Time) } func NewGenerationHandler( @@ -52,6 +46,7 @@ func NewGenerationHandler( urGenerator webhookgenerate.Generator, urUpdater webhookutils.UpdateRequestUpdater, eventGen event.Interface, + metrics metrics.MetricsConfigManager, ) GenerationHandler { return &generationHandler{ log: log, @@ -63,6 +58,7 @@ func NewGenerationHandler( urGenerator: urGenerator, urUpdater: urUpdater, eventGen: eventGen, + metrics: metrics, } } @@ -76,11 +72,12 @@ type generationHandler struct { urGenerator webhookgenerate.Generator urUpdater webhookutils.UpdateRequestUpdater eventGen event.Interface + metrics metrics.MetricsConfigManager } // Handle handles admission-requests for policies with generate rules func (h *generationHandler) Handle( - metricsConfig metrics.MetricsConfigManager, + ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, @@ -99,7 +96,7 @@ func (h *generationHandler) Handle( engineResponse := engine.ApplyBackgroundChecks(h.rclient, policyContext) for _, rule := range engineResponse.PolicyResponse.Rules { if rule.Status != response.RuleStatusPass { - h.deleteGR(engineResponse) + h.deleteGR(ctx, engineResponse) continue } rules = append(rules, rule) @@ -112,12 +109,12 @@ func (h *generationHandler) Handle( } // registering the kyverno_policy_results_total metric concurrently - go webhookutils.RegisterPolicyResultsMetricGeneration(context.TODO(), h.log, metricsConfig, string(request.Operation), policy, *engineResponse) + go webhookutils.RegisterPolicyResultsMetricGeneration(context.TODO(), h.log, h.metrics, string(request.Operation), policy, *engineResponse) // registering the kyverno_policy_execution_duration_seconds metric concurrently - go webhookutils.RegisterPolicyExecutionDurationMetricGenerate(context.TODO(), h.log, metricsConfig, string(request.Operation), policy, *engineResponse) + go webhookutils.RegisterPolicyExecutionDurationMetricGenerate(context.TODO(), h.log, h.metrics, string(request.Operation), policy, *engineResponse) } - if failedResponse := applyUpdateRequest(request, kyvernov1beta1.Generate, h.urGenerator, policyContext.AdmissionInfo(), request.Operation, engineResponses...); failedResponse != nil { + if failedResponse := applyUpdateRequest(ctx, request, kyvernov1beta1.Generate, h.urGenerator, policyContext.AdmissionInfo(), request.Operation, engineResponses...); failedResponse != nil { // report failure event for _, failedUR := range failedResponse { err := fmt.Errorf("failed to create Update Request: %v", failedUR.err) @@ -129,12 +126,12 @@ func (h *generationHandler) Handle( } if request.Operation == admissionv1.Update { - h.HandleUpdatesForGenerateRules(request, policies) + h.HandleUpdatesForGenerateRules(ctx, request, policies) } } // HandleUpdatesForGenerateRules handles admission-requests for update -func (h *generationHandler) HandleUpdatesForGenerateRules(request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface) { +func (h *generationHandler) HandleUpdatesForGenerateRules(ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface) { if request.Operation != admissionv1.Update { return } @@ -146,20 +143,20 @@ func (h *generationHandler) HandleUpdatesForGenerateRules(request *admissionv1.A resLabels := resource.GetLabels() if resLabels["generate.kyverno.io/clone-policy-name"] != "" { - h.handleUpdateGenerateSourceResource(resLabels) + h.handleUpdateGenerateSourceResource(ctx, resLabels) } if resLabels[kyvernov1.LabelAppManagedBy] == kyvernov1.ValueKyvernoApp && resLabels["policy.kyverno.io/synchronize"] == "enable" && request.Operation == admissionv1.Update { - h.handleUpdateGenerateTargetResource(request, policies, resLabels) + h.handleUpdateGenerateTargetResource(ctx, request, policies, resLabels) } } // handleUpdateGenerateSourceResource - handles update of clone source for generate policy -func (h *generationHandler) handleUpdateGenerateSourceResource(resLabels map[string]string) { +func (h *generationHandler) handleUpdateGenerateSourceResource(ctx context.Context, resLabels map[string]string) { policyNames := strings.Split(resLabels["generate.kyverno.io/clone-policy-name"], ",") for _, policyName := range policyNames { // check if the policy exists - _, err := h.kyvernoClient.KyvernoV1().ClusterPolicies().Get(context.TODO(), policyName, metav1.GetOptions{}) + _, err := h.kyvernoClient.KyvernoV1().ClusterPolicies().Get(ctx, policyName, metav1.GetOptions{}) if err != nil { if strings.Contains(err.Error(), "not found") { h.log.V(4).Info("skipping update of update request as policy is deleted") @@ -185,7 +182,7 @@ func (h *generationHandler) handleUpdateGenerateSourceResource(resLabels map[str } // handleUpdateGenerateTargetResource - handles update of target resource for generate policy -func (h *generationHandler) handleUpdateGenerateTargetResource(request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, resLabels map[string]string) { +func (h *generationHandler) handleUpdateGenerateTargetResource(ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, resLabels map[string]string) { enqueueBool := false newRes, err := enginutils.ConvertToUnstructured(request.Object.Raw) if err != nil { @@ -196,7 +193,7 @@ func (h *generationHandler) handleUpdateGenerateTargetResource(request *admissio targetSourceName := newRes.GetName() targetSourceKind := newRes.GetKind() - policy, err := h.kyvernoClient.KyvernoV1().ClusterPolicies().Get(context.TODO(), policyName, metav1.GetOptions{}) + policy, err := h.kyvernoClient.KyvernoV1().ClusterPolicies().Get(ctx, policyName, metav1.GetOptions{}) if err != nil { h.log.Error(err, "failed to get policy from kyverno client.", "policy name", policyName) return @@ -204,7 +201,7 @@ func (h *generationHandler) handleUpdateGenerateTargetResource(request *admissio for _, rule := range autogen.ComputeRules(policy) { if rule.Generation.Kind == targetSourceKind && rule.Generation.Name == targetSourceName { - updatedRule, err := getGeneratedByResource(newRes, resLabels, h.client, rule, h.log) + updatedRule, err := getGeneratedByResource(ctx, newRes, resLabels, h.client, rule, h.log) if err != nil { h.log.V(4).Info("skipping generate policy and resource pattern validaton", "error", err) } else { @@ -218,7 +215,7 @@ func (h *generationHandler) handleUpdateGenerateTargetResource(request *admissio cloneName := updatedRule.Generation.Clone.Name if cloneName != "" { - obj, err := h.client.GetResource(context.TODO(), "", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name) + obj, err := h.client.GetResource(ctx, "", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name) if err != nil { h.log.Error(err, fmt.Sprintf("source resource %s/%s/%s not found.", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name)) continue @@ -246,7 +243,7 @@ func (h *generationHandler) handleUpdateGenerateTargetResource(request *admissio } } -func (h *generationHandler) deleteGR(engineResponse *response.EngineResponse) { +func (h *generationHandler) deleteGR(ctx context.Context, engineResponse *response.EngineResponse) { h.log.V(4).Info("querying all update requests") selector := labels.SelectorFromSet(labels.Set(map[string]string{ kyvernov1beta1.URGeneratePolicyLabel: engineResponse.PolicyResponse.Policy.Name, @@ -262,7 +259,7 @@ func (h *generationHandler) deleteGR(engineResponse *response.EngineResponse) { } for _, v := range urList { - err := h.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), v.GetName(), metav1.DeleteOptions{}) + err := h.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(ctx, v.GetName(), metav1.DeleteOptions{}) if err != nil { h.log.Error(err, "failed to update ur") } diff --git a/pkg/webhooks/resource/generation/utils.go b/pkg/webhooks/resource/generation/utils.go index b4b6622149..411c6aa801 100644 --- a/pkg/webhooks/resource/generation/utils.go +++ b/pkg/webhooks/resource/generation/utils.go @@ -9,7 +9,7 @@ import ( kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" "github.com/kyverno/kyverno/pkg/clients/dclient" - enginectx "github.com/kyverno/kyverno/pkg/engine/context" + enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/variables" "github.com/kyverno/kyverno/pkg/webhooks/updaterequest" @@ -17,7 +17,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -func getGeneratedByResource(newRes *unstructured.Unstructured, resLabels map[string]string, client dclient.Interface, rule kyvernov1.Rule, logger logr.Logger) (kyvernov1.Rule, error) { +func getGeneratedByResource(ctx context.Context, newRes *unstructured.Unstructured, resLabels map[string]string, client dclient.Interface, rule kyvernov1.Rule, logger logr.Logger) (kyvernov1.Rule, error) { var apiVersion, kind, name, namespace string sourceRequest := &admissionv1.AdmissionRequest{} kind = resLabels["kyverno.io/generated-by-kind"] @@ -25,7 +25,7 @@ func getGeneratedByResource(newRes *unstructured.Unstructured, resLabels map[str if kind != "Namespace" { namespace = resLabels["kyverno.io/generated-by-namespace"] } - obj, err := client.GetResource(context.TODO(), apiVersion, kind, namespace, name) + obj, err := client.GetResource(ctx, apiVersion, kind, namespace, name) if err != nil { logger.Error(err, "source resource not found.") return rule, err @@ -37,12 +37,12 @@ func getGeneratedByResource(newRes *unstructured.Unstructured, resLabels map[str } sourceRequest.Object.Raw = rawObj sourceRequest.Operation = "CREATE" - ctx := enginectx.NewContext() - if err := ctx.AddRequest(sourceRequest); err != nil { + enginectx := enginecontext.NewContext() + if err := enginectx.AddRequest(sourceRequest); err != nil { logger.Error(err, "failed to load incoming request in context") return rule, err } - if rule, err = variables.SubstituteAllInRule(logger, ctx, rule); err != nil { + if rule, err = variables.SubstituteAllInRule(logger, enginectx, rule); err != nil { logger.Error(err, "variable substitution failed for rule %s", rule.Name) return rule, err } @@ -115,8 +115,14 @@ type updateRequestResponse struct { err error } -func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Generator, userRequestInfo kyvernov1beta1.RequestInfo, - action admissionv1.Operation, engineResponses ...*response.EngineResponse, +func applyUpdateRequest( + ctx context.Context, + request *admissionv1.AdmissionRequest, + ruleType kyvernov1beta1.RequestType, + grGenerator updaterequest.Generator, + userRequestInfo kyvernov1beta1.RequestInfo, + action admissionv1.Operation, + engineResponses ...*response.EngineResponse, ) (failedUpdateRequest []updateRequestResponse) { admissionRequestInfo := kyvernov1beta1.AdmissionRequestInfoObject{ AdmissionRequest: request, @@ -125,7 +131,7 @@ func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov for _, er := range engineResponses { ur := transform(admissionRequestInfo, userRequestInfo, er, ruleType) - if err := grGenerator.Apply(ur, action); err != nil { + if err := grGenerator.Apply(ctx, ur, action); err != nil { failedUpdateRequest = append(failedUpdateRequest, updateRequestResponse{ur: ur, err: err}) } } diff --git a/pkg/webhooks/resource/handlers.go b/pkg/webhooks/resource/handlers.go index 627e318430..59404f7f44 100644 --- a/pkg/webhooks/resource/handlers.go +++ b/pkg/webhooks/resource/handlers.go @@ -117,8 +117,8 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad } if len(generatePolicies) == 0 && request.Operation == admissionv1.Update { // handle generate source resource updates - gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen) - go gh.HandleUpdatesForGenerateRules(request, []kyvernov1.PolicyInterface{}) + gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig) + go gh.HandleUpdatesForGenerateRules(context.TODO(), request, []kyvernov1.PolicyInterface{}) } logger.V(4).Info("processing policies for validate admission request", "validate", len(policies), "mutate", len(mutatePolicies), "generate", len(generatePolicies)) @@ -133,9 +133,9 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad namespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, logger) } - vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports) + vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig) - ok, msg, warnings := vh.HandleValidation(h.metricsConfig, request, policies, policyContext, namespaceLabels, startTime) + ok, msg, warnings := vh.HandleValidation(ctx, request, policies, policyContext, namespaceLabels, startTime) if !ok { logger.Info("admission request denied") return admissionutils.Response(request.UID, errors.New(msg), warnings...) @@ -167,8 +167,8 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi if err := enginectx.MutateResourceWithImageInfo(request.Object.Raw, policyContext.JSONContext()); err != nil { logger.Error(err, "failed to patch images info to resource, policies that mutate images may be impacted") } - mh := mutation.NewMutationHandler(logger, h.rclient, h.eventGen, h.openApiManager, h.nsLister) - mutatePatches, mutateWarnings, err := mh.HandleMutation(h.metricsConfig, request, mutatePolicies, policyContext, startTime) + mh := mutation.NewMutationHandler(logger, h.rclient, h.eventGen, h.openApiManager, h.nsLister, h.metricsConfig) + mutatePatches, mutateWarnings, err := mh.HandleMutation(ctx, request, mutatePolicies, policyContext, startTime) if err != nil { logger.Error(err, "mutation failed") return admissionutils.Response(request.UID, err) @@ -181,7 +181,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi return admissionutils.Response(request.UID, err) } ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports) - imagePatches, imageVerifyWarnings, err := ivh.Handle(newRequest, verifyImagesPolicies, policyContext) + imagePatches, imageVerifyWarnings, err := ivh.Handle(ctx, newRequest, verifyImagesPolicies, policyContext) if err != nil { logger.Error(err, "image verification failed") return admissionutils.Response(request.UID, err) diff --git a/pkg/webhooks/resource/imageverification/handler.go b/pkg/webhooks/resource/imageverification/handler.go index 8012608b33..d997298dfa 100644 --- a/pkg/webhooks/resource/imageverification/handler.go +++ b/pkg/webhooks/resource/imageverification/handler.go @@ -23,11 +23,7 @@ import ( ) type ImageVerificationHandler interface { - Handle( - *admissionv1.AdmissionRequest, - []kyvernov1.PolicyInterface, - *engine.PolicyContext, - ) ([]byte, []string, error) + Handle(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext) ([]byte, []string, error) } func NewImageVerificationHandler( @@ -55,11 +51,12 @@ type imageVerificationHandler struct { } func (h *imageVerificationHandler) Handle( + ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, ) ([]byte, []string, error) { - ok, message, imagePatches, warnings := h.handleVerifyImages(h.log, request, policyContext, policies) + ok, message, imagePatches, warnings := h.handleVerifyImages(ctx, h.log, request, policyContext, policies) if !ok { return nil, nil, errors.New(message) } @@ -67,7 +64,13 @@ func (h *imageVerificationHandler) Handle( return imagePatches, warnings, nil } -func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, policies []kyvernov1.PolicyInterface) (bool, string, []byte, []string) { +func (h *imageVerificationHandler) handleVerifyImages( + ctx context.Context, + logger logr.Logger, + request *admissionv1.AdmissionRequest, + policyContext *engine.PolicyContext, + policies []kyvernov1.PolicyInterface, +) (bool, string, []byte, []string) { if len(policies) == 0 { return true, "", nil, nil } @@ -77,7 +80,7 @@ func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, reques verifiedImageData := &engine.ImageVerificationMetadata{} for _, p := range policies { policyContext := policyContext.WithPolicy(p) - resp, ivm := engine.VerifyAndPatchImages(h.rclient, policyContext) + resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext) engineResponses = append(engineResponses, resp) patches = append(patches, resp.GetPatches()...) @@ -107,7 +110,7 @@ func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, reques } } - go h.handleAudit(policyContext.NewResource(), request, nil, engineResponses...) + go h.handleAudit(context.TODO(), policyContext.NewResource(), request, nil, engineResponses...) warnings := webhookutils.GetWarningMessages(engineResponses) return true, "", jsonutils.JoinPatches(patches...), warnings @@ -132,6 +135,7 @@ func isResourceDeleted(policyContext *engine.PolicyContext) bool { } func (v *imageVerificationHandler) handleAudit( + ctx context.Context, resource unstructured.Unstructured, request *admissionv1.AdmissionRequest, namespaceLabels map[string]string, diff --git a/pkg/webhooks/resource/mutation/mutation.go b/pkg/webhooks/resource/mutation/mutation.go index f4ffe65a99..8360843095 100644 --- a/pkg/webhooks/resource/mutation/mutation.go +++ b/pkg/webhooks/resource/mutation/mutation.go @@ -30,14 +30,7 @@ type MutationHandler interface { // HandleMutation handles validating webhook admission request // If there are no errors in validating rule we apply generation rules // patchedResource is the (resource + patches) after applying mutation rules - HandleMutation( - metrics.MetricsConfigManager, - *admissionv1.AdmissionRequest, - []kyvernov1.PolicyInterface, - *engine.PolicyContext, - // map[string]string, - time.Time, - ) ([]byte, []string, error) + HandleMutation(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext, time.Time) ([]byte, []string, error) } func NewMutationHandler( @@ -46,6 +39,7 @@ func NewMutationHandler( eventGen event.Interface, openApiManager openapi.ValidateInterface, nsLister corev1listers.NamespaceLister, + metrics metrics.MetricsConfigManager, ) MutationHandler { return &mutationHandler{ log: log, @@ -53,6 +47,7 @@ func NewMutationHandler( eventGen: eventGen, openApiManager: openApiManager, nsLister: nsLister, + metrics: metrics, } } @@ -62,16 +57,17 @@ type mutationHandler struct { eventGen event.Interface openApiManager openapi.ValidateInterface nsLister corev1listers.NamespaceLister + metrics metrics.MetricsConfigManager } func (h *mutationHandler) HandleMutation( - metricsConfig metrics.MetricsConfigManager, + ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp time.Time, ) ([]byte, []string, error) { - mutatePatches, mutateEngineResponses, err := h.applyMutations(metricsConfig, request, policies, policyContext) + mutatePatches, mutateEngineResponses, err := h.applyMutations(ctx, request, policies, policyContext) if err != nil { return nil, nil, err } @@ -82,7 +78,7 @@ func (h *mutationHandler) HandleMutation( // applyMutations handles mutating webhook admission request // return value: generated patches, triggered policies, engine responses correspdonding to the triggered policies func (v *mutationHandler) applyMutations( - metricsConfig metrics.MetricsConfigManager, + ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, @@ -105,7 +101,7 @@ func (v *mutationHandler) applyMutations( } v.log.V(3).Info("applying policy mutate rules", "policy", policy.GetName()) currentContext := policyContext.WithPolicy(policy) - engineResponse, policyPatches, err := v.applyMutation(request, currentContext) + engineResponse, policyPatches, err := v.applyMutation(ctx, request, currentContext) if err != nil { return nil, nil, fmt.Errorf("mutation policy %s error: %v", policy.GetName(), err) } @@ -122,9 +118,9 @@ func (v *mutationHandler) applyMutations( engineResponses = append(engineResponses, engineResponse) // registering the kyverno_policy_results_total metric concurrently - go webhookutils.RegisterPolicyResultsMetricMutation(context.TODO(), v.log, metricsConfig, string(request.Operation), policy, *engineResponse) + go webhookutils.RegisterPolicyResultsMetricMutation(context.TODO(), v.log, v.metrics, string(request.Operation), policy, *engineResponse) // registering the kyverno_policy_execution_duration_seconds metric concurrently - go webhookutils.RegisterPolicyExecutionDurationMetricMutate(context.TODO(), v.log, metricsConfig, string(request.Operation), policy, *engineResponse) + go webhookutils.RegisterPolicyExecutionDurationMetricMutate(context.TODO(), v.log, v.metrics, string(request.Operation), policy, *engineResponse) } // generate annotations @@ -143,12 +139,12 @@ func (v *mutationHandler) applyMutations( return jsonutils.JoinPatches(patches...), engineResponses, nil } -func (h *mutationHandler) applyMutation(request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext) (*response.EngineResponse, [][]byte, error) { +func (h *mutationHandler) applyMutation(ctx context.Context, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext) (*response.EngineResponse, [][]byte, error) { if request.Kind.Kind != "Namespace" && request.Namespace != "" { policyContext = policyContext.WithNamespaceLabels(common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log)) } - engineResponse := engine.Mutate(h.rclient, policyContext) + engineResponse := engine.Mutate(ctx, h.rclient, policyContext) policyPatches := engineResponse.GetPatches() if !engineResponse.IsSuccessful() { diff --git a/pkg/webhooks/resource/updaterequest.go b/pkg/webhooks/resource/updaterequest.go index 85d9154dd0..af15260cf9 100644 --- a/pkg/webhooks/resource/updaterequest.go +++ b/pkg/webhooks/resource/updaterequest.go @@ -18,12 +18,12 @@ import ( // createUpdateRequests applies generate and mutateExisting policies, and creates update requests for background reconcile func (h *handlers) createUpdateRequests(logger logr.Logger, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyvernov1.PolicyInterface, ts time.Time) { - gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen) - go h.handleMutateExisting(logger, request, mutatePolicies, policyContext, ts) - go gh.Handle(h.metricsConfig, request, generatePolicies, policyContext, ts) + gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig) + go h.handleMutateExisting(context.TODO(), logger, request, mutatePolicies, policyContext, ts) + go gh.Handle(context.TODO(), request, generatePolicies, policyContext, ts) } -func (h *handlers) handleMutateExisting(logger logr.Logger, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp time.Time) { +func (h *handlers) handleMutateExisting(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp time.Time) { if request.Operation == admissionv1.Delete { policyContext = policyContext.WithNewResource(policyContext.OldResource()) } @@ -62,7 +62,7 @@ func (h *handlers) handleMutateExisting(logger logr.Logger, request *admissionv1 go webhookutils.RegisterPolicyExecutionDurationMetricMutate(context.TODO(), logger, h.metricsConfig, string(request.Operation), policy, *engineResponse) } - if failedResponse := applyUpdateRequest(request, kyvernov1beta1.Mutate, h.urGenerator, policyContext.AdmissionInfo(), request.Operation, engineResponses...); failedResponse != nil { + if failedResponse := applyUpdateRequest(ctx, request, kyvernov1beta1.Mutate, h.urGenerator, policyContext.AdmissionInfo(), request.Operation, engineResponses...); failedResponse != nil { for _, failedUR := range failedResponse { err := fmt.Errorf("failed to create update request: %v", failedUR.err) resource := policyContext.NewResource() diff --git a/pkg/webhooks/resource/utils.go b/pkg/webhooks/resource/utils.go index f043056499..c95c66f9d0 100644 --- a/pkg/webhooks/resource/utils.go +++ b/pkg/webhooks/resource/utils.go @@ -1,6 +1,7 @@ package resource import ( + "context" "errors" "github.com/go-logr/logr" @@ -44,8 +45,14 @@ func processResourceWithPatches(patch []byte, resource []byte, log logr.Logger) return resource } -func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Generator, userRequestInfo kyvernov1beta1.RequestInfo, - action admissionv1.Operation, engineResponses ...*response.EngineResponse, +func applyUpdateRequest( + ctx context.Context, + request *admissionv1.AdmissionRequest, + ruleType kyvernov1beta1.RequestType, + grGenerator updaterequest.Generator, + userRequestInfo kyvernov1beta1.RequestInfo, + action admissionv1.Operation, + engineResponses ...*response.EngineResponse, ) (failedUpdateRequest []updateRequestResponse) { admissionRequestInfo := kyvernov1beta1.AdmissionRequestInfoObject{ AdmissionRequest: request, @@ -54,7 +61,7 @@ func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov for _, er := range engineResponses { ur := transform(admissionRequestInfo, userRequestInfo, er, ruleType) - if err := grGenerator.Apply(ur, action); err != nil { + if err := grGenerator.Apply(ctx, ur, action); err != nil { failedUpdateRequest = append(failedUpdateRequest, updateRequestResponse{ur: ur, err: err}) } } diff --git a/pkg/webhooks/resource/validation/validation.go b/pkg/webhooks/resource/validation/validation.go index 6b42d6d0b9..857a3628a9 100644 --- a/pkg/webhooks/resource/validation/validation.go +++ b/pkg/webhooks/resource/validation/validation.go @@ -28,7 +28,7 @@ type ValidationHandler interface { // HandleValidation handles validating webhook admission request // If there are no errors in validating rule we apply generation rules // patchedResource is the (resource + patches) after applying mutation rules - HandleValidation(metrics.MetricsConfigManager, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext, map[string]string, time.Time) (bool, string, []string) + HandleValidation(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext, map[string]string, time.Time) (bool, string, []string) } func NewValidationHandler( @@ -39,6 +39,7 @@ func NewValidationHandler( pcBuilder webhookutils.PolicyContextBuilder, eventGen event.Interface, admissionReports bool, + metrics metrics.MetricsConfigManager, ) ValidationHandler { return &validationHandler{ log: log, @@ -48,6 +49,7 @@ func NewValidationHandler( pcBuilder: pcBuilder, eventGen: eventGen, admissionReports: admissionReports, + metrics: metrics, } } @@ -59,10 +61,11 @@ type validationHandler struct { pcBuilder webhookutils.PolicyContextBuilder eventGen event.Interface admissionReports bool + metrics metrics.MetricsConfigManager } func (v *validationHandler) HandleValidation( - metricsConfig metrics.MetricsConfigManager, + ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, @@ -71,7 +74,7 @@ func (v *validationHandler) HandleValidation( ) (bool, string, []string) { if len(policies) == 0 { // invoke handleAudit as we may have some policies in audit mode to consider - go v.handleAudit(policyContext.NewResource(), request, namespaceLabels) + go v.handleAudit(context.TODO(), policyContext.NewResource(), request, namespaceLabels) return true, "", nil } @@ -99,15 +102,15 @@ func (v *validationHandler) HandleValidation( failurePolicy = kyvernov1.Fail } - engineResponse := engine.Validate(v.rclient, policyContext) + engineResponse := engine.Validate(ctx, v.rclient, policyContext) if engineResponse.IsNil() { // we get an empty response if old and new resources created the same response // allow updates if resource update doesnt change the policy evaluation continue } - go webhookutils.RegisterPolicyResultsMetricValidation(context.TODO(), logger, metricsConfig, string(request.Operation), policyContext.Policy(), *engineResponse) - go webhookutils.RegisterPolicyExecutionDurationMetricValidate(context.TODO(), logger, metricsConfig, string(request.Operation), policyContext.Policy(), *engineResponse) + go webhookutils.RegisterPolicyResultsMetricValidation(context.TODO(), logger, v.metrics, string(request.Operation), policyContext.Policy(), *engineResponse) + go webhookutils.RegisterPolicyExecutionDurationMetricValidate(context.TODO(), logger, v.metrics, string(request.Operation), policyContext.Policy(), *engineResponse) engineResponses = append(engineResponses, engineResponse) if !engineResponse.IsSuccessful() { @@ -131,13 +134,18 @@ func (v *validationHandler) HandleValidation( return false, webhookutils.GetBlockedMessages(engineResponses), nil } - go v.handleAudit(policyContext.NewResource(), request, namespaceLabels, engineResponses...) + go v.handleAudit(context.TODO(), policyContext.NewResource(), request, namespaceLabels, engineResponses...) warnings := webhookutils.GetWarningMessages(engineResponses) return true, "", warnings } -func (v *validationHandler) buildAuditResponses(resource unstructured.Unstructured, request *admissionv1.AdmissionRequest, namespaceLabels map[string]string) ([]*response.EngineResponse, error) { +func (v *validationHandler) buildAuditResponses( + ctx context.Context, + resource unstructured.Unstructured, + request *admissionv1.AdmissionRequest, + namespaceLabels map[string]string, +) ([]*response.EngineResponse, error) { policies := v.pCache.GetPolicies(policycache.ValidateAudit, request.Kind.Kind, request.Namespace) policyContext, err := v.pcBuilder.Build(request) if err != nil { @@ -146,12 +154,13 @@ func (v *validationHandler) buildAuditResponses(resource unstructured.Unstructur var responses []*response.EngineResponse for _, policy := range policies { policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels) - responses = append(responses, engine.Validate(v.rclient, policyContext)) + responses = append(responses, engine.Validate(ctx, v.rclient, policyContext)) } return responses, nil } func (v *validationHandler) handleAudit( + ctx context.Context, resource unstructured.Unstructured, request *admissionv1.AdmissionRequest, namespaceLabels map[string]string, @@ -171,7 +180,7 @@ func (v *validationHandler) handleAudit( if !reportutils.IsGvkSupported(schema.GroupVersionKind(request.Kind)) { return } - responses, err := v.buildAuditResponses(resource, request, namespaceLabels) + responses, err := v.buildAuditResponses(ctx, resource, request, namespaceLabels) if err != nil { v.log.Error(err, "failed to build audit responses") } diff --git a/pkg/webhooks/resource/validation_test.go b/pkg/webhooks/resource/validation_test.go index 85cb946802..96b1146f76 100644 --- a/pkg/webhooks/resource/validation_test.go +++ b/pkg/webhooks/resource/validation_test.go @@ -1,6 +1,7 @@ package resource import ( + "context" "encoding/json" "fmt" "testing" @@ -532,6 +533,7 @@ func TestValidate_failure_action_overrides(t *testing.T) { assert.NilError(t, err) er := engine.Validate( + context.TODO(), registryclient.NewOrDie(), engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured), ) @@ -594,7 +596,7 @@ func Test_RuleSelector(t *testing.T) { ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured) - resp := engine.Validate(registryclient.NewOrDie(), ctx) + resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx) assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 2) assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0) @@ -605,7 +607,7 @@ func Test_RuleSelector(t *testing.T) { applyOne := kyvernov1.ApplyOne policy.Spec.ApplyRules = &applyOne - resp = engine.Validate(registryclient.NewOrDie(), ctx) + resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx) assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 1) assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0) diff --git a/pkg/webhooks/updaterequest/fake.go b/pkg/webhooks/updaterequest/fake.go index b5304c261f..9621679120 100644 --- a/pkg/webhooks/updaterequest/fake.go +++ b/pkg/webhooks/updaterequest/fake.go @@ -1,6 +1,8 @@ package updaterequest import ( + "context" + kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1" admissionv1 "k8s.io/api/admission/v1" ) @@ -11,6 +13,6 @@ func NewFake() Generator { type fakeGenerator struct{} -func (f *fakeGenerator) Apply(gr kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error { +func (f *fakeGenerator) Apply(ctx context.Context, gr kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error { return nil } diff --git a/pkg/webhooks/updaterequest/generator.go b/pkg/webhooks/updaterequest/generator.go index 79ea520736..9747096dc3 100644 --- a/pkg/webhooks/updaterequest/generator.go +++ b/pkg/webhooks/updaterequest/generator.go @@ -18,7 +18,7 @@ import ( // Generator provides interface to manage update requests type Generator interface { - Apply(gr kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error + Apply(context.Context, kyvernov1beta1.UpdateRequestSpec, admissionv1.Operation) error } // generator defines the implementation to manage update request resource @@ -39,16 +39,16 @@ func NewGenerator(client versioned.Interface, urInformer kyvernov1beta1informers } // Apply creates update request resource -func (g *generator) Apply(ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error { +func (g *generator) Apply(ctx context.Context, ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error { logger.V(4).Info("reconcile Update Request", "request", ur) if action == admissionv1.Delete && ur.Type == kyvernov1beta1.Generate { return nil } - go g.applyResource(ur) + go g.applyResource(context.TODO(), ur) return nil } -func (g *generator) applyResource(urSpec kyvernov1beta1.UpdateRequestSpec) { +func (g *generator) applyResource(ctx context.Context, urSpec kyvernov1beta1.UpdateRequestSpec) { exbackoff := &backoff.ExponentialBackOff{ InitialInterval: 500 * time.Millisecond, RandomizationFactor: 0.5, @@ -58,12 +58,12 @@ func (g *generator) applyResource(urSpec kyvernov1beta1.UpdateRequestSpec) { Clock: backoff.SystemClock, } exbackoff.Reset() - if err := backoff.Retry(func() error { return g.tryApplyResource(urSpec) }, exbackoff); err != nil { + if err := backoff.Retry(func() error { return g.tryApplyResource(ctx, urSpec) }, exbackoff); err != nil { logger.Error(err, "failed to update request CR") } } -func (g *generator) tryApplyResource(urSpec kyvernov1beta1.UpdateRequestSpec) error { +func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov1beta1.UpdateRequestSpec) error { l := logger.WithValues("ruleType", urSpec.Type, "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace) var queryLabels labels.Set @@ -103,7 +103,7 @@ func (g *generator) tryApplyResource(urSpec kyvernov1beta1.UpdateRequestSpec) er }, Spec: urSpec, } - if new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), &ur, metav1.CreateOptions{}); err != nil { + if new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(ctx, &ur, metav1.CreateOptions{}); err != nil { l.V(4).Error(err, "failed to create UpdateRequest, retrying", "name", ur.GetGenerateName(), "namespace", ur.GetNamespace()) return err } else {