1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

refactor: make policy context immutable and fields private (#5523)

* refactor: make policy context immutable and fields private

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* refactor: make policy context immutable and fields private

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-12-02 09:14:23 +01:00 committed by GitHub
parent d7c7bbc843
commit 5b89e2e5f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 538 additions and 470 deletions

View file

@ -450,14 +450,12 @@ OuterLoop:
log.Log.Error(err, "failed to add image variables to context")
}
policyContext := &engine.PolicyContext{
Policy: c.Policy,
NewResource: *updatedResource,
JSONContext: ctx,
NamespaceLabels: namespaceLabels,
AdmissionInfo: c.UserInfo,
Client: c.Client,
}
policyContext := engine.NewPolicyContextWithJsonContext(ctx).
WithPolicy(c.Policy).
WithNewResource(*updatedResource).
WithNamespaceLabels(namespaceLabels).
WithAdmissionInfo(c.UserInfo).
WithClient(c.Client)
mutateResponse := engine.Mutate(policyContext)
if mutateResponse != nil {
@ -478,7 +476,7 @@ OuterLoop:
}
}
policyContext.NewResource = mutateResponse.PatchedResource
policyContext = policyContext.WithNewResource(mutateResponse.PatchedResource)
var info Info
var validateResponse *response.EngineResponse
@ -505,16 +503,6 @@ OuterLoop:
}
if policyHasGenerate {
policyContext := &engine.PolicyContext{
NewResource: *c.Resource,
Policy: c.Policy,
ExcludeGroupRole: []string{},
ExcludeResourceFunc: func(s1, s2, s3 string) bool {
return false
},
JSONContext: ctx,
NamespaceLabels: namespaceLabels,
}
generateResponse := engine.ApplyBackgroundChecks(policyContext)
if generateResponse != nil && !generateResponse.IsEmpty() {
newRuleResponse, err := handleGeneratePolicy(generateResponse, *policyContext, c.RuleToCloneSourceResource)
@ -1011,7 +999,8 @@ func initializeMockController(objects []runtime.Object) (*generate.GenerateContr
// handleGeneratePolicy returns a new RuleResponse with the Kyverno generated resource configuration by applying the generate rule.
func handleGeneratePolicy(generateResponse *response.EngineResponse, policyContext engine.PolicyContext, ruleToCloneSourceResource map[string]string) ([]response.RuleResponse, error) {
objects := []runtime.Object{&policyContext.NewResource}
resource := policyContext.NewResource()
objects := []runtime.Object{&resource}
resources := []*unstructured.Unstructured{}
for _, rule := range generateResponse.PolicyResponse.Rules {
if path, ok := ruleToCloneSourceResource[rule.Name]; ok {

View file

@ -77,18 +77,14 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
logger.Error(err, "unable to add image info to variables context")
}
policyContext := &engine.PolicyContext{
NewResource: *trigger,
OldResource: old,
Policy: policy,
AdmissionInfo: ur.Spec.Context.UserRequestInfo,
ExcludeGroupRole: cfg.GetExcludeGroupRole(),
ExcludeResourceFunc: cfg.ToFilter,
JSONContext: ctx,
NamespaceLabels: namespaceLabels,
Client: dclient,
AdmissionOperation: false,
}
policyContext := engine.NewPolicyContextWithJsonContext(ctx).
WithPolicy(policy).
WithNewResource(*trigger).
WithOldResource(old).
WithAdmissionInfo(ur.Spec.Context.UserRequestInfo).
WithConfiguration(cfg).
WithNamespaceLabels(namespaceLabels).
WithClient(dclient)
return policyContext, false, nil
}

View file

@ -306,13 +306,12 @@ func updateStatus(statusControl common.StatusControlInterface, ur kyvernov1beta1
func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, ur kyvernov1beta1.UpdateRequest, applicableRules []string) (genResources []kyvernov1.ResourceSpec, processExisting bool, err error) {
// Get the response as the actions to be performed on the resource
// - - substitute values
policy := policyContext.Policy
resource := policyContext.NewResource
jsonContext := policyContext.JSONContext
policy := policyContext.Policy()
resource := policyContext.NewResource()
jsonContext := policyContext.JSONContext()
// To manage existing resources, we compare the creation time for the default resource to be generated and policy creation time
ruleNameToProcessingTime := make(map[string]time.Duration)
applyRules := policyContext.Policy.GetSpec().GetApplyRules()
applyRules := policy.GetSpec().GetApplyRules()
applyCount := 0
for _, rule := range autogen.ComputeRules(policy) {
@ -347,7 +346,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
return nil, processExisting, err
}
if rule, err = variables.SubstituteAllInRule(log, policyContext.JSONContext, rule); err != nil {
if rule, err = variables.SubstituteAllInRule(log, policyContext.JSONContext(), rule); err != nil {
log.Error(err, "variable substitution failed for rule %s", rule.Name)
return nil, processExisting, err
}

View file

@ -75,14 +75,12 @@ func (s *scanner) validateResource(resource unstructured.Unstructured, nsLabels
if err := ctx.AddOperation("CREATE"); err != nil {
return nil, err
}
policyCtx := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
JSONContext: ctx,
Client: s.client,
NamespaceLabels: nsLabels,
ExcludeGroupRole: s.excludeGroupRole,
}
policyCtx := engine.NewPolicyContextWithJsonContext(ctx).
WithNewResource(resource).
WithPolicy(policy).
WithClient(s.client).
WithNamespaceLabels(nsLabels).
WithExcludeGroupRole(s.excludeGroupRole...)
return engine.Validate(policyCtx), nil
}
@ -100,14 +98,12 @@ func (s *scanner) validateImages(resource unstructured.Unstructured, nsLabels ma
if err := ctx.AddOperation("CREATE"); err != nil {
return nil, err
}
policyCtx := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
JSONContext: ctx,
Client: s.client,
NamespaceLabels: nsLabels,
ExcludeGroupRole: s.excludeGroupRole,
}
policyCtx := engine.NewPolicyContextWithJsonContext(ctx).
WithNewResource(resource).
WithPolicy(policy).
WithClient(s.client).
WithNamespaceLabels(nsLabels).
WithExcludeGroupRole(s.excludeGroupRole...)
response, _ := engine.VerifyAndPatchImages(policyCtx)
if len(response.PolicyResponse.Rules) > 0 {
s.logger.Info("validateImages", "policy", policy, "response", response)

View file

@ -12,7 +12,6 @@ var client Cosign = &driver{}
type Cosign interface {
VerifyImageSignatures(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) ([]oci.Signature, bool, error)
VerifyImageAttestations(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) (checkedAttestations []oci.Signature, bundleVerified bool, err error)
}

View file

@ -22,15 +22,15 @@ func ApplyBackgroundChecks(policyContext *PolicyContext) (resp *response.EngineR
}
func filterRules(policyContext *PolicyContext, startTime time.Time) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
apiVersion := policyContext.NewResource.GetAPIVersion()
kind := policyContext.newResource.GetKind()
name := policyContext.newResource.GetName()
namespace := policyContext.newResource.GetNamespace()
apiVersion := policyContext.newResource.GetAPIVersion()
resp := &response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: response.PolicySpec{
Name: policyContext.Policy.GetName(),
Namespace: policyContext.Policy.GetNamespace(),
Name: policyContext.policy.GetName(),
Namespace: policyContext.policy.GetNamespace(),
},
PolicyStats: response.PolicyStats{
PolicyExecutionTimestamp: startTime.Unix(),
@ -44,13 +44,13 @@ func filterRules(policyContext *PolicyContext, startTime time.Time) *response.En
},
}
if policyContext.ExcludeResourceFunc(kind, namespace, name) {
if policyContext.excludeResourceFunc(kind, namespace, name) {
logging.WithName("ApplyBackgroundChecks").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
return resp
}
applyRules := policyContext.Policy.GetSpec().GetApplyRules()
for _, rule := range autogen.ComputeRules(policyContext.Policy) {
applyRules := policyContext.policy.GetSpec().GetApplyRules()
for _, rule := range autogen.ComputeRules(policyContext.policy) {
if ruleResp := filterRule(rule, policyContext); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
if applyRules == kyvernov1.ApplyOne && ruleResp.Status != response.RuleStatusSkip {
@ -75,13 +75,13 @@ func filterRule(rule kyvernov1.Rule, policyContext *PolicyContext) *response.Rul
var err error
startTime := time.Now()
policy := policyContext.Policy
newResource := policyContext.NewResource
oldResource := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.JSONContext
excludeGroupRole := policyContext.ExcludeGroupRole
namespaceLabels := policyContext.NamespaceLabels
policy := policyContext.policy
newResource := policyContext.newResource
oldResource := policyContext.oldResource
admissionInfo := policyContext.admissionInfo
ctx := policyContext.jsonContext
excludeGroupRole := policyContext.excludeGroupRole
namespaceLabels := policyContext.namespaceLabels
logger := logging.WithName(string(ruleType)).WithValues("policy", policy.GetName(),
"kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName())
@ -105,8 +105,8 @@ func filterRule(rule kyvernov1.Rule, policyContext *PolicyContext) *response.Rul
return nil
}
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
policyContext.jsonContext.Checkpoint()
defer policyContext.jsonContext.Restore()
if err = LoadContext(logger, rule.Context, policyContext, rule.Name); err != nil {
logger.V(4).Info("cannot add external data to the context", "reason", err.Error())

View file

@ -17,10 +17,10 @@ func GenerateResponse(policyContext *PolicyContext, gr kyvernov1beta1.UpdateRequ
}
func filterGenerateRules(policyContext *PolicyContext, policyNameKey string, startTime time.Time) *response.EngineResponse {
kind := policyContext.NewResource.GetKind()
name := policyContext.NewResource.GetName()
namespace := policyContext.NewResource.GetNamespace()
apiVersion := policyContext.NewResource.GetAPIVersion()
kind := policyContext.newResource.GetKind()
name := policyContext.newResource.GetName()
namespace := policyContext.newResource.GetNamespace()
apiVersion := policyContext.newResource.GetAPIVersion()
pNamespace, pName, err := cache.SplitMetaNamespaceKey(policyNameKey)
if err != nil {
logging.Error(err, "failed to spilt name and namespace", policyNameKey)
@ -44,12 +44,12 @@ func filterGenerateRules(policyContext *PolicyContext, policyNameKey string, sta
},
}
if policyContext.ExcludeResourceFunc(kind, namespace, name) {
if policyContext.excludeResourceFunc(kind, namespace, name) {
logging.WithName("Generate").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
return resp
}
for _, rule := range autogen.ComputeRules(policyContext.Policy) {
for _, rule := range autogen.ComputeRules(policyContext.policy) {
if ruleResp := filterRule(rule, policyContext); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
}

View file

@ -48,10 +48,10 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) (
images map[string]map[string]apiutils.ImageInfo
err error
)
images = policyContext.JSONContext.ImageInfo()
images = policyContext.jsonContext.ImageInfo()
if rule.ImageExtractors != nil {
images, err = policyContext.JSONContext.GenerateCustomImageInfo(
&policyContext.NewResource, rule.ImageExtractors)
images, err = policyContext.jsonContext.GenerateCustomImageInfo(
&policyContext.newResource, rule.ImageExtractors)
if err != nil {
// if we get an error while generating custom images from image extractors,
// don't check for matching images in imageExtractors
@ -65,8 +65,8 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule) (
func VerifyAndPatchImages(policyContext *PolicyContext) (*response.EngineResponse, *ImageVerificationMetadata) {
resp := &response.EngineResponse{}
policy := policyContext.Policy
patchedResource := policyContext.NewResource
policy := policyContext.policy
patchedResource := policyContext.newResource
logger := logging.WithName("EngineVerifyImages").WithValues("policy", policy.GetName(),
"kind", patchedResource.GetKind(), "namespace", patchedResource.GetNamespace(), "name", patchedResource.GetName())
@ -78,8 +78,8 @@ func VerifyAndPatchImages(policyContext *PolicyContext) (*response.EngineRespons
"applied", resp.PolicyResponse.RulesAppliedCount, "successful", resp.IsSuccessful())
}()
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
policyContext.jsonContext.Checkpoint()
defer policyContext.jsonContext.Restore()
// update image registry secrets
if err := registryclient.DefaultClient.RefreshKeychainPullSecrets(); err != nil {
@ -87,7 +87,7 @@ func VerifyAndPatchImages(policyContext *PolicyContext) (*response.EngineRespons
}
ivm := &ImageVerificationMetadata{}
rules := autogen.ComputeRules(policyContext.Policy)
rules := autogen.ComputeRules(policyContext.policy)
applyRules := policy.GetSpec().GetApplyRules()
for i := range rules {
@ -115,13 +115,13 @@ func VerifyAndPatchImages(policyContext *PolicyContext) (*response.EngineRespons
continue
}
policyContext.JSONContext.Restore()
policyContext.jsonContext.Restore()
if err := LoadContext(logger, rule.Context, policyContext, rule.Name); err != nil {
appendResponse(resp, rule, fmt.Sprintf("failed to load context: %s", err.Error()), response.RuleStatusError)
continue
}
ruleCopy, err := substituteVariables(rule, policyContext.JSONContext, logger)
ruleCopy, err := substituteVariables(rule, policyContext.jsonContext, logger)
if err != nil {
appendResponse(resp, rule, fmt.Sprintf("failed to substitute variables: %s", err.Error()), response.RuleStatusError)
continue
@ -201,13 +201,13 @@ func (iv *imageVerifier) verify(imageVerify kyvernov1.ImageVerification, matched
}
pointer := jsonpointer.ParsePath(imageInfo.Pointer).JMESPath()
changed, err := iv.policyContext.JSONContext.HasChanged(pointer)
changed, err := iv.policyContext.jsonContext.HasChanged(pointer)
if err == nil && !changed {
iv.logger.V(4).Info("no change in image, skipping check", "image", image)
continue
}
verified, err := isImageVerified(iv.policyContext.NewResource, image, iv.logger)
verified, err := isImageVerified(iv.policyContext.newResource, image, iv.logger)
if err == nil && verified {
iv.logger.Info("image was previously verified, skipping check", "image", image)
continue
@ -266,14 +266,14 @@ func (iv *imageVerifier) handleMutateDigest(digest string, imageInfo apiutils.Im
}
func hasImageVerifiedAnnotationChanged(ctx *PolicyContext, log logr.Logger) bool {
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) ||
reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
if reflect.DeepEqual(ctx.newResource, unstructured.Unstructured{}) ||
reflect.DeepEqual(ctx.oldResource, unstructured.Unstructured{}) {
return false
}
key := imageVerifyAnnotationKey
newValue := ctx.NewResource.GetAnnotations()[key]
oldValue := ctx.OldResource.GetAnnotations()[key]
newValue := ctx.newResource.GetAnnotations()[key]
oldValue := ctx.oldResource.GetAnnotations()[key]
result := newValue != oldValue
if result {
log.V(2).Info("annotation mismatch", "oldValue", oldValue, "newValue", newValue, "key", key)
@ -301,7 +301,7 @@ func (iv *imageVerifier) verifyImage(imageVerify kyvernov1.ImageVerification, im
iv.logger.V(2).Info("verifying image signatures", "image", image,
"attestors", len(imageVerify.Attestors), "attestations", len(imageVerify.Attestations))
if err := iv.policyContext.JSONContext.AddImageInfo(imageInfo); err != nil {
if err := iv.policyContext.jsonContext.AddImageInfo(imageInfo); err != nil {
iv.logger.Error(err, "failed to add image to context")
msg := fmt.Sprintf("failed to add image to context %s: %s", image, err.Error())
return ruleResponse(*iv.rule, response.ImageVerify, msg, response.RuleStatusError, nil), ""
@ -628,10 +628,10 @@ func (iv *imageVerifier) checkAttestations(a kyvernov1.Attestation, s map[string
return true, nil
}
iv.policyContext.JSONContext.Checkpoint()
defer iv.policyContext.JSONContext.Restore()
iv.policyContext.jsonContext.Checkpoint()
defer iv.policyContext.jsonContext.Restore()
return evaluateConditions(a.Conditions, iv.policyContext.JSONContext, s, iv.logger)
return evaluateConditions(a.Conditions, iv.policyContext.jsonContext, s, iv.logger)
}
func evaluateConditions(

View file

@ -42,7 +42,7 @@ func processImageValidationRule(log logr.Logger, ctx *PolicyContext, rule *kyver
}
if !preconditionsPassed {
if ctx.Policy.GetSpec().ValidationFailureAction.Audit() {
if ctx.policy.GetSpec().ValidationFailureAction.Audit() {
return nil
}
@ -51,7 +51,7 @@ func processImageValidationRule(log logr.Logger, ctx *PolicyContext, rule *kyver
for _, v := range rule.VerifyImages {
imageVerify := v.Convert()
for _, infoMap := range ctx.JSONContext.ImageInfo() {
for _, infoMap := range ctx.jsonContext.ImageInfo() {
for name, imageInfo := range infoMap {
image := imageInfo.String()
log = log.WithValues("rule", rule.Name)
@ -80,8 +80,8 @@ func validateImage(ctx *PolicyContext, imageVerify *kyvernov1.ImageVerification,
return fmt.Errorf("missing digest for %s", image)
}
if imageVerify.Required && !reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
verified, err := isImageVerified(ctx.NewResource, image, log)
if imageVerify.Required && !reflect.DeepEqual(ctx.newResource, unstructured.Unstructured{}) {
verified, err := isImageVerified(ctx.newResource, image, log)
if err != nil {
return err
}

View file

@ -181,9 +181,9 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &cpol,
JSONContext: ctx,
NewResource: *resourceUnstructured,
policy: &cpol,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
if oldResource != "" {
@ -193,7 +193,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
err = context.AddOldResource(ctx, []byte(oldResource))
assert.NilError(t, err)
policyContext.OldResource = *oldResourceUnstructured
policyContext.oldResource = *oldResourceUnstructured
}
if err := ctx.AddImageInfos(resourceUnstructured); err != nil {
@ -418,7 +418,7 @@ func Test_ConfigMapMissingSuccess(t *testing.T) {
func Test_ConfigMapMissingFailure(t *testing.T) {
ghcrImage := strings.Replace(testConfigMapMissingResource, "nginx:latest", "ghcr.io/kyverno/test-verify-image:signed", -1)
policyContext := buildContext(t, testConfigMapMissing, ghcrImage, "")
policyContext.Client = client.NewEmptyFakeClient()
policyContext.client = client.NewEmptyFakeClient()
cosign.ClearMock()
err, _ := VerifyAndPatchImages(policyContext)
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
@ -499,7 +499,7 @@ func Test_RuleSelectorImageVerify(t *testing.T) {
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
rule := newStaticKeyRule("match-all", "*", testOtherKey)
spec := policyContext.Policy.GetSpec()
spec := policyContext.policy.GetSpec()
spec.Rules = append(spec.Rules, *rule)
applyAll := kyverno.ApplyAll

View file

@ -19,13 +19,13 @@ func LoadContext(logger logr.Logger, contextEntries []kyvernov1.ContextEntry, ct
return nil
}
policyName := ctx.Policy.GetName()
policyName := ctx.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 := ctx.jsonContext.AddVariable(key, value); err != nil {
return err
}
}
@ -52,7 +52,7 @@ func LoadContext(logger logr.Logger, contextEntries []kyvernov1.ContextEntry, ct
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 := ctx.jsonContext.AddVariable(key, value[store.ForeachElement]); err != nil {
return err
}
}
@ -84,7 +84,7 @@ func LoadContext(logger logr.Logger, contextEntries []kyvernov1.ContextEntry, ct
func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) (err error) {
path := ""
if entry.Variable.JMESPath != "" {
jp, err := variables.SubstituteAll(logger, ctx.JSONContext, entry.Variable.JMESPath)
jp, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.Variable.JMESPath)
if err != nil {
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.JMESPath, err)
}
@ -97,7 +97,7 @@ func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyC
if err != nil {
return fmt.Errorf("invalid default for variable %s", entry.Name)
}
defaultValue, err = variables.SubstituteAll(logger, ctx.JSONContext, value)
defaultValue, err = variables.SubstituteAll(logger, ctx.jsonContext, value)
if err != nil {
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Default, err)
}
@ -106,7 +106,7 @@ func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyC
var output interface{} = defaultValue
if entry.Variable.Value != nil {
value, _ := variables.DocumentToUntyped(entry.Variable.Value)
variable, err := variables.SubstituteAll(logger, ctx.JSONContext, value)
variable, err := variables.SubstituteAll(logger, ctx.jsonContext, value)
if err != nil {
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Value, err)
}
@ -122,7 +122,7 @@ func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyC
}
} else {
if path != "" {
if variable, err := ctx.JSONContext.Query(path); err == nil {
if variable, err := ctx.jsonContext.Query(path); err == nil {
output = variable
} else if defaultValue == nil {
return fmt.Errorf("failed to apply jmespath %s to variable %v", path, err)
@ -134,7 +134,7 @@ func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyC
return fmt.Errorf("unable to add context entry for variable %s since it evaluated to nil", entry.Name)
}
if outputBytes, err := json.Marshal(output); err == nil {
return ctx.JSONContext.ReplaceContextEntry(entry.Name, outputBytes)
return ctx.jsonContext.ReplaceContextEntry(entry.Name, outputBytes)
} else {
return fmt.Errorf("unable to add context entry for variable %s: %w", entry.Name, err)
}
@ -152,14 +152,14 @@ func loadImageData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Policy
if err != nil {
return err
}
if err := ctx.JSONContext.AddContextEntry(entry.Name, jsonBytes); err != nil {
if err := ctx.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(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) (interface{}, error) {
ref, err := variables.SubstituteAll(logger, ctx.JSONContext, entry.ImageRegistry.Reference)
ref, err := variables.SubstituteAll(logger, ctx.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)
}
@ -167,7 +167,7 @@ func fetchImageData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Polic
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, ctx.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)
}
@ -246,7 +246,7 @@ func loadAPIData(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCo
}
if entry.APICall.JMESPath == "" {
err = ctx.JSONContext.AddContextEntry(entry.Name, jsonData)
err = ctx.jsonContext.AddContextEntry(entry.Name, jsonData)
if err != nil {
return fmt.Errorf("failed to add resource data to context: contextEntry: %v, error: %v", entry, err)
}
@ -254,7 +254,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, ctx.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)
}
@ -269,7 +269,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 = ctx.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)
}
@ -301,7 +301,7 @@ func fetchAPIData(log logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCont
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, ctx.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)
}
@ -317,7 +317,7 @@ func fetchAPIData(log logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyCont
}
func getResource(ctx *PolicyContext, p string) ([]byte, error) {
return ctx.Client.RawAbsPath(context.TODO(), p)
return ctx.client.RawAbsPath(context.TODO(), p)
}
func loadConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) error {
@ -326,7 +326,7 @@ func loadConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Policy
return fmt.Errorf("failed to retrieve config map for context entry %s: %v", entry.Name, err)
}
err = ctx.JSONContext.AddContextEntry(entry.Name, data)
err = ctx.jsonContext.AddContextEntry(entry.Name, data)
if err != nil {
return fmt.Errorf("failed to add config map for context entry %s: %v", entry.Name, err)
}
@ -337,12 +337,12 @@ func loadConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Policy
func fetchConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) ([]byte, error) {
contextData := make(map[string]interface{})
name, err := variables.SubstituteAll(logger, ctx.JSONContext, entry.ConfigMap.Name)
name, err := variables.SubstituteAll(logger, ctx.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, ctx.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)
}
@ -351,7 +351,7 @@ func fetchConfigMap(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *Polic
namespace = "default"
}
obj, err := ctx.Client.GetResource(context.TODO(), "v1", "ConfigMap", namespace.(string), name.(string))
obj, err := ctx.client.GetResource(context.TODO(), "v1", "ConfigMap", namespace.(string), name.(string))
if err != nil {
return nil, fmt.Errorf("failed to get configmap %s/%s : %v", namespace, name, err)
}

View file

@ -58,7 +58,7 @@ func handleVerifyManifest(ctx *PolicyContext, rule *kyvernov1.Rule, logger logr.
func verifyManifest(policyContext *PolicyContext, verifyRule kyvernov1.Manifests, logger logr.Logger) (bool, string, error) {
// load AdmissionRequest
request, err := policyContext.JSONContext.Query("request")
request, err := policyContext.jsonContext.Query("request")
if err != nil {
return false, "", errors.Wrapf(err, "failed to get a request from policyContext")
}
@ -106,7 +106,7 @@ func verifyManifest(policyContext *PolicyContext, verifyRule kyvernov1.Manifests
}
if !vo.DisableDryRun {
// check if kyverno can 'create' dryrun resource
ok, err := checkDryRunPermission(policyContext.Client, adreq.Kind.Kind, vo.DryRunNamespace)
ok, err := checkDryRunPermission(policyContext.client, adreq.Kind.Kind, vo.DryRunNamespace)
if err != nil {
logger.V(1).Info("failed to check permissions to 'create' resource. disabled DryRun option.", "dryrun namespace", vo.DryRunNamespace, "kind", adreq.Kind.Kind, "error", err.Error())
vo.DisableDryRun = true

View file

@ -614,8 +614,8 @@ func Test_VerifyManifest_SignedYAML(t *testing.T) {
policyContext := buildContext(t, test_policy, signed_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(signed_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
Entries: []kyvernov1.Attestor{
@ -636,8 +636,8 @@ func Test_VerifyManifest_UnsignedYAML(t *testing.T) {
policyContext := buildContext(t, test_policy, unsigned_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(unsigned_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
Entries: []kyvernov1.Attestor{
@ -658,8 +658,8 @@ func Test_VerifyManifest_InvalidYAML(t *testing.T) {
policyContext := buildContext(t, test_policy, invalid_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(invalid_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
Entries: []kyvernov1.Attestor{
@ -680,8 +680,8 @@ func Test_VerifyManifest_MustAll_InvalidYAML(t *testing.T) {
policyContext := buildContext(t, test_policy, multi_sig_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(multi_sig_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
Entries: []kyvernov1.Attestor{
@ -708,8 +708,8 @@ func Test_VerifyManifest_MustAll_ValidYAML(t *testing.T) {
policyContext := buildContext(t, test_policy, multi_sig2_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(multi_sig2_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
count := 3
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{
@ -740,8 +740,8 @@ func Test_VerifyManifest_AtLeastOne(t *testing.T) {
policyContext := buildContext(t, test_policy, multi_sig_resource, "")
var request *v1.AdmissionRequest
_ = json.Unmarshal([]byte(multi_sig_adreq), &request)
policyContext.JSONContext.AddRequest(request)
policyContext.Policy.SetName("test-policy")
policyContext.jsonContext.AddRequest(request)
policyContext.policy.SetName("test-policy")
verifyRule := kyvernov1.Manifests{}
count := 1
verifyRule.Attestors = append(verifyRule.Attestors, kyvernov1.AttestorSet{

View file

@ -36,22 +36,22 @@ func loadTargets(targets []kyvernov1.ResourceSpec, ctx *PolicyContext, logger lo
}
func resolveSpec(i int, target kyvernov1.ResourceSpec, ctx *PolicyContext, logger logr.Logger) (kyvernov1.ResourceSpec, error) {
kind, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Kind)
kind, err := variables.SubstituteAll(logger, ctx.jsonContext, target.Kind)
if err != nil {
return kyvernov1.ResourceSpec{}, fmt.Errorf("failed to substitute variables in target[%d].Kind %s: %v", i, target.Kind, err)
}
apiversion, err := variables.SubstituteAll(logger, ctx.JSONContext, target.APIVersion)
apiversion, err := variables.SubstituteAll(logger, ctx.jsonContext, target.APIVersion)
if err != nil {
return kyvernov1.ResourceSpec{}, fmt.Errorf("failed to substitute variables in target[%d].APIVersion %s: %v", i, target.APIVersion, err)
}
namespace, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Namespace)
namespace, err := variables.SubstituteAll(logger, ctx.jsonContext, target.Namespace)
if err != nil {
return kyvernov1.ResourceSpec{}, fmt.Errorf("failed to substitute variables in target[%d].Namespace %s: %v", i, target.Namespace, err)
}
name, err := variables.SubstituteAll(logger, ctx.JSONContext, target.Name)
name, err := variables.SubstituteAll(logger, ctx.jsonContext, target.Name)
if err != nil {
return kyvernov1.ResourceSpec{}, fmt.Errorf("failed to substitute variables in target[%d].Name %s: %v", i, target.Name, err)
}
@ -70,13 +70,13 @@ func getTargets(target kyvernov1.ResourceSpec, ctx *PolicyContext, logger logr.L
name := target.Name
// if it's namespaced policy, targets has to be loaded only from the policy's namespace
if ctx.Policy.IsNamespaced() {
namespace = ctx.Policy.GetNamespace()
if ctx.policy.IsNamespaced() {
namespace = ctx.policy.GetNamespace()
}
if namespace != "" && name != "" &&
!wildcard.ContainsWildcard(namespace) && !wildcard.ContainsWildcard(name) {
obj, err := ctx.Client.GetResource(context.TODO(), target.APIVersion, target.Kind, namespace, name)
obj, err := ctx.client.GetResource(context.TODO(), target.APIVersion, target.Kind, namespace, name)
if err != nil {
return nil, fmt.Errorf("failed to get target %s/%s %s/%s : %v", target.APIVersion, target.Kind, namespace, name, err)
}
@ -85,7 +85,7 @@ func getTargets(target kyvernov1.ResourceSpec, ctx *PolicyContext, logger logr.L
}
// list all targets if wildcard is specified
objList, err := ctx.Client.ListResource(context.TODO(), target.APIVersion, target.Kind, "", nil)
objList, err := ctx.client.ListResource(context.TODO(), target.APIVersion, target.Kind, "", nil)
if err != nil {
return nil, err
}

View file

@ -19,12 +19,12 @@ import (
// Mutate performs mutation. Overlay first and then mutation patches
func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
startTime := time.Now()
policy := policyContext.Policy
policy := policyContext.policy
resp = &response.EngineResponse{
Policy: policy,
}
matchedResource := policyContext.NewResource
ctx := policyContext.JSONContext
matchedResource := policyContext.newResource
ctx := policyContext.jsonContext
var skippedRules []string
logger := logging.WithName("EngineMutate").WithValues("policy", policy.GetName(), "kind", matchedResource.GetKind(),
@ -35,8 +35,8 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
startMutateResultResponse(resp, policy, matchedResource)
defer endMutateResultResponse(logger, resp, startTime)
policyContext.JSONContext.Checkpoint()
defer policyContext.JSONContext.Restore()
policyContext.jsonContext.Checkpoint()
defer policyContext.jsonContext.Restore()
var err error
applyRules := policy.GetSpec().GetApplyRules()
@ -48,19 +48,19 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
logger := logger.WithValues("rule", rule.Name)
var excludeResource []string
if len(policyContext.ExcludeGroupRole) > 0 {
excludeResource = policyContext.ExcludeGroupRole
if len(policyContext.excludeGroupRole) > 0 {
excludeResource = policyContext.excludeGroupRole
}
if err = MatchesResourceDescription(matchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels, policyContext.Policy.GetNamespace()); err != nil {
if err = MatchesResourceDescription(matchedResource, rule, policyContext.admissionInfo, excludeResource, policyContext.namespaceLabels, policyContext.policy.GetNamespace()); err != nil {
logger.V(4).Info("rule not matched", "reason", err.Error())
skippedRules = append(skippedRules, rule.Name)
continue
}
logger.V(3).Info("processing mutate rule", "applyRules", applyRules)
resource, err := policyContext.JSONContext.Query("request.object")
policyContext.JSONContext.Reset()
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 {
logger.Error(err, "unable to update resource object")
@ -80,7 +80,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
ruleCopy := rule.DeepCopy()
var patchedResources []unstructured.Unstructured
if !policyContext.AdmissionOperation && rule.IsMutateExisting() {
if !policyContext.admissionOperation && rule.IsMutateExisting() {
targets, err := loadTargets(ruleCopy.Mutation.Targets, policyContext, logger)
if err != nil {
rr := ruleResponse(rule, response.Mutation, err.Error(), response.RuleStatusError, nil)
@ -97,9 +97,9 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
continue
}
if !policyContext.AdmissionOperation && rule.IsMutateExisting() {
if !policyContext.admissionOperation && rule.IsMutateExisting() {
policyContext := policyContext.Copy()
if err := policyContext.JSONContext.AddTargetResource(patchedResource.Object); err != nil {
if err := policyContext.jsonContext.AddTargetResource(patchedResource.Object); err != nil {
logging.Error(err, "failed to add target resource to the context")
continue
}
@ -153,7 +153,7 @@ func mutateResource(rule *kyvernov1.Rule, ctx *PolicyContext, resource unstructu
return ruleResponse(*rule, response.Mutation, "preconditions not met", response.RuleStatusSkip, &resource), resource
}
mutateResp := mutate.Mutate(rule, ctx.JSONContext, resource, logger)
mutateResp := mutate.Mutate(rule, ctx.jsonContext, resource, logger)
ruleResp := buildRuleResponse(rule, mutateResp, &mutateResp.PatchedResource)
return ruleResp, mutateResp.PatchedResource
}
@ -183,7 +183,7 @@ func mutateForEach(rule *kyvernov1.Rule, ctx *PolicyContext, resource unstructur
return ruleResponse(*rule, response.Mutation, "preconditions not met", response.RuleStatusSkip, &patchedResource), resource
}
elements, err := evaluateList(foreach.List, ctx.JSONContext)
elements, err := evaluateList(foreach.List, ctx.jsonContext)
if err != nil {
msg := fmt.Sprintf("failed to evaluate list %s", foreach.List)
return ruleError(rule, response.Mutation, msg, err), resource
@ -214,8 +214,8 @@ func mutateForEach(rule *kyvernov1.Rule, ctx *PolicyContext, resource unstructur
}
func mutateElements(name string, foreach kyvernov1.ForEachMutation, ctx *PolicyContext, elements []interface{}, resource unstructured.Unstructured, logger logr.Logger) *mutate.Response {
ctx.JSONContext.Checkpoint()
defer ctx.JSONContext.Restore()
ctx.jsonContext.Checkpoint()
defer ctx.jsonContext.Restore()
patchedResource := resource
var allPatches [][]byte
@ -227,7 +227,7 @@ func mutateElements(name string, foreach kyvernov1.ForEachMutation, ctx *PolicyC
if e == nil {
continue
}
ctx.JSONContext.Reset()
ctx.jsonContext.Reset()
ctx := ctx.Copy()
store.SetForeachElement(i)
falseVar := false
@ -249,7 +249,7 @@ func mutateElements(name string, foreach kyvernov1.ForEachMutation, ctx *PolicyC
continue
}
mutateResp := mutate.ForEach(name, foreach, ctx.JSONContext, patchedResource, logger)
mutateResp := mutate.ForEach(name, foreach, ctx.jsonContext, patchedResource, logger)
if mutateResp.Status == response.RuleStatusFail || mutateResp.Status == response.RuleStatusError {
return mutateResp
}

View file

@ -90,9 +90,9 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
t.Error(err)
}
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Mutate(policyContext)
t.Log(string(expectedPatch))
@ -163,9 +163,9 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Mutate(policyContext)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
@ -258,9 +258,9 @@ func Test_variableSubstitutionCLI(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured,
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Mutate(policyContext)
@ -361,9 +361,9 @@ func Test_chained_rules(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
@ -455,9 +455,9 @@ func Test_precondition(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured,
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Mutate(policyContext)
@ -552,9 +552,9 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured,
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Mutate(policyContext)
@ -640,9 +640,9 @@ func Test_foreach(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
@ -747,9 +747,9 @@ func Test_foreach_element_mutation(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
@ -873,9 +873,9 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
@ -1000,9 +1000,9 @@ func Test_foreach_order_mutation_(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
err = ctx.AddImageInfos(resource)
@ -1451,10 +1451,10 @@ func Test_mutate_existing_resources(t *testing.T) {
assert.NilError(t, err)
policyContext = &PolicyContext{
Client: dclient,
Policy: &policy,
JSONContext: ctx,
NewResource: *trigger,
client: dclient,
policy: &policy,
jsonContext: ctx,
newResource: *trigger,
}
}
er := Mutate(policyContext)
@ -1560,9 +1560,9 @@ func Test_RuleSelectorMutate(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured,
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured,
}
er := Mutate(policyContext)
@ -1578,7 +1578,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
}
applyOne := kyverno.ApplyOne
policyContext.Policy.GetSpec().ApplyRules = &applyOne
policyContext.policy.GetSpec().ApplyRules = &applyOne
er = Mutate(policyContext)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
@ -1941,9 +1941,9 @@ func Test_SpecialCharacters(t *testing.T) {
// Create policy context.
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resource,
policy: &policy,
jsonContext: ctx,
newResource: *resource,
}
// Mutate and make sure that we got the expected amount of rules.

View file

@ -4,55 +4,196 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// ExcludeFunc is a function used to determine if a resource is excluded
type ExcludeFunc = func(kind, namespace, name string) bool
// PolicyContext contains the contexts for engine to process
type PolicyContext struct {
// Policy is the policy to be processed
Policy kyvernov1.PolicyInterface
// policy is the policy to be processed
policy kyvernov1.PolicyInterface
// NewResource is the resource to be processed
NewResource unstructured.Unstructured
// newResource is the resource to be processed
newResource unstructured.Unstructured
// OldResource is the prior resource for an update, or nil
OldResource unstructured.Unstructured
// oldResource is the prior resource for an update, or nil
oldResource unstructured.Unstructured
// Element is set when the context is used for processing a foreach loop
Element unstructured.Unstructured
// element is set when the context is used for processing a foreach loop
element unstructured.Unstructured
// AdmissionInfo contains the admission request information
AdmissionInfo kyvernov1beta1.RequestInfo
// admissionInfo contains the admission request information
admissionInfo kyvernov1beta1.RequestInfo
// Dynamic client - used for api lookups
Client dclient.Interface
client dclient.Interface
// Config handler
ExcludeGroupRole []string
excludeGroupRole []string
ExcludeResourceFunc func(kind, namespace, name string) bool
excludeResourceFunc ExcludeFunc
// JSONContext is the variable context
JSONContext context.Interface
// jsonContext is the variable context
jsonContext context.Interface
// NamespaceLabels stores the label of namespace to be processed by namespace selector
NamespaceLabels map[string]string
// namespaceLabels stores the label of namespace to be processed by namespace selector
namespaceLabels map[string]string
// AdmissionOperation represents if the caller is from the webhook server
AdmissionOperation bool
// admissionOperation represents if the caller is from the webhook server
admissionOperation bool
}
func (pc *PolicyContext) Copy() *PolicyContext {
// Getters
func (c *PolicyContext) Policy() kyvernov1.PolicyInterface {
return c.policy
}
func (c *PolicyContext) NewResource() unstructured.Unstructured {
return c.newResource
}
func (c *PolicyContext) OldResource() unstructured.Unstructured {
return c.oldResource
}
func (c *PolicyContext) AdmissionInfo() kyvernov1beta1.RequestInfo {
return c.admissionInfo
}
func (c *PolicyContext) JSONContext() context.Interface {
return c.jsonContext
}
// Mutators
func (c *PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext {
copy := c.Copy()
copy.policy = policy
return copy
}
func (c *PolicyContext) WithNamespaceLabels(namespaceLabels map[string]string) *PolicyContext {
copy := c.Copy()
copy.namespaceLabels = namespaceLabels
return copy
}
func (c *PolicyContext) WithAdmissionInfo(admissionInfo kyvernov1beta1.RequestInfo) *PolicyContext {
copy := c.Copy()
copy.admissionInfo = admissionInfo
return copy
}
func (c *PolicyContext) WithNewResource(resource unstructured.Unstructured) *PolicyContext {
copy := c.Copy()
copy.newResource = resource
return copy
}
func (c *PolicyContext) WithOldResource(resource unstructured.Unstructured) *PolicyContext {
copy := c.Copy()
copy.oldResource = resource
return copy
}
func (c *PolicyContext) WithResources(newResource unstructured.Unstructured, oldResource unstructured.Unstructured) *PolicyContext {
return c.WithNewResource(newResource).WithOldResource(oldResource)
}
func (c *PolicyContext) WithClient(client dclient.Interface) *PolicyContext {
copy := c.Copy()
copy.client = client
return copy
}
func (c *PolicyContext) WithExcludeGroupRole(excludeGroupRole ...string) *PolicyContext {
copy := c.Copy()
copy.excludeGroupRole = excludeGroupRole
return copy
}
func (c *PolicyContext) WithExcludeResourceFunc(excludeResourceFunc ExcludeFunc) *PolicyContext {
copy := c.Copy()
copy.excludeResourceFunc = excludeResourceFunc
return copy
}
func (c *PolicyContext) WithConfiguration(configuration config.Configuration) *PolicyContext {
return c.WithExcludeResourceFunc(configuration.ToFilter).WithExcludeGroupRole(configuration.GetExcludeGroupRole()...)
}
func (c *PolicyContext) WithAdmissionOperation(admissionOperation bool) *PolicyContext {
copy := c.Copy()
copy.admissionOperation = admissionOperation
return copy
}
// Constructors
func NewPolicyContextWithJsonContext(jsonContext context.Interface) *PolicyContext {
return &PolicyContext{
Policy: pc.Policy,
NewResource: pc.NewResource,
OldResource: pc.OldResource,
AdmissionInfo: pc.AdmissionInfo,
Client: pc.Client,
ExcludeGroupRole: pc.ExcludeGroupRole,
ExcludeResourceFunc: pc.ExcludeResourceFunc,
JSONContext: pc.JSONContext,
NamespaceLabels: pc.NamespaceLabels,
jsonContext: jsonContext,
excludeGroupRole: []string{},
excludeResourceFunc: func(string, string, string) bool {
return false
},
}
}
func NewPolicyContext() *PolicyContext {
return NewPolicyContextWithJsonContext(context.NewContext())
}
func NewPolicyContextFromAdmissionRequest(
request *admissionv1.AdmissionRequest,
admissionInfo kyvernov1beta1.RequestInfo,
configuration config.Configuration,
client dclient.Interface,
) (*PolicyContext, error) {
ctx, err := newVariablesContext(request, &admissionInfo)
if err != nil {
return nil, errors.Wrap(err, "failed to create policy rule context")
}
newResource, oldResource, err := utils.ExtractResources(nil, request)
if err != nil {
return nil, errors.Wrap(err, "failed to parse resource")
}
if err := ctx.AddImageInfos(&newResource); err != nil {
return nil, errors.Wrap(err, "failed to add image information to the policy rule context")
}
policyContext := NewPolicyContextWithJsonContext(ctx).
WithNewResource(newResource).
WithOldResource(oldResource).
WithAdmissionInfo(admissionInfo).
WithConfiguration(configuration).
WithClient(client).
WithAdmissionOperation(true)
return policyContext, nil
}
func (c PolicyContext) Copy() *PolicyContext {
return &c
}
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
ctx := enginectx.NewContext()
if err := ctx.AddRequest(request); err != nil {
return nil, errors.Wrap(err, "failed to load incoming request in context")
}
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
return nil, errors.Wrap(err, "failed to load userInfo in context")
}
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
return nil, errors.Wrap(err, "failed to load service account in context")
}
return ctx, nil
}

View file

@ -426,7 +426,7 @@ func ManagedPodResource(policy kyvernov1.PolicyInterface, resource unstructured.
}
func checkPreconditions(logger logr.Logger, ctx *PolicyContext, anyAllConditions apiextensions.JSON) (bool, error) {
preconditions, err := variables.SubstituteAllInPreconditions(logger, ctx.JSONContext, anyAllConditions)
preconditions, err := variables.SubstituteAllInPreconditions(logger, ctx.jsonContext, anyAllConditions)
if err != nil {
return false, errors.Wrapf(err, "failed to substitute variables in preconditions")
}
@ -436,7 +436,7 @@ func checkPreconditions(logger logr.Logger, ctx *PolicyContext, anyAllConditions
return false, errors.Wrapf(err, "failed to parse preconditions")
}
pass := variables.EvaluateConditions(logger, ctx.JSONContext, typeConditions)
pass := variables.EvaluateConditions(logger, ctx.jsonContext, typeConditions)
return pass, nil
}

View file

@ -46,11 +46,11 @@ func Validate(policyContext *PolicyContext) (resp *response.EngineResponse) {
}
func buildLogger(ctx *PolicyContext) logr.Logger {
logger := logging.WithName("EngineValidate").WithValues("policy", ctx.Policy.GetName())
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", ctx.OldResource.GetKind(), "namespace", ctx.OldResource.GetNamespace(), "name", ctx.OldResource.GetName())
logger := logging.WithName("EngineValidate").WithValues("policy", ctx.policy.GetName())
if reflect.DeepEqual(ctx.newResource, unstructured.Unstructured{}) {
logger = logger.WithValues("kind", ctx.oldResource.GetKind(), "namespace", ctx.oldResource.GetNamespace(), "name", ctx.oldResource.GetName())
} else {
logger = logger.WithValues("kind", ctx.NewResource.GetKind(), "namespace", ctx.NewResource.GetNamespace(), "name", ctx.NewResource.GetName())
logger = logger.WithValues("kind", ctx.newResource.GetKind(), "namespace", ctx.newResource.GetNamespace(), "name", ctx.newResource.GetName())
}
return logger
@ -63,24 +63,24 @@ func buildResponse(ctx *PolicyContext, resp *response.EngineResponse, startTime
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
// for delete requests patched resource will be oldResource since newResource is empty
resource := ctx.NewResource
if reflect.DeepEqual(ctx.NewResource, unstructured.Unstructured{}) {
resource = ctx.OldResource
resource := ctx.newResource
if reflect.DeepEqual(ctx.newResource, unstructured.Unstructured{}) {
resource = ctx.oldResource
}
resp.PatchedResource = resource
}
resp.Policy = ctx.Policy
resp.PolicyResponse.Policy.Name = ctx.Policy.GetName()
resp.PolicyResponse.Policy.Namespace = ctx.Policy.GetNamespace()
resp.Policy = ctx.policy
resp.PolicyResponse.Policy.Name = ctx.policy.GetName()
resp.PolicyResponse.Policy.Namespace = ctx.policy.GetNamespace()
resp.PolicyResponse.Resource.Name = resp.PatchedResource.GetName()
resp.PolicyResponse.Resource.Namespace = resp.PatchedResource.GetNamespace()
resp.PolicyResponse.Resource.Kind = resp.PatchedResource.GetKind()
resp.PolicyResponse.Resource.APIVersion = resp.PatchedResource.GetAPIVersion()
resp.PolicyResponse.ValidationFailureAction = ctx.Policy.GetSpec().ValidationFailureAction
resp.PolicyResponse.ValidationFailureAction = ctx.policy.GetSpec().ValidationFailureAction
for _, v := range ctx.Policy.GetSpec().ValidationFailureActionOverrides {
for _, v := range ctx.policy.GetSpec().ValidationFailureActionOverrides {
resp.PolicyResponse.ValidationFailureActionOverrides = append(resp.PolicyResponse.ValidationFailureActionOverrides, response.ValidationFailureActionOverride{Action: v.Action, Namespaces: v.Namespaces})
}
@ -91,19 +91,19 @@ func buildResponse(ctx *PolicyContext, resp *response.EngineResponse, startTime
func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineResponse {
resp := &response.EngineResponse{}
ctx.JSONContext.Checkpoint()
defer ctx.JSONContext.Restore()
ctx.jsonContext.Checkpoint()
defer ctx.jsonContext.Restore()
rules := autogen.ComputeRules(ctx.Policy)
rules := autogen.ComputeRules(ctx.policy)
matchCount := 0
applyRules := ctx.Policy.GetSpec().GetApplyRules()
applyRules := ctx.policy.GetSpec().GetApplyRules()
if ctx.Policy.IsNamespaced() {
polNs := ctx.Policy.GetNamespace()
if ctx.NewResource.Object != nil && (ctx.NewResource.GetNamespace() != polNs || ctx.NewResource.GetNamespace() == "") {
if ctx.policy.IsNamespaced() {
polNs := ctx.policy.GetNamespace()
if ctx.newResource.Object != nil && (ctx.newResource.GetNamespace() != polNs || ctx.newResource.GetNamespace() == "") {
return resp
}
if ctx.OldResource.Object != nil && (ctx.OldResource.GetNamespace() != polNs || ctx.OldResource.GetNamespace() == "") {
if ctx.oldResource.Object != nil && (ctx.oldResource.GetNamespace() != polNs || ctx.oldResource.GetNamespace() == "") {
return resp
}
}
@ -123,7 +123,7 @@ func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineRespo
}
log.V(3).Info("processing validation rule", "matchCount", matchCount, "applyRules", applyRules)
ctx.JSONContext.Reset()
ctx.jsonContext.Reset()
startTime := time.Now()
var ruleResp *response.RuleResponse
@ -148,14 +148,14 @@ func validateResource(log logr.Logger, ctx *PolicyContext) *response.EngineRespo
func validateOldObject(log logr.Logger, ctx *PolicyContext, rule *kyvernov1.Rule) (*response.RuleResponse, error) {
ctxCopy := ctx.Copy()
ctxCopy.NewResource = *ctxCopy.OldResource.DeepCopy()
ctxCopy.OldResource = unstructured.Unstructured{}
ctxCopy.newResource = *ctxCopy.oldResource.DeepCopy()
ctxCopy.oldResource = unstructured.Unstructured{}
if err := context.ReplaceResource(ctxCopy.JSONContext, ctxCopy.NewResource.Object); err != nil {
if err := context.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 := context.ReplaceOldResource(ctxCopy.jsonContext, ctxCopy.oldResource.Object); err != nil {
return nil, errors.Wrapf(err, "failed to replace old object in the JSON context")
}
@ -300,7 +300,7 @@ func (v *validator) validateForEach() *response.RuleResponse {
}
for _, foreach := range foreachList {
elements, err := evaluateList(foreach.List, v.ctx.JSONContext)
elements, err := evaluateList(foreach.List, v.ctx.jsonContext)
if err != nil {
v.log.V(2).Info("failed to evaluate list", "list", foreach.List, "error", err.Error())
continue
@ -321,8 +321,8 @@ func (v *validator) validateForEach() *response.RuleResponse {
}
func (v *validator) validateElements(foreach kyvernov1.ForEachValidation, elements []interface{}, elementScope *bool) (*response.RuleResponse, int) {
v.ctx.JSONContext.Checkpoint()
defer v.ctx.JSONContext.Restore()
v.ctx.jsonContext.Checkpoint()
defer v.ctx.jsonContext.Restore()
applyCount := 0
for i, e := range elements {
@ -330,7 +330,7 @@ func (v *validator) validateElements(foreach kyvernov1.ForEachValidation, elemen
continue
}
store.SetForeachElement(i)
v.ctx.JSONContext.Reset()
v.ctx.jsonContext.Reset()
ctx := v.ctx.Copy()
if err := addElementToContext(ctx, e, i, elementScope); err != nil {
@ -369,7 +369,7 @@ func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex int, el
if err != nil {
return err
}
if err := ctx.JSONContext.AddElement(data, elementIndex); err != nil {
if err := ctx.jsonContext.AddElement(data, elementIndex); err != nil {
return errors.Wrapf(err, "failed to add element (%v) to JSON context", e)
}
dataMap, ok := data.(map[string]interface{})
@ -392,7 +392,7 @@ func addElementToContext(ctx *PolicyContext, e interface{}, elementIndex int, el
if scoped {
u := unstructured.Unstructured{}
u.SetUnstructuredContent(dataMap)
ctx.Element = u
ctx.element = u
}
return nil
}
@ -413,7 +413,7 @@ func (v *validator) loadContext() error {
func (v *validator) validateDeny() *response.RuleResponse {
anyAllCond := v.deny.GetAnyAllConditions()
anyAllCond, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, anyAllCond)
anyAllCond, err := variables.SubstituteAll(v.log, v.ctx.jsonContext, anyAllCond)
if err != nil {
return ruleError(v.rule, response.Validation, "failed to substitute variables in deny conditions", err)
}
@ -427,7 +427,7 @@ func (v *validator) validateDeny() *response.RuleResponse {
return ruleError(v.rule, response.Validation, "invalid deny conditions", err)
}
deny := variables.EvaluateConditions(v.log, v.ctx.JSONContext, denyConditions)
deny := variables.EvaluateConditions(v.log, v.ctx.jsonContext, denyConditions)
if deny {
return ruleResponse(*v.rule, response.Validation, v.getDenyMessage(deny), response.RuleStatusFail, nil)
}
@ -445,7 +445,7 @@ func (v *validator) getDenyMessage(deny bool) string {
return fmt.Sprintf("validation error: rule %s failed", v.rule.Name)
}
raw, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, msg)
raw, err := variables.SubstituteAll(v.log, v.ctx.jsonContext, msg)
if err != nil {
return msg
}
@ -454,12 +454,12 @@ func (v *validator) getDenyMessage(deny bool) string {
}
func getSpec(v *validator) (podSpec *corev1.PodSpec, metadata *metav1.ObjectMeta, err error) {
kind := v.ctx.NewResource.GetKind()
kind := v.ctx.newResource.GetKind()
if kind == "DaemonSet" || kind == "Deployment" || kind == "Job" || kind == "StatefulSet" || kind == "ReplicaSet" || kind == "ReplicationController" {
var deployment appsv1.Deployment
resourceBytes, err := v.ctx.NewResource.MarshalJSON()
resourceBytes, err := v.ctx.newResource.MarshalJSON()
if err != nil {
return nil, nil, err
}
@ -473,7 +473,7 @@ func getSpec(v *validator) (podSpec *corev1.PodSpec, metadata *metav1.ObjectMeta
} else if kind == "CronJob" {
var cronJob batchv1.CronJob
resourceBytes, err := v.ctx.NewResource.MarshalJSON()
resourceBytes, err := v.ctx.newResource.MarshalJSON()
if err != nil {
return nil, nil, err
}
@ -486,7 +486,7 @@ func getSpec(v *validator) (podSpec *corev1.PodSpec, metadata *metav1.ObjectMeta
} else if kind == "Pod" {
var pod corev1.Pod
resourceBytes, err := v.ctx.NewResource.MarshalJSON()
resourceBytes, err := v.ctx.newResource.MarshalJSON()
if err != nil {
return nil, nil, err
}
@ -531,8 +531,8 @@ func (v *validator) validatePodSecurity() *response.RuleResponse {
}
func (v *validator) validateResourceWithRule() *response.RuleResponse {
if !isEmptyUnstructured(&v.ctx.Element) {
return v.validatePatterns(v.ctx.Element)
if !isEmptyUnstructured(&v.ctx.element) {
return v.validatePatterns(v.ctx.element)
}
if isDeleteRequest(v.ctx) {
@ -540,18 +540,18 @@ func (v *validator) validateResourceWithRule() *response.RuleResponse {
return nil
}
resp := v.validatePatterns(v.ctx.NewResource)
resp := v.validatePatterns(v.ctx.newResource)
return resp
}
func isDeleteRequest(ctx *PolicyContext) bool {
// if the OldResource is not empty, and the NewResource is empty, the request is a DELETE
return isEmptyUnstructured(&ctx.NewResource)
return isEmptyUnstructured(&ctx.newResource)
}
func isUpdateRequest(ctx *PolicyContext) bool {
// is the OldObject and NewObject are available, the request is an UPDATE
return !isEmptyUnstructured(&ctx.OldResource) && !isEmptyUnstructured(&ctx.NewResource)
return !isEmptyUnstructured(&ctx.oldResource) && !isEmptyUnstructured(&ctx.newResource)
}
func isEmptyUnstructured(u *unstructured.Unstructured) bool {
@ -568,13 +568,13 @@ func isEmptyUnstructured(u *unstructured.Unstructured) bool {
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
func matches(logger logr.Logger, rule *kyvernov1.Rule, ctx *PolicyContext) bool {
err := MatchesResourceDescription(ctx.NewResource, *rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels, "")
err := MatchesResourceDescription(ctx.newResource, *rule, ctx.admissionInfo, ctx.excludeGroupRole, ctx.namespaceLabels, "")
if err == nil {
return true
}
if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
err := MatchesResourceDescription(ctx.OldResource, *rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels, "")
if !reflect.DeepEqual(ctx.oldResource, unstructured.Unstructured{}) {
err := MatchesResourceDescription(ctx.oldResource, *rule, ctx.admissionInfo, ctx.excludeGroupRole, ctx.namespaceLabels, "")
if err == nil {
return true
}
@ -718,7 +718,7 @@ func (v *validator) buildErrorMessage(err error, path string) string {
return fmt.Sprintf("validation error: rule %s execution error: %s", v.rule.Name, err.Error())
}
msgRaw, sErr := variables.SubstituteAll(v.log, v.ctx.JSONContext, v.rule.Validation.Message)
msgRaw, sErr := variables.SubstituteAll(v.log, v.ctx.jsonContext, v.rule.Validation.Message)
if sErr != nil {
v.log.V(2).Info("failed to substitute variables in message", "error", sErr)
return fmt.Sprintf("validation error: variables substitution error in rule %s execution error: %s", v.rule.Name, err.Error())
@ -749,7 +749,7 @@ func buildAnyPatternErrorMessage(rule *kyvernov1.Rule, errors []string) string {
func (v *validator) substitutePatterns() error {
if v.pattern != nil {
i, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, v.pattern)
i, err := variables.SubstituteAll(v.log, v.ctx.jsonContext, v.pattern)
if err != nil {
return err
}
@ -759,7 +759,7 @@ func (v *validator) substitutePatterns() error {
}
if v.anyPattern != nil {
i, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, v.anyPattern)
i, err := variables.SubstituteAll(v.log, v.ctx.jsonContext, v.anyPattern)
if err != nil {
return err
}
@ -776,7 +776,7 @@ func (v *validator) substituteDeny() error {
return nil
}
i, err := variables.SubstituteAll(v.log, v.ctx.JSONContext, v.deny)
i, err := variables.SubstituteAll(v.log, v.ctx.jsonContext, v.deny)
if err != nil {
return err
}

View file

@ -131,7 +131,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(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -231,7 +231,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
"validation rule 'validate-tag' passed.",
"validation rule 'validate-latest' passed.",
}
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -305,7 +305,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.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/"}
@ -388,7 +388,7 @@ func TestValidate_host_network_port(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.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 {
@ -478,7 +478,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -566,7 +566,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.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 {
@ -636,7 +636,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -709,7 +709,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -783,7 +783,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -863,7 +863,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -937,7 +937,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.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 {
@ -1012,7 +1012,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1087,7 +1087,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
assert.Assert(t, !er.IsSuccessful())
}
@ -1157,7 +1157,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
assert.Assert(t, !er.IsSuccessful())
}
@ -1227,7 +1227,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1315,7 +1315,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.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 {
@ -1402,7 +1402,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1475,9 +1475,9 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
@ -1568,9 +1568,9 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
@ -1629,9 +1629,9 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(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/")
@ -1720,9 +1720,9 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
@ -1813,9 +1813,9 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
@ -1918,9 +1918,9 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(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.")
@ -1971,9 +1971,9 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
for i, rule := range er.PolicyResponse.Rules {
@ -2133,11 +2133,11 @@ func executeTest(t *testing.T, test testCase) {
}
pc := &PolicyContext{
Policy: &policy,
NewResource: newR,
OldResource: oldR,
AdmissionInfo: userInfo,
JSONContext: ctx,
policy: &policy,
newResource: newR,
oldResource: oldR,
admissionInfo: userInfo,
jsonContext: ctx,
}
resp := Validate(pc)
@ -2239,7 +2239,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(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
@ -2328,7 +2328,7 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: ctx})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
assert.Assert(t, !er.IsSuccessful())
}
@ -2417,7 +2417,7 @@ func Test_StringInDenyCondition(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: ctx})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx})
assert.Assert(t, er.IsSuccessful())
}
@ -3001,9 +3001,9 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
@ -3065,17 +3065,17 @@ func Test_delete_ignore_pattern(t *testing.T) {
assert.NilError(t, err)
policyContextCreate := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
newResource: *resourceUnstructured}
engineResponseCreate := Validate(policyContextCreate)
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
policyContextDelete := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
OldResource: *resourceUnstructured}
policy: &policy,
jsonContext: ctx,
oldResource: *resourceUnstructured}
engineResponseDelete := Validate(policyContextDelete)
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
}
@ -3135,7 +3135,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(tc.rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := Validate(&PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: context.NewContext()})
if tc.expectedFailed {
assert.Assert(t, er.IsFailed())
} else if tc.expectedSkipped {

View file

@ -61,14 +61,12 @@ func applyPolicy(policy kyvernov1.PolicyInterface, resource unstructured.Unstruc
logger.Error(err, "failed to process mutation rule")
}
policyCtx := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
ExcludeGroupRole: excludeGroupRole,
JSONContext: ctx,
Client: client,
NamespaceLabels: namespaceLabels,
}
policyCtx := engine.NewPolicyContextWithJsonContext(ctx).
WithPolicy(policy).
WithNewResource(resource).
WithNamespaceLabels(namespaceLabels).
WithClient(client).
WithExcludeGroupRole(excludeGroupRole...)
engineResponseValidation = engine.Validate(policyCtx)
engineResponses = append(engineResponses, mergeRuleRespose(engineResponseMutation, engineResponseValidation))
@ -77,12 +75,10 @@ func applyPolicy(policy kyvernov1.PolicyInterface, resource unstructured.Unstruc
}
func mutation(policy kyvernov1.PolicyInterface, resource unstructured.Unstructured, log logr.Logger, jsonContext context.Interface, namespaceLabels map[string]string) (*response.EngineResponse, error) {
policyContext := &engine.PolicyContext{
Policy: policy,
NewResource: resource,
JSONContext: jsonContext,
NamespaceLabels: namespaceLabels,
}
policyContext := engine.NewPolicyContextWithJsonContext(jsonContext).
WithPolicy(policy).
WithNamespaceLabels(namespaceLabels).
WithNewResource(resource)
engineResponse := engine.Mutate(policyContext)
if !engineResponse.IsSuccessful() {

View file

@ -14,7 +14,6 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/engine"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
@ -144,14 +143,9 @@ func runTestCase(t *testing.T, tc TestCase) bool {
t.FailNow()
}
ctx := &engine.PolicyContext{
Policy: policy,
NewResource: *resource,
ExcludeGroupRole: []string{},
JSONContext: enginecontext.NewContext(),
}
policyContext := engine.NewPolicyContext().WithPolicy(policy).WithNewResource(*resource)
er := engine.Mutate(ctx)
er := engine.Mutate(policyContext)
t.Log("---Mutation---")
validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource)
validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse)
@ -161,14 +155,9 @@ func runTestCase(t *testing.T, tc TestCase) bool {
resource = &er.PatchedResource
}
ctx = &engine.PolicyContext{
Policy: policy,
NewResource: *resource,
ExcludeGroupRole: []string{},
JSONContext: enginecontext.NewContext(),
}
policyContext = policyContext.WithNewResource(*resource)
er = engine.Validate(ctx)
er = engine.Validate(policyContext)
t.Log("---Validation---")
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)
@ -182,16 +171,7 @@ func runTestCase(t *testing.T, tc TestCase) bool {
if err := createNamespace(client, resource); err != nil {
t.Error(err)
} else {
policyContext := &engine.PolicyContext{
NewResource: *resource,
Policy: policy,
Client: client,
ExcludeGroupRole: []string{},
ExcludeResourceFunc: func(s1, s2, s3 string) bool {
return false
},
JSONContext: enginecontext.NewContext(),
}
policyContext := policyContext.WithClient(client)
er = engine.ApplyBackgroundChecks(policyContext)
t.Log(("---Generation---"))

View file

@ -88,9 +88,9 @@ func (h *generationHandler) Handle(
if (request.Operation == admissionv1.Create || request.Operation == admissionv1.Update) && len(policies) != 0 {
for _, policy := range policies {
var rules []response.RuleResponse
policyContext.Policy = policy
policyContext := policyContext.WithPolicy(policy)
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
policyContext.NamespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log)
policyContext = policyContext.WithNamespaceLabels(common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log))
}
engineResponse := engine.ApplyBackgroundChecks(policyContext)
for _, rule := range engineResponse.PolicyResponse.Rules {
@ -113,11 +113,12 @@ func (h *generationHandler) Handle(
go webhookutils.RegisterPolicyExecutionDurationMetricGenerate(context.TODO(), h.log, metricsConfig, string(request.Operation), policy, *engineResponse)
}
if failedResponse := applyUpdateRequest(request, kyvernov1beta1.Generate, h.urGenerator, policyContext.AdmissionInfo, request.Operation, engineResponses...); failedResponse != nil {
if failedResponse := applyUpdateRequest(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)
e := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &policyContext.NewResource)
newResource := policyContext.NewResource()
e := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &newResource)
h.eventGen.Add(e...)
}
}

View file

@ -117,7 +117,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
logger.V(4).Info("processing policies for validate admission request", "validate", len(policies), "mutate", len(mutatePolicies), "generate", len(generatePolicies))
policyContext, err := h.pcBuilder.Build(request, generatePolicies...)
policyContext, err := h.pcBuilder.Build(request)
if err != nil {
return errorResponse(logger, request.UID, err, "failed create policy context")
}
@ -152,13 +152,13 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
return admissionutils.ResponseSuccess(request.UID)
}
logger.V(4).Info("processing policies for mutate admission request", "mutatePolicies", len(mutatePolicies), "verifyImagesPolicies", len(verifyImagesPolicies))
policyContext, err := h.pcBuilder.Build(request, mutatePolicies...)
policyContext, err := h.pcBuilder.Build(request)
if err != nil {
logger.Error(err, "failed to build policy context")
return admissionutils.Response(request.UID, err)
}
// update container images to a canonical form
if err := enginectx.MutateResourceWithImageInfo(request.Object.Raw, policyContext.JSONContext); err != nil {
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.eventGen, h.openApiManager, h.nsLister)
@ -169,7 +169,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
}
newRequest := patchRequest(mutatePatches, request, logger)
// rebuild context to process images updated via mutate policies
policyContext, err = h.pcBuilder.Build(newRequest, mutatePolicies...)
policyContext, err = h.pcBuilder.Build(newRequest)
if err != nil {
logger.Error(err, "failed to build policy context")
return admissionutils.Response(request.UID, err)

View file

@ -75,7 +75,7 @@ func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, reques
var patches [][]byte
verifiedImageData := &engine.ImageVerificationMetadata{}
for _, p := range policies {
policyContext.Policy = p
policyContext := policyContext.WithPolicy(p)
resp, ivm := engine.VerifyAndPatchImages(policyContext)
engineResponses = append(engineResponses, resp)
@ -83,7 +83,7 @@ func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, reques
verifiedImageData.Merge(ivm)
}
failurePolicy := policyContext.Policy.GetSpec().GetFailurePolicy()
failurePolicy := policies[0].GetSpec().GetFailurePolicy()
blocked := webhookutils.BlockRequest(engineResponses, failurePolicy, logger)
if !isResourceDeleted(policyContext) {
events := webhookutils.GenerateEvents(engineResponses, blocked)
@ -106,23 +106,26 @@ func (h *imageVerificationHandler) handleVerifyImages(logger logr.Logger, reques
}
}
go h.handleAudit(policyContext.NewResource, request, nil, engineResponses...)
go h.handleAudit(policyContext.NewResource(), request, nil, engineResponses...)
warnings := webhookutils.GetWarningMessages(engineResponses)
return true, "", jsonutils.JoinPatches(patches...), warnings
}
func hasAnnotations(context *engine.PolicyContext) bool {
annotations := context.NewResource.GetAnnotations()
newResource := context.NewResource()
annotations := newResource.GetAnnotations()
return len(annotations) != 0
}
func isResourceDeleted(policyContext *engine.PolicyContext) bool {
var deletionTimeStamp *metav1.Time
if reflect.DeepEqual(policyContext.NewResource, unstructured.Unstructured{}) {
deletionTimeStamp = policyContext.NewResource.GetDeletionTimestamp()
resource := policyContext.NewResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
} else {
deletionTimeStamp = policyContext.OldResource.GetDeletionTimestamp()
resource := policyContext.OldResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
}
return deletionTimeStamp != nil
}

View file

@ -100,8 +100,8 @@ func (v *mutationHandler) applyMutations(
continue
}
v.log.V(3).Info("applying policy mutate rules", "policy", policy.GetName())
policyContext.Policy = policy
engineResponse, policyPatches, err := v.applyMutation(request, policyContext)
currentContext := policyContext.WithPolicy(policy)
engineResponse, policyPatches, err := v.applyMutation(request, currentContext)
if err != nil {
return nil, nil, fmt.Errorf("mutation policy %s error: %v", policy.GetName(), err)
}
@ -114,7 +114,7 @@ func (v *mutationHandler) applyMutations(
}
}
policyContext.NewResource = engineResponse.PatchedResource
policyContext = currentContext.WithNewResource(engineResponse.PatchedResource)
engineResponses = append(engineResponses, engineResponse)
// registering the kyverno_policy_results_total metric concurrently
@ -141,20 +141,20 @@ func (v *mutationHandler) applyMutations(
func (h *mutationHandler) applyMutation(request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext) (*response.EngineResponse, [][]byte, error) {
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
policyContext.NamespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log)
policyContext = policyContext.WithNamespaceLabels(common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log))
}
engineResponse := engine.Mutate(policyContext)
policyPatches := engineResponse.GetPatches()
if !engineResponse.IsSuccessful() {
return nil, nil, fmt.Errorf("failed to apply policy %s rules %v", policyContext.Policy.GetName(), engineResponse.GetFailedRules())
return nil, nil, fmt.Errorf("failed to apply policy %s rules %v", policyContext.Policy().GetName(), engineResponse.GetFailedRules())
}
if policyContext.Policy.ValidateSchema() && engineResponse.PatchedResource.GetKind() != "*" {
if policyContext.Policy().ValidateSchema() && engineResponse.PatchedResource.GetKind() != "*" {
err := h.openApiManager.ValidateResource(*engineResponse.PatchedResource.DeepCopy(), engineResponse.PatchedResource.GetAPIVersion(), engineResponse.PatchedResource.GetKind())
if err != nil {
return nil, nil, errors.Wrapf(err, "failed to validate resource mutated by policy %s", policyContext.Policy.GetName())
return nil, nil, errors.Wrapf(err, "failed to validate resource mutated by policy %s", policyContext.Policy().GetName())
}
}
@ -175,9 +175,11 @@ func logMutationResponse(patches [][]byte, engineResponses []*response.EngineRes
func isResourceDeleted(policyContext *engine.PolicyContext) bool {
var deletionTimeStamp *metav1.Time
if reflect.DeepEqual(policyContext.NewResource, unstructured.Unstructured{}) {
deletionTimeStamp = policyContext.NewResource.GetDeletionTimestamp()
resource := policyContext.NewResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
} else {
deletionTimeStamp = policyContext.OldResource.GetDeletionTimestamp()
resource := policyContext.OldResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
}
return deletionTimeStamp != nil
}

View file

@ -25,10 +25,11 @@ func (h *handlers) createUpdateRequests(logger logr.Logger, request *admissionv1
func (h *handlers) handleMutateExisting(logger logr.Logger, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp time.Time) {
if request.Operation == admissionv1.Delete {
policyContext.NewResource = policyContext.OldResource
policyContext = policyContext.WithNewResource(policyContext.OldResource())
}
if request.Operation == admissionv1.Update && policyContext.NewResource.GetDeletionTimestamp() != nil {
resource := policyContext.NewResource()
if request.Operation == admissionv1.Update && resource.GetDeletionTimestamp() != nil {
logger.V(4).Info("skip creating UR for the trigger resource that is in termination")
return
}
@ -41,7 +42,7 @@ func (h *handlers) handleMutateExisting(logger logr.Logger, request *admissionv1
logger.V(4).Info("update request for mutateExisting policy")
var rules []response.RuleResponse
policyContext.Policy = policy
policyContext := policyContext.WithPolicy(policy)
engineResponse := engine.ApplyBackgroundChecks(policyContext)
for _, rule := range engineResponse.PolicyResponse.Rules {
@ -61,10 +62,11 @@ 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(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)
events := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &policyContext.NewResource)
resource := policyContext.NewResource()
events := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &resource)
h.eventGen.Add(events...)
}
}

View file

@ -67,7 +67,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(policyContext.NewResource(), request, namespaceLabels)
return true, "", nil
}
@ -76,9 +76,11 @@ func (v *validationHandler) HandleValidation(
var deletionTimeStamp *metav1.Time
if reflect.DeepEqual(policyContext.NewResource, unstructured.Unstructured{}) {
deletionTimeStamp = policyContext.NewResource.GetDeletionTimestamp()
resource := policyContext.NewResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
} else {
deletionTimeStamp = policyContext.OldResource.GetDeletionTimestamp()
resource := policyContext.OldResource()
deletionTimeStamp = resource.GetDeletionTimestamp()
}
if deletionTimeStamp != nil && request.Operation == admissionv1.Update {
@ -88,8 +90,7 @@ func (v *validationHandler) HandleValidation(
var engineResponses []*response.EngineResponse
failurePolicy := kyvernov1.Ignore
for _, policy := range policies {
policyContext.Policy = policy
policyContext.NamespaceLabels = namespaceLabels
policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels)
if policy.GetSpec().GetFailurePolicy() == kyvernov1.Fail {
failurePolicy = kyvernov1.Fail
}
@ -101,8 +102,8 @@ func (v *validationHandler) HandleValidation(
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, metricsConfig, string(request.Operation), policyContext.Policy(), *engineResponse)
go webhookutils.RegisterPolicyExecutionDurationMetricValidate(context.TODO(), logger, metricsConfig, string(request.Operation), policyContext.Policy(), *engineResponse)
engineResponses = append(engineResponses, engineResponse)
if !engineResponse.IsSuccessful() {
@ -126,7 +127,7 @@ func (v *validationHandler) HandleValidation(
return false, webhookutils.GetBlockedMessages(engineResponses), nil
}
go v.handleAudit(policyContext.NewResource, request, namespaceLabels, engineResponses...)
go v.handleAudit(policyContext.NewResource(), request, namespaceLabels, engineResponses...)
warnings := webhookutils.GetWarningMessages(engineResponses)
return true, "", warnings
@ -134,14 +135,13 @@ func (v *validationHandler) HandleValidation(
func (v *validationHandler) buildAuditResponses(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, policies...)
policyContext, err := v.pcBuilder.Build(request)
if err != nil {
return nil, err
}
var responses []*response.EngineResponse
for _, policy := range policies {
policyContext.Policy = policy
policyContext.NamespaceLabels = namespaceLabels
policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels)
responses = append(responses, engine.Validate(policyContext))
}
return responses, nil

View file

@ -9,7 +9,6 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
webhookutils "github.com/kyverno/kyverno/pkg/webhooks/utils"
@ -531,7 +530,9 @@ func TestValidate_failure_action_overrides(t *testing.T) {
resourceUnstructured, err := utils.ConvertToUnstructured(tc.rawResource)
assert.NilError(t, err)
er := engine.Validate(&engine.PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
er := engine.Validate(
engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured),
)
if tc.blocked && tc.messages != nil {
for _, r := range er.PolicyResponse.Rules {
msg := tc.messages[r.Name]
@ -589,7 +590,8 @@ func Test_RuleSelector(t *testing.T) {
assert.NilError(t, err)
assert.Assert(t, resourceUnstructured != nil)
ctx := &engine.PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()}
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured)
resp := engine.Validate(ctx)
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 2)
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)

View file

@ -1,35 +1,18 @@
package utils
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/userinfo"
"github.com/kyverno/kyverno/pkg/utils"
"github.com/pkg/errors"
admissionv1 "k8s.io/api/admission/v1"
rbacv1listers "k8s.io/client-go/listers/rbac/v1"
)
type PolicyContextBuilder interface {
Build(*admissionv1.AdmissionRequest, ...kyvernov1.PolicyInterface) (*engine.PolicyContext, error)
}
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
ctx := enginectx.NewContext()
if err := ctx.AddRequest(request); err != nil {
return nil, errors.Wrap(err, "failed to load incoming request in context")
}
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
return nil, errors.Wrap(err, "failed to load userInfo in context")
}
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
return nil, errors.Wrap(err, "failed to load service account in context")
}
return ctx, nil
Build(*admissionv1.AdmissionRequest) (*engine.PolicyContext, error)
}
type policyContextBuilder struct {
@ -53,7 +36,7 @@ func NewPolicyContextBuilder(
}
}
func (b *policyContextBuilder) Build(request *admissionv1.AdmissionRequest, policies ...kyvernov1.PolicyInterface) (*engine.PolicyContext, error) {
func (b *policyContextBuilder) Build(request *admissionv1.AdmissionRequest) (*engine.PolicyContext, error) {
userRequestInfo := kyvernov1beta1.RequestInfo{
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
}
@ -63,26 +46,5 @@ func (b *policyContextBuilder) Build(request *admissionv1.AdmissionRequest, poli
userRequestInfo.Roles = roles
userRequestInfo.ClusterRoles = clusterRoles
}
ctx, err := newVariablesContext(request, &userRequestInfo)
if err != nil {
return nil, errors.Wrap(err, "failed to create policy rule context")
}
newResource, oldResource, err := utils.ExtractResources(nil, request)
if err != nil {
return nil, errors.Wrap(err, "failed to parse resource")
}
if err := ctx.AddImageInfos(&newResource); err != nil {
return nil, errors.Wrap(err, "failed to add image information to the policy rule context")
}
policyContext := &engine.PolicyContext{
NewResource: newResource,
OldResource: oldResource,
AdmissionInfo: userRequestInfo,
ExcludeGroupRole: b.configuration.GetExcludeGroupRole(),
ExcludeResourceFunc: b.configuration.ToFilter,
JSONContext: ctx,
Client: b.client,
AdmissionOperation: true,
}
return policyContext, nil
return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, b.configuration, b.client)
}