1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00

feat: add support for more context elements (#11986)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2025-01-24 09:37:33 +01:00 committed by GitHub
parent 02c54490bc
commit ed80be3eff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 121 additions and 1 deletions

View file

@ -26,3 +26,33 @@ func (c *impl) get_configmap_string_string(args ...ref.Val) ref.Val {
return c.NativeToValue(cm.UnstructuredContent())
}
}
func (c *impl) get_globalreference_string(ctx ref.Val, name ref.Val) ref.Val {
if self, err := utils.ConvertToNative[Context](ctx); err != nil {
return types.WrapErr(err)
} else if name, err := utils.ConvertToNative[string](name); err != nil {
return types.WrapErr(err)
} else {
globalRef, err := self.GetGlobalReference(name)
if err != nil {
// Errors are not expected here since Parse is a more lenient parser than ParseRequestURI.
return types.NewErr("failed to get global reference: %v", err)
}
return c.NativeToValue(globalRef)
}
}
func (c *impl) get_imagedata_string(ctx ref.Val, image ref.Val) ref.Val {
if self, err := utils.ConvertToNative[Context](ctx); err != nil {
return types.WrapErr(err)
} else if image, err := utils.ConvertToNative[string](image); err != nil {
return types.WrapErr(err)
} else {
globalRef, err := self.GetImageData(image)
if err != nil {
// Errors are not expected here since Parse is a more lenient parser than ParseRequestURI.
return types.NewErr("failed to get image data: %v", err)
}
return c.NativeToValue(globalRef)
}
}

View file

@ -9,13 +9,23 @@ import (
)
type ctx struct {
GetConfigMapFunc func(string, string) (unstructured.Unstructured, error)
GetConfigMapFunc func(string, string) (unstructured.Unstructured, error)
GetGlobalReferenceFunc func(string) (any, error)
GetImageDataFunc func(string) (any, error)
}
func (mock *ctx) GetConfigMap(ns string, n string) (unstructured.Unstructured, error) {
return mock.GetConfigMapFunc(ns, n)
}
func (mock *ctx) GetGlobalReference(n string) (any, error) {
return mock.GetGlobalReferenceFunc(n)
}
func (mock *ctx) GetImageData(n string) (any, error) {
return mock.GetImageDataFunc(n)
}
func Test_impl_get_configmap_string_string(t *testing.T) {
opts := Lib()
base, err := cel.NewEnv(opts)
@ -47,3 +57,73 @@ func Test_impl_get_configmap_string_string(t *testing.T) {
assert.NotNil(t, out)
assert.True(t, called)
}
func Test_impl_get_globalreference_string(t *testing.T) {
opts := Lib()
base, err := cel.NewEnv(opts)
assert.NoError(t, err)
assert.NotNil(t, base)
options := []cel.EnvOption{
cel.Variable("context", ContextType),
}
env, err := base.Extend(options...)
assert.NoError(t, err)
assert.NotNil(t, env)
ast, issues := env.Compile(`context.GetGlobalReference("foo")`)
assert.Nil(t, issues)
assert.NotNil(t, ast)
prog, err := env.Program(ast)
assert.NoError(t, err)
assert.NotNil(t, prog)
called := false
data := map[string]any{
"context": Context{&ctx{
GetGlobalReferenceFunc: func(string) (any, error) {
type foo struct {
s string
}
called = true
return foo{"bar"}, nil
},
}},
}
out, _, err := prog.Eval(data)
assert.NoError(t, err)
assert.NotNil(t, out)
assert.True(t, called)
}
func Test_impl_get_imagedata_string(t *testing.T) {
opts := Lib()
base, err := cel.NewEnv(opts)
assert.NoError(t, err)
assert.NotNil(t, base)
options := []cel.EnvOption{
cel.Variable("context", ContextType),
}
env, err := base.Extend(options...)
assert.NoError(t, err)
assert.NotNil(t, env)
ast, issues := env.Compile(`context.GetGlobalReference("foo")`)
assert.Nil(t, issues)
assert.NotNil(t, ast)
prog, err := env.Program(ast)
assert.NoError(t, err)
assert.NotNil(t, prog)
called := false
data := map[string]any{
"context": Context{&ctx{
GetGlobalReferenceFunc: func(string) (any, error) {
type foo struct {
s string
}
called = true
return foo{"bar"}, nil
},
}},
}
out, _, err := prog.Eval(data)
assert.NoError(t, err)
assert.NotNil(t, out)
assert.True(t, called)
}

View file

@ -43,6 +43,14 @@ func (c *lib) extendEnv(env *cel.Env) (*cel.Env, error) {
// TODO: should not use DynType in return
cel.MemberOverload("get_configmap_string_string", []*cel.Type{ContextType, types.StringType, types.StringType}, types.DynType, cel.FunctionBinding(impl.get_configmap_string_string)),
},
"GetGlobalReference": {
// TODO: should not use DynType in return
cel.MemberOverload("get_globalreference_string", []*cel.Type{ContextType, types.StringType}, types.DynType, cel.BinaryBinding(impl.get_globalreference_string)),
},
"GetImageData": {
// TODO: should not use DynType in return
cel.MemberOverload("get_imagedata_string", []*cel.Type{ContextType, types.StringType}, types.DynType, cel.BinaryBinding(impl.get_imagedata_string)),
},
}
// create env options corresponding to our function overloads
options := []cel.EnvOption{}

View file

@ -9,6 +9,8 @@ var ContextType = types.NewOpaqueType("context.Context")
type ContextInterface interface {
GetConfigMap(string, string) (unstructured.Unstructured, error)
GetGlobalReference(string) (any, error)
GetImageData(string) (any, error)
}
type Context struct {