mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
feat: introduce evaluation results in cel engine (#11971)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
07a23746d8
commit
9d11e8f98c
2 changed files with 64 additions and 45 deletions
|
@ -2,9 +2,11 @@ package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||||
"github.com/kyverno/kyverno/pkg/cel/policy"
|
"github.com/kyverno/kyverno/pkg/cel/policy"
|
||||||
|
"github.com/kyverno/kyverno/pkg/cel/utils"
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||||
|
@ -72,14 +74,23 @@ func (e *engine) Handle(ctx context.Context, request EngineRequest) (EngineRespo
|
||||||
|
|
||||||
func (e *engine) handlePolicy(ctx context.Context, policy policy.CompiledPolicy, resource *unstructured.Unstructured, namespace *unstructured.Unstructured) PolicyResponse {
|
func (e *engine) handlePolicy(ctx context.Context, policy policy.CompiledPolicy, resource *unstructured.Unstructured, namespace *unstructured.Unstructured) PolicyResponse {
|
||||||
var rules []engineapi.RuleResponse
|
var rules []engineapi.RuleResponse
|
||||||
ok, err := policy.Evaluate(ctx, resource, namespace)
|
results, err := policy.Evaluate(ctx, resource, namespace)
|
||||||
// TODO: evaluation should be per rule
|
// TODO: error is about match conditions here ?
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rules = handlers.WithResponses(engineapi.RuleError("todo", engineapi.Validation, "failed to load context", err, nil))
|
rules = handlers.WithResponses(engineapi.RuleError("evaluation", engineapi.Validation, "failed to load context", err, nil))
|
||||||
} else if ok {
|
|
||||||
rules = handlers.WithResponses(engineapi.RulePass("todo", engineapi.Validation, "success", nil))
|
|
||||||
} else {
|
} else {
|
||||||
rules = handlers.WithResponses(engineapi.RuleFail("todo", engineapi.Validation, "failure", nil))
|
for index, result := range results {
|
||||||
|
ruleName := fmt.Sprintf("rule-%d", index)
|
||||||
|
if result.Error != nil {
|
||||||
|
rules = append(rules, *engineapi.RuleError(ruleName, engineapi.Validation, "error", err, nil))
|
||||||
|
} else if result, err := utils.ConvertToNative[bool](result.Result); err != nil {
|
||||||
|
rules = append(rules, *engineapi.RuleError(ruleName, engineapi.Validation, "conversion error", err, nil))
|
||||||
|
} else if result {
|
||||||
|
rules = append(rules, *engineapi.RulePass(ruleName, engineapi.Validation, "success", nil))
|
||||||
|
} else {
|
||||||
|
rules = append(rules, *engineapi.RuleFail(ruleName, engineapi.Validation, "failure", nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return PolicyResponse{
|
return PolicyResponse{
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -18,8 +18,13 @@ type (
|
||||||
namespace = *unstructured.Unstructured
|
namespace = *unstructured.Unstructured
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EvaluationResult struct {
|
||||||
|
Result ref.Val
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
type CompiledPolicy interface {
|
type CompiledPolicy interface {
|
||||||
Evaluate(context.Context, resource, namespace) (bool, error)
|
Evaluate(context.Context, resource, namespace) ([]EvaluationResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type compiledPolicy struct {
|
type compiledPolicy struct {
|
||||||
|
@ -30,57 +35,60 @@ type compiledPolicy struct {
|
||||||
auditAnnotations map[string]cel.Program
|
auditAnnotations map[string]cel.Program
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *compiledPolicy) Evaluate(ctx context.Context, resource resource, namespace namespace) (bool, error) {
|
func (p *compiledPolicy) Evaluate(ctx context.Context, resource resource, namespace namespace) ([]EvaluationResult, error) {
|
||||||
match, err := p.match(ctx, resource, namespace)
|
match, err := p.match(ctx, resource, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !match {
|
if !match {
|
||||||
return true, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var nsData map[string]any
|
var nsData map[string]any
|
||||||
if namespace != nil {
|
if namespace != nil {
|
||||||
nsData = namespace.UnstructuredContent()
|
nsData = namespace.UnstructuredContent()
|
||||||
}
|
}
|
||||||
variables := func() map[string]any {
|
vars := lazy.NewMapValue(VariablesType)
|
||||||
vars := lazy.NewMapValue(VariablesType)
|
data := map[string]any{
|
||||||
data := map[string]any{
|
NamespaceObjectKey: nsData,
|
||||||
NamespaceObjectKey: nsData,
|
ObjectKey: resource.UnstructuredContent(),
|
||||||
ObjectKey: resource.UnstructuredContent(),
|
VariablesKey: vars,
|
||||||
VariablesKey: vars,
|
|
||||||
}
|
|
||||||
for name, variable := range p.variables {
|
|
||||||
vars.Append(name, func(*lazy.MapValue) ref.Val {
|
|
||||||
out, _, err := variable.Eval(data)
|
|
||||||
if out != nil {
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return types.WrapErr(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
data := variables()
|
for name, variable := range p.variables {
|
||||||
|
vars.Append(name, func(*lazy.MapValue) ref.Val {
|
||||||
|
out, _, err := variable.Eval(data)
|
||||||
|
if out != nil {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return types.WrapErr(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
results := make([]EvaluationResult, 0, len(p.validations))
|
||||||
for _, rule := range p.validations {
|
for _, rule := range p.validations {
|
||||||
out, _, err := rule.Eval(data)
|
out, _, err := rule.Eval(data)
|
||||||
// check error
|
results = append(results, EvaluationResult{
|
||||||
if err != nil {
|
Result: out,
|
||||||
return false, err
|
Error: err,
|
||||||
}
|
})
|
||||||
response, err := utils.ConvertToNative[bool](out)
|
// // check error
|
||||||
// check error
|
// if err != nil {
|
||||||
if err != nil {
|
// results = append(results, EvaluationResult{
|
||||||
return false, err
|
// Error: err,
|
||||||
}
|
// })
|
||||||
// if response is false, return
|
// }
|
||||||
if !response {
|
// response, err := utils.ConvertToNative[bool](out)
|
||||||
return false, nil
|
// // check error
|
||||||
}
|
// if err != nil {
|
||||||
|
// return false, err
|
||||||
|
// }
|
||||||
|
// // if response is false, return
|
||||||
|
// if !response {
|
||||||
|
// return false, nil
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
return true, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *compiledPolicy) match(ctx context.Context, resource resource, namespace namespace) (bool, error) {
|
func (p *compiledPolicy) match(ctx context.Context, resource resource, namespace namespace) (bool, error) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue