Skip to content

Commit 10ad3cb

Browse files
committed
Simplify the CEL library code structure
Remind the original cel package to constraints pkg to reflect that there will be more type of constraints. Remove the evaluator/provider interfaces that are not needed yet. The generic interface can be designed later when a new type of constraint is introduced. Signed-off-by: Vu Dinh <[email protected]>
1 parent b646b4c commit 10ad3cb

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

pkg/cel/cel.go renamed to pkg/constraints/cel.go

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package cel
1+
package constraints
22

33
import (
44
"fmt"
@@ -16,6 +16,7 @@ import (
1616
// PropertiesKey is the key for bundle properties map (input data for CEL evaluation)
1717
const PropertiesKey = "properties"
1818

19+
// Constraint is a struct representing the new generic constraint type
1920
type Constraint struct {
2021
// Constraint message that surfaces in resolution
2122
// This field is optional
@@ -26,37 +27,38 @@ type Constraint struct {
2627
Cel *Cel `json:"cel" yaml:"cel"`
2728
}
2829

30+
// Cel is a struct representing CEL expression information
2931
type Cel struct {
3032
// The CEL expression
3133
Rule string `json:"rule" yaml:"rule"`
3234
}
3335

34-
type Evaluator interface {
35-
Evaluate(env map[string]interface{}) (bool, error)
36-
}
37-
38-
type EvaluatorProvider interface {
39-
Evaluator(rule string) (Evaluator, error)
40-
}
41-
42-
func NewCelEvaluatorProvider() *celEvaluatorProvider {
36+
// NewCelEnvironment returns a CEL environment which can be used to
37+
// evaluate CEL expression and an error if occurs
38+
func NewCelEnvironment() *CelEnvironment {
4339
env, err := cel.NewEnv(cel.Declarations(
4440
decls.NewVar(PropertiesKey, decls.NewListType(decls.NewMapType(decls.String, decls.Any)))),
4541
cel.Lib(semverLib{}),
4642
)
43+
// If an error occurs here, it means the CEL enviroment is unable to load
44+
// configuration for custom libraries propertly. Hence, the CEL enviroment is
45+
// unusable. Panic here will cause the program to fail immediately to prevent
46+
// cascading failures later on when this CEL env is in use.
4747
if err != nil {
4848
panic(err)
4949
}
50-
return &celEvaluatorProvider{
50+
return &CelEnvironment{
5151
env: env,
5252
}
5353
}
5454

55-
type celEvaluatorProvider struct {
55+
// CelEnvironment is a struct that encapsulates CEL custom program enviroment
56+
type CelEnvironment struct {
5657
env *cel.Env
5758
}
5859

59-
type celEvaluator struct {
60+
// CelProgram is a struct that encapsulates compiled CEL program
61+
type CelProgram struct {
6062
program cel.Program
6163
}
6264

@@ -110,8 +112,9 @@ func semverCompare(val1, val2 ref.Val) ref.Val {
110112
return types.Int(v1.Compare(v2))
111113
}
112114

113-
func (e celEvaluator) Evaluate(env map[string]interface{}) (bool, error) {
114-
result, _, err := e.program.Eval(env)
115+
// Evaluate to evaluate the compiled CEL program against input data (map)
116+
func (e CelProgram) Evaluate(data map[string]interface{}) (bool, error) {
117+
result, _, err := e.program.Eval(data)
115118
if err != nil {
116119
return false, err
117120
}
@@ -123,19 +126,21 @@ func (e celEvaluator) Evaluate(env map[string]interface{}) (bool, error) {
123126
return false, fmt.Errorf("cel expression evalutated to %T, not bool", result.Value())
124127
}
125128

126-
func (e *celEvaluatorProvider) Evaluator(rule string) (Evaluator, error) {
129+
// Validate to validate the CEL expression string by compiling it into CEL program
130+
func (e *CelEnvironment) Validate(rule string) (CelProgram, error) {
131+
var celProg CelProgram
127132
ast, issues := e.env.Compile(rule)
128133
if err := issues.Err(); err != nil {
129-
return nil, err
134+
return celProg, err
130135
}
131136

132137
if ast.ResultType() != decls.Bool {
133-
return nil, fmt.Errorf("cel expressions must have type Bool")
138+
return celProg, fmt.Errorf("cel expressions must have type Bool")
134139
}
135140

136141
prog, err := e.env.Program(ast)
137142
if err != nil {
138-
return nil, err
143+
return celProg, err
139144
}
140-
return celEvaluator{program: prog}, nil
145+
return CelProgram{program: prog}, nil
141146
}

pkg/cel/cel_test.go renamed to pkg/constraints/cel_test.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package cel
1+
package constraints
22

33
import (
44
"testing"
@@ -28,22 +28,37 @@ func TestCelLibrary(t *testing.T) {
2828
isErr: false,
2929
},
3030
{
31-
name: "ValidCelExpression/False",
31+
name: "ValidCelExpression/NotEqual/False",
3232
rule: "properties.exists(p, p.type == 'olm.test' && (semver_compare(p.value, '1.0.1') == 0))",
3333
out: false,
3434
isErr: false,
3535
},
3636
{
37-
name: "InvalidCelExpression",
37+
name: "ValidCelExpression/Less/False",
38+
rule: "properties.exists(p, p.type == 'olm.test' && (semver_compare(p.value, '1.0.0') < 0))",
39+
isErr: false,
40+
},
41+
{
42+
name: "ValidCelExpression/Larger/False",
43+
rule: "properties.exists(p, p.type == 'olm.test' && (semver_compare(p.value, '1.0.0') > 0))",
44+
isErr: false,
45+
},
46+
{
47+
name: "InvalidCelExpression/NotExistedFunc",
3848
rule: "properties.exists(p, p.type == 'olm.test' && (doesnt_exist(p.value, '1.0.0') == 0))",
3949
isErr: true,
4050
},
51+
{
52+
name: "InvalidCelExpression/NonBoolReturn",
53+
rule: "1",
54+
isErr: true,
55+
},
4156
}
4257

43-
validator := NewCelEvaluatorProvider()
58+
validator := NewCelEnvironment()
4459
for _, tt := range tests {
4560
t.Run(tt.name, func(t *testing.T) {
46-
prog, err := validator.Evaluator(tt.rule)
61+
prog, err := validator.Validate(tt.rule)
4762
if tt.isErr {
4863
assert.Error(t, err)
4964
} else {

0 commit comments

Comments
 (0)