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

feat: compile CEL exceptions (#12066)

Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
Mariam Fahmy 2025-02-03 17:17:41 +02:00 committed by GitHub
parent 1cb0d1c356
commit 202ab74ff5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 118 additions and 0 deletions

View file

@ -0,0 +1,58 @@
package exception
import (
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
engine "github.com/kyverno/kyverno/pkg/cel"
policy "github.com/kyverno/kyverno/pkg/cel/policy"
"k8s.io/apimachinery/pkg/util/validation/field"
)
type Compiler interface {
Compile(*kyvernov2alpha1.CELPolicyException) (*CompiledException, field.ErrorList)
}
func NewCompiler() Compiler {
return &compiler{}
}
type compiler struct{}
func (c *compiler) Compile(exception *kyvernov2alpha1.CELPolicyException) (*CompiledException, field.ErrorList) {
var allErrs field.ErrorList
base, err := engine.NewEnv()
if err != nil {
return nil, append(allErrs, field.InternalError(nil, err))
}
options := []cel.EnvOption{
cel.Variable(policy.ObjectKey, cel.DynType),
}
env, err := base.Extend(options...)
if err != nil {
return nil, append(allErrs, field.InternalError(nil, err))
}
path := field.NewPath("spec.matchConditions")
matchConditions := make([]cel.Program, 0, len(exception.Spec.MatchConditions))
for i, matchCondition := range exception.Spec.MatchConditions {
path := path.Index(i).Child("expression")
ast, issues := env.Compile(matchCondition.Expression)
if err := issues.Err(); err != nil {
return nil, append(allErrs, field.Invalid(path, matchCondition.Expression, err.Error()))
}
if !ast.OutputType().IsExactType(types.BoolType) {
msg := fmt.Sprintf("output is expected to be of type %s", types.BoolType.TypeName())
return nil, append(allErrs, field.Invalid(path, matchCondition.Expression, msg))
}
prog, err := env.Program(ast)
if err != nil {
return nil, append(allErrs, field.Invalid(path, matchCondition.Expression, err.Error()))
}
matchConditions = append(matchConditions, prog)
}
return &CompiledException{
matchConditions: matchConditions,
}, nil
}

View file

@ -0,0 +1,51 @@
package exception
import (
"testing"
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
"github.com/stretchr/testify/assert"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Test_compiler_Compile(t *testing.T) {
tests := []struct {
name string
exception *kyvernov2alpha1.CELPolicyException
wantErr bool
}{
{
name: "simple",
exception: &kyvernov2alpha1.CELPolicyException{
TypeMeta: metav1.TypeMeta{
APIVersion: kyvernov2alpha1.GroupVersion.String(),
Kind: "CELPolicyException",
},
ObjectMeta: metav1.ObjectMeta{
Name: "exception",
},
Spec: kyvernov2alpha1.CELPolicyExceptionSpec{
MatchConditions: []admissionregistrationv1.MatchCondition{
{
Name: "check env label",
Expression: "has(object.metadata.labels) && 'env' in object.metadata.labels && object.metadata.labels['env'] == 'prod'",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := NewCompiler()
compiled, errs := c.Compile(tt.exception)
if tt.wantErr {
assert.Error(t, errs.ToAggregate())
} else {
assert.NoError(t, errs.ToAggregate())
assert.NotNil(t, compiled)
}
})
}
}

View file

@ -0,0 +1,9 @@
package exception
import (
"github.com/google/cel-go/cel"
)
type CompiledException struct {
matchConditions []cel.Program
}