1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

refactor: introduce jmespath interface (#6882)

* refactor: introduce jmespath interface

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>

* fix

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

---------

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-04-13 13:29:40 +02:00 committed by GitHub
parent 3ca6311947
commit 544fe04508
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 482 additions and 315 deletions

View file

@ -18,6 +18,7 @@ import (
"github.com/kyverno/kyverno/pkg/config"
policymetricscontroller "github.com/kyverno/kyverno/pkg/controllers/metrics/policy"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/logging"
@ -43,6 +44,7 @@ func createrLeaderControllers(
configuration config.Configuration,
metricsConfig metrics.MetricsConfigManager,
eventGenerator event.Interface,
jp jmespath.Interface,
) ([]internal.Controller, error) {
policyCtrl, err := policy.NewPolicyController(
kyvernoClient,
@ -57,6 +59,7 @@ func createrLeaderControllers(
logging.WithName("PolicyController"),
time.Hour,
metricsConfig,
jp,
)
if err != nil {
return nil, err
@ -71,6 +74,7 @@ func createrLeaderControllers(
kubeInformer.Core().V1().Namespaces(),
eventGenerator,
configuration,
jp,
)
return []internal.Controller{
internal.NewController("policy-controller", policyCtrl, 2),
@ -137,6 +141,7 @@ func main() {
setup.Logger,
setup.Configuration,
setup.MetricsConfiguration,
setup.Jp,
dClient,
setup.RegistryClient,
setup.KubeClient,
@ -174,6 +179,7 @@ func main() {
setup.Configuration,
setup.MetricsManager,
eventGenerator,
setup.Jp,
)
if err != nil {
logger.Error(err, "failed to create leader controllers")

View file

@ -5,13 +5,17 @@ import (
"github.com/go-logr/logr"
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
"github.com/kyverno/kyverno/pkg/config"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/logging"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
var jp = jmespath.New(config.NewDefaultConfiguration(false))
func Test_checkCondition(t *testing.T) {
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
ctx.AddResource(map[string]interface{}{
"name": "dummy",
})

View file

@ -11,6 +11,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
@ -34,6 +35,7 @@ type handlers struct {
polLister kyvernov2alpha1listers.CleanupPolicyLister
nsLister corev1listers.NamespaceLister
recorder record.EventRecorder
jp jmespath.Interface
metrics cleanupMetrics
}
@ -65,11 +67,12 @@ func newCleanupMetrics(logger logr.Logger) cleanupMetrics {
}
func New(
logger logr.Logger,
client dclient.Interface,
cpolLister kyvernov2alpha1listers.ClusterCleanupPolicyLister,
polLister kyvernov2alpha1listers.CleanupPolicyLister,
nsLister corev1listers.NamespaceLister,
logger logr.Logger,
jp jmespath.Interface,
) *handlers {
return &handlers{
client: client,
@ -78,6 +81,7 @@ func New(
nsLister: nsLister,
recorder: event.NewRecorder(event.CleanupController, client.GetEventsInterface()),
metrics: newCleanupMetrics(logger),
jp: jp,
}
}
@ -181,7 +185,7 @@ func (h *handlers) executePolicy(ctx context.Context, logger logr.Logger, policy
}
// check conditions
if spec.Conditions != nil {
enginectx := enginecontext.NewContext()
enginectx := enginecontext.NewContext(h.jp)
if err := enginectx.AddTargetResource(resource.Object); err != nil {
debug.Error(err, "failed to add resource in context")
errs = append(errs, err)

View file

@ -199,7 +199,7 @@ func main() {
}
// create handlers
admissionHandlers := admissionhandlers.New(dClient)
cleanupHandlers := cleanuphandlers.New(dClient, cpolLister, polLister, nsLister, setup.Logger.WithName("cleanup-handler"))
cleanupHandlers := cleanuphandlers.New(setup.Logger.WithName("cleanup-handler"), dClient, cpolLister, polLister, nsLister, setup.Jp)
// create server
server := NewServer(
func() ([]byte, []byte, error) {

View file

@ -10,6 +10,7 @@ import (
"strings"
gojmespath "github.com/jmespath/go-jmespath"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
@ -162,11 +163,12 @@ func loadInput(file string) (interface{}, error) {
}
func evaluate(input interface{}, query string) (interface{}, error) {
jp, err := jmespath.New(query)
jp := jmespath.New(config.NewDefaultConfiguration(false))
q, err := jp.Query(query)
if err != nil {
return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", query, err)
}
result, err := jp.Search(input)
result, err := q.Search(input)
if err != nil {
if syntaxError, ok := err.(gojmespath.SyntaxError); ok {
return nil, fmt.Errorf("%s\n%s", syntaxError, syntaxError.HighlightLocation())

View file

@ -23,6 +23,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
engineContext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
"github.com/kyverno/kyverno/pkg/registryclient"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
@ -369,6 +370,8 @@ func GetVariable(variablesString, valuesFile string, fs billy.Filesystem, isGit
// ApplyPolicyOnResource - function to apply policy on resource
func ApplyPolicyOnResource(c ApplyPolicyConfig) ([]engineapi.EngineResponse, error) {
jp := jmespath.New(config.NewDefaultConfiguration(false))
var engineResponses []engineapi.EngineResponse
namespaceLabels := make(map[string]string)
operationIsDelete := false
@ -431,7 +434,7 @@ OuterLoop:
if err != nil {
log.Log.Error(err, "unable to convert raw resource to unstructured")
}
ctx := engineContext.NewContext()
ctx := engineContext.NewContext(jp)
if operationIsDelete {
err = engineContext.AddOldResource(ctx, resourceRaw)
@ -478,6 +481,7 @@ OuterLoop:
eng := engine.NewEngine(
cfg,
config.NewDefaultMetricsConfiguration(),
jmespath.New(cfg),
c.Client,
registryclient.NewOrDie(),
store.ContextLoaderFactory(nil),
@ -1025,9 +1029,11 @@ func initializeMockController(objects []runtime.Object) (*generate.GenerateContr
}
client.SetDiscovery(dclient.NewFakeDiscoveryClient(nil))
cfg := config.NewDefaultConfiguration(false)
c := generate.NewGenerateControllerWithOnlyClient(client, engine.NewEngine(
config.NewDefaultConfiguration(false),
cfg,
config.NewDefaultMetricsConfiguration(),
jmespath.New(cfg),
client,
nil,
store.ContextLoaderFactory(nil),

View file

@ -8,6 +8,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
)
@ -37,6 +38,7 @@ type mockContextLoader struct {
func (l *mockContextLoader) Load(
ctx context.Context,
jp jmespath.Interface,
client dclient.Interface,
_ registryclient.Client,
contextEntries []kyvernov1.ContextEntry,
@ -56,15 +58,15 @@ func (l *mockContextLoader) Load(
for _, entry := range contextEntries {
if entry.ImageRegistry != nil && hasRegistryAccess {
rclient := GetRegistryClient()
if err := engineapi.LoadImageData(ctx, rclient, l.logger, entry, jsonContext); err != nil {
if err := engineapi.LoadImageData(ctx, jp, rclient, l.logger, entry, jsonContext); err != nil {
return err
}
} else if entry.Variable != nil {
if err := engineapi.LoadVariable(l.logger, entry, jsonContext); err != nil {
if err := engineapi.LoadVariable(l.logger, jp, entry, jsonContext); err != nil {
return err
}
} else if entry.APICall != nil && IsApiCallAllowed() {
if err := engineapi.LoadAPIData(ctx, l.logger, entry, jsonContext, client); err != nil {
if err := engineapi.LoadAPIData(ctx, jp, l.logger, entry, jsonContext, client); err != nil {
return err
}
}

View file

@ -13,6 +13,7 @@ import (
"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/engine/jmespath"
"github.com/kyverno/kyverno/pkg/registryclient"
"k8s.io/client-go/kubernetes"
)
@ -22,6 +23,7 @@ func NewEngine(
logger logr.Logger,
configuration config.Configuration,
metricsConfiguration config.MetricsConfiguration,
jp jmespath.Interface,
client dclient.Interface,
rclient registryclient.Client,
kubeClient kubernetes.Interface,
@ -34,6 +36,7 @@ func NewEngine(
return engine.NewEngine(
configuration,
metricsConfiguration,
jp,
client,
rclient,
engineapi.DefaultContextLoaderFactory(configMapResolver),

View file

@ -6,6 +6,7 @@ import (
"github.com/go-logr/logr"
kubeclient "github.com/kyverno/kyverno/pkg/clients/kube"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/registryclient"
"k8s.io/client-go/kubernetes"
@ -27,6 +28,7 @@ type SetupResult struct {
Configuration config.Configuration
MetricsConfiguration config.MetricsConfiguration
MetricsManager metrics.MetricsConfigManager
Jp jmespath.Interface
KubeClient kubernetes.Interface
LeaderElectionClient kubernetes.Interface
RegistryClient registryclient.Client
@ -59,6 +61,7 @@ func Setup(config Configuration, name string, skipResourceFilters bool) (context
Configuration: configuration,
MetricsConfiguration: metricsConfiguration,
MetricsManager: metricsManager,
Jp: jmespath.New(configuration),
KubeClient: client,
LeaderElectionClient: leaderElectionClient,
RegistryClient: registryClient,

View file

@ -303,6 +303,7 @@ func main() {
setup.Logger,
setup.Configuration,
setup.MetricsConfiguration,
setup.Jp,
dClient,
setup.RegistryClient,
setup.KubeClient,
@ -426,8 +427,6 @@ func main() {
setup.MetricsManager,
policyCache,
kubeInformer.Core().V1().Namespaces().Lister(),
kubeInformer.Rbac().V1().RoleBindings().Lister(),
kubeInformer.Rbac().V1().ClusterRoleBindings().Lister(),
kyvernoInformer.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
kyvernoInformer.Kyverno().V1().Policies(),
@ -436,6 +435,7 @@ func main() {
openApiManager,
admissionReports,
backgroundServiceAccountName,
setup.Jp,
)
exceptionHandlers := webhooksexception.NewHandlers(exception.ValidationOptions{
Enabled: internal.PolicyExceptionEnabled(),

View file

@ -21,6 +21,7 @@ import (
backgroundscancontroller "github.com/kyverno/kyverno/pkg/controllers/report/background"
resourcereportcontroller "github.com/kyverno/kyverno/pkg/controllers/report/resource"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/logging"
@ -49,6 +50,7 @@ func createReportControllers(
kyvernoInformer kyvernoinformer.SharedInformerFactory,
backgroundScanInterval time.Duration,
configuration config.Configuration,
jp jmespath.Interface,
eventGenerator event.Interface,
) ([]internal.Controller, func(context.Context) error) {
var ctrls []internal.Controller
@ -105,6 +107,7 @@ func createReportControllers(
resourceReportController,
backgroundScanInterval,
configuration,
jp,
eventGenerator,
),
backgroundScanWorkers,
@ -134,6 +137,7 @@ func createrLeaderControllers(
dynamicClient dclient.Interface,
rclient registryclient.Client,
configuration config.Configuration,
jp jmespath.Interface,
eventGenerator event.Interface,
backgroundScanInterval time.Duration,
) ([]internal.Controller, func(context.Context) error, error) {
@ -151,6 +155,7 @@ func createrLeaderControllers(
kyvernoInformer,
backgroundScanInterval,
configuration,
jp,
eventGenerator,
)
return reportControllers, warmup, nil
@ -223,6 +228,7 @@ func main() {
setup.Logger,
setup.Configuration,
setup.MetricsConfiguration,
setup.Jp,
dClient,
setup.RegistryClient,
setup.KubeClient,
@ -265,6 +271,7 @@ func main() {
dClient,
setup.RegistryClient,
setup.Configuration,
setup.Jp,
eventGenerator,
backgroundScanInterval,
)

View file

@ -10,18 +10,22 @@ import (
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRequest,
func NewBackgroundContext(
logger logr.Logger,
dclient dclient.Interface,
ur *kyvernov1beta1.UpdateRequest,
policy kyvernov1.PolicyInterface,
trigger *unstructured.Unstructured,
cfg config.Configuration,
jp jmespath.Interface,
namespaceLabels map[string]string,
logger logr.Logger,
) (*engine.PolicyContext, error) {
ctx := context.NewContext()
ctx := context.NewContext(jp)
var new, old unstructured.Unstructured
var err error

View file

@ -20,6 +20,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/variables"
"github.com/kyverno/kyverno/pkg/event"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
@ -55,6 +56,7 @@ type GenerateController struct {
eventGen event.Interface
log logr.Logger
jp jmespath.Interface
}
// NewGenerateController returns an instance of the Generate-Request Controller
@ -70,6 +72,7 @@ func NewGenerateController(
dynamicConfig config.Configuration,
eventGen event.Interface,
log logr.Logger,
jp jmespath.Interface,
) *GenerateController {
c := GenerateController{
client: client,
@ -83,6 +86,7 @@ func NewGenerateController(
configuration: dynamicConfig,
eventGen: eventGen,
log: log,
jp: jp,
}
return &c
}
@ -198,7 +202,7 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
return nil, err
}
policyContext, err := common.NewBackgroundContext(c.client, &ur, policy, &resource, c.configuration, namespaceLabels, logger)
policyContext, err := common.NewBackgroundContext(logger, c.client, &ur, policy, &resource, c.configuration, c.jp, namespaceLabels)
if err != nil {
return nil, err
}

View file

@ -13,6 +13,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/utils"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
@ -28,7 +29,7 @@ import (
var ErrEmptyPatch error = fmt.Errorf("empty resource to patch")
type MutateExistingController struct {
type mutateExistingController struct {
// clients
client dclient.Interface
statusControl common.StatusControlInterface
@ -43,6 +44,7 @@ type MutateExistingController struct {
eventGen event.Interface
log logr.Logger
jp jmespath.Interface
}
// NewMutateExistingController returns an instance of the MutateExistingController
@ -56,8 +58,9 @@ func NewMutateExistingController(
dynamicConfig config.Configuration,
eventGen event.Interface,
log logr.Logger,
) *MutateExistingController {
c := MutateExistingController{
jp jmespath.Interface,
) *mutateExistingController {
c := mutateExistingController{
client: client,
statusControl: statusControl,
engine: engine,
@ -67,11 +70,12 @@ func NewMutateExistingController(
configuration: dynamicConfig,
eventGen: eventGen,
log: log,
jp: jp,
}
return &c
}
func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error {
func (c *mutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error {
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.GetPolicyKey(), "resource", ur.Spec.GetResource().String())
var errs []error
@ -130,7 +134,7 @@ func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
}
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(trigger.GetKind(), trigger.GetNamespace(), c.nsLister, logger)
policyContext, err := common.NewBackgroundContext(c.client, ur, policy, trigger, c.configuration, namespaceLabels, logger)
policyContext, err := common.NewBackgroundContext(logger, c.client, ur, policy, trigger, c.configuration, c.jp, namespaceLabels)
if err != nil {
logger.WithName(rule.Name).Error(err, "failed to build policy context")
errs = append(errs, err)
@ -210,7 +214,7 @@ func (c *MutateExistingController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) e
return updateURStatus(c.statusControl, *ur, err)
}
func (c *MutateExistingController) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
func (c *mutateExistingController) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
pNamespace, pName, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
return nil, err
@ -223,7 +227,7 @@ func (c *MutateExistingController) getPolicy(key string) (kyvernov1.PolicyInterf
return c.policyLister.Get(pName)
}
func (c *MutateExistingController) report(err error, policy, rule string, target *unstructured.Unstructured) {
func (c *mutateExistingController) report(err error, policy, rule string, target *unstructured.Unstructured) {
var events []event.Info
if target == nil {

View file

@ -18,6 +18,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -58,6 +59,7 @@ type controller struct {
eventGen event.Interface
configuration config.Configuration
jp jmespath.Interface
}
// NewController returns an instance of the Generate-Request Controller
@ -70,7 +72,8 @@ func NewController(
urInformer kyvernov1beta1informers.UpdateRequestInformer,
namespaceInformer corev1informers.NamespaceInformer,
eventGen event.Interface,
dynamicConfig config.Configuration,
configuration config.Configuration,
jp jmespath.Interface,
) Controller {
urLister := urInformer.Lister().UpdateRequests(config.KyvernoNamespace())
c := controller{
@ -83,7 +86,8 @@ func NewController(
nsLister: namespaceInformer.Lister(),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "background"),
eventGen: eventGen,
configuration: dynamicConfig,
configuration: configuration,
jp: jp,
}
_, _ = urInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: c.addUR,
@ -216,10 +220,10 @@ func (c *controller) processUR(ur *kyvernov1beta1.UpdateRequest) error {
statusControl := common.NewStatusControl(c.kyvernoClient, c.urLister)
switch ur.Spec.GetRequestType() {
case kyvernov1beta1.Mutate:
ctrl := mutate.NewMutateExistingController(c.client, statusControl, c.engine, c.cpolLister, c.polLister, c.nsLister, c.configuration, c.eventGen, logger)
ctrl := mutate.NewMutateExistingController(c.client, statusControl, c.engine, c.cpolLister, c.polLister, c.nsLister, c.configuration, c.eventGen, logger, c.jp)
return ctrl.ProcessUR(ur)
case kyvernov1beta1.Generate:
ctrl := generate.NewGenerateController(c.client, c.kyvernoClient, statusControl, c.engine, c.cpolLister, c.polLister, c.urLister, c.nsLister, c.configuration, c.eventGen, logger)
ctrl := generate.NewGenerateController(c.client, c.kyvernoClient, statusControl, c.engine, c.cpolLister, c.polLister, c.urLister, c.nsLister, c.configuration, c.eventGen, logger, c.jp)
return ctrl.ProcessUR(ur)
}
return nil

View file

@ -17,6 +17,7 @@ import (
"github.com/kyverno/kyverno/pkg/controllers/report/resource"
"github.com/kyverno/kyverno/pkg/controllers/report/utils"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
@ -64,6 +65,7 @@ type controller struct {
// config
config config.Configuration
jp jmespath.Interface
eventGen event.Interface
}
@ -78,6 +80,7 @@ func NewController(
metadataCache resource.MetadataCache,
forceDelay time.Duration,
config config.Configuration,
jp jmespath.Interface,
eventGen event.Interface,
) controllers.Controller {
bgscanr := metadataFactory.ForResource(kyvernov1alpha2.SchemeGroupVersion.WithResource("backgroundscanreports"))
@ -96,6 +99,7 @@ func NewController(
metadataCache: metadataCache,
forceDelay: forceDelay,
config: config,
jp: jp,
eventGen: eventGen,
}
controllerutils.AddDefaultEventHandlers(logger, bgscanr.Informer(), queue)
@ -301,7 +305,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.engine, c.config)
scanner := utils.NewScanner(logger, c.engine, c.config, c.jp)
for _, result := range scanner.ScanResource(ctx, *target, nsLabels, policy) {
if result.Error != nil {
return result.Error

View file

@ -9,6 +9,7 @@ import (
"github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"go.uber.org/multierr"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -17,6 +18,7 @@ type scanner struct {
logger logr.Logger
engine engineapi.Engine
config config.Configuration
jp jmespath.Interface
}
type ScanResult struct {
@ -32,11 +34,13 @@ func NewScanner(
logger logr.Logger,
engine engineapi.Engine,
config config.Configuration,
jp jmespath.Interface,
) Scanner {
return &scanner{
logger: logger,
engine: engine,
config: config,
jp: jp,
}
}
@ -68,7 +72,7 @@ func (s *scanner) ScanResource(ctx context.Context, resource unstructured.Unstru
}
func (s *scanner) validateResource(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*engineapi.EngineResponse, error) {
enginectx := enginecontext.NewContext()
enginectx := enginecontext.NewContext(s.jp)
if err := enginectx.AddResource(resource.Object); err != nil {
return nil, err
}
@ -90,7 +94,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
}
func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unstructured, nsLabels map[string]string, policy kyvernov1.PolicyInterface) (*engineapi.EngineResponse, error) {
enginectx := enginecontext.NewContext()
enginectx := enginecontext.NewContext(s.jp)
if err := enginectx.AddResource(resource.Object); err != nil {
return nil, err
}

View file

@ -15,7 +15,7 @@ import (
"github.com/kyverno/kyverno/pkg/registryclient"
)
func LoadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx enginecontext.Interface) (err error) {
func LoadVariable(logger logr.Logger, jp jmespath.Interface, entry kyvernov1.ContextEntry, ctx enginecontext.Interface) (err error) {
path := ""
if entry.Variable.JMESPath != "" {
jp, err := variables.SubstituteAll(logger, ctx, entry.Variable.JMESPath)
@ -45,7 +45,7 @@ func LoadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx engineco
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Value, err)
}
if path != "" {
variable, err := applyJMESPath(path, variable)
variable, err := applyJMESPath(jp, path, variable)
if err == nil {
output = variable
} else if defaultValue == nil {
@ -74,8 +74,8 @@ func LoadVariable(logger logr.Logger, entry kyvernov1.ContextEntry, ctx engineco
}
}
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)
func LoadImageData(ctx context.Context, jp jmespath.Interface, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface) error {
imageData, err := fetchImageData(ctx, jp, rclient, logger, entry, enginectx)
if err != nil {
return err
}
@ -89,8 +89,8 @@ func LoadImageData(ctx context.Context, rclient registryclient.Client, logger lo
return nil
}
func LoadAPIData(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, client dclient.Interface) error {
executor, err := apicall.New(logger, entry, enginectx, client)
func LoadAPIData(ctx context.Context, jp jmespath.Interface, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, client dclient.Interface) error {
executor, err := apicall.New(logger, jp, entry, enginectx, client)
if err != nil {
return fmt.Errorf("failed to initialize APICall: %w", err)
}
@ -112,7 +112,7 @@ func LoadConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.Cont
return nil
}
func fetchImageData(ctx context.Context, rclient registryclient.Client, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface) (interface{}, error) {
func fetchImageData(ctx context.Context, jp jmespath.Interface, 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)
@ -130,7 +130,7 @@ func fetchImageData(ctx context.Context, rclient registryclient.Client, logger l
return nil, err
}
if path != "" {
imageData, err = applyJMESPath(path.(string), imageData)
imageData, err = applyJMESPath(jp, path.(string), imageData)
if err != nil {
return nil, fmt.Errorf("failed to apply JMESPath (%s) results to context entry %s, error: %v", entry.ImageRegistry.JMESPath, entry.Name, err)
}
@ -193,12 +193,12 @@ func fetchImageDataMap(ctx context.Context, rclient registryclient.Client, ref s
return untyped, nil
}
func applyJMESPath(jmesPath string, data interface{}) (interface{}, error) {
jp, err := jmespath.New(jmesPath)
func applyJMESPath(jp jmespath.Interface, query string, data interface{}) (interface{}, error) {
q, err := jp.Query(query)
if err != nil {
return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", jmesPath, err)
return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", query, err)
}
return jp.Search(data)
return q.Search(data)
}
func fetchConfigMap(ctx context.Context, logger logr.Logger, entry kyvernov1.ContextEntry, enginectx enginecontext.Interface, resolver ConfigmapResolver) ([]byte, error) {

View file

@ -7,6 +7,7 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/clients/dclient"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
)
@ -18,6 +19,7 @@ type ContextLoaderFactory = func(policy kyvernov1.PolicyInterface, rule kyvernov
type ContextLoader interface {
Load(
ctx context.Context,
jp jmespath.Interface,
client dclient.Interface,
rclient registryclient.Client,
contextEntries []kyvernov1.ContextEntry,
@ -43,6 +45,7 @@ type contextLoader struct {
func (l *contextLoader) Load(
ctx context.Context,
jp jmespath.Interface,
client dclient.Interface,
rclient registryclient.Client,
contextEntries []kyvernov1.ContextEntry,
@ -54,15 +57,15 @@ func (l *contextLoader) Load(
return err
}
} else if entry.APICall != nil {
if err := LoadAPIData(ctx, l.logger, entry, jsonContext, client); err != nil {
if err := LoadAPIData(ctx, jp, l.logger, entry, jsonContext, client); err != nil {
return err
}
} else if entry.ImageRegistry != nil {
if err := LoadImageData(ctx, rclient, l.logger, entry, jsonContext); err != nil {
if err := LoadImageData(ctx, jp, rclient, l.logger, entry, jsonContext); err != nil {
return err
}
} else if entry.Variable != nil {
if err := LoadVariable(l.logger, entry, jsonContext); err != nil {
if err := LoadVariable(l.logger, jp, entry, jsonContext); err != nil {
return err
}
}

View file

@ -21,13 +21,15 @@ import (
type apiCall struct {
logger logr.Logger
jp jmespath.Interface
entry kyvernov1.ContextEntry
jsonCtx enginecontext.Interface
client dclient.Interface
}
func New(
log logr.Logger,
logger logr.Logger,
jp jmespath.Interface,
entry kyvernov1.ContextEntry,
jsonCtx enginecontext.Interface,
client dclient.Interface,
@ -36,10 +38,11 @@ func New(
return nil, fmt.Errorf("missing APICall in context entry %v", entry)
}
return &apiCall{
logger: logger,
jp: jp,
entry: entry,
jsonCtx: jsonCtx,
client: client,
logger: log,
}, nil
}
@ -205,7 +208,7 @@ func (a *apiCall) transformAndStore(jsonData []byte) ([]byte, error) {
return nil, fmt.Errorf("failed to substitute variables in context entry %s JMESPath %s: %w", a.entry.Name, a.entry.APICall.JMESPath, err)
}
results, err := applyJMESPathJSON(path.(string), jsonData)
results, err := a.applyJMESPathJSON(path.(string), jsonData)
if err != nil {
return nil, fmt.Errorf("failed to apply JMESPath %s for context entry %s: %w", path, a.entry.Name, err)
}
@ -224,17 +227,11 @@ func (a *apiCall) transformAndStore(jsonData []byte) ([]byte, error) {
return contextData, nil
}
func applyJMESPathJSON(jmesPath string, jsonData []byte) (interface{}, error) {
func (a *apiCall) applyJMESPathJSON(jmesPath string, jsonData []byte) (interface{}, error) {
var data interface{}
err := json.Unmarshal(jsonData, &data)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %s, error: %w", string(jsonData), err)
}
jp, err := jmespath.New(jmesPath)
if err != nil {
return nil, fmt.Errorf("failed to compile JMESPath: %s, error: %v", jmesPath, err)
}
return jp.Search(data)
return a.jp.Search(jmesPath, data)
}

View file

@ -9,11 +9,15 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"gotest.tools/assert"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
var jp = jmespath.New(config.NewDefaultConfiguration(false))
func buildTestServer(responseData []byte) *httptest.Server {
mux := http.NewServeMux()
mux.HandleFunc("/resource", func(w http.ResponseWriter, r *http.Request) {
@ -38,9 +42,9 @@ func Test_serviceGetRequest(t *testing.T) {
defer s.Close()
entry := kyvernov1.ContextEntry{}
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
_, err := New(logr.Discard(), entry, ctx, nil)
_, err := New(logr.Discard(), jp, entry, ctx, nil)
assert.ErrorContains(t, err, "missing APICall")
entry.Name = "test"
@ -50,19 +54,19 @@ func Test_serviceGetRequest(t *testing.T) {
},
}
call, err := New(logr.Discard(), entry, ctx, nil)
call, err := New(logr.Discard(), jp, entry, ctx, nil)
assert.NilError(t, err)
_, err = call.Execute(context.TODO())
assert.ErrorContains(t, err, "invalid request type")
entry.APICall.Service.Method = "GET"
call, err = New(logr.Discard(), entry, ctx, nil)
call, err = New(logr.Discard(), jp, entry, ctx, nil)
assert.NilError(t, err)
_, err = call.Execute(context.TODO())
assert.ErrorContains(t, err, "HTTP 404")
entry.APICall.Service.URL = s.URL + "/resource"
call, err = New(logr.Discard(), entry, ctx, nil)
call, err = New(logr.Discard(), jp, entry, ctx, nil)
assert.NilError(t, err)
data, err := call.Execute(context.TODO())
@ -86,8 +90,8 @@ func Test_servicePostRequest(t *testing.T) {
},
}
ctx := enginecontext.NewContext()
call, err := New(logr.Discard(), entry, ctx, nil)
ctx := enginecontext.NewContext(jp)
call, err := New(logr.Discard(), jp, entry, ctx, nil)
assert.NilError(t, err)
data, err := call.Execute(context.TODO())
assert.NilError(t, err)
@ -135,7 +139,7 @@ func Test_servicePostRequest(t *testing.T) {
},
}
call, err = New(logr.Discard(), entry, ctx, nil)
call, err = New(logr.Discard(), jp, entry, ctx, nil)
assert.NilError(t, err)
data, err = call.Execute(context.TODO())
assert.NilError(t, err)

View file

@ -6,8 +6,10 @@ import (
"github.com/go-logr/logr"
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/internal"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/utils/api"
"github.com/kyverno/kyverno/pkg/utils/image"
"gotest.tools/assert"
@ -245,7 +247,7 @@ func Test_Conditions(t *testing.T) {
},
}
ctx := context.NewContext()
ctx := context.NewContext(jmespath.New(config.NewDefaultConfiguration(false)))
img := api.ImageInfo{Pointer: "/spec/containers/0/image"}
img.ImageInfo = image.ImageInfo{
Registry: "docker.io",

View file

@ -10,6 +10,7 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/logging"
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
admissionv1 "k8s.io/api/admission/v1"
@ -98,6 +99,7 @@ type Interface interface {
// Context stores the data resources as JSON
type context struct {
jp jmespath.Interface
mutex sync.RWMutex
jsonRaw []byte
jsonRawCheckpoints [][]byte
@ -105,17 +107,17 @@ type context struct {
}
// NewContext returns a new context
func NewContext() Interface {
return NewContextFromRaw([]byte(`{}`))
func NewContext(jp jmespath.Interface) Interface {
return NewContextFromRaw(jp, []byte(`{}`))
}
// NewContextFromRaw returns a new context initialized with raw data
func NewContextFromRaw(raw []byte) Interface {
ctx := context{
func NewContextFromRaw(jp jmespath.Interface, raw []byte) Interface {
return &context{
jp: jp,
jsonRaw: raw,
jsonRawCheckpoints: make([][]byte, 0),
}
return &ctx
}
// addJSON merges json data

View file

@ -5,9 +5,13 @@ import (
"testing"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
authenticationv1 "k8s.io/api/authentication/v1"
)
var jp = jmespath.New(config.NewDefaultConfiguration(false))
func Test_addResourceAndUserContext(t *testing.T) {
var err error
rawResource := []byte(`
@ -55,7 +59,7 @@ func Test_addResourceAndUserContext(t *testing.T) {
}
var expectedResult string
ctx := NewContext()
ctx := NewContext(jp)
err = AddResource(ctx, rawResource)
if err != nil {
t.Error(err)

View file

@ -5,7 +5,6 @@ import (
"fmt"
"strings"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
)
@ -16,7 +15,7 @@ func (ctx *context) Query(query string) (interface{}, error) {
return nil, fmt.Errorf("invalid query (nil)")
}
// compile the query
queryPath, err := jmespath.New(query)
queryPath, err := ctx.jp.Query(query)
if err != nil {
logger.Error(err, "incorrect query", "query", query)
return nil, fmt.Errorf("incorrect query %s: %v", query, err)

View file

@ -28,7 +28,7 @@ func TestHasChanged(t *testing.T) {
func TestRequestNotInitialize(t *testing.T) {
request := admissionv1.AdmissionRequest{}
ctx := NewContext()
ctx := NewContext(jp)
ctx.AddRequest(request)
_, err := ctx.HasChanged("x.y.z")
@ -37,7 +37,7 @@ func TestRequestNotInitialize(t *testing.T) {
func TestMissingOldObject(t *testing.T) {
request := admissionv1.AdmissionRequest{}
ctx := NewContext()
ctx := NewContext(jp)
ctx.AddRequest(request)
request.Object.Raw = []byte(`{"a": {"b": 1, "c": 2}, "d": 3}`)
@ -47,7 +47,7 @@ func TestMissingOldObject(t *testing.T) {
func TestMissingObject(t *testing.T) {
request := admissionv1.AdmissionRequest{}
ctx := NewContext()
ctx := NewContext(jp)
ctx.AddRequest(request)
request.OldObject.Raw = []byte(`{"a": {"b": 1, "c": 2}, "d": 3}`)
@ -61,7 +61,7 @@ func createTestContext(obj, oldObj string) Interface {
request.Object.Raw = []byte(obj)
request.OldObject.Raw = []byte(oldObj)
ctx := NewContext()
ctx := NewContext(jp)
ctx.AddRequest(request)
return ctx
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"sync"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
)
@ -41,7 +42,8 @@ func (ctx *MockContext) Query(query string) (interface{}, error) {
var emptyResult interface{}
// compile the query
if _, err := jmespath.New(query); err != nil {
jp := jmespath.New(config.NewDefaultConfiguration(false))
if _, err := jp.Query(query); err != nil {
return emptyResult, fmt.Errorf("invalid JMESPath query %s: %v", query, err)
}

View file

@ -14,6 +14,7 @@ import (
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/handlers"
"github.com/kyverno/kyverno/pkg/engine/internal"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/metrics"
@ -28,6 +29,7 @@ import (
type engine struct {
configuration config.Configuration
metricsConfiguration config.MetricsConfiguration
jp jmespath.Interface
client dclient.Interface
rclient registryclient.Client
contextLoader engineapi.ContextLoaderFactory
@ -42,6 +44,7 @@ type handlerFactory = func() (handlers.Handler, error)
func NewEngine(
configuration config.Configuration,
metricsConfiguration config.MetricsConfiguration,
jp jmespath.Interface,
client dclient.Interface,
rclient registryclient.Client,
contextLoader engineapi.ContextLoaderFactory,
@ -50,7 +53,7 @@ func NewEngine(
meter := global.MeterProvider().Meter(metrics.MeterName)
resultCounter, err := meter.Int64Counter(
"kyverno_policy_results",
instrument.WithDescription("can be used to track the results associated with the policies applied in the users cluster, at the level from rule to policy to admission requests"),
instrument.WithDescription("can be used to track the results associated with the policies applied in the user's cluster, at the level from rule to policy to admission requests"),
)
if err != nil {
logging.Error(err, "failed to register metric kyverno_policy_results")
@ -65,6 +68,7 @@ func NewEngine(
return &engine{
configuration: configuration,
metricsConfiguration: metricsConfiguration,
jp: jp,
client: client,
rclient: rclient,
contextLoader: contextLoader,
@ -165,6 +169,7 @@ func (e *engine) ContextLoader(
return func(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error {
return loader.Load(
ctx,
e.jp,
e.client,
e.rclient,
contextEntries,

View file

@ -6,7 +6,9 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"gotest.tools/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -100,7 +102,8 @@ func Test_ForceMutateSubstituteVars(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
ctx := context.NewContext()
jp := jmespath.New(config.NewDefaultConfiguration(false))
ctx := context.NewContext(jp)
err = context.AddResource(ctx, rawResource)
assert.NilError(t, err)
@ -205,7 +208,8 @@ func Test_ForceMutateSubstituteVarsWithPatchesJson6902(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
ctx := context.NewContext()
jp := jmespath.New(config.NewDefaultConfiguration(false))
ctx := context.NewContext(jp)
err = context.AddResource(ctx, rawResource)
assert.NilError(t, err)
@ -291,7 +295,8 @@ func Test_ForceMutateSubstituteVarsWithPatchStrategicMerge(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
ctx := context.NewContext()
jp := jmespath.New(config.NewDefaultConfiguration(false))
ctx := context.NewContext(jp)
err = context.AddResource(ctx, rawResource)
assert.NilError(t, err)

View file

@ -10,6 +10,7 @@ import (
"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/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/policycontext"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"gotest.tools/assert"
@ -17,6 +18,8 @@ import (
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
var jp = jmespath.New(config.NewDefaultConfiguration(false))
var test_policy = `{}`
var signed_resource = `{
@ -785,7 +788,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) eng
resourceUnstructured, err := kubeutils.BytesToUnstructured([]byte(resource))
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, []byte(resource))
assert.NilError(t, err)

View file

@ -15,6 +15,7 @@ import (
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
"github.com/kyverno/kyverno/pkg/engine/internal"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/policycontext"
"github.com/kyverno/kyverno/pkg/engine/utils"
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
@ -164,6 +165,7 @@ var signaturePayloads = [][]byte{
var (
cfg = config.NewDefaultConfiguration(false)
metricsCfg = config.NewDefaultMetricsConfiguration()
jp = jmespath.New(cfg)
)
func testVerifyAndPatchImages(
@ -176,6 +178,7 @@ func testVerifyAndPatchImages(
e := NewEngine(
cfg,
metricsCfg,
jp,
nil,
rclient,
engineapi.DefaultContextLoaderFactory(cmResolver),
@ -219,7 +222,7 @@ func buildContext(t *testing.T, policy, resource string, oldResource string) *Po
resourceUnstructured, err := kubeutils.BytesToUnstructured([]byte(resource))
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, []byte(resource))
assert.NilError(t, err)

View file

@ -10,7 +10,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
type Operand interface {
type operand interface {
Add(interface{}, string) (interface{}, error)
Subtract(interface{}) (interface{}, error)
Multiply(interface{}) (interface{}, error)
@ -18,30 +18,30 @@ type Operand interface {
Modulo(interface{}) (interface{}, error)
}
type Quantity struct {
type quantity struct {
resource.Quantity
}
type Duration struct {
type duration struct {
time.Duration
}
type Scalar struct {
type scalar struct {
float64
}
func ParseArithemticOperands(arguments []interface{}, operator string) (Operand, Operand, error) {
op := [2]Operand{nil, nil}
func parseArithemticOperands(arguments []interface{}, operator string) (operand, operand, error) {
op := [2]operand{nil, nil}
for i := 0; i < 2; i++ {
if tmp, err := validateArg(divide, arguments, i, reflect.Float64); err == nil {
var sc Scalar
var sc scalar
sc.float64 = tmp.Float()
op[i] = sc
} else if tmp, err = validateArg(divide, arguments, i, reflect.String); err == nil {
if q, err := resource.ParseQuantity(tmp.String()); err == nil {
op[i] = Quantity{Quantity: q}
op[i] = quantity{Quantity: q}
} else if d, err := time.ParseDuration(tmp.String()); err == nil {
op[i] = Duration{Duration: d}
op[i] = duration{Duration: d}
}
}
}
@ -58,9 +58,9 @@ func ParseArithemticOperands(arguments []interface{}, operator string) (Operand,
// Scalar +|- Scalar -> Scalar
// Scalar +|- Quantity|Duration -> error
func (op1 Quantity) Add(op2 interface{}, operator string) (interface{}, error) {
func (op1 quantity) Add(op2 interface{}, operator string) (interface{}, error) {
switch v := op2.(type) {
case Quantity:
case quantity:
op1.Quantity.Add(v.Quantity)
return op1.String(), nil
default:
@ -68,27 +68,27 @@ func (op1 Quantity) Add(op2 interface{}, operator string) (interface{}, error) {
}
}
func (op1 Duration) Add(op2 interface{}, operator string) (interface{}, error) {
func (op1 duration) Add(op2 interface{}, operator string) (interface{}, error) {
switch v := op2.(type) {
case Duration:
case duration:
return (op1.Duration + v.Duration).String(), nil
default:
return nil, formatError(typeMismatchError, operator)
}
}
func (op1 Scalar) Add(op2 interface{}, operator string) (interface{}, error) {
func (op1 scalar) Add(op2 interface{}, operator string) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
return op1.float64 + v.float64, nil
default:
return nil, formatError(typeMismatchError, operator)
}
}
func (op1 Quantity) Subtract(op2 interface{}) (interface{}, error) {
func (op1 quantity) Subtract(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Quantity:
case quantity:
op1.Quantity.Sub(v.Quantity)
return op1.String(), nil
default:
@ -96,18 +96,18 @@ func (op1 Quantity) Subtract(op2 interface{}) (interface{}, error) {
}
}
func (op1 Duration) Subtract(op2 interface{}) (interface{}, error) {
func (op1 duration) Subtract(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Duration:
case duration:
return (op1.Duration - v.Duration).String(), nil
default:
return nil, formatError(typeMismatchError, subtract)
}
}
func (op1 Scalar) Subtract(op2 interface{}) (interface{}, error) {
func (op1 scalar) Subtract(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
return op1.float64 - v.float64, nil
default:
return nil, formatError(typeMismatchError, subtract)
@ -124,9 +124,9 @@ func (op1 Scalar) Subtract(op2 interface{}) (interface{}, error) {
// Scalar * Quantity -> Quantity
// Scalar * Duration -> Duration
func (op1 Quantity) Multiply(op2 interface{}) (interface{}, error) {
func (op1 quantity) Multiply(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
q, err := resource.ParseQuantity(fmt.Sprintf("%v", v.float64))
if err != nil {
return nil, err
@ -139,9 +139,9 @@ func (op1 Quantity) Multiply(op2 interface{}) (interface{}, error) {
}
}
func (op1 Duration) Multiply(op2 interface{}) (interface{}, error) {
func (op1 duration) Multiply(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
seconds := op1.Seconds() * v.float64
return time.Duration(seconds * float64(time.Second)).String(), nil
default:
@ -149,13 +149,13 @@ func (op1 Duration) Multiply(op2 interface{}) (interface{}, error) {
}
}
func (op1 Scalar) Multiply(op2 interface{}) (interface{}, error) {
func (op1 scalar) Multiply(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
return op1.float64 * v.float64, nil
case Quantity:
case quantity:
return v.Multiply(op1)
case Duration:
case duration:
return v.Multiply(op1)
default:
return nil, formatError(typeMismatchError, multiply)
@ -174,16 +174,16 @@ func (op1 Scalar) Multiply(op2 interface{}) (interface{}, error) {
// Scalar / Quantity -> error
// Scalar / Duration -> error
func (op1 Quantity) Divide(op2 interface{}) (interface{}, error) {
func (op1 quantity) Divide(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Quantity:
case quantity:
divisor := v.AsApproximateFloat64()
if divisor == 0 {
return nil, formatError(zeroDivisionError, divide)
}
dividend := op1.AsApproximateFloat64()
return dividend / divisor, nil
case Scalar:
case scalar:
if v.float64 == 0 {
return nil, formatError(zeroDivisionError, divide)
}
@ -200,14 +200,14 @@ func (op1 Quantity) Divide(op2 interface{}) (interface{}, error) {
}
}
func (op1 Duration) Divide(op2 interface{}) (interface{}, error) {
func (op1 duration) Divide(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Duration:
case duration:
if v.Seconds() == 0 {
return nil, formatError(zeroDivisionError, divide)
}
return op1.Seconds() / v.Seconds(), nil
case Scalar:
case scalar:
if v.float64 == 0 {
return nil, formatError(zeroDivisionError, divide)
}
@ -218,9 +218,9 @@ func (op1 Duration) Divide(op2 interface{}) (interface{}, error) {
}
}
func (op1 Scalar) Divide(op2 interface{}) (interface{}, error) {
func (op1 scalar) Divide(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
if v.float64 == 0 {
return nil, formatError(zeroDivisionError, divide)
}
@ -239,9 +239,9 @@ func (op1 Scalar) Divide(op2 interface{}) (interface{}, error) {
// Scalar % Quantity|Duration -> error
// Scalar % Scalar -> Scalar
func (op1 Quantity) Modulo(op2 interface{}) (interface{}, error) {
func (op1 quantity) Modulo(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Quantity:
case quantity:
f1 := op1.ToDec().AsApproximateFloat64()
f2 := v.ToDec().AsApproximateFloat64()
i1 := int64(f1)
@ -261,9 +261,9 @@ func (op1 Quantity) Modulo(op2 interface{}) (interface{}, error) {
}
}
func (op1 Duration) Modulo(op2 interface{}) (interface{}, error) {
func (op1 duration) Modulo(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Duration:
case duration:
if v.Duration == 0 {
return nil, formatError(zeroDivisionError, modulo)
}
@ -273,9 +273,9 @@ func (op1 Duration) Modulo(op2 interface{}) (interface{}, error) {
}
}
func (op1 Scalar) Modulo(op2 interface{}) (interface{}, error) {
func (op1 scalar) Modulo(op2 interface{}) (interface{}, error) {
switch v := op2.(type) {
case Scalar:
case scalar:
val1 := int64(op1.float64)
val2 := int64(v.float64)
if op1.float64 != float64(val1) {

View file

@ -82,7 +82,7 @@ func Test_Add(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -228,7 +228,7 @@ func Test_Sum(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -327,7 +327,7 @@ func Test_Subtract(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -426,7 +426,7 @@ func Test_Multiply(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -588,7 +588,7 @@ func Test_Divide(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -744,7 +744,7 @@ func Test_Modulo(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
jp, err := New(tc.test)
jp, err := newJMESPath(tc.test)
assert.NilError(t, err)
result, err := jp.Search("")
@ -792,7 +792,7 @@ func TestScalar_Multiply(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
op1 := Scalar{
op1 := scalar{
float64: tt.fields.float64,
}
got, err := op1.Multiply(tt.args.op2)
@ -815,8 +815,8 @@ func TestParseArithemticOperands(t *testing.T) {
tests := []struct {
name string
args args
want Operand
want1 Operand
want operand
want1 operand
wantErr bool
}{{
args: args{
@ -837,7 +837,7 @@ func TestParseArithemticOperands(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1, err := ParseArithemticOperands(tt.args.arguments, tt.args.operator)
got, got1, err := parseArithemticOperands(tt.args.arguments, tt.args.operator)
if (err != nil) != tt.wantErr {
t.Errorf("ParseArithemticOperands() error = %v, wantErr %v", err, tt.wantErr)
return

View file

@ -773,7 +773,7 @@ func jpToBoolean(arguments []interface{}) (interface{}, error) {
}
func _jpAdd(arguments []interface{}, operator string) (interface{}, error) {
op1, op2, err := ParseArithemticOperands(arguments, operator)
op1, op2, err := parseArithemticOperands(arguments, operator)
if err != nil {
return nil, err
}
@ -804,7 +804,7 @@ func jpSum(arguments []interface{}) (interface{}, error) {
}
func jpSubtract(arguments []interface{}) (interface{}, error) {
op1, op2, err := ParseArithemticOperands(arguments, subtract)
op1, op2, err := parseArithemticOperands(arguments, subtract)
if err != nil {
return nil, err
}
@ -813,7 +813,7 @@ func jpSubtract(arguments []interface{}) (interface{}, error) {
}
func jpMultiply(arguments []interface{}) (interface{}, error) {
op1, op2, err := ParseArithemticOperands(arguments, multiply)
op1, op2, err := parseArithemticOperands(arguments, multiply)
if err != nil {
return nil, err
}
@ -822,7 +822,7 @@ func jpMultiply(arguments []interface{}) (interface{}, error) {
}
func jpDivide(arguments []interface{}) (interface{}, error) {
op1, op2, err := ParseArithemticOperands(arguments, divide)
op1, op2, err := parseArithemticOperands(arguments, divide)
if err != nil {
return nil, err
}
@ -831,7 +831,7 @@ func jpDivide(arguments []interface{}) (interface{}, error) {
}
func jpModulo(arguments []interface{}) (interface{}, error) {
op1, op2, err := ParseArithemticOperands(arguments, modulo)
op1, op2, err := parseArithemticOperands(arguments, modulo)
if err != nil {
return nil, err
}

View file

@ -30,7 +30,7 @@ func Test_Compare(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -57,7 +57,7 @@ func Test_ParseJsonSerde(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc, func(t *testing.T) {
jp, err := New(fmt.Sprintf(`to_string(parse_json('%s'))`, tc))
jp, err := newJMESPath(fmt.Sprintf(`to_string(parse_json('%s'))`, tc))
assert.NilError(t, err)
result, err := jp.Search("")
@ -88,7 +88,7 @@ func Test_ParseJsonComplex(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
jp, err := New(tc.input)
jp, err := newJMESPath(tc.input)
assert.NilError(t, err)
result, err := jp.Search("")
@ -165,7 +165,7 @@ bar: null
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
jp, err := New(fmt.Sprintf(`parse_yaml('%s')`, tc.input))
jp, err := newJMESPath(fmt.Sprintf(`parse_yaml('%s')`, tc.input))
assert.NilError(t, err)
result, err := jp.Search("")
assert.NilError(t, err)
@ -194,7 +194,7 @@ func Test_EqualFold(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -231,7 +231,7 @@ func Test_Replace(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -245,7 +245,7 @@ func Test_Replace(t *testing.T) {
}
func Test_ReplaceAll(t *testing.T) {
jp, err := New("replace_all('Lorem ipsum dolor sit amet', 'ipsum', 'muspi')")
jp, err := newJMESPath("replace_all('Lorem ipsum dolor sit amet', 'ipsum', 'muspi')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -276,7 +276,7 @@ func Test_ToUpper(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -309,7 +309,7 @@ func Test_ToLower(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -323,7 +323,7 @@ func Test_ToLower(t *testing.T) {
}
func Test_Trim(t *testing.T) {
jp, err := New("trim('¡¡¡Hello, Gophers!!!', '!¡')")
jp, err := newJMESPath("trim('¡¡¡Hello, Gophers!!!', '!¡')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -394,7 +394,7 @@ func Test_TrimPrefix(t *testing.T) {
}
func Test_Split(t *testing.T) {
jp, err := New("split('Hello, Gophers', ', ')")
jp, err := newJMESPath("split('Hello, Gophers', ', ')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -407,7 +407,7 @@ func Test_Split(t *testing.T) {
}
func Test_HasPrefix(t *testing.T) {
jp, err := New("starts_with('Gophers', 'Go')")
jp, err := newJMESPath("starts_with('Gophers', 'Go')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -419,7 +419,7 @@ func Test_HasPrefix(t *testing.T) {
}
func Test_HasSuffix(t *testing.T) {
jp, err := New("ends_with('Amigo', 'go')")
jp, err := newJMESPath("ends_with('Amigo', 'go')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -434,7 +434,7 @@ func Test_RegexMatch(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = "hgf'b1a2r'b12g"
query, err := New("regex_match('12.*', foo)")
query, err := newJMESPath("regex_match('12.*', foo)")
assert.NilError(t, err)
result, err := query.Search(data)
@ -446,7 +446,7 @@ func Test_RegexMatchWithNumber(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = -12.0
query, err := New("regex_match('12.*', abs(foo))")
query, err := newJMESPath("regex_match('12.*', abs(foo))")
assert.NilError(t, err)
result, err := query.Search(data)
@ -458,7 +458,7 @@ func Test_PatternMatch(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = "prefix-foo"
query, err := New("pattern_match('prefix-*', foo)")
query, err := newJMESPath("pattern_match('prefix-*', foo)")
assert.NilError(t, err)
result, err := query.Search(data)
@ -470,7 +470,7 @@ func Test_PatternMatchWithNumber(t *testing.T) {
data := make(map[string]interface{})
data["foo"] = -12.0
query, err := New("pattern_match('12*', abs(foo))")
query, err := newJMESPath("pattern_match('12*', abs(foo))")
assert.NilError(t, err)
result, err := query.Search(data)
@ -497,7 +497,7 @@ func Test_RegexReplaceAll(t *testing.T) {
var resource interface{}
err := json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
query, err := New(`regex_replace_all('([Hh]e|G)l', spec.field, '${2}G')`)
query, err := newJMESPath(`regex_replace_all('([Hh]e|G)l', spec.field, '${2}G')`)
assert.NilError(t, err)
res, err := query.Search(resource)
@ -528,7 +528,7 @@ func Test_RegexReplaceAllLiteral(t *testing.T) {
err := json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
query, err := New(`regex_replace_all_literal('[Hh]el?', spec.field, 'G')`)
query, err := newJMESPath(`regex_replace_all_literal('[Hh]el?', spec.field, 'G')`)
assert.NilError(t, err)
res, err := query.Search(resource)
@ -583,7 +583,7 @@ func Test_LabelMatch(t *testing.T) {
err := json.Unmarshal(tc.resource, &resource)
assert.NilError(t, err)
query, err := New("label_match(`" + tc.test + "`, metadata.labels)")
query, err := newJMESPath("label_match(`" + tc.test + "`, metadata.labels)")
assert.NilError(t, err)
res, err := query.Search(resource)
@ -627,7 +627,7 @@ func Test_JpToBoolean(t *testing.T) {
}
func Test_Base64Decode(t *testing.T) {
jp, err := New("base64_decode('SGVsbG8sIHdvcmxkIQ==')")
jp, err := newJMESPath("base64_decode('SGVsbG8sIHdvcmxkIQ==')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -639,7 +639,7 @@ func Test_Base64Decode(t *testing.T) {
}
func Test_Base64Encode(t *testing.T) {
jp, err := New("base64_encode('Hello, world!')")
jp, err := newJMESPath("base64_encode('Hello, world!')")
assert.NilError(t, err)
result, err := jp.Search("")
@ -669,7 +669,7 @@ func Test_Base64Decode_Secret(t *testing.T) {
err := json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
query, err := New(`base64_decode(data.example1)`)
query, err := newJMESPath(`base64_decode(data.example1)`)
assert.NilError(t, err)
res, err := query.Search(resource)
@ -744,7 +744,7 @@ func Test_PathCanonicalize(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -793,7 +793,7 @@ func Test_Truncate(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -830,7 +830,7 @@ func Test_SemverCompare(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")
@ -877,7 +877,7 @@ func Test_Items(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New("items(`" + tc.object + "`,`" + tc.keyName + "`,`" + tc.valName + "`)")
query, err := newJMESPath("items(`" + tc.object + "`,`" + tc.keyName + "`,`" + tc.valName + "`)")
assert.NilError(t, err)
res, err := query.Search("")
@ -928,7 +928,7 @@ func Test_ObjectFromLists(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New("object_from_lists(`" + tc.keys + "`,`" + tc.values + "`)")
query, err := newJMESPath("object_from_lists(`" + tc.keys + "`,`" + tc.values + "`)")
assert.NilError(t, err)
res, err := query.Search("")
assert.NilError(t, err)
@ -1022,7 +1022,7 @@ UFOZZVoELaasWS559wy8og39Eq21dDMynb8Bndn/
}}
for _, tc := range testCases {
t.Run(tc.jmesPath, func(t *testing.T) {
jp, err := New(tc.jmesPath)
jp, err := newJMESPath(tc.jmesPath)
assert.NilError(t, err)
result, err := jp.Search("")

View file

@ -0,0 +1,34 @@
package jmespath
import "github.com/kyverno/kyverno/pkg/config"
type Query interface {
Search(interface{}) (interface{}, error)
}
type Interface interface {
Query(string) (Query, error)
Search(string, interface{}) (interface{}, error)
}
type implementation struct {
configuration config.Configuration
}
func New(configuration config.Configuration) Interface {
return implementation{
configuration: configuration,
}
}
func (i implementation) Query(query string) (Query, error) {
return newJMESPath(query)
}
func (i implementation) Search(query string, data interface{}) (interface{}, error) {
if query, err := i.Query(query); err != nil {
return nil, err
} else {
return query.Search(data)
}
}

View file

@ -4,7 +4,7 @@ import (
gojmespath "github.com/jmespath/go-jmespath"
)
func New(query string) (*gojmespath.JMESPath, error) {
func newJMESPath(query string) (*gojmespath.JMESPath, error) {
jp, err := gojmespath.Compile(query)
if err != nil {
return nil, err

View file

@ -25,7 +25,7 @@ func TestNew(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := New(tt.args.query)
_, err := newJMESPath(tt.args.query)
if (err != nil) != tt.wantErr {
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
return

View file

@ -25,7 +25,7 @@ func Test_TimeSince(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")
@ -55,7 +55,7 @@ func Test_TimeToCron(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")
@ -85,7 +85,7 @@ func Test_TimeAdd(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")
@ -115,7 +115,7 @@ func Test_TimeParse(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")
@ -145,7 +145,7 @@ func Test_TimeUtc(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")
@ -171,7 +171,7 @@ func Test_TimeDiff(t *testing.T) {
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
query, err := New(tc.test)
query, err := newJMESPath(tc.test)
assert.NilError(t, err)
res, err := query.Search("")

View file

@ -6,8 +6,10 @@ import (
"github.com/go-logr/logr"
types "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/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"gotest.tools/assert"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@ -47,7 +49,7 @@ const endpointsDocument string = `{
}`
func applyPatches(rule *types.Rule, resource unstructured.Unstructured) (*engineapi.RuleResponse, unstructured.Unstructured) {
mutateResp := Mutate(rule, context.NewContext(), resource, logr.Discard())
mutateResp := Mutate(rule, context.NewContext(jmespath.New(config.NewDefaultConfiguration(false))), resource, logr.Discard())
if mutateResp.Status != engineapi.RuleStatusPass {
return engineapi.NewRuleResponse("", engineapi.Mutation, mutateResp.Message, mutateResp.Status), resource
}

View file

@ -34,6 +34,7 @@ func testMutate(
e := NewEngine(
cfg,
config.NewDefaultMetricsConfiguration(),
jp,
client,
rclient,
contextLoader,
@ -104,7 +105,7 @@ func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
}
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -185,7 +186,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -262,7 +263,7 @@ func Test_variableSubstitutionCLI(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -382,7 +383,7 @@ func Test_chained_rules(t *testing.T) {
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
assert.NilError(t, err)
@ -470,7 +471,7 @@ func Test_precondition(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -564,7 +565,7 @@ func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -650,7 +651,7 @@ func Test_foreach(t *testing.T) {
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
assert.NilError(t, err)
@ -752,7 +753,7 @@ func Test_foreach_element_mutation(t *testing.T) {
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
assert.NilError(t, err)
@ -873,7 +874,7 @@ func Test_Container_InitContainer_foreach(t *testing.T) {
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
assert.NilError(t, err)
@ -1018,7 +1019,7 @@ func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) engi
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
assert.NilError(t, err)
@ -1556,7 +1557,7 @@ func Test_mutate_existing_resources(t *testing.T) {
target, err := kubeutils.BytesToUnstructured(target)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(trigger.Object)
assert.NilError(t, err)
@ -1671,7 +1672,7 @@ func Test_RuleSelectorMutate(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -2052,7 +2053,7 @@ func Test_SpecialCharacters(t *testing.T) {
}
// Create JSON context and add the resource.
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddResource(resource.Object)
if err != nil {
t.Fatalf("ctx.AddResource() error = %v", err)

View file

@ -8,6 +8,7 @@ import (
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -184,17 +185,18 @@ func NewPolicyContextWithJsonContext(operation kyvernov1.AdmissionOperation, jso
}
}
func NewPolicyContext(operation kyvernov1.AdmissionOperation) *PolicyContext {
return NewPolicyContextWithJsonContext(operation, enginectx.NewContext())
func NewPolicyContext(jp jmespath.Interface, operation kyvernov1.AdmissionOperation) *PolicyContext {
return NewPolicyContextWithJsonContext(operation, enginectx.NewContext(jp))
}
func NewPolicyContextFromAdmissionRequest(
jp jmespath.Interface,
request admissionv1.AdmissionRequest,
admissionInfo kyvernov1beta1.RequestInfo,
gvk schema.GroupVersionKind,
configuration config.Configuration,
) (*PolicyContext, error) {
ctx, err := newVariablesContext(request, &admissionInfo)
ctx, err := newVariablesContext(jp, request, &admissionInfo)
if err != nil {
return nil, fmt.Errorf("failed to create policy rule context: %w", err)
}
@ -215,8 +217,12 @@ func NewPolicyContextFromAdmissionRequest(
return policyContext, nil
}
func newVariablesContext(request admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
ctx := enginectx.NewContext()
func newVariablesContext(
jp jmespath.Interface,
request admissionv1.AdmissionRequest,
userRequestInfo *kyvernov1beta1.RequestInfo,
) (enginectx.Interface, error) {
ctx := enginectx.NewContext(jp)
if err := ctx.AddRequest(request); err != nil {
return nil, fmt.Errorf("failed to load incoming request in context: %w", err)
}

View file

@ -8,6 +8,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
)
@ -44,6 +45,7 @@ type mockContextLoader struct {
func (l *mockContextLoader) Load(
ctx context.Context,
jp jmespath.Interface,
client dclient.Interface,
rclient registryclient.Client,
contextEntries []kyvernov1.ContextEntry,
@ -63,15 +65,15 @@ func (l *mockContextLoader) Load(
// Context Variable should be loaded after the values loaded from values file
for _, entry := range contextEntries {
if entry.ImageRegistry != nil && rclient != nil {
if err := engineapi.LoadImageData(ctx, rclient, l.logger, entry, jsonContext); err != nil {
if err := engineapi.LoadImageData(ctx, jp, rclient, l.logger, entry, jsonContext); err != nil {
return err
}
} else if entry.Variable != nil {
if err := engineapi.LoadVariable(l.logger, entry, jsonContext); err != nil {
if err := engineapi.LoadVariable(l.logger, jp, entry, jsonContext); err != nil {
return err
}
} else if entry.APICall != nil && l.allowApiCall {
if err := engineapi.LoadAPIData(ctx, l.logger, entry, jsonContext, client); err != nil {
if err := engineapi.LoadAPIData(ctx, jp, l.logger, entry, jsonContext, client); err != nil {
return err
}
}

View file

@ -32,6 +32,7 @@ func testValidate(
e := NewEngine(
cfg,
config.NewDefaultMetricsConfiguration(),
jp,
nil,
rclient,
contextLoader,
@ -136,7 +137,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 := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message(), msgs[index])
}
@ -236,7 +237,7 @@ func TestValidate_image_tag_pass(t *testing.T) {
"validation rule 'validate-tag' passed.",
"validation rule 'validate-latest' passed.",
}
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message(), msgs[index])
}
@ -310,7 +311,7 @@ func TestValidate_Fail_anyPattern(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
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/"}
@ -393,7 +394,7 @@ func TestValidate_host_network_port(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
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 {
@ -483,7 +484,7 @@ func TestValidate_anchor_arraymap_pass(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -571,7 +572,7 @@ func TestValidate_anchor_arraymap_fail(t *testing.T) {
assert.NilError(t, err)
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
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 {
@ -641,7 +642,7 @@ func TestValidate_anchor_map_notfound(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -714,7 +715,7 @@ func TestValidate_anchor_map_found_valid(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -788,7 +789,7 @@ func TestValidate_inequality_List_Processing(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -868,7 +869,7 @@ func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -942,7 +943,7 @@ func TestValidate_anchor_map_found_invalid(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
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 {
@ -1017,7 +1018,7 @@ func TestValidate_AnchorList_pass(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1092,7 +1093,7 @@ func TestValidate_AnchorList_fail(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
assert.Assert(t, !er.IsSuccessful())
}
@ -1162,7 +1163,7 @@ func TestValidate_existenceAnchor_fail(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
assert.Assert(t, !er.IsSuccessful())
}
@ -1232,7 +1233,7 @@ func TestValidate_existenceAnchor_pass(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'pod image rule' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1320,7 +1321,7 @@ func TestValidate_negationAnchor_deny(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
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 {
@ -1407,7 +1408,7 @@ func TestValidate_negationAnchor_pass(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
msgs := []string{"validation rule 'validate-host-path' passed."}
for index, r := range er.PolicyResponse.Rules {
@ -1475,7 +1476,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1565,7 +1566,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSu
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1623,7 +1624,7 @@ func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1711,7 +1712,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1801,7 +1802,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1903,7 +1904,7 @@ func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -1953,7 +1954,7 @@ func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(test.resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, test.resourceRaw)
assert.NilError(t, err)
@ -2095,7 +2096,7 @@ func executeTest(t *testing.T, test testCase) {
t.Fatal(err)
}
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = ctx.AddRequest(request)
if err != nil {
t.Fatal(err)
@ -2205,7 +2206,7 @@ func TestValidate_context_variable_substitution_CLI(t *testing.T) {
er := testValidate(
context.TODO(),
registryclient.NewOrDie(),
NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured),
NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured),
cfg,
enginetest.ContextLoaderFactory(
nil,
@ -2303,7 +2304,7 @@ func Test_EmptyStringInDenyCondition(t *testing.T) {
err := json.Unmarshal(policyRaw, &policy)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -2396,7 +2397,7 @@ func Test_StringInDenyCondition(t *testing.T) {
err := json.Unmarshal(policyRaw, &policy)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -3079,7 +3080,7 @@ func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string,
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -3141,7 +3142,7 @@ func Test_delete_ignore_pattern(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := enginecontext.NewContext()
ctx := enginecontext.NewContext(jp)
err = enginecontext.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -3216,7 +3217,7 @@ func Test_ValidatePattern_anyPattern(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
assert.NilError(t, err)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext()).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
er := testValidate(context.TODO(), registryclient.NewOrDie(), NewPolicyContextWithJsonContext(kyverno.Create, enginecontext.NewContext(jp)).WithPolicy(&policy).WithNewResource(*resourceUnstructured), cfg, nil)
if tc.expectedFailed {
assert.Assert(t, er.IsFailed())
} else if tc.expectedSkipped {

View file

@ -6,7 +6,9 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/stretchr/testify/assert"
)
@ -376,7 +378,7 @@ func TestEvaluate(t *testing.T) {
{kyverno.Condition{RawKey: kyverno.ToJSON([]interface{}{1, 5, 7}), Operator: kyverno.ConditionOperators["AnyNotIn"], RawValue: kyverno.ToJSON("0-10")}, false},
}
ctx := context.NewContext()
ctx := context.NewContext(jmespath.New(config.NewDefaultConfiguration(false)))
for _, tc := range testCases {
if Evaluate(logr.Discard(), ctx, tc.Condition) != tc.Result {
t.Errorf("%v - expected result to be %v", tc.Condition, tc.Result)
@ -401,7 +403,7 @@ func Test_Eval_Equal_Var_Pass(t *testing.T) {
`)
// context
ctx := context.NewContext()
ctx := context.NewContext(jmespath.New(config.NewDefaultConfiguration(false)))
err := context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -443,7 +445,7 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) {
`)
// context
ctx := context.NewContext()
ctx := context.NewContext(jmespath.New(config.NewDefaultConfiguration(false)))
err := context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)

View file

@ -7,11 +7,15 @@ import (
"github.com/go-logr/logr"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"gotest.tools/assert"
authenticationv1 "k8s.io/api/authentication/v1"
)
var jp = jmespath.New(config.NewDefaultConfiguration(false))
func Test_variablesub1(t *testing.T) {
patternMap := []byte(`
{
@ -74,7 +78,7 @@ func Test_variablesub1(t *testing.T) {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -164,7 +168,7 @@ func Test_variablesub_multiple(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -252,7 +256,7 @@ func Test_variablesubstitution(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -317,7 +321,7 @@ func Test_variableSubstitutionValue(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -374,7 +378,7 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -432,7 +436,7 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -489,7 +493,7 @@ func Test_variableSubstitutionObject(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -553,7 +557,7 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -628,7 +632,7 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)

View file

@ -64,7 +64,7 @@ func Test_subVars_success(t *testing.T) {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -125,7 +125,7 @@ func Test_subVars_failed(t *testing.T) {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
if err != nil {
t.Error(err)
@ -219,7 +219,7 @@ func Test_subVars_with_JMESPath_At(t *testing.T) {
err = json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -278,7 +278,7 @@ func Test_subVars_withRegexMatch(t *testing.T) {
err = json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -308,7 +308,7 @@ func Test_subVars_withMerge(t *testing.T) {
err = json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -351,7 +351,7 @@ func Test_subVars_withRegexReplaceAll(t *testing.T) {
err = json.Unmarshal(resourceRaw, &resource)
assert.NilError(t, err)
// context
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
@ -396,7 +396,7 @@ func Test_ReplacingPathWhenDeleting(t *testing.T) {
if err != nil {
t.Error(err)
}
ctx := context.NewContextFromRaw(resourceRaw)
ctx := context.NewContextFromRaw(jp, resourceRaw)
assert.NilError(t, err)
pattern, err = SubstituteAll(logr.Discard(), ctx, pattern)
@ -431,7 +431,7 @@ func Test_ReplacingNestedVariableWhenDeleting(t *testing.T) {
if err != nil {
t.Error(err)
}
ctx := context.NewContextFromRaw(resourceRaw)
ctx := context.NewContextFromRaw(jp, resourceRaw)
assert.NilError(t, err)
pattern, err = SubstituteAll(logr.Discard(), ctx, pattern)
@ -457,7 +457,7 @@ var resourceRaw = []byte(`
`)
func Test_SubstituteSuccess(t *testing.T) {
ctx := context.NewContext()
ctx := context.NewContext(jp)
assert.Assert(t, context.AddResource(ctx, resourceRaw))
var pattern interface{}
@ -481,7 +481,7 @@ func Test_SubstituteSuccess(t *testing.T) {
}
func Test_SubstituteRecursiveErrors(t *testing.T) {
ctx := context.NewContext()
ctx := context.NewContext(jp)
assert.Assert(t, context.AddResource(ctx, resourceRaw))
var pattern interface{}
@ -515,7 +515,7 @@ func Test_SubstituteRecursiveErrors(t *testing.T) {
}
func Test_SubstituteRecursive(t *testing.T) {
ctx := context.NewContext()
ctx := context.NewContext(jp)
assert.Assert(t, context.AddResource(ctx, resourceRaw))
var pattern interface{}
@ -633,7 +633,7 @@ func Test_variableSubstitution_array(t *testing.T) {
err := json.Unmarshal(ruleRaw, &rule)
assert.NilError(t, err)
ctx := context.NewContextFromRaw(configmapRaw)
ctx := context.NewContextFromRaw(jp, configmapRaw)
context.AddResource(ctx, resourceRaw)
vars, err := SubstituteAllInRule(logr.Discard(), ctx, rule)
@ -679,7 +679,7 @@ func Test_SubstituteNull(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -708,7 +708,7 @@ func Test_SubstituteNullInString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -737,7 +737,7 @@ func Test_SubstituteArray(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -766,7 +766,7 @@ func Test_SubstituteArrayInString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -795,7 +795,7 @@ func Test_SubstituteInt(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -824,7 +824,7 @@ func Test_SubstituteIntInString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -853,7 +853,7 @@ func Test_SubstituteBool(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -882,7 +882,7 @@ func Test_SubstituteBoolInString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -911,7 +911,7 @@ func Test_SubstituteString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -940,7 +940,7 @@ func Test_SubstituteStringInString(t *testing.T) {
err = json.Unmarshal(variableObject, &resource)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
context.AddResource(ctx, variableObject)
resolved, err := SubstituteAll(logr.Discard(), ctx, pattern)
@ -991,7 +991,7 @@ func Test_ReferenceSubstitution(t *testing.T) {
err = json.Unmarshal(expectedJSON, &expectedDocument)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, jsonRaw)
assert.NilError(t, err)
@ -1135,7 +1135,7 @@ func Test_EscpReferenceSubstitution(t *testing.T) {
err = json.Unmarshal(expectedJSON, &expectedDocument)
assert.NilError(t, err)
ctx := context.NewContext()
ctx := context.NewContext(jp)
err = context.AddResource(ctx, jsonRaw)
assert.NilError(t, err)
@ -1171,7 +1171,7 @@ func Test_ReplacingEscpNestedVariableWhenDeleting(t *testing.T) {
if err != nil {
t.Error(err)
}
ctx := context.NewContextFromRaw(resourceRaw)
ctx := context.NewContextFromRaw(jp, resourceRaw)
assert.NilError(t, err)
pattern, err = SubstituteAll(logr.Discard(), ctx, pattern)

View file

@ -14,7 +14,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (pc *PolicyController) handleGenerate(policyKey string, policy kyvernov1.PolicyInterface) error {
func (pc *policyController) handleGenerate(policyKey string, policy kyvernov1.PolicyInterface) error {
logger := pc.log.WithName("handleGenerate").WithName(policyKey)
logger.Info("update URs on policy event")
@ -41,7 +41,7 @@ func (pc *PolicyController) handleGenerate(policyKey string, policy kyvernov1.Po
return nil
}
func (pc *PolicyController) handleGenerateForExisting(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) error {
func (pc *policyController) handleGenerateForExisting(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) error {
var errors []error
ruleType := kyvernov1beta1.Generate
triggers := generateTriggers(pc.client, rule, pc.log)
@ -65,7 +65,7 @@ func (pc *PolicyController) handleGenerateForExisting(policy kyvernov1.PolicyInt
return multierr.Combine(errors...)
}
func (pc *PolicyController) createURForDownstreamDeletion(policy kyvernov1.PolicyInterface) error {
func (pc *policyController) createURForDownstreamDeletion(policy kyvernov1.PolicyInterface) error {
var errs []error
rules := autogen.ComputeRules(policy)
for _, r := range rules {
@ -79,7 +79,7 @@ func (pc *PolicyController) createURForDownstreamDeletion(policy kyvernov1.Polic
return multierr.Combine(errs...)
}
func (pc *PolicyController) createURForDataRule(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, deleteDownstream bool) (bool, error) {
func (pc *policyController) createURForDataRule(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, deleteDownstream bool) (bool, error) {
downstreamExist := false
generate := rule.Generation
if !generate.Synchronize {

View file

@ -10,7 +10,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
)
func (pc *PolicyController) handleMutate(policyKey string, policy kyvernov1.PolicyInterface) error {
func (pc *policyController) handleMutate(policyKey string, policy kyvernov1.PolicyInterface) error {
logger := pc.log.WithName("handleMutate").WithName(policyKey)
if !policy.GetSpec().MutateExistingOnPolicyUpdate {
logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate)
@ -49,7 +49,7 @@ func (pc *PolicyController) handleMutate(policyKey string, policy kyvernov1.Poli
return nil
}
func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
func (pc *policyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(backgroundcommon.MutateLabelsSet(policyKey, trigger)))
if err != nil {
pc.log.Error(err, "failed to list update request for mutate policy")

View file

@ -18,6 +18,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
datautils "github.com/kyverno/kyverno/pkg/utils/data"
@ -47,9 +48,9 @@ const (
maxRetries = 15
)
// PolicyController is responsible for synchronizing Policy objects stored
// policyController is responsible for synchronizing Policy objects stored
// in the system with the corresponding policy violations
type PolicyController struct {
type policyController struct {
client dclient.Interface
kyvernoClient versioned.Interface
engine engineapi.Engine
@ -78,13 +79,15 @@ type PolicyController struct {
informersSynced []cache.InformerSynced
// helpers to validate against current loaded configuration
configHandler config.Configuration
configuration config.Configuration
reconcilePeriod time.Duration
log logr.Logger
metricsConfig metrics.MetricsConfigManager
jp jmespath.Interface
}
// NewPolicyController create a new PolicyController
@ -95,20 +98,21 @@ func NewPolicyController(
pInformer kyvernov1informers.ClusterPolicyInformer,
npInformer kyvernov1informers.PolicyInformer,
urInformer kyvernov1beta1informers.UpdateRequestInformer,
configHandler config.Configuration,
configuration config.Configuration,
eventGen event.Interface,
namespaces corev1informers.NamespaceInformer,
log logr.Logger,
reconcilePeriod time.Duration,
metricsConfig metrics.MetricsConfigManager,
) (*PolicyController, error) {
jp jmespath.Interface,
) (*policyController, error) {
// Event broad caster
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(log.V(5).Info)
eventInterface := client.GetEventsInterface()
eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: eventInterface})
pc := PolicyController{
pc := policyController{
client: client,
kyvernoClient: kyvernoClient,
engine: engine,
@ -117,10 +121,11 @@ func NewPolicyController(
eventGen: eventGen,
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: "policy_controller"}),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"),
configHandler: configHandler,
configuration: configuration,
reconcilePeriod: reconcilePeriod,
metricsConfig: metricsConfig,
log: log,
jp: jp,
}
pc.pLister = pInformer.Lister()
@ -133,7 +138,7 @@ func NewPolicyController(
return &pc, nil
}
func (pc *PolicyController) canBackgroundProcess(p kyvernov1.PolicyInterface) bool {
func (pc *policyController) canBackgroundProcess(p kyvernov1.PolicyInterface) bool {
logger := pc.log.WithValues("policy", p.GetName())
if !p.BackgroundProcessingEnabled() {
if !p.GetSpec().HasGenerate() && !p.GetSpec().IsMutateExisting() {
@ -150,7 +155,7 @@ func (pc *PolicyController) canBackgroundProcess(p kyvernov1.PolicyInterface) bo
return true
}
func (pc *PolicyController) addPolicy(obj interface{}) {
func (pc *policyController) addPolicy(obj interface{}) {
logger := pc.log
var p kyvernov1.PolicyInterface
@ -173,7 +178,7 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
pc.enqueuePolicy(p)
}
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
func (pc *policyController) updatePolicy(old, cur interface{}) {
logger := pc.log
var oldP, curP kyvernov1.PolicyInterface
@ -214,7 +219,7 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
pc.enqueuePolicy(curP)
}
func (pc *PolicyController) deletePolicy(obj interface{}) {
func (pc *policyController) deletePolicy(obj interface{}) {
logger := pc.log
var p kyvernov1.PolicyInterface
@ -235,7 +240,7 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
}
}
func (pc *PolicyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
func (pc *policyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
logger := pc.log
key, err := cache.MetaNamespaceKeyFunc(policy)
if err != nil {
@ -246,7 +251,7 @@ func (pc *PolicyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
}
// Run begins watching and syncing.
func (pc *PolicyController) Run(ctx context.Context, workers int) {
func (pc *policyController) Run(ctx context.Context, workers int) {
logger := pc.log
defer utilruntime.HandleCrash()
@ -282,12 +287,12 @@ func (pc *PolicyController) Run(ctx context.Context, workers int) {
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
// It enforces that the syncHandler is never invoked concurrently with the same key.
func (pc *PolicyController) worker(ctx context.Context) {
func (pc *policyController) worker(ctx context.Context) {
for pc.processNextWorkItem() {
}
}
func (pc *PolicyController) processNextWorkItem() bool {
func (pc *policyController) processNextWorkItem() bool {
key, quit := pc.queue.Get()
if quit {
return false
@ -299,7 +304,7 @@ func (pc *PolicyController) processNextWorkItem() bool {
return true
}
func (pc *PolicyController) handleErr(err error, key interface{}) {
func (pc *policyController) handleErr(err error, key interface{}) {
logger := pc.log
if err == nil {
pc.queue.Forget(key)
@ -317,7 +322,7 @@ func (pc *PolicyController) handleErr(err error, key interface{}) {
pc.queue.Forget(key)
}
func (pc *PolicyController) syncPolicy(key string) error {
func (pc *policyController) syncPolicy(key string) error {
logger := pc.log.WithName("syncPolicy")
startTime := time.Now()
logger.V(4).Info("started syncing policy", "key", key, "startTime", startTime)
@ -345,7 +350,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
return nil
}
func (pc *PolicyController) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
func (pc *policyController) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
if ns, name, err := cache.SplitMetaNamespaceKey(key); err != nil {
pc.log.Error(err, "failed to parse policy name", "policyName", key)
return nil, err
@ -359,7 +364,7 @@ func (pc *PolicyController) getPolicy(key string) (kyvernov1.PolicyInterface, er
}
// forceReconciliation forces a background scan by adding all policies to the workqueue
func (pc *PolicyController) forceReconciliation(ctx context.Context) {
func (pc *policyController) forceReconciliation(ctx context.Context) {
logger := pc.log.WithName("forceReconciliation")
ticker := time.NewTicker(pc.reconcilePeriod)
@ -375,7 +380,7 @@ func (pc *PolicyController) forceReconciliation(ctx context.Context) {
}
}
func (pc *PolicyController) requeuePolicies() {
func (pc *policyController) requeuePolicies() {
logger := pc.log.WithName("requeuePolicies")
if cpols, err := pc.pLister.List(labels.Everything()); err == nil {
for _, cpol := range cpols {
@ -399,9 +404,9 @@ func (pc *PolicyController) requeuePolicies() {
}
}
func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyvernov1.Rule, policy kyvernov1.PolicyInterface) (skip bool, err error) {
func (pc *policyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyvernov1.Rule, policy kyvernov1.PolicyInterface) (skip bool, err error) {
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(triggerResource.GetKind(), triggerResource.GetNamespace(), pc.nsLister, pc.log)
policyContext, err := backgroundcommon.NewBackgroundContext(pc.client, ur, policy, triggerResource, pc.configHandler, namespaceLabels, pc.log)
policyContext, err := backgroundcommon.NewBackgroundContext(pc.log, pc.client, ur, policy, triggerResource, pc.configuration, pc.jp, namespaceLabels)
if err != nil {
return false, fmt.Errorf("failed to build policy context for rule %s: %w", rule.Name, err)
}

View file

@ -51,7 +51,16 @@ func (i *imageExtractor) ExtractFromResource(resource interface{}, cfg config.Co
return imageInfo, nil
}
func extract(obj interface{}, path []string, keyPath, valuePath string, fields []string, jmesPath string, imageInfos *map[string]ImageInfo, cfg config.Configuration) error {
func extract(
obj interface{},
path []string,
keyPath string,
valuePath string,
fields []string,
jmesPath string,
imageInfos *map[string]ImageInfo,
cfg config.Configuration,
) error {
if obj == nil {
return nil
}
@ -94,11 +103,13 @@ func extract(obj interface{}, path []string, keyPath, valuePath string, fields [
return nil
}
if jmesPath != "" {
jp, err := jmespath.New(jmesPath)
// TODO: should be injected
jp := jmespath.New(cfg)
q, err := jp.Query(jmesPath)
if err != nil {
return fmt.Errorf("invalid jmespath %s: %v", jmesPath, err)
}
result, err := jp.Search(value)
result, err := q.Search(value)
if err != nil {
return fmt.Errorf("failed to apply jmespath %s: %v", jmesPath, err)
}
@ -171,12 +182,10 @@ func lookupImageExtractor(kind string, configs kyvernov1.ImageExtractorConfigs)
func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyvernov1.ImageExtractorConfigs, cfg config.Configuration) (map[string]map[string]ImageInfo, error) {
infos := map[string]map[string]ImageInfo{}
extractors := lookupImageExtractor(resource.GetKind(), configs)
if extractors != nil && len(extractors) == 0 {
return nil, fmt.Errorf("no extractors found for %s", resource.GetKind())
}
for _, extractor := range extractors {
if infoMap, err := extractor.ExtractFromResource(resource.Object, cfg); err != nil {
return nil, err
@ -184,6 +193,5 @@ func ExtractImagesFromResource(resource unstructured.Unstructured, configs kyver
infos[extractor.Name] = infoMap
}
}
return infos, nil
}

View file

@ -10,6 +10,7 @@ import (
"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/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/openapi"
@ -39,6 +40,7 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
urLister := kyvernoInformers.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace())
peLister := kyvernoInformers.Kyverno().V2alpha1().PolicyExceptions().Lister()
rclient := registryclient.NewOrDie()
jp := jmespath.New(configuration)
return &resourceHandlers{
client: dclient,
@ -51,10 +53,11 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
urGenerator: updaterequest.NewFake(),
eventGen: event.NewFake(),
openApiManager: openapi.NewFake(),
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration),
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, jp),
engine: engine.NewEngine(
configuration,
config.NewDefaultMetricsConfiguration(),
jp,
dclient,
rclient,
engineapi.DefaultContextLoaderFactory(configMapResolver),

View file

@ -14,6 +14,7 @@ import (
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/openapi"
@ -31,7 +32,6 @@ import (
webhookutils "github.com/kyverno/kyverno/pkg/webhooks/utils"
"k8s.io/apimachinery/pkg/runtime/schema"
corev1listers "k8s.io/client-go/listers/core/v1"
rbacv1listers "k8s.io/client-go/listers/rbac/v1"
)
type resourceHandlers struct {
@ -72,8 +72,6 @@ func NewHandlers(
metricsConfig metrics.MetricsConfigManager,
pCache policycache.Cache,
nsLister corev1listers.NamespaceLister,
rbLister rbacv1listers.RoleBindingLister,
crbLister rbacv1listers.ClusterRoleBindingLister,
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
cpolInformer kyvernov1informers.ClusterPolicyInformer,
polInformer kyvernov1informers.PolicyInformer,
@ -82,6 +80,7 @@ func NewHandlers(
openApiManager openapi.ValidateInterface,
admissionReports bool,
backgroungServiceAccountName string,
jp jmespath.Interface,
) webhooks.ResourceHandlers {
return &resourceHandlers{
engine: engine,
@ -98,7 +97,7 @@ func NewHandlers(
urGenerator: urGenerator,
eventGen: eventGen,
openApiManager: openApiManager,
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration),
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, jp),
admissionReports: admissionReports,
backgroungServiceAccountName: backgroungServiceAccountName,
}

View file

@ -10,6 +10,7 @@ import (
"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/engine/jmespath"
log "github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
@ -1048,10 +1049,12 @@ func TestValidate_failure_action_overrides(t *testing.T) {
},
},
}
cfg := config.NewDefaultConfiguration(false)
jp := jmespath.New(cfg)
eng := engine.NewEngine(
config.NewDefaultConfiguration(false),
cfg,
config.NewDefaultMetricsConfiguration(),
jp,
nil,
registryclient.NewOrDie(),
engineapi.DefaultContextLoaderFactory(nil),
@ -1065,7 +1068,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
assert.NilError(t, err)
ctx := engine.NewPolicyContext(kyvernov1.Create).WithPolicy(&policy).WithNewResource(*resourceUnstructured).WithNamespaceLabels(tc.rawResourceNamespaceLabels)
ctx := engine.NewPolicyContext(jp, kyvernov1.Create).WithPolicy(&policy).WithNewResource(*resourceUnstructured).WithNamespaceLabels(tc.rawResourceNamespaceLabels)
er := eng.Validate(
context.TODO(),
ctx,
@ -1127,11 +1130,14 @@ func Test_RuleSelector(t *testing.T) {
assert.NilError(t, err)
assert.Assert(t, resourceUnstructured != nil)
ctx := engine.NewPolicyContext(kyvernov1.Create).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
cfg := config.NewDefaultConfiguration(false)
jp := jmespath.New(cfg)
ctx := engine.NewPolicyContext(jp, kyvernov1.Create).WithPolicy(&policy).WithNewResource(*resourceUnstructured)
eng := engine.NewEngine(
config.NewDefaultConfiguration(false),
cfg,
config.NewDefaultMetricsConfiguration(),
jp,
nil,
registryclient.NewOrDie(),
engineapi.DefaultContextLoaderFactory(nil),

View file

@ -4,6 +4,7 @@ import (
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
admissionv1 "k8s.io/api/admission/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@ -14,13 +15,16 @@ type PolicyContextBuilder interface {
type policyContextBuilder struct {
configuration config.Configuration
jp jmespath.Interface
}
func NewPolicyContextBuilder(
configuration config.Configuration,
jp jmespath.Interface,
) PolicyContextBuilder {
return &policyContextBuilder{
configuration: configuration,
jp: jp,
}
}
@ -30,5 +34,5 @@ func (b *policyContextBuilder) Build(request admissionv1.AdmissionRequest, roles
Roles: roles,
ClusterRoles: clusterRoles,
}
return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, gvk, b.configuration)
return engine.NewPolicyContextFromAdmissionRequest(b.jp, request, userRequestInfo, gvk, b.configuration)
}