mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-29 02:45:06 +00:00
refactor: introduce context loader interface in engine api (#6164)
* refactor: introduce context loader interface in engine api Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * factory Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * mock 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> * 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> * test Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
fe9ecc8ae6
commit
848596ca8d
30 changed files with 448 additions and 253 deletions
|
@ -486,7 +486,11 @@ OuterLoop:
|
|||
WithClient(c.Client).
|
||||
WithSubresourcesInPolicy(subresources)
|
||||
|
||||
mutateResponse := engine.Mutate(context.Background(), registryclient.NewOrDie(), policyContext)
|
||||
mutateResponse := engine.Mutate(
|
||||
context.Background(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
)
|
||||
if mutateResponse != nil {
|
||||
engineResponses = append(engineResponses, mutateResponse)
|
||||
}
|
||||
|
@ -510,7 +514,12 @@ OuterLoop:
|
|||
var info Info
|
||||
var validateResponse *engineapi.EngineResponse
|
||||
if policyHasValidate {
|
||||
validateResponse = engine.Validate(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
validateResponse = engine.Validate(
|
||||
context.Background(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
cfg,
|
||||
)
|
||||
info = ProcessValidateEngineResponse(c.Policy, validateResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
|
||||
}
|
||||
|
||||
|
@ -518,7 +527,13 @@ OuterLoop:
|
|||
engineResponses = append(engineResponses, validateResponse)
|
||||
}
|
||||
|
||||
verifyImageResponse, _ := engine.VerifyAndPatchImages(context.Background(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
verifyImageResponse, _ := engine.VerifyAndPatchImages(
|
||||
context.Background(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
registryclient.NewOrDie(),
|
||||
policyContext,
|
||||
cfg,
|
||||
)
|
||||
if verifyImageResponse != nil && !verifyImageResponse.IsEmpty() {
|
||||
engineResponses = append(engineResponses, verifyImageResponse)
|
||||
info = ProcessValidateEngineResponse(c.Policy, verifyImageResponse, resPath, c.Rc, c.PolicyReport, c.AuditWarn)
|
||||
|
@ -532,7 +547,10 @@ OuterLoop:
|
|||
}
|
||||
|
||||
if policyHasGenerate {
|
||||
generateResponse := engine.ApplyBackgroundChecks(registryclient.NewOrDie(), policyContext)
|
||||
generateResponse := engine.ApplyBackgroundChecks(
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
)
|
||||
if generateResponse != nil && !generateResponse.IsEmpty() {
|
||||
newRuleResponse, err := handleGeneratePolicy(generateResponse, *policyContext, c.RuleToCloneSourceResource)
|
||||
if err != nil {
|
||||
|
@ -1065,7 +1083,7 @@ func initializeMockController(objects []runtime.Object) (*generate.GenerateContr
|
|||
}
|
||||
|
||||
client.SetDiscovery(dclient.NewFakeDiscoveryClient(nil))
|
||||
c := generate.NewGenerateControllerWithOnlyClient(client)
|
||||
c := generate.NewGenerateControllerWithOnlyClient(client, engine.LegacyContextLoaderFactory(nil))
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ func createNonLeaderControllers(
|
|||
updateRequestController := background.NewController(
|
||||
kyvernoClient,
|
||||
dynamicClient,
|
||||
rclient,
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
|
||||
kyvernoInformer.Kyverno().V1().Policies(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
|
||||
|
@ -177,7 +177,7 @@ func createrLeaderControllers(
|
|||
policyCtrl, err := policy.NewPolicyController(
|
||||
kyvernoClient,
|
||||
dynamicClient,
|
||||
rclient,
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
|
||||
kyvernoInformer.Kyverno().V1().Policies(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
|
||||
|
@ -523,6 +523,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
resourceHandlers := webhooksresource.NewHandlers(
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
dClient,
|
||||
kyvernoClient,
|
||||
rclient,
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
backgroundscancontroller "github.com/kyverno/kyverno/pkg/controllers/report/background"
|
||||
resourcereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/resource"
|
||||
"github.com/kyverno/kyverno/pkg/cosign"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
|
@ -129,6 +130,7 @@ func createReportControllers(
|
|||
client,
|
||||
kyvernoClient,
|
||||
rclient,
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
metadataFactory,
|
||||
kyvernoV1.Policies(),
|
||||
kyvernoV1.ClusterPolicies(),
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/config"
|
||||
policymetricscontroller "github.com/kyverno/kyverno/pkg/controllers/metrics/policy"
|
||||
"github.com/kyverno/kyverno/pkg/cosign"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
|
@ -77,7 +78,7 @@ func createNonLeaderControllers(
|
|||
updateRequestController := background.NewController(
|
||||
kyvernoClient,
|
||||
dynamicClient,
|
||||
rclient,
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
|
||||
kyvernoInformer.Kyverno().V1().Policies(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
|
||||
|
@ -104,7 +105,7 @@ func createrLeaderControllers(
|
|||
policyCtrl, err := policy.NewPolicyController(
|
||||
kyvernoClient,
|
||||
dynamicClient,
|
||||
rclient,
|
||||
engine.LegacyContextLoaderFactory(rclient),
|
||||
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
|
||||
kyvernoInformer.Kyverno().V1().Policies(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
|
@ -43,7 +42,7 @@ type GenerateController struct {
|
|||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
statusControl common.StatusControlInterface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
// listers
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
|
@ -63,7 +62,7 @@ func NewGenerateController(
|
|||
client dclient.Interface,
|
||||
kyvernoClient versioned.Interface,
|
||||
statusControl common.StatusControlInterface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
policyLister kyvernov1listers.ClusterPolicyLister,
|
||||
npolicyLister kyvernov1listers.PolicyLister,
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
|
||||
|
@ -75,9 +74,9 @@ func NewGenerateController(
|
|||
) *GenerateController {
|
||||
c := GenerateController{
|
||||
client: client,
|
||||
contextLoader: contextLoader,
|
||||
kyvernoClient: kyvernoClient,
|
||||
statusControl: statusControl,
|
||||
rclient: rclient,
|
||||
policyLister: policyLister,
|
||||
npolicyLister: npolicyLister,
|
||||
urLister: urLister,
|
||||
|
@ -201,7 +200,7 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
|
|||
}
|
||||
|
||||
// check if the policy still applies to the resource
|
||||
engineResponse := engine.GenerateResponse(c.rclient, policyContext, ur)
|
||||
engineResponse := engine.GenerateResponse(c.contextLoader, policyContext, ur)
|
||||
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
||||
logger.V(4).Info(doesNotApply)
|
||||
return nil, false, errors.New(doesNotApply)
|
||||
|
@ -347,7 +346,7 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
}
|
||||
|
||||
// add configmap json data to context
|
||||
if err := engine.LoadContext(context.TODO(), log, c.rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if err := engine.LoadContext(context.TODO(), c.contextLoader, rule.Context, policyContext, rule.Name); err != nil {
|
||||
log.Error(err, "cannot add configmaps to context")
|
||||
return nil, processExisting, err
|
||||
}
|
||||
|
@ -829,9 +828,10 @@ func (c *GenerateController) ApplyResource(resource *unstructured.Unstructured)
|
|||
}
|
||||
|
||||
// NewGenerateControllerWithOnlyClient returns an instance of Controller with only the client.
|
||||
func NewGenerateControllerWithOnlyClient(client dclient.Interface) *GenerateController {
|
||||
func NewGenerateControllerWithOnlyClient(client dclient.Interface, contextLoader engine.ContextLoaderFactory) *GenerateController {
|
||||
c := GenerateController{
|
||||
client: client,
|
||||
client: client,
|
||||
contextLoader: contextLoader,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
"go.uber.org/multierr"
|
||||
yamlv2 "gopkg.in/yaml.v2"
|
||||
|
@ -30,7 +29,8 @@ type MutateExistingController struct {
|
|||
// clients
|
||||
client dclient.Interface
|
||||
statusControl common.StatusControlInterface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
// listers
|
||||
policyLister kyvernov1listers.ClusterPolicyLister
|
||||
npolicyLister kyvernov1listers.PolicyLister
|
||||
|
@ -46,7 +46,7 @@ type MutateExistingController struct {
|
|||
func NewMutateExistingController(
|
||||
client dclient.Interface,
|
||||
statusControl common.StatusControlInterface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
policyLister kyvernov1listers.ClusterPolicyLister,
|
||||
npolicyLister kyvernov1listers.PolicyLister,
|
||||
dynamicConfig config.Configuration,
|
||||
|
@ -57,7 +57,7 @@ func NewMutateExistingController(
|
|||
c := MutateExistingController{
|
||||
client: client,
|
||||
statusControl: statusControl,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
policyLister: policyLister,
|
||||
npolicyLister: npolicyLister,
|
||||
configuration: dynamicConfig,
|
||||
|
@ -97,7 +97,7 @@ func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
|
|||
continue
|
||||
}
|
||||
|
||||
er := engine.Mutate(context.TODO(), c.rclient, policyContext)
|
||||
er := engine.Mutate(context.TODO(), c.contextLoader, policyContext)
|
||||
for _, r := range er.PolicyResponse.Rules {
|
||||
patched := r.PatchedTarget
|
||||
patchedTargetSubresourceName := r.PatchedTargetSubresourceName
|
||||
|
|
|
@ -18,9 +18,9 @@ import (
|
|||
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"github.com/pkg/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
@ -49,7 +49,7 @@ type controller struct {
|
|||
// clients
|
||||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
// listers
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
|
@ -72,7 +72,7 @@ type controller struct {
|
|||
func NewController(
|
||||
kyvernoClient versioned.Interface,
|
||||
client dclient.Interface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
polInformer kyvernov1informers.PolicyInformer,
|
||||
urInformer kyvernov1beta1informers.UpdateRequestInformer,
|
||||
|
@ -86,7 +86,7 @@ func NewController(
|
|||
c := controller{
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
cpolLister: cpolInformer.Lister(),
|
||||
polLister: polInformer.Lister(),
|
||||
urLister: urLister,
|
||||
|
@ -420,10 +420,10 @@ func (c *controller) processUR(ur *kyvernov1beta1.UpdateRequest) error {
|
|||
statusControl := common.NewStatusControl(c.kyvernoClient, c.urLister)
|
||||
switch ur.Spec.Type {
|
||||
case kyvernov1beta1.Mutate:
|
||||
ctrl := mutate.NewMutateExistingController(c.client, statusControl, c.rclient, c.cpolLister, c.polLister, c.configuration, c.informerCacheResolvers, c.eventGen, logger)
|
||||
ctrl := mutate.NewMutateExistingController(c.client, statusControl, c.contextLoader, c.cpolLister, c.polLister, c.configuration, c.informerCacheResolvers, c.eventGen, logger)
|
||||
return ctrl.ProcessUR(ur)
|
||||
case kyvernov1beta1.Generate:
|
||||
ctrl := generate.NewGenerateController(c.client, c.kyvernoClient, statusControl, c.rclient, c.cpolLister, c.polLister, c.urLister, c.nsLister, c.configuration, c.informerCacheResolvers, c.eventGen, logger)
|
||||
ctrl := generate.NewGenerateController(c.client, c.kyvernoClient, statusControl, c.contextLoader, c.cpolLister, c.polLister, c.urLister, c.nsLister, c.configuration, c.informerCacheResolvers, c.eventGen, logger)
|
||||
return ctrl.ProcessUR(ur)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -49,6 +49,7 @@ type controller struct {
|
|||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
// listers
|
||||
polLister kyvernov1listers.PolicyLister
|
||||
|
@ -75,6 +76,7 @@ func NewController(
|
|||
client dclient.Interface,
|
||||
kyvernoClient versioned.Interface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
metadataFactory metadatainformers.SharedInformerFactory,
|
||||
polInformer kyvernov1informers.PolicyInformer,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
|
@ -93,6 +95,7 @@ func NewController(
|
|||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
polLister: polInformer.Lister(),
|
||||
cpolLister: cpolInformer.Lister(),
|
||||
bgscanrLister: bgscanr.Lister(),
|
||||
|
@ -309,7 +312,7 @@ func (c *controller) reconcileReport(
|
|||
// calculate necessary results
|
||||
for _, policy := range backgroundPolicies {
|
||||
if full || actual[reportutils.PolicyLabel(policy)] != policy.GetResourceVersion() {
|
||||
scanner := utils.NewScanner(logger, c.client, c.rclient, c.informerCacheResolvers, c.polexLister, c.config)
|
||||
scanner := utils.NewScanner(logger, c.contextLoader, c.client, c.rclient, c.informerCacheResolvers, c.polexLister, c.config)
|
||||
for _, result := range scanner.ScanResource(ctx, *target, nsLabels, policy) {
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
type scanner struct {
|
||||
logger logr.Logger
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
informerCacheResolvers engineapi.ConfigmapResolver
|
||||
|
@ -36,6 +37,7 @@ type Scanner interface {
|
|||
|
||||
func NewScanner(
|
||||
logger logr.Logger,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
client dclient.Interface,
|
||||
rclient registryclient.Client,
|
||||
informerCacheResolvers engineapi.ConfigmapResolver,
|
||||
|
@ -45,6 +47,7 @@ func NewScanner(
|
|||
) Scanner {
|
||||
return &scanner{
|
||||
logger: logger,
|
||||
contextLoader: contextLoader,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
informerCacheResolvers: informerCacheResolvers,
|
||||
|
@ -103,7 +106,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
|
|||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithInformerCacheResolver(s.informerCacheResolvers).
|
||||
WithExceptions(s.polexLister)
|
||||
return engine.Validate(ctx, s.rclient, policyCtx, s.config), nil
|
||||
return engine.Validate(ctx, s.contextLoader, policyCtx, s.config), nil
|
||||
}
|
||||
|
||||
func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*engineapi.EngineResponse, error) {
|
||||
|
@ -128,7 +131,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
|
|||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithInformerCacheResolver(s.informerCacheResolvers).
|
||||
WithExceptions(s.polexLister)
|
||||
response, _ := engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx, s.config)
|
||||
response, _ := engine.VerifyAndPatchImages(ctx, s.contextLoader, s.rclient, policyCtx, s.config)
|
||||
if len(response.PolicyResponse.Rules) > 0 {
|
||||
s.logger.Info("validateImages", "policy", policy, "response", response)
|
||||
}
|
||||
|
|
12
pkg/engine/api/contextloader.go
Normal file
12
pkg/engine/api/contextloader.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
)
|
||||
|
||||
type ContextLoader interface {
|
||||
Load(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error
|
||||
}
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
)
|
||||
|
||||
// ApplyBackgroundChecks checks for validity of generate and mutateExisting rules on the resource
|
||||
|
@ -18,12 +17,19 @@ import (
|
|||
// - the caller has to check the ruleResponse to determine whether the path exist
|
||||
//
|
||||
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
|
||||
func ApplyBackgroundChecks(rclient registryclient.Client, policyContext *PolicyContext) (resp *engineapi.EngineResponse) {
|
||||
func ApplyBackgroundChecks(
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
policyStartTime := time.Now()
|
||||
return filterRules(rclient, policyContext, policyStartTime)
|
||||
return filterRules(contextLoader, policyContext, policyStartTime)
|
||||
}
|
||||
|
||||
func filterRules(rclient registryclient.Client, policyContext *PolicyContext, startTime time.Time) *engineapi.EngineResponse {
|
||||
func filterRules(
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
startTime time.Time,
|
||||
) *engineapi.EngineResponse {
|
||||
kind := policyContext.newResource.GetKind()
|
||||
name := policyContext.newResource.GetName()
|
||||
namespace := policyContext.newResource.GetNamespace()
|
||||
|
@ -55,7 +61,7 @@ func filterRules(rclient registryclient.Client, policyContext *PolicyContext, st
|
|||
|
||||
applyRules := policyContext.policy.GetSpec().GetApplyRules()
|
||||
for _, rule := range autogen.ComputeRules(policyContext.policy) {
|
||||
if ruleResp := filterRule(rclient, rule, policyContext); ruleResp != nil {
|
||||
if ruleResp := filterRule(contextLoader, rule, policyContext); ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
if applyRules == kyvernov1.ApplyOne && ruleResp.Status != engineapi.RuleStatusSkip {
|
||||
break
|
||||
|
@ -66,7 +72,11 @@ func filterRules(rclient registryclient.Client, policyContext *PolicyContext, st
|
|||
return resp
|
||||
}
|
||||
|
||||
func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContext *PolicyContext) *engineapi.RuleResponse {
|
||||
func filterRule(
|
||||
contextLoader ContextLoaderFactory,
|
||||
rule kyvernov1.Rule,
|
||||
policyContext *PolicyContext,
|
||||
) *engineapi.RuleResponse {
|
||||
if !rule.HasGenerate() && !rule.IsMutateExisting() {
|
||||
return nil
|
||||
}
|
||||
|
@ -122,7 +132,7 @@ func filterRule(rclient registryclient.Client, rule kyvernov1.Rule, policyContex
|
|||
policyContext.jsonContext.Checkpoint()
|
||||
defer policyContext.jsonContext.Restore()
|
||||
|
||||
if err := LoadContext(context.TODO(), logger, rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if err := LoadContext(context.TODO(), contextLoader, rule.Context, policyContext, rule.Name); err != nil {
|
||||
logger.V(4).Info("cannot add external data to the context", "reason", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,17 +7,25 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// GenerateResponse checks for validity of generate rule on the resource
|
||||
func GenerateResponse(rclient registryclient.Client, policyContext *PolicyContext, gr kyvernov1beta1.UpdateRequest) (resp *engineapi.EngineResponse) {
|
||||
func GenerateResponse(
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
gr kyvernov1beta1.UpdateRequest,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
policyStartTime := time.Now()
|
||||
return filterGenerateRules(rclient, policyContext, gr.Spec.Policy, policyStartTime)
|
||||
return filterGenerateRules(contextLoader, policyContext, gr.Spec.Policy, policyStartTime)
|
||||
}
|
||||
|
||||
func filterGenerateRules(rclient registryclient.Client, policyContext *PolicyContext, policyNameKey string, startTime time.Time) *engineapi.EngineResponse {
|
||||
func filterGenerateRules(
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
policyNameKey string,
|
||||
startTime time.Time,
|
||||
) *engineapi.EngineResponse {
|
||||
kind := policyContext.newResource.GetKind()
|
||||
name := policyContext.newResource.GetName()
|
||||
namespace := policyContext.newResource.GetNamespace()
|
||||
|
@ -53,7 +61,7 @@ func filterGenerateRules(rclient registryclient.Client, policyContext *PolicyCon
|
|||
}
|
||||
|
||||
for _, rule := range autogen.ComputeRules(policyContext.policy) {
|
||||
if ruleResp := filterRule(rclient, rule, policyContext); ruleResp != nil {
|
||||
if ruleResp := filterRule(contextLoader, rule, policyContext); ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ func extractMatchingImages(policyContext *PolicyContext, rule *kyvernov1.Rule, c
|
|||
|
||||
func VerifyAndPatchImages(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
rclient registryclient.Client,
|
||||
policyContext *PolicyContext,
|
||||
cfg config.Configuration,
|
||||
|
@ -138,7 +139,7 @@ func VerifyAndPatchImages(
|
|||
}
|
||||
|
||||
policyContext.jsonContext.Restore()
|
||||
if err := LoadContext(ctx, logger, rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, contextLoader, rule.Context, policyContext, rule.Name); err != nil {
|
||||
appendResponse(resp, rule, fmt.Sprintf("failed to load context: %s", err.Error()), engineapi.RuleStatusError)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -10,13 +10,19 @@ import (
|
|||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func processImageValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, rule *kyvernov1.Rule, cfg config.Configuration) *engineapi.RuleResponse {
|
||||
func processImageValidationRule(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
log logr.Logger,
|
||||
enginectx *PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.RuleResponse {
|
||||
if isDeleteRequest(enginectx) {
|
||||
return nil
|
||||
}
|
||||
|
@ -29,7 +35,7 @@ func processImageValidationRule(ctx context.Context, log logr.Logger, rclient re
|
|||
if len(matchingImages) == 0 {
|
||||
return ruleResponse(*rule, engineapi.Validation, "image verified", engineapi.RuleStatusSkip)
|
||||
}
|
||||
if err := LoadContext(ctx, log, rclient, rule.Context, enginectx, rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, contextLoader, rule.Context, enginectx, rule.Name); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
log.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
|
|
|
@ -160,12 +160,28 @@ var signaturePayloads = [][]byte{
|
|||
|
||||
var cfg = config.NewDefaultConfiguration()
|
||||
|
||||
func doVerifyAndPatchImages(
|
||||
ctx context.Context,
|
||||
rclient registryclient.Client,
|
||||
pContext *PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (*engineapi.EngineResponse, *ImageVerificationMetadata) {
|
||||
return VerifyAndPatchImages(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient),
|
||||
rclient,
|
||||
pContext,
|
||||
cfg,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func Test_CosignMockAttest(t *testing.T) {
|
||||
policyContext := buildContext(t, testPolicyGood, testResource, "")
|
||||
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er, ivm := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er, ivm := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass,
|
||||
fmt.Sprintf("expected: %v, got: %v, failure: %v",
|
||||
|
@ -179,7 +195,7 @@ func Test_CosignMockAttest_fail(t *testing.T) {
|
|||
err := cosign.SetMock("ghcr.io/jimbugwadia/pause2:latest", attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
}
|
||||
|
@ -428,7 +444,7 @@ var (
|
|||
func Test_ConfigMapMissingSuccess(t *testing.T) {
|
||||
policyContext := buildContext(t, testConfigMapMissing, testConfigMapMissingResource, "")
|
||||
cosign.ClearMock()
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
err, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, engineapi.RuleStatusSkip, err.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -440,7 +456,7 @@ func Test_ConfigMapMissingFailure(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
policyContext.informerCacheResolvers = resolver
|
||||
cosign.ClearMock()
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
resp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusError, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -449,7 +465,7 @@ func Test_SignatureGoodSigned(t *testing.T) {
|
|||
policyContext := buildContext(t, testSampleSingleKeyPolicy, testSampleResource, "")
|
||||
policyContext.policy.GetSpec().Rules[0].VerifyImages[0].MutateDigest = true
|
||||
cosign.ClearMock()
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules[0].Patches), 1)
|
||||
|
@ -461,7 +477,7 @@ func Test_SignatureUnsigned(t *testing.T) {
|
|||
cosign.ClearMock()
|
||||
unsigned := strings.Replace(testSampleResource, ":signed", ":unsigned", -1)
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, unsigned, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -470,7 +486,7 @@ func Test_SignatureWrongKey(t *testing.T) {
|
|||
cosign.ClearMock()
|
||||
otherKey := strings.Replace(testSampleResource, ":signed", ":signed-by-someone-else", -1)
|
||||
policyContext := buildContext(t, testSampleSingleKeyPolicy, otherKey, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -481,7 +497,7 @@ func Test_SignaturesMultiKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -491,7 +507,7 @@ func Test_SignaturesMultiKeyFail(t *testing.T) {
|
|||
policy := strings.Replace(testSampleMultipleKeyPolicy, "KEY1", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -502,7 +518,7 @@ func Test_SignaturesMultiKeyOneGoodKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
engineResp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(engineResp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass, engineResp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -513,7 +529,7 @@ func Test_SignaturesMultiKeyZeroGoodKey(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
resp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -529,14 +545,14 @@ func Test_RuleSelectorImageVerify(t *testing.T) {
|
|||
applyAll := kyverno.ApplyAll
|
||||
spec.ApplyRules = &applyAll
|
||||
|
||||
resp, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
resp, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 2)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[1].Status, engineapi.RuleStatusFail, resp.PolicyResponse.Rules[1].Message)
|
||||
|
||||
applyOne := kyverno.ApplyOne
|
||||
spec.ApplyRules = &applyOne
|
||||
resp, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
resp, _ = doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(resp.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, resp.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass, resp.PolicyResponse.Rules[0].Message)
|
||||
}
|
||||
|
@ -640,7 +656,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testVerifyImageKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext := buildContext(t, policy, testSampleResource, "")
|
||||
err, _ := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
err, _ := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
||||
|
@ -648,7 +664,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "0", -1)
|
||||
policyContext = buildContext(t, policy, testSampleResource, "")
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
err, _ = doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
|
||||
|
@ -656,7 +672,7 @@ func Test_NestedAttestors(t *testing.T) {
|
|||
policy = strings.Replace(policy, "KEY2", testOtherKey, -1)
|
||||
policy = strings.Replace(policy, "COUNT", "1", -1)
|
||||
policyContext = buildContext(t, policy, testSampleResource, "")
|
||||
err, _ = VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
err, _ = doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, len(err.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, err.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
}
|
||||
|
@ -749,7 +765,7 @@ func Test_MarkImageVerified(t *testing.T) {
|
|||
err := cosign.SetMock(image, attestationPayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResponse, verifiedImages := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Assert(t, engineResponse != nil)
|
||||
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
@ -842,7 +858,7 @@ func Test_ParsePEMDelimited(t *testing.T) {
|
|||
err := cosign.SetMock(image, signaturePayloads)
|
||||
assert.NilError(t, err)
|
||||
|
||||
engineResponse, verifiedImages := VerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
engineResponse, verifiedImages := doVerifyAndPatchImages(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Assert(t, engineResponse != nil)
|
||||
assert.Equal(t, len(engineResponse.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponse.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
|
|
@ -8,86 +8,128 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/apicall"
|
||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
jmespath "github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// LoadContext - Fetches and adds external data to the Context.
|
||||
func LoadContext(ctx context.Context, logger logr.Logger, rclient registryclient.Client, contextEntries []kyvernov1.ContextEntry, enginectx *PolicyContext, ruleName string) error {
|
||||
if len(contextEntries) == 0 {
|
||||
return nil
|
||||
}
|
||||
type ContextLoaderFactory = func(pContext *PolicyContext, ruleName string) engineapi.ContextLoader
|
||||
|
||||
policyName := enginectx.policy.GetName()
|
||||
func LegacyContextLoaderFactory(rclient registryclient.Client) ContextLoaderFactory {
|
||||
if store.IsMock() {
|
||||
rule := store.GetPolicyRule(policyName, ruleName)
|
||||
if rule != nil && len(rule.Values) > 0 {
|
||||
variables := rule.Values
|
||||
for key, value := range variables {
|
||||
if err := enginectx.jsonContext.AddVariable(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return func(pContext *PolicyContext, ruleName string) engineapi.ContextLoader {
|
||||
policy := pContext.Policy()
|
||||
return &mockContextLoader{
|
||||
logger: logging.WithName("MockContextLoaderFactory"),
|
||||
policyName: policy.GetName(),
|
||||
ruleName: ruleName,
|
||||
client: pContext.Client(),
|
||||
rclient: rclient,
|
||||
cmResolver: pContext.informerCacheResolvers,
|
||||
}
|
||||
}
|
||||
|
||||
hasRegistryAccess := store.GetRegistryAccess()
|
||||
|
||||
// Context Variable should be loaded after the values loaded from values file
|
||||
for _, entry := range contextEntries {
|
||||
if entry.ImageRegistry != nil && hasRegistryAccess {
|
||||
rclient := store.GetRegistryClient()
|
||||
if err := loadImageData(ctx, rclient, logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.Variable != nil {
|
||||
if err := loadVariable(logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.APICall != nil && store.IsApiCallAllowed() {
|
||||
if err := loadAPIData(ctx, logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return func(pContext *PolicyContext, ruleName string) engineapi.ContextLoader {
|
||||
return &contextLoader{
|
||||
logger: logging.WithName("LegacyContextLoaderFactory"),
|
||||
client: pContext.Client(),
|
||||
rclient: rclient,
|
||||
cmResolver: pContext.informerCacheResolvers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if rule != nil && len(rule.ForEachValues) > 0 {
|
||||
for key, value := range rule.ForEachValues {
|
||||
if err := enginectx.jsonContext.AddVariable(key, value[store.GetForeachElement()]); err != nil {
|
||||
return err
|
||||
}
|
||||
type contextLoader struct {
|
||||
logger logr.Logger
|
||||
rclient registryclient.Client
|
||||
client dclient.Interface
|
||||
cmResolver engineapi.ConfigmapResolver
|
||||
}
|
||||
|
||||
func (l *contextLoader) Load(ctx context.Context, contextEntries []kyvernov1.ContextEntry, enginectx enginecontext.Interface) error {
|
||||
for _, entry := range contextEntries {
|
||||
if entry.ConfigMap != nil {
|
||||
if err := loadConfigMap(ctx, l.logger, entry, enginectx, l.cmResolver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, entry := range contextEntries {
|
||||
if entry.ConfigMap != nil {
|
||||
if err := loadConfigMap(ctx, logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.APICall != nil {
|
||||
if err := loadAPIData(ctx, logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.ImageRegistry != nil {
|
||||
if err := loadImageData(ctx, rclient, logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.Variable != nil {
|
||||
if err := loadVariable(logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.APICall != nil {
|
||||
if err := loadAPIData(ctx, l.logger, entry, enginectx, l.client); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.ImageRegistry != nil {
|
||||
if err := loadImageData(ctx, l.rclient, l.logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.Variable != nil {
|
||||
if err := loadVariable(l.logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx *PolicyContext) (err error) {
|
||||
type mockContextLoader struct {
|
||||
logger logr.Logger
|
||||
policyName string
|
||||
ruleName string
|
||||
rclient registryclient.Client
|
||||
client dclient.Interface
|
||||
cmResolver engineapi.ConfigmapResolver
|
||||
}
|
||||
|
||||
func (l *mockContextLoader) Load(ctx context.Context, contextEntries []kyvernov1.ContextEntry, enginectx enginecontext.Interface) error {
|
||||
rule := store.GetPolicyRule(l.policyName, l.ruleName)
|
||||
if rule != nil && len(rule.Values) > 0 {
|
||||
variables := rule.Values
|
||||
for key, value := range variables {
|
||||
if err := enginectx.AddVariable(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
hasRegistryAccess := store.GetRegistryAccess()
|
||||
// Context Variable should be loaded after the values loaded from values file
|
||||
for _, entry := range contextEntries {
|
||||
if entry.ImageRegistry != nil && hasRegistryAccess {
|
||||
rclient := store.GetRegistryClient()
|
||||
if err := loadImageData(ctx, rclient, l.logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.Variable != nil {
|
||||
if err := loadVariable(l.logger, entry, enginectx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if entry.APICall != nil && store.IsApiCallAllowed() {
|
||||
if err := loadAPIData(ctx, l.logger, entry, enginectx, l.client); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if rule != nil && len(rule.ForEachValues) > 0 {
|
||||
for key, value := range rule.ForEachValues {
|
||||
if err := enginectx.AddVariable(key, value[store.GetForeachElement()]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadContext(ctx context.Context, factory ContextLoaderFactory, contextEntries []kyvernov1.ContextEntry, pContext *PolicyContext, ruleName string) error {
|
||||
return factory(pContext, ruleName).Load(ctx, contextEntries, pContext.JSONContext())
|
||||
}
|
||||
|
||||
func loadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx enginecontext.Interface) (err error) {
|
||||
path := ""
|
||||
if entry.Variable.JMESPath != "" {
|
||||
jp, err := variables.SubstituteAll(logger, ctx.jsonContext, entry.Variable.JMESPath)
|
||||
jp, err := variables.SubstituteAll(logger, ctx, 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)
|
||||
}
|
||||
|
@ -100,7 +142,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, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Default, err)
|
||||
}
|
||||
|
@ -109,7 +151,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, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Value, err)
|
||||
}
|
||||
|
@ -125,7 +167,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.Query(path); err == nil {
|
||||
output = variable
|
||||
} else if defaultValue == nil {
|
||||
return fmt.Errorf("failed to apply jmespath %s to variable %v", path, err)
|
||||
|
@ -137,13 +179,13 @@ 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.ReplaceContextEntry(entry.Name, outputBytes)
|
||||
} else {
|
||||
return fmt.Errorf("unable to add context entry for variable %s: %w", entry.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func loadImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error {
|
||||
func loadImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface) error {
|
||||
imageData, err := fetchImageData(ctx, rclient, logger, entry, enginectx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -152,14 +194,14 @@ func loadImageData(ctx context.Context, rclient registryclient.Client, logger lo
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enginectx.jsonContext.AddContextEntry(entry.Name, jsonBytes); err != nil {
|
||||
if err := enginectx.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(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) (interface{}, error) {
|
||||
ref, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ImageRegistry.Reference)
|
||||
func fetchImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface) (interface{}, error) {
|
||||
ref, err := variables.SubstituteAll(logger, enginectx, 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 +209,7 @@ func fetchImageData(ctx context.Context, rclient registryclient.Client, logger l
|
|||
if !ok {
|
||||
return nil, fmt.Errorf("invalid image reference %s, image reference must be a string", ref)
|
||||
}
|
||||
path, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ImageRegistry.JMESPath)
|
||||
path, err := variables.SubstituteAll(logger, enginectx, 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)
|
||||
}
|
||||
|
@ -239,16 +281,14 @@ func fetchImageDataMap(ctx context.Context, rclient registryclient.Client, ref s
|
|||
return untyped, nil
|
||||
}
|
||||
|
||||
func loadAPIData(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error {
|
||||
executor, err := apicall.New(ctx, entry, enginectx.JSONContext(), enginectx.Client(), logger)
|
||||
func loadAPIData(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, client dclient.Interface) error {
|
||||
executor, err := apicall.New(ctx, entry, enginectx, client, logger)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to initialize APICall")
|
||||
}
|
||||
|
||||
if _, err := executor.Execute(); err != nil {
|
||||
return errors.Wrapf(err, "failed to execute APICall")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -257,33 +297,30 @@ func applyJMESPath(jmesPath string, data interface{}) (interface{}, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", jmesPath, err)
|
||||
}
|
||||
|
||||
return jp.Search(data)
|
||||
}
|
||||
|
||||
func loadConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) error {
|
||||
data, err := fetchConfigMap(ctx, logger, entry, enginectx)
|
||||
func loadConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, resolver engineapi.ConfigmapResolver) error {
|
||||
data, err := fetchConfigMap(ctx, logger, entry, enginectx, resolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve config map for context entry %s: %v", entry.Name, err)
|
||||
}
|
||||
|
||||
err = enginectx.jsonContext.AddContextEntry(entry.Name, data)
|
||||
err = enginectx.AddContextEntry(entry.Name, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add config map for context entry %s: %v", entry.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx *PolicyContext) ([]byte, error) {
|
||||
func fetchConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, resolver engineapi.ConfigmapResolver) ([]byte, error) {
|
||||
contextData := make(map[string]interface{})
|
||||
|
||||
name, err := variables.SubstituteAll(logger, enginectx.jsonContext, entry.ConfigMap.Name)
|
||||
name, err := variables.SubstituteAll(logger, enginectx, 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, enginectx.jsonContext, entry.ConfigMap.Namespace)
|
||||
namespace, err := variables.SubstituteAll(logger, enginectx, 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)
|
||||
}
|
||||
|
@ -292,7 +329,7 @@ func fetchConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.Con
|
|||
namespace = "default"
|
||||
}
|
||||
|
||||
obj, err := enginectx.informerCacheResolvers.Get(ctx, namespace.(string), name.(string))
|
||||
obj, err := resolver.Get(ctx, namespace.(string), name.(string))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get configmap %s/%s : %v", namespace, name, err)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/mutate"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/kyverno/kyverno/pkg/tracing"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
@ -22,7 +21,11 @@ import (
|
|||
)
|
||||
|
||||
// Mutate performs mutation. Overlay first and then mutation patches
|
||||
func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext) (resp *engineapi.EngineResponse) {
|
||||
func Mutate(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
startTime := time.Now()
|
||||
policy := policyContext.policy
|
||||
resp = &engineapi.EngineResponse{
|
||||
|
@ -89,7 +92,7 @@ func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *P
|
|||
logger.Error(err, "failed to query resource object")
|
||||
}
|
||||
|
||||
if err := LoadContext(ctx, logger, rclient, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, contextLoader, rule.Context, policyContext, rule.Name); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
|
@ -142,7 +145,7 @@ func Mutate(ctx context.Context, rclient registryclient.Client, policyContext *P
|
|||
policyContext: policyContext,
|
||||
resource: patchedResource,
|
||||
log: logger,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
nesting: 0,
|
||||
}
|
||||
|
||||
|
@ -202,7 +205,7 @@ type forEachMutator struct {
|
|||
foreach []kyvernov1.ForEachMutation
|
||||
resource resourceInfo
|
||||
nesting int
|
||||
rclient registryclient.Client
|
||||
contextLoader ContextLoaderFactory
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
|
@ -211,7 +214,7 @@ func (f *forEachMutator) mutateForEach(ctx context.Context) *mutate.Response {
|
|||
allPatches := make([][]byte, 0)
|
||||
|
||||
for _, foreach := range f.foreach {
|
||||
if err := LoadContext(ctx, f.log, f.rclient, f.rule.Context, f.policyContext, f.rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, f.contextLoader, f.rule.Context, f.policyContext, f.rule.Name); err != nil {
|
||||
f.log.Error(err, "failed to load context")
|
||||
return mutate.NewErrorResponse("failed to load context", err)
|
||||
}
|
||||
|
@ -276,7 +279,7 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
return mutate.NewErrorResponse(fmt.Sprintf("failed to add element to mutate.foreach[%d].context", index), err)
|
||||
}
|
||||
|
||||
if err := LoadContext(ctx, f.log, f.rclient, foreach.Context, policyContext, f.rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, f.contextLoader, foreach.Context, policyContext, f.rule.Name); err != nil {
|
||||
return mutate.NewErrorResponse(fmt.Sprintf("failed to load to mutate.foreach[%d].context", index), err)
|
||||
}
|
||||
|
||||
|
@ -304,6 +307,7 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
log: f.log,
|
||||
foreach: nestedForEach,
|
||||
nesting: f.nesting + 1,
|
||||
contextLoader: f.contextLoader,
|
||||
}
|
||||
|
||||
mutateResp = m.mutateForEach(ctx)
|
||||
|
|
|
@ -20,6 +20,18 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func doMutate(
|
||||
ctx context.Context,
|
||||
rclient registryclient.Client,
|
||||
pContext *PolicyContext,
|
||||
) *engineapi.EngineResponse {
|
||||
return Mutate(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient),
|
||||
pContext,
|
||||
)
|
||||
}
|
||||
|
||||
func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
|
||||
policyRaw := []byte(`{
|
||||
"apiVersion": "kyverno.io/v1",
|
||||
|
@ -95,7 +107,7 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
t.Log(string(expectedPatch))
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
|
@ -169,7 +181,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
|
||||
}
|
||||
|
@ -262,7 +274,7 @@ func Test_variableSubstitutionCLI(t *testing.T) {
|
|||
newResource: *resourceUnstructured,
|
||||
}
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
||||
t.Log(string(expectedPatch))
|
||||
|
@ -371,7 +383,7 @@ func Test_chained_rules(t *testing.T) {
|
|||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, containers[0].(map[string]interface{})["image"], "otherregistry.corp.com/foo/bash:5.0")
|
||||
|
@ -459,7 +471,7 @@ func Test_precondition(t *testing.T) {
|
|||
newResource: *resourceUnstructured,
|
||||
}
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
t.Log(string(expectedPatch))
|
||||
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
||||
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
||||
|
@ -556,7 +568,7 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) {
|
|||
newResource: *resourceUnstructured,
|
||||
}
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
t.Log(string(expectedPatch))
|
||||
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
||||
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
||||
|
@ -650,7 +662,7 @@ func Test_foreach(t *testing.T) {
|
|||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
@ -757,7 +769,7 @@ func Test_foreach_element_mutation(t *testing.T) {
|
|||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
@ -883,7 +895,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
|
|||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
||||
|
@ -1033,7 +1045,7 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) *eng
|
|||
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
return er
|
||||
}
|
||||
|
||||
|
@ -1584,7 +1596,7 @@ func Test_mutate_existing_resources(t *testing.T) {
|
|||
newResource: *trigger,
|
||||
}
|
||||
}
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
|
||||
for _, rr := range er.PolicyResponse.Rules {
|
||||
for i, p := range rr.Patches {
|
||||
|
@ -1692,7 +1704,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
|
|||
newResource: *resourceUnstructured,
|
||||
}
|
||||
|
||||
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 2)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules[1].Patches), 1)
|
||||
|
@ -1707,7 +1719,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
|
|||
applyOne := kyverno.ApplyOne
|
||||
policyContext.policy.GetSpec().ApplyRules = &applyOne
|
||||
|
||||
er = Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er = doMutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
||||
|
||||
|
@ -2074,7 +2086,7 @@ func Test_SpecialCharacters(t *testing.T) {
|
|||
}
|
||||
|
||||
// Mutate and make sure that we got the expected amount of rules.
|
||||
patches := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext).GetPatches()
|
||||
patches := doMutate(context.TODO(), registryclient.NewOrDie(), policyContext).GetPatches()
|
||||
if !reflect.DeepEqual(patches, tt.want) {
|
||||
t.Errorf("Mutate() got patches %s, expected %s", patches, tt.want)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"github.com/kyverno/kyverno/pkg/pss"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/kyverno/kyverno/pkg/tracing"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
|
@ -37,7 +36,12 @@ import (
|
|||
)
|
||||
|
||||
// Validate applies validation rules from policy on the resource
|
||||
func Validate(ctx context.Context, rclient registryclient.Client, policyContext *PolicyContext, cfg config.Configuration) (resp *engineapi.EngineResponse) {
|
||||
func Validate(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
policyContext *PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
resp = &engineapi.EngineResponse{}
|
||||
startTime := time.Now()
|
||||
|
||||
|
@ -48,7 +52,7 @@ func Validate(ctx context.Context, rclient registryclient.Client, policyContext
|
|||
logger.V(4).Info("finished policy processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
||||
}()
|
||||
|
||||
resp = validateResource(ctx, logger, rclient, policyContext, cfg)
|
||||
resp = validateResource(ctx, contextLoader, logger, policyContext, cfg)
|
||||
resp.NamespaceLabels = policyContext.namespaceLabels
|
||||
return
|
||||
}
|
||||
|
@ -97,7 +101,13 @@ func buildResponse(ctx *PolicyContext, resp *engineapi.EngineResponse, startTime
|
|||
resp.PolicyResponse.Timestamp = startTime.Unix()
|
||||
}
|
||||
|
||||
func validateResource(ctx context.Context, log logr.Logger, rclient registryclient.Client, enginectx *PolicyContext, cfg config.Configuration) *engineapi.EngineResponse {
|
||||
func validateResource(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
log logr.Logger,
|
||||
enginectx *PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.EngineResponse {
|
||||
resp := &engineapi.EngineResponse{}
|
||||
|
||||
enginectx.jsonContext.Checkpoint()
|
||||
|
@ -148,9 +158,9 @@ func validateResource(ctx context.Context, log logr.Logger, rclient registryclie
|
|||
log.V(3).Info("processing validation rule", "matchCount", matchCount, "applyRules", applyRules)
|
||||
enginectx.jsonContext.Reset()
|
||||
if hasValidate && !hasYAMLSignatureVerify {
|
||||
return processValidationRule(ctx, log, rclient, enginectx, rule)
|
||||
return processValidationRule(ctx, contextLoader, log, enginectx, rule)
|
||||
} else if hasValidateImage {
|
||||
return processImageValidationRule(ctx, log, rclient, enginectx, rule, cfg)
|
||||
return processImageValidationRule(ctx, contextLoader, log, enginectx, rule, cfg)
|
||||
} else if hasYAMLSignatureVerify {
|
||||
return processYAMLValidationRule(log, enginectx, rule)
|
||||
}
|
||||
|
@ -168,8 +178,14 @@ func validateResource(ctx context.Context, log logr.Logger, rclient registryclie
|
|||
return resp
|
||||
}
|
||||
|
||||
func processValidationRule(ctx context.Context, log logr.Logger, rclient registryclient.Client, policyContext *PolicyContext, rule *kyvernov1.Rule) *engineapi.RuleResponse {
|
||||
v := newValidator(log, rclient, policyContext, rule)
|
||||
func processValidationRule(
|
||||
ctx context.Context,
|
||||
contextLoader ContextLoaderFactory,
|
||||
log logr.Logger,
|
||||
policyContext *PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
) *engineapi.RuleResponse {
|
||||
v := newValidator(log, contextLoader, policyContext, rule)
|
||||
return v.validate(ctx)
|
||||
}
|
||||
|
||||
|
@ -198,17 +214,17 @@ type validator struct {
|
|||
deny *kyvernov1.Deny
|
||||
podSecurity *kyvernov1.PodSecurity
|
||||
forEach []kyvernov1.ForEachValidation
|
||||
rclient registryclient.Client
|
||||
contextLoader ContextLoaderFactory
|
||||
nesting int
|
||||
}
|
||||
|
||||
func newValidator(log logr.Logger, rclient registryclient.Client, ctx *PolicyContext, rule *kyvernov1.Rule) *validator {
|
||||
func newValidator(log logr.Logger, contextLoader ContextLoaderFactory, ctx *PolicyContext, rule *kyvernov1.Rule) *validator {
|
||||
ruleCopy := rule.DeepCopy()
|
||||
return &validator{
|
||||
log: log,
|
||||
rule: ruleCopy,
|
||||
policyContext: ctx,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
contextEntries: ruleCopy.Context,
|
||||
anyAllConditions: ruleCopy.GetAnyAllConditions(),
|
||||
pattern: ruleCopy.Validation.GetPattern(),
|
||||
|
@ -219,7 +235,14 @@ func newValidator(log logr.Logger, rclient registryclient.Client, ctx *PolicyCon
|
|||
}
|
||||
}
|
||||
|
||||
func newForEachValidator(foreach kyvernov1.ForEachValidation, rclient registryclient.Client, nesting int, rule *kyvernov1.Rule, ctx *PolicyContext, log logr.Logger) (*validator, error) {
|
||||
func newForEachValidator(
|
||||
foreach kyvernov1.ForEachValidation,
|
||||
contextLoader ContextLoaderFactory,
|
||||
nesting int,
|
||||
rule *kyvernov1.Rule,
|
||||
ctx *PolicyContext,
|
||||
log logr.Logger,
|
||||
) (*validator, error) {
|
||||
ruleCopy := rule.DeepCopy()
|
||||
anyAllConditions, err := datautils.ToMap(foreach.AnyAllConditions)
|
||||
if err != nil {
|
||||
|
@ -235,7 +258,7 @@ func newForEachValidator(foreach kyvernov1.ForEachValidation, rclient registrycl
|
|||
log: log,
|
||||
policyContext: ctx,
|
||||
rule: ruleCopy,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
contextEntries: foreach.Context,
|
||||
anyAllConditions: anyAllConditions,
|
||||
pattern: foreach.GetPattern(),
|
||||
|
@ -298,7 +321,7 @@ func (v *validator) validateForEach(ctx context.Context) *engineapi.RuleResponse
|
|||
continue
|
||||
}
|
||||
|
||||
resp, count := v.validateElements(ctx, v.rclient, foreach, elements, foreach.ElementScope)
|
||||
resp, count := v.validateElements(ctx, foreach, elements, foreach.ElementScope)
|
||||
if resp.Status != engineapi.RuleStatusPass {
|
||||
return resp
|
||||
}
|
||||
|
@ -317,7 +340,7 @@ func (v *validator) validateForEach(ctx context.Context) *engineapi.RuleResponse
|
|||
return ruleResponse(*v.rule, engineapi.Validation, "rule passed", engineapi.RuleStatusPass)
|
||||
}
|
||||
|
||||
func (v *validator) validateElements(ctx context.Context, rclient registryclient.Client, foreach kyvernov1.ForEachValidation, elements []interface{}, elementScope *bool) (*engineapi.RuleResponse, int) {
|
||||
func (v *validator) validateElements(ctx context.Context, foreach kyvernov1.ForEachValidation, elements []interface{}, elementScope *bool) (*engineapi.RuleResponse, int) {
|
||||
v.policyContext.jsonContext.Checkpoint()
|
||||
defer v.policyContext.jsonContext.Restore()
|
||||
applyCount := 0
|
||||
|
@ -334,7 +357,7 @@ func (v *validator) validateElements(ctx context.Context, rclient registryclient
|
|||
return ruleError(v.rule, engineapi.Validation, "failed to process foreach", err), applyCount
|
||||
}
|
||||
|
||||
foreachValidator, err := newForEachValidator(foreach, rclient, v.nesting+1, v.rule, policyContext, v.log)
|
||||
foreachValidator, err := newForEachValidator(foreach, v.contextLoader, v.nesting+1, v.rule, policyContext, v.log)
|
||||
if err != nil {
|
||||
v.log.Error(err, "failed to create foreach validator")
|
||||
return ruleError(v.rule, engineapi.Validation, "failed to create foreach validator", err), applyCount
|
||||
|
@ -399,7 +422,7 @@ func addElementToContext(ctx *PolicyContext, element interface{}, index, nesting
|
|||
}
|
||||
|
||||
func (v *validator) loadContext(ctx context.Context) error {
|
||||
if err := LoadContext(ctx, v.log, v.rclient, v.contextEntries, v.policyContext, v.rule.Name); err != nil {
|
||||
if err := LoadContext(ctx, v.contextLoader, v.contextEntries, v.policyContext, v.rule.Name); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
v.log.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
@ -18,6 +19,15 @@ import (
|
|||
admissionv1 "k8s.io/api/admission/v1"
|
||||
)
|
||||
|
||||
func doValidate(ctx context.Context, rclient registryclient.Client, pContext *PolicyContext, cfg config.Configuration) *engineapi.EngineResponse {
|
||||
return Validate(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient),
|
||||
pContext,
|
||||
cfg,
|
||||
)
|
||||
}
|
||||
|
||||
func TestValidate_image_tag_fail(t *testing.T) {
|
||||
// If image tag is latest then imagepull policy needs to be checked
|
||||
rawPolicy := []byte(`{
|
||||
|
@ -111,7 +121,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(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -211,7 +221,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
|
|||
"validation rule 'validate-tag' passed.",
|
||||
"validation rule 'validate-latest' passed.",
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -285,7 +295,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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/"}
|
||||
|
@ -368,7 +378,7 @@ func TestValidate_host_network_port(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -458,7 +468,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -546,7 +556,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -616,7 +626,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -689,7 +699,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -763,7 +773,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -843,7 +853,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod rule 2' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -917,7 +927,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -992,7 +1002,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1067,7 +1077,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1137,7 +1147,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -1207,7 +1217,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'pod image rule' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1295,7 +1305,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
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 {
|
||||
|
@ -1382,7 +1392,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
|
|||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
||||
assert.NilError(t, err)
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
msgs := []string{"validation rule 'validate-host-path' passed."}
|
||||
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
|
@ -1459,7 +1469,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusError)
|
||||
|
@ -1553,7 +1563,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusError)
|
||||
|
@ -1615,7 +1625,7 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.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/")
|
||||
}
|
||||
|
@ -1707,7 +1717,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusError)
|
||||
|
@ -1801,7 +1811,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
|
||||
|
@ -1907,7 +1917,7 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.")
|
||||
}
|
||||
|
@ -1961,7 +1971,7 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
for i, rule := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, er.PolicyResponse.Rules[i].Status, test.expectedResults[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedResults[i], er.PolicyResponse.Rules[i].Status)
|
||||
|
@ -2127,7 +2137,7 @@ func executeTest(t *testing.T, test testCase) {
|
|||
jsonContext: ctx,
|
||||
}
|
||||
|
||||
resp := Validate(context.TODO(), registryclient.NewOrDie(), pc, cfg)
|
||||
resp := doValidate(context.TODO(), registryclient.NewOrDie(), pc, cfg)
|
||||
if resp.IsSuccessful() && test.requestDenied {
|
||||
t.Errorf("Testcase has failed, policy: %v", policy.Name)
|
||||
}
|
||||
|
@ -2222,7 +2232,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(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
for index, r := range er.PolicyResponse.Rules {
|
||||
assert.Equal(t, r.Message, msgs[index])
|
||||
}
|
||||
|
@ -2311,7 +2321,7 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
assert.Assert(t, !er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -2400,7 +2410,7 @@ func Test_StringInDenyCondition(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: ctx}, cfg)
|
||||
assert.Assert(t, er.IsSuccessful())
|
||||
}
|
||||
|
||||
|
@ -3071,7 +3081,7 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
|
||||
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
|
||||
if msg != "" {
|
||||
|
@ -3135,7 +3145,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
newResource: *resourceUnstructured,
|
||||
}
|
||||
engineResponseCreate := Validate(context.TODO(), registryclient.NewOrDie(), policyContextCreate, cfg)
|
||||
engineResponseCreate := doValidate(context.TODO(), registryclient.NewOrDie(), policyContextCreate, cfg)
|
||||
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
|
||||
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, engineapi.RuleStatusFail)
|
||||
|
||||
|
@ -3144,7 +3154,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
|
|||
jsonContext: ctx,
|
||||
oldResource: *resourceUnstructured,
|
||||
}
|
||||
engineResponseDelete := Validate(context.TODO(), registryclient.NewOrDie(), policyContextDelete, cfg)
|
||||
engineResponseDelete := doValidate(context.TODO(), registryclient.NewOrDie(), policyContextDelete, cfg)
|
||||
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
|
||||
}
|
||||
|
||||
|
@ -3203,7 +3213,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
er := Validate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
er := doValidate(context.TODO(), registryclient.NewOrDie(), &PolicyContext{policy: &policy, newResource: *resourceUnstructured, jsonContext: enginecontext.NewContext()}, cfg)
|
||||
if tc.expectedFailed {
|
||||
assert.Assert(t, er.IsFailed())
|
||||
} else if tc.expectedSkipped {
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/multierr"
|
||||
|
@ -58,7 +57,7 @@ const (
|
|||
type PolicyController struct {
|
||||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
pInformer kyvernov1informers.ClusterPolicyInformer
|
||||
npInformer kyvernov1informers.PolicyInformer
|
||||
|
@ -99,7 +98,7 @@ type PolicyController struct {
|
|||
func NewPolicyController(
|
||||
kyvernoClient versioned.Interface,
|
||||
client dclient.Interface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
pInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
npInformer kyvernov1informers.PolicyInformer,
|
||||
urInformer kyvernov1beta1informers.UpdateRequestInformer,
|
||||
|
@ -120,7 +119,7 @@ func NewPolicyController(
|
|||
pc := PolicyController{
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
pInformer: pInformer,
|
||||
npInformer: npInformer,
|
||||
eventGen: eventGen,
|
||||
|
@ -514,7 +513,7 @@ func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest
|
|||
return false, errors.Wrapf(err, "failed to build policy context for rule %s", rule.Name)
|
||||
}
|
||||
|
||||
engineResponse := engine.ApplyBackgroundChecks(pc.rclient, policyContext)
|
||||
engineResponse := engine.ApplyBackgroundChecks(pc.contextLoader, policyContext)
|
||||
if len(engineResponse.PolicyResponse.Rules) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
@ -147,7 +147,11 @@ func runTestCase(t *testing.T, tc TestCase) bool {
|
|||
|
||||
policyContext := engine.NewPolicyContext().WithPolicy(policy).WithNewResource(*resource)
|
||||
|
||||
er := engine.Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
||||
er := engine.Mutate(
|
||||
context.TODO(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
)
|
||||
t.Log("---Mutation---")
|
||||
validateResource(t, er.PatchedResource, tc.Expected.Mutation.PatchedResource)
|
||||
validateResponse(t, er.PolicyResponse, tc.Expected.Mutation.PolicyResponse)
|
||||
|
@ -160,7 +164,12 @@ func runTestCase(t *testing.T, tc TestCase) bool {
|
|||
policyContext = policyContext.WithNewResource(*resource)
|
||||
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
er = engine.Validate(context.TODO(), registryclient.NewOrDie(), policyContext, cfg)
|
||||
er = engine.Validate(
|
||||
context.TODO(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
cfg,
|
||||
)
|
||||
t.Log("---Validation---")
|
||||
validateResponse(t, er.PolicyResponse, tc.Expected.Validation.PolicyResponse)
|
||||
|
||||
|
@ -176,7 +185,10 @@ func runTestCase(t *testing.T, tc TestCase) bool {
|
|||
} else {
|
||||
policyContext := policyContext.WithClient(client)
|
||||
|
||||
er = engine.ApplyBackgroundChecks(registryclient.NewOrDie(), policyContext)
|
||||
er = engine.ApplyBackgroundChecks(
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
policyContext,
|
||||
)
|
||||
t.Log(("---Generation---"))
|
||||
validateResponse(t, er.PolicyResponse, tc.Expected.Generation.PolicyResponse)
|
||||
// Expected generate resource will be in same namespaces as resource
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
kyvernoinformers "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
|
@ -38,10 +39,11 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
|
|||
crbLister := informers.Rbac().V1().ClusterRoleBindings().Lister()
|
||||
urLister := kyvernoInformers.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace())
|
||||
peLister := kyvernoInformers.Kyverno().V2alpha1().PolicyExceptions().Lister()
|
||||
rclient := registryclient.NewOrDie()
|
||||
|
||||
return &handlers{
|
||||
client: dclient,
|
||||
rclient: registryclient.NewOrDie(),
|
||||
rclient: rclient,
|
||||
configuration: configuration,
|
||||
metricsConfig: metricsConfig,
|
||||
pCache: policyCache,
|
||||
|
@ -54,5 +56,6 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
|
|||
openApiManager: openapi.NewFake(),
|
||||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, dclient, rbLister, crbLister, configMapResolver, peLister),
|
||||
urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoclient, urLister),
|
||||
contextLoader: engine.LegacyContextLoaderFactory(rclient),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/updaterequest"
|
||||
|
@ -40,7 +39,7 @@ func NewGenerationHandler(
|
|||
log logr.Logger,
|
||||
client dclient.Interface,
|
||||
kyvernoClient versioned.Interface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
nsLister corev1listers.NamespaceLister,
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
|
||||
urGenerator webhookgenerate.Generator,
|
||||
|
@ -52,7 +51,7 @@ func NewGenerationHandler(
|
|||
log: log,
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
nsLister: nsLister,
|
||||
urLister: urLister,
|
||||
urGenerator: urGenerator,
|
||||
|
@ -66,7 +65,7 @@ type generationHandler struct {
|
|||
log logr.Logger
|
||||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
nsLister corev1listers.NamespaceLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
urGenerator webhookgenerate.Generator
|
||||
|
@ -93,7 +92,7 @@ func (h *generationHandler) Handle(
|
|||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
policyContext = policyContext.WithNamespaceLabels(engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log))
|
||||
}
|
||||
engineResponse := engine.ApplyBackgroundChecks(h.rclient, policyContext)
|
||||
engineResponse := engine.ApplyBackgroundChecks(h.contextLoader, policyContext)
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if rule.Status != engineapi.RuleStatusPass {
|
||||
h.deleteGR(ctx, engineResponse)
|
||||
|
|
|
@ -41,6 +41,7 @@ type handlers struct {
|
|||
client dclient.Interface
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
|
||||
// config
|
||||
configuration config.Configuration
|
||||
|
@ -66,6 +67,7 @@ type handlers struct {
|
|||
}
|
||||
|
||||
func NewHandlers(
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
client dclient.Interface,
|
||||
kyvernoClient versioned.Interface,
|
||||
rclient registryclient.Client,
|
||||
|
@ -84,6 +86,7 @@ func NewHandlers(
|
|||
admissionReports bool,
|
||||
) webhooks.ResourceHandlers {
|
||||
return &handlers{
|
||||
contextLoader: contextLoader,
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
|
@ -121,7 +124,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
|
|||
}
|
||||
if len(generatePolicies) == 0 && request.Operation == admissionv1.Update {
|
||||
// handle generate source resource updates
|
||||
gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.contextLoader, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
go gh.HandleUpdatesForGenerateRules(context.TODO(), request, []kyvernov1.PolicyInterface{})
|
||||
}
|
||||
|
||||
|
@ -137,7 +140,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
|
|||
namespaceLabels = engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, logger)
|
||||
}
|
||||
|
||||
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.rclient, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig, h.configuration)
|
||||
vh := validation.NewValidationHandler(logger, h.kyvernoClient, h.contextLoader, h.pCache, h.pcBuilder, h.eventGen, h.admissionReports, h.metricsConfig, h.configuration)
|
||||
|
||||
ok, msg, warnings := vh.HandleValidation(ctx, request, policies, policyContext, namespaceLabels, startTime)
|
||||
if !ok {
|
||||
|
@ -171,7 +174,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
|
|||
if err := enginectx.MutateResourceWithImageInfo(request.Object.Raw, policyContext.JSONContext()); err != nil {
|
||||
logger.Error(err, "failed to patch images info to resource, policies that mutate images may be impacted")
|
||||
}
|
||||
mh := mutation.NewMutationHandler(logger, h.rclient, h.eventGen, h.openApiManager, h.nsLister, h.metricsConfig)
|
||||
mh := mutation.NewMutationHandler(logger, h.contextLoader, h.eventGen, h.openApiManager, h.nsLister, h.metricsConfig)
|
||||
mutatePatches, mutateWarnings, err := mh.HandleMutation(ctx, request, mutatePolicies, policyContext, startTime)
|
||||
if err != nil {
|
||||
logger.Error(err, "mutation failed")
|
||||
|
@ -184,7 +187,7 @@ func (h *handlers) Mutate(ctx context.Context, logger logr.Logger, request *admi
|
|||
logger.Error(err, "failed to build policy context")
|
||||
return admissionutils.Response(request.UID, err)
|
||||
}
|
||||
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.rclient, h.eventGen, h.admissionReports, h.configuration)
|
||||
ivh := imageverification.NewImageVerificationHandler(logger, h.kyvernoClient, h.contextLoader, h.rclient, h.eventGen, h.admissionReports, h.configuration)
|
||||
imagePatches, imageVerifyWarnings, err := ivh.Handle(ctx, newRequest, verifyImagesPolicies, policyContext)
|
||||
if err != nil {
|
||||
logger.Error(err, "image verification failed")
|
||||
|
|
|
@ -32,6 +32,7 @@ type ImageVerificationHandler interface {
|
|||
|
||||
type imageVerificationHandler struct {
|
||||
kyvernoClient versioned.Interface
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
rclient registryclient.Client
|
||||
log logr.Logger
|
||||
eventGen event.Interface
|
||||
|
@ -42,6 +43,7 @@ type imageVerificationHandler struct {
|
|||
func NewImageVerificationHandler(
|
||||
log logr.Logger,
|
||||
kyvernoClient versioned.Interface,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
rclient registryclient.Client,
|
||||
eventGen event.Interface,
|
||||
admissionReports bool,
|
||||
|
@ -49,6 +51,7 @@ func NewImageVerificationHandler(
|
|||
) ImageVerificationHandler {
|
||||
return &imageVerificationHandler{
|
||||
kyvernoClient: kyvernoClient,
|
||||
contextLoader: contextLoader,
|
||||
rclient: rclient,
|
||||
log: log,
|
||||
eventGen: eventGen,
|
||||
|
@ -91,7 +94,7 @@ func (h *imageVerificationHandler) handleVerifyImages(
|
|||
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
|
||||
func(ctx context.Context, span trace.Span) {
|
||||
policyContext := policyContext.WithPolicy(policy)
|
||||
resp, ivm := engine.VerifyAndPatchImages(ctx, h.rclient, policyContext, h.cfg)
|
||||
resp, ivm := engine.VerifyAndPatchImages(ctx, h.contextLoader, h.rclient, policyContext, h.cfg)
|
||||
|
||||
engineResponses = append(engineResponses, resp)
|
||||
patches = append(patches, resp.GetPatches()...)
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
"github.com/kyverno/kyverno/pkg/openapi"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/kyverno/kyverno/pkg/tracing"
|
||||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
|
@ -36,7 +35,7 @@ type MutationHandler interface {
|
|||
|
||||
func NewMutationHandler(
|
||||
log logr.Logger,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
eventGen event.Interface,
|
||||
openApiManager openapi.ValidateInterface,
|
||||
nsLister corev1listers.NamespaceLister,
|
||||
|
@ -44,7 +43,7 @@ func NewMutationHandler(
|
|||
) MutationHandler {
|
||||
return &mutationHandler{
|
||||
log: log,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
eventGen: eventGen,
|
||||
openApiManager: openApiManager,
|
||||
nsLister: nsLister,
|
||||
|
@ -54,7 +53,7 @@ func NewMutationHandler(
|
|||
|
||||
type mutationHandler struct {
|
||||
log logr.Logger
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
eventGen event.Interface
|
||||
openApiManager openapi.ValidateInterface
|
||||
nsLister corev1listers.NamespaceLister
|
||||
|
@ -158,7 +157,7 @@ func (h *mutationHandler) applyMutation(ctx context.Context, request *admissionv
|
|||
policyContext = policyContext.WithNamespaceLabels(engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log))
|
||||
}
|
||||
|
||||
engineResponse := engine.Mutate(ctx, h.rclient, policyContext)
|
||||
engineResponse := engine.Mutate(ctx, h.contextLoader, policyContext)
|
||||
policyPatches := engineResponse.GetPatches()
|
||||
|
||||
if !engineResponse.IsSuccessful() {
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
|
||||
// createUpdateRequests applies generate and mutateExisting policies, and creates update requests for background reconcile
|
||||
func (h *handlers) createUpdateRequests(logger logr.Logger, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyvernov1.PolicyInterface, ts time.Time) {
|
||||
gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.rclient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
gh := generation.NewGenerationHandler(logger, h.client, h.kyvernoClient, h.contextLoader, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
go h.handleMutateExisting(context.TODO(), logger, request, mutatePolicies, policyContext, ts)
|
||||
go gh.Handle(context.TODO(), request, generatePolicies, policyContext, ts)
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func (h *handlers) handleMutateExisting(ctx context.Context, logger logr.Logger,
|
|||
|
||||
var rules []engineapi.RuleResponse
|
||||
policyContext := policyContext.WithPolicy(policy)
|
||||
engineResponse := engine.ApplyBackgroundChecks(h.rclient, policyContext)
|
||||
engineResponse := engine.ApplyBackgroundChecks(h.contextLoader, policyContext)
|
||||
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if rule.Status == engineapi.RuleStatusPass {
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
"github.com/kyverno/kyverno/pkg/policycache"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"github.com/kyverno/kyverno/pkg/tracing"
|
||||
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
||||
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
|
||||
|
@ -38,7 +37,7 @@ type ValidationHandler interface {
|
|||
func NewValidationHandler(
|
||||
log logr.Logger,
|
||||
kyvernoClient versioned.Interface,
|
||||
rclient registryclient.Client,
|
||||
contextLoader engine.ContextLoaderFactory,
|
||||
pCache policycache.Cache,
|
||||
pcBuilder webhookutils.PolicyContextBuilder,
|
||||
eventGen event.Interface,
|
||||
|
@ -49,7 +48,7 @@ func NewValidationHandler(
|
|||
return &validationHandler{
|
||||
log: log,
|
||||
kyvernoClient: kyvernoClient,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
pCache: pCache,
|
||||
pcBuilder: pcBuilder,
|
||||
eventGen: eventGen,
|
||||
|
@ -62,7 +61,7 @@ func NewValidationHandler(
|
|||
type validationHandler struct {
|
||||
log logr.Logger
|
||||
kyvernoClient versioned.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engine.ContextLoaderFactory
|
||||
pCache policycache.Cache
|
||||
pcBuilder webhookutils.PolicyContextBuilder
|
||||
eventGen event.Interface
|
||||
|
@ -114,7 +113,7 @@ func (v *validationHandler) HandleValidation(
|
|||
failurePolicy = kyvernov1.Fail
|
||||
}
|
||||
|
||||
engineResponse := engine.Validate(ctx, v.rclient, policyContext, v.cfg)
|
||||
engineResponse := engine.Validate(ctx, v.contextLoader, policyContext, v.cfg)
|
||||
if engineResponse.IsNil() {
|
||||
// we get an empty response if old and new resources created the same response
|
||||
// allow updates if resource update doesnt change the policy evaluation
|
||||
|
@ -173,7 +172,7 @@ func (v *validationHandler) buildAuditResponses(
|
|||
fmt.Sprintf("POLICY %s/%s", policy.GetNamespace(), policy.GetName()),
|
||||
func(ctx context.Context, span trace.Span) {
|
||||
policyContext := policyContext.WithPolicy(policy).WithNamespaceLabels(namespaceLabels)
|
||||
responses = append(responses, engine.Validate(ctx, v.rclient, policyContext, v.cfg))
|
||||
responses = append(responses, engine.Validate(ctx, v.contextLoader, policyContext, v.cfg))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1058,10 +1058,11 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
|
||||
assert.NilError(t, err)
|
||||
|
||||
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured).WithNamespaceLabels(tc.rawResourceNamespaceLabels)
|
||||
er := engine.Validate(
|
||||
context.TODO(),
|
||||
registryclient.NewOrDie(),
|
||||
engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured).WithNamespaceLabels(tc.rawResourceNamespaceLabels),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
ctx,
|
||||
cfg,
|
||||
)
|
||||
if tc.blocked && tc.messages != nil {
|
||||
|
@ -1124,7 +1125,12 @@ func Test_RuleSelector(t *testing.T) {
|
|||
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured)
|
||||
|
||||
cfg := config.NewDefaultConfiguration()
|
||||
resp := engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
|
||||
resp := engine.Validate(
|
||||
context.TODO(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
ctx,
|
||||
cfg,
|
||||
)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 2)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)
|
||||
|
||||
|
@ -1135,7 +1141,12 @@ func Test_RuleSelector(t *testing.T) {
|
|||
applyOne := kyvernov1.ApplyOne
|
||||
policy.Spec.ApplyRules = &applyOne
|
||||
|
||||
resp = engine.Validate(context.TODO(), registryclient.NewOrDie(), ctx, cfg)
|
||||
resp = engine.Validate(
|
||||
context.TODO(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie()),
|
||||
ctx,
|
||||
cfg,
|
||||
)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount == 1)
|
||||
assert.Assert(t, resp.PolicyResponse.RulesErrorCount == 0)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue