@@ -24,49 +24,24 @@ import (
2424 "net/http"
2525 "strings"
2626
27- "github.com/google/cel-go /cel"
27+ "github.com/fluxcd/pkg/runtime /cel"
2828 "github.com/google/cel-go/common/types"
29- "github.com/google/cel-go/common/types/ref"
30- "github.com/google/cel-go/common/types/traits"
31- celext "github.com/google/cel-go/ext"
3229 "sigs.k8s.io/controller-runtime/pkg/client"
3330)
3431
3532// ValidateCELEXpression accepts a CEL expression and will parse and check that
3633// it's valid, if it's not valid an error is returned.
3734func ValidateCELExpression (s string ) error {
38- _ , err := newCELProgram (s )
39- return err
40- }
41-
42- func newCELProgram (expr string ) (cel.Program , error ) {
43- env , err := makeCELEnv ()
44- if err != nil {
45- return nil , err
46- }
47- parsed , issues := env .Parse (expr )
48- if issues != nil && issues .Err () != nil {
49- return nil , fmt .Errorf ("failed to parse expression %v: %w" , expr , issues .Err ())
50- }
51-
52- checked , issues := env .Check (parsed )
53- if issues != nil && issues .Err () != nil {
54- return nil , fmt .Errorf ("expression %v check failed: %w" , expr , issues .Err ())
55- }
56- if checked .OutputType () != types .BoolType {
57- return nil , fmt .Errorf ("invalid expression output type %v" , checked .OutputType ())
58- }
35+ _ , err := cel .NewExpression (s ,
36+ cel .WithCompile (),
37+ cel .WithOutputType (types .BoolType ),
38+ cel .WithStructVariables ("resource" , "request" ))
5939
60- prg , err := env .Program (checked , cel .EvalOptions (cel .OptOptimize ), cel .InterruptCheckFrequency (100 ))
61- if err != nil {
62- return nil , fmt .Errorf ("expression %v failed to create a Program: %w" , expr , err )
63- }
64-
65- return prg , nil
40+ return err
6641}
6742
6843func newCELEvaluator (expr string , req * http.Request ) (resourcePredicate , error ) {
69- prg , err := newCELProgram (expr )
44+ celExpr , err := cel . NewExpression (expr , cel . WithCompile (), cel . WithStructVariables ( "resource" , "request" ) )
7045 if err != nil {
7146 return nil , err
7247 }
@@ -86,7 +61,7 @@ func newCELEvaluator(expr string, req *http.Request) (resourcePredicate, error)
8661 return nil , err
8762 }
8863
89- out , _ , err := prg . ContextEval (ctx , map [string ]any {
64+ result , err := celExpr . EvaluateBoolean (ctx , map [string ]any {
9065 "resource" : data ,
9166 "request" : map [string ]any {
9267 "body" : body ,
@@ -96,21 +71,10 @@ func newCELEvaluator(expr string, req *http.Request) (resourcePredicate, error)
9671 return nil , fmt .Errorf ("expression %v failed to evaluate: %w" , expr , err )
9772 }
9873
99- result := out .Value ().(bool )
100-
10174 return & result , nil
10275 }, nil
10376}
10477
105- func makeCELEnv () (* cel.Env , error ) {
106- return cel .NewEnv (
107- celext .Strings (),
108- notifications (),
109- cel .Variable ("resource" , cel .ObjectType ("google.protobuf.Struct" )),
110- cel .Variable ("request" , cel .ObjectType ("google.protobuf.Struct" )),
111- )
112- }
113-
11478func isJSONContent (r * http.Request ) bool {
11579 contentType := r .Header .Get ("Content-type" )
11680 for _ , v := range strings .Split (contentType , "," ) {
@@ -126,59 +90,6 @@ func isJSONContent(r *http.Request) bool {
12690 return false
12791}
12892
129- func notifications () cel.EnvOption {
130- return cel .Lib (& notificationsLib {})
131- }
132-
133- type notificationsLib struct {}
134-
135- // LibraryName implements the SingletonLibrary interface method.
136- func (* notificationsLib ) LibraryName () string {
137- return "flux.notifications.lib"
138- }
139-
140- // CompileOptions implements the Library interface method.
141- func (l * notificationsLib ) CompileOptions () []cel.EnvOption {
142- listDyn := cel .ListType (cel .DynType )
143- opts := []cel.EnvOption {
144- cel .Function ("first" ,
145- cel .MemberOverload ("first_list" , []* cel.Type {listDyn }, cel .DynType ,
146- cel .UnaryBinding (listFirst ))),
147- cel .Function ("last" ,
148- cel .MemberOverload ("last_list" , []* cel.Type {listDyn }, cel .DynType ,
149- cel .UnaryBinding (listLast ))),
150- }
151-
152- return opts
153- }
154-
155- // ProgramOptions implements the Library interface method.
156- func (* notificationsLib ) ProgramOptions () []cel.ProgramOption {
157- return []cel.ProgramOption {}
158- }
159-
160- func listLast (val ref.Val ) ref.Val {
161- l := val .(traits.Lister )
162- sz := l .Size ().Value ().(int64 )
163-
164- if sz == 0 {
165- return types .NullValue
166- }
167-
168- return l .Get (types .Int (sz - 1 ))
169- }
170-
171- func listFirst (val ref.Val ) ref.Val {
172- l := val .(traits.Lister )
173- sz := l .Size ().Value ().(int64 )
174-
175- if sz == 0 {
176- return types .NullValue
177- }
178-
179- return l .Get (types .Int (0 ))
180- }
181-
18293func clientObjectToMap (v client.Object ) (map [string ]any , error ) {
18394 b , err := json .Marshal (v )
18495 if err != nil {
0 commit comments