mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
fix: implement cel context lib correctly (#11983)
* fix: implement cel context lib correctly Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * more changes Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
e481ec4231
commit
144bf436ed
6 changed files with 92 additions and 6 deletions
|
@ -74,7 +74,7 @@ func (e *engine) Handle(ctx context.Context, request EngineRequest) (EngineRespo
|
||||||
|
|
||||||
func (e *engine) handlePolicy(ctx context.Context, policy CompiledPolicy, resource *unstructured.Unstructured, namespace *unstructured.Unstructured) PolicyResponse {
|
func (e *engine) handlePolicy(ctx context.Context, policy CompiledPolicy, resource *unstructured.Unstructured, namespace *unstructured.Unstructured) PolicyResponse {
|
||||||
var rules []engineapi.RuleResponse
|
var rules []engineapi.RuleResponse
|
||||||
results, err := policy.CompiledPolicy.Evaluate(ctx, resource, namespace)
|
results, err := policy.CompiledPolicy.Evaluate(ctx, resource, namespace, nil)
|
||||||
// TODO: error is about match conditions here ?
|
// TODO: error is about match conditions here ?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rules = handlers.WithResponses(engineapi.RuleError("evaluation", engineapi.Validation, "failed to load context", err, nil))
|
rules = handlers.WithResponses(engineapi.RuleError("evaluation", engineapi.Validation, "failed to load context", err, nil))
|
||||||
|
|
49
pkg/cel/libs/context/impl_test.go
Normal file
49
pkg/cel/libs/context/impl_test.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/cel-go/cel"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctx struct {
|
||||||
|
GetConfigMapFunc func(string, string) (unstructured.Unstructured, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *ctx) GetConfigMap(ns string, n string) (unstructured.Unstructured, error) {
|
||||||
|
return mock.GetConfigMapFunc(ns, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_impl_get_configmap_string_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.GetConfigMap("foo","bar")`)
|
||||||
|
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{
|
||||||
|
GetConfigMapFunc: func(string, string) (unstructured.Unstructured, error) {
|
||||||
|
called = true
|
||||||
|
return unstructured.Unstructured{}, nil
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
out, _, err := prog.Eval(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, out)
|
||||||
|
assert.True(t, called)
|
||||||
|
}
|
|
@ -1,10 +1,15 @@
|
||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
|
"github.com/google/cel-go/ext"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const libraryName = "kyverno.context"
|
||||||
|
|
||||||
type lib struct{}
|
type lib struct{}
|
||||||
|
|
||||||
func Lib() cel.EnvOption {
|
func Lib() cel.EnvOption {
|
||||||
|
@ -13,11 +18,12 @@ func Lib() cel.EnvOption {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*lib) LibraryName() string {
|
func (*lib) LibraryName() string {
|
||||||
return "kyverno.context"
|
return libraryName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *lib) CompileOptions() []cel.EnvOption {
|
func (c *lib) CompileOptions() []cel.EnvOption {
|
||||||
return []cel.EnvOption{
|
return []cel.EnvOption{
|
||||||
|
ext.NativeTypes(reflect.TypeFor[Context]()),
|
||||||
c.extendEnv,
|
c.extendEnv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
pkg/cel/libs/context/lib_test.go
Normal file
20
pkg/cel/libs/context/lib_test.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/cel-go/cel"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLib(t *testing.T) {
|
||||||
|
opts := Lib()
|
||||||
|
env, err := cel.NewEnv(opts)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_lib_LibraryName(t *testing.T) {
|
||||||
|
var l lib
|
||||||
|
assert.Equal(t, libraryName, l.LibraryName())
|
||||||
|
}
|
|
@ -5,8 +5,12 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ContextType = types.NewObjectType("context.Context")
|
var ContextType = types.NewOpaqueType("context.Context")
|
||||||
|
|
||||||
type Context interface {
|
type ContextInterface interface {
|
||||||
GetConfigMap(string, string) (unstructured.Unstructured, error)
|
GetConfigMap(string, string) (unstructured.Unstructured, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
ContextInterface
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
"github.com/google/cel-go/common/types/ref"
|
"github.com/google/cel-go/common/types/ref"
|
||||||
|
contextlib "github.com/kyverno/kyverno/pkg/cel/libs/context"
|
||||||
"github.com/kyverno/kyverno/pkg/cel/utils"
|
"github.com/kyverno/kyverno/pkg/cel/utils"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||||
|
@ -24,7 +25,7 @@ type EvaluationResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompiledPolicy interface {
|
type CompiledPolicy interface {
|
||||||
Evaluate(context.Context, resource, namespace) ([]EvaluationResult, error)
|
Evaluate(context.Context, resource, namespace, contextlib.ContextInterface) ([]EvaluationResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type compiledPolicy struct {
|
type compiledPolicy struct {
|
||||||
|
@ -35,7 +36,12 @@ type compiledPolicy struct {
|
||||||
auditAnnotations map[string]cel.Program
|
auditAnnotations map[string]cel.Program
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *compiledPolicy) Evaluate(ctx context.Context, resource resource, namespace namespace) ([]EvaluationResult, error) {
|
func (p *compiledPolicy) Evaluate(
|
||||||
|
ctx context.Context,
|
||||||
|
resource resource,
|
||||||
|
namespace namespace,
|
||||||
|
context contextlib.ContextInterface,
|
||||||
|
) ([]EvaluationResult, error) {
|
||||||
match, err := p.match(ctx, resource, namespace)
|
match, err := p.match(ctx, resource, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -52,6 +58,7 @@ func (p *compiledPolicy) Evaluate(ctx context.Context, resource resource, namesp
|
||||||
NamespaceObjectKey: nsData,
|
NamespaceObjectKey: nsData,
|
||||||
ObjectKey: resource.UnstructuredContent(),
|
ObjectKey: resource.UnstructuredContent(),
|
||||||
VariablesKey: vars,
|
VariablesKey: vars,
|
||||||
|
ContextKey: contextlib.Context{ContextInterface: context},
|
||||||
}
|
}
|
||||||
for name, variable := range p.variables {
|
for name, variable := range p.variables {
|
||||||
vars.Append(name, func(*lazy.MapValue) ref.Val {
|
vars.Append(name, func(*lazy.MapValue) ref.Val {
|
||||||
|
|
Loading…
Add table
Reference in a new issue