mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 07:57:07 +00:00
feat: compile CEL exceptions (#12066)
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
1cb0d1c356
commit
202ab74ff5
3 changed files with 118 additions and 0 deletions
58
pkg/cel/exception/compiler.go
Normal file
58
pkg/cel/exception/compiler.go
Normal 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
|
||||
}
|
51
pkg/cel/exception/compiler_test.go
Normal file
51
pkg/cel/exception/compiler_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
9
pkg/cel/exception/exception.go
Normal file
9
pkg/cel/exception/exception.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package exception
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/cel"
|
||||
)
|
||||
|
||||
type CompiledException struct {
|
||||
matchConditions []cel.Program
|
||||
}
|
Loading…
Add table
Reference in a new issue