Skip to content

Commit

Permalink
Rework to pull in upstream changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
bigkevmcd committed Feb 3, 2025
1 parent 0a09f46 commit eb6f1ce
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 112 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ require (
github.com/fluxcd/pkg/apis/meta v1.9.0
github.com/fluxcd/pkg/git v0.23.0
github.com/fluxcd/pkg/masktoken v0.6.0
github.com/fluxcd/pkg/runtime v0.51.0
github.com/fluxcd/pkg/runtime v0.52.1-0.20250128144821-a77a0699e750
github.com/fluxcd/pkg/ssa v0.43.0
github.com/getsentry/sentry-go v0.30.0
github.com/go-logr/logr v1.4.2
github.com/google/cel-go v0.22.0
github.com/google/go-github/v64 v64.0.0
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/ktrysmt/go-bitbucket v0.9.81
Expand All @@ -52,7 +51,7 @@ require (
replace gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1

require (
cel.dev/expr v0.18.0 // indirect
cel.dev/expr v0.19.1 // indirect
cloud.google.com/go v0.116.0 // indirect
cloud.google.com/go/auth v0.12.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
Expand Down Expand Up @@ -94,6 +93,7 @@ require (
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fluxcd/pkg/apis/acl v0.5.0 // indirect
github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58 // indirect
github.com/fluxcd/pkg/auth v0.2.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
Expand All @@ -113,6 +113,7 @@ require (
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/cel-go v0.23.0 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-github/v66 v66.0.0 // indirect
Expand Down
16 changes: 10 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4=
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
Expand Down Expand Up @@ -148,6 +148,8 @@ github.com/fluxcd/pkg/apis/acl v0.5.0 h1:+ykKezgerKUlZwSYFUy03lPMOIAyWlqvMNNLIWW
github.com/fluxcd/pkg/apis/acl v0.5.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs=
github.com/fluxcd/pkg/apis/event v0.15.0 h1:k1suqIfVxnhEeKlGkvlHAbOYXjY8wRixT/OZcIuakqA=
github.com/fluxcd/pkg/apis/event v0.15.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58 h1:zhTfTbXKv+R+f1gwu2ekEu0b1Q5CjinCtj1prVEVbVo=
github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ=
github.com/fluxcd/pkg/apis/meta v1.9.0/go.mod h1:pMea8eEZcsFSI7ngRnTHFtDZk2CEZGgtrueNgI6Iu70=
github.com/fluxcd/pkg/auth v0.2.0 h1:Df3pHGMDJjpr8AcGKgPvudXF3Lb3SuBlkAmhrkp7U1k=
Expand All @@ -156,8 +158,10 @@ github.com/fluxcd/pkg/git v0.23.0 h1:5iPHO9dghbuSy1AToeqFxGdMRk9plgVmIBG3OYwhiZY
github.com/fluxcd/pkg/git v0.23.0/go.mod h1:O44NBzAC4CtRA7ZpTn8mv4R3wli9ptlhZX+/6+3Lsts=
github.com/fluxcd/pkg/masktoken v0.6.0 h1:ijSqMl2L9jBR3QFcHA0FX7kxV0xgSB4PY5p//8FdVR4=
github.com/fluxcd/pkg/masktoken v0.6.0/go.mod h1:bMj45KySJ2gLeFiFaXD5nQLNFlvDqGbZolsiurZKVUU=
github.com/fluxcd/pkg/runtime v0.51.0 h1:F4gKLUBUdvUdtg2lBsg72KUPqlOnaf9ChEL8bmP7CvQ=
github.com/fluxcd/pkg/runtime v0.51.0/go.mod h1:uMJ+s81+TyNGVjcnn+PIXUGGYs9VA3AK8nDmQWXAnis=
github.com/fluxcd/pkg/runtime v0.52.1-0.20250128132758-79a726e45f65 h1:7NC8IGDnAqtLF2HBpF5Wy20TzAjMnQuGmnwM7NXoETA=
github.com/fluxcd/pkg/runtime v0.52.1-0.20250128132758-79a726e45f65/go.mod h1:RB7Gz0ExoMlS60dq4nEzR78gojIQLximcUDEB0nIWiE=
github.com/fluxcd/pkg/runtime v0.52.1-0.20250128144821-a77a0699e750 h1:EMyo0Hb4rJO4mNm+mHBbnrse4Do57c/UuAAjPX8A1Hs=
github.com/fluxcd/pkg/runtime v0.52.1-0.20250128144821-a77a0699e750/go.mod h1:RB7Gz0ExoMlS60dq4nEzR78gojIQLximcUDEB0nIWiE=
github.com/fluxcd/pkg/ssa v0.43.0 h1:XmADD3C0erYZayKfGI0WTsMlW9TtS4bp5gy4Axo1dcA=
github.com/fluxcd/pkg/ssa v0.43.0/go.mod h1:MjkaOr4/5C8wkwsdVLMmfS64lDZOgJP4VNxmmJL0Iuc=
github.com/fluxcd/pkg/ssh v0.16.0 h1:dhSWNp30p05EJ86bhICezad9pG3fJi4CAVKnZ3EmUV8=
Expand Down Expand Up @@ -226,8 +230,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/cel-go v0.23.0 h1:knsnzeUOcREUFo0ZFJqZI8Rk6uEVyobAlir7GEbf5v0=
github.com/google/cel-go v0.23.0/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand Down
105 changes: 8 additions & 97 deletions internal/server/cel.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,49 +24,24 @@ import (
"net/http"
"strings"

"github.com/google/cel-go/cel"
"github.com/fluxcd/pkg/runtime/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
celext "github.com/google/cel-go/ext"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ValidateCELEXpression accepts a CEL expression and will parse and check that
// it's valid, if it's not valid an error is returned.
func ValidateCELExpression(s string) error {
_, err := newCELProgram(s)
return err
}

func newCELProgram(expr string) (cel.Program, error) {
env, err := makeCELEnv()
if err != nil {
return nil, err
}
parsed, issues := env.Parse(expr)
if issues != nil && issues.Err() != nil {
return nil, fmt.Errorf("failed to parse expression %v: %w", expr, issues.Err())
}

checked, issues := env.Check(parsed)
if issues != nil && issues.Err() != nil {
return nil, fmt.Errorf("expression %v check failed: %w", expr, issues.Err())
}
if checked.OutputType() != types.BoolType {
return nil, fmt.Errorf("invalid expression output type %v", checked.OutputType())
}
_, err := cel.NewExpression(s,
cel.WithCompile(),
cel.WithOutputType(types.BoolType),
cel.WithStructVariables("resource", "request"))

prg, err := env.Program(checked, cel.EvalOptions(cel.OptOptimize), cel.InterruptCheckFrequency(100))
if err != nil {
return nil, fmt.Errorf("expression %v failed to create a Program: %w", expr, err)
}

return prg, nil
return err
}

func newCELEvaluator(expr string, req *http.Request) (resourcePredicate, error) {
prg, err := newCELProgram(expr)
celExpr, err := cel.NewExpression(expr, cel.WithCompile(), cel.WithStructVariables("resource", "request"))
if err != nil {
return nil, err
}
Expand All @@ -86,7 +61,7 @@ func newCELEvaluator(expr string, req *http.Request) (resourcePredicate, error)
return nil, err
}

out, _, err := prg.ContextEval(ctx, map[string]any{
result, err := celExpr.EvaluateBoolean(ctx, map[string]any{
"resource": data,
"request": map[string]any{
"body": body,
Expand All @@ -96,21 +71,10 @@ func newCELEvaluator(expr string, req *http.Request) (resourcePredicate, error)
return nil, fmt.Errorf("expression %v failed to evaluate: %w", expr, err)
}

result := out.Value().(bool)

return &result, nil
}, nil
}

func makeCELEnv() (*cel.Env, error) {
return cel.NewEnv(
celext.Strings(),
notifications(),
cel.Variable("resource", cel.ObjectType("google.protobuf.Struct")),
cel.Variable("request", cel.ObjectType("google.protobuf.Struct")),
)
}

func isJSONContent(r *http.Request) bool {
contentType := r.Header.Get("Content-type")
for _, v := range strings.Split(contentType, ",") {
Expand All @@ -126,59 +90,6 @@ func isJSONContent(r *http.Request) bool {
return false
}

func notifications() cel.EnvOption {
return cel.Lib(&notificationsLib{})
}

type notificationsLib struct{}

// LibraryName implements the SingletonLibrary interface method.
func (*notificationsLib) LibraryName() string {
return "flux.notifications.lib"
}

// CompileOptions implements the Library interface method.
func (l *notificationsLib) CompileOptions() []cel.EnvOption {
listDyn := cel.ListType(cel.DynType)
opts := []cel.EnvOption{
cel.Function("first",
cel.MemberOverload("first_list", []*cel.Type{listDyn}, cel.DynType,
cel.UnaryBinding(listFirst))),
cel.Function("last",
cel.MemberOverload("last_list", []*cel.Type{listDyn}, cel.DynType,
cel.UnaryBinding(listLast))),
}

return opts
}

// ProgramOptions implements the Library interface method.
func (*notificationsLib) ProgramOptions() []cel.ProgramOption {
return []cel.ProgramOption{}
}

func listLast(val ref.Val) ref.Val {
l := val.(traits.Lister)
sz := l.Size().Value().(int64)

if sz == 0 {
return types.NullValue
}

return l.Get(types.Int(sz - 1))
}

func listFirst(val ref.Val) ref.Val {
l := val.(traits.Lister)
sz := l.Size().Value().(int64)

if sz == 0 {
return types.NullValue
}

return l.Get(types.Int(0))
}

func clientObjectToMap(v client.Object) (map[string]any, error) {
b, err := json.Marshal(v)
if err != nil {
Expand Down
20 changes: 18 additions & 2 deletions internal/server/cel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestValidateCELExpressionInvalidExpressions(t *testing.T) {
}{
{
"'test'",
"invalid expression output type string",
"CEL expression output type mismatch: expected bool, got string",
},
{
"requrest.body.value",
Expand Down Expand Up @@ -78,7 +78,23 @@ func TestCELEvaluation(t *testing.T) {
wantResult: true,
},
{
expression: `resource.metadata.name == 'test-resource' && request.body.image.source.split(':').last().startsWith('v')`,
expression: `request.body.bool`,
request: testNewHTTPRequest(t, http.MethodPost, "/test", map[string]any{
"bool": true,
}),
resource: &apiv1.Receiver{
TypeMeta: metav1.TypeMeta{
Kind: apiv1.ReceiverKind,
APIVersion: apiv1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-resource",
},
},
wantResult: true,
},
{
expression: `resource.metadata.name == 'test-resource' && request.body.image.source.split(':').last().value().startsWith('v')`,
request: testNewHTTPRequest(t, http.MethodPost, "/test", map[string]any{
"image": map[string]any{
"source": "hello-world:v1.0.0",
Expand Down
8 changes: 4 additions & 4 deletions internal/server/receiver_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ func Test_handlePayload(t *testing.T) {
},
},
},
ResourceFilter: `has(resource.metadata.annotations) && request.body.tag.split('/').last().split(":").first() == resource.metadata.annotations['update-image']`,
ResourceFilter: `has(resource.metadata.annotations) && request.body.tag.split('/').last().value().split(":").first().value() == resource.metadata.annotations['update-image']`,
},
Status: apiv1.ReceiverStatus{
WebhookPath: apiv1.ReceiverWebhookPath,
Expand Down Expand Up @@ -785,7 +785,7 @@ func Test_handlePayload(t *testing.T) {
Name: "test-resource",
},
},
ResourceFilter: `has(resource.metadata.annotations) && request.body.tag.split('/').last().split(":").first() == resource.metadata.annotations['update-image']`,
ResourceFilter: `has(resource.metadata.annotations) && request.body.tag.split('/').last().value().split(":").first().value() == resource.metadata.annotations['update-image']`,
},
Status: apiv1.ReceiverStatus{
WebhookPath: apiv1.ReceiverWebhookPath,
Expand Down Expand Up @@ -1096,7 +1096,7 @@ func Test_handlePayload(t *testing.T) {
Name: "test-resource",
},
},
ResourceFilter: `resource.metadata.name == 'test-resource' && request.body.push_data.tag.split('/').last().split(':').first() == 'test-repo'`,
ResourceFilter: `resource.metadata.name == 'test-resource' && request.body.push_data.tag.split('/').last().value().split(':').first().value() == 'test-repo'`,
},
Status: apiv1.ReceiverStatus{
WebhookPath: apiv1.ReceiverWebhookPath,
Expand Down Expand Up @@ -1139,7 +1139,7 @@ func Test_handlePayload(t *testing.T) {
Name: "test-resource",
},
},
ResourceFilter: `resource.metadata.name == 'test-resource' && request.body.tag.split('/').last().split(":").first() == 'app1'`,
ResourceFilter: `resource.metadata.name == 'test-resource' && request.body.tag.split('/').last().value().split(":").first().value() == 'app1'`,
},
Status: apiv1.ReceiverStatus{
WebhookPath: apiv1.ReceiverWebhookPath,
Expand Down

0 comments on commit eb6f1ce

Please sign in to comment.