gogoproto support

65 views
Skip to first unread message

ki xu

unread,
Aug 9, 2020, 5:18:11 AM8/9/20
to CEL Go Discussion Forum
Hi,
I want use cel-go to parse k8s audit log, but the k8s api is gen by gogoproto.

When i use `Program.Eval` method to parse gogoprotoMessage and access message fields cause this error.

```
=== RUN   TestEval
time="2020-08-09T16:32:08+08:00" level=error msg="Evaluation error: %v internal error: reflect: call of reflect.Value.Call on zero Value"
```

How can I solve this problem?
Thanks.

Tristan Swadell

unread,
Aug 10, 2020, 10:53:38 AM8/10/20
to ki xu, CEL Go Discussion Forum
Hi Ki Xu,

Do you have a reference example that you'd like me to look at for reproducing the problem? Off the top of my head, it's hard to diagnose and fix the problem without a better understanding of your CEL environment setup.

-Tristan

--
You received this message because you are subscribed to the Google Groups "CEL Go Discussion Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cel-go-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cel-go-discuss/af4fe38b-74f7-4e82-9c9c-e1c70ea7bbc4n%40googlegroups.com.

ki xu

unread,
Aug 11, 2020, 8:45:19 AM8/11/20
to CEL Go Discussion Forum
Hi Tristan,

Thanks for your reply, the following code can reproduce the problem.

```
package main

import (
"fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto1 "github.com/gogo/protobuf/proto"
goproto "github.com/golang/protobuf/proto"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/checker/decls"
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
)

var ProtoMap = []string{
"k8s.io/api/authentication/v1/generated.proto",
"k8s.io/apimachinery/pkg/runtime/generated.proto",
"k8s.io/apimachinery/pkg/runtime/schema/generated.proto",
"k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto",
}

func main() {
event := &v1beta1.Event{}
event.UserAgent = "test"

for _, p:= range ProtoMap {
descriptor := proto1.FileDescriptor("k8s.io/kubernetes/vendor/"+p)
goproto.RegisterFile(p, descriptor)
}

goproto.RegisterFile(
"github.com/gogo/protobuf/gogoproto/gogo.proto",
proto1.FileDescriptor("gogo.proto"))


env, err := cel.NewEnv(
cel.Types(&v1beta1.Event{}),
cel.Declarations(
decls.NewVar("event",
decls.NewObjectType("k8s.io.apiserver.pkg.apis.audit.v1beta1.Event"),
),
),
)

ast, iss := env.Compile(`event.userAgent == "test"`)
if iss.Err() != nil {
fmt.Print(iss.Err())
}

prog, err := env.Program(ast)

if err != nil {
fmt.Print(err)
}

vars := make(map[string]interface{})
vars["event"] = event

out, _ , err := prog.Eval(vars)

if err != nil {
fmt.Print(err)
}

// expected = True

fmt.Print("result:", out)
}
```

I think this example expect result is bool value. but i got an error.

Error stack infomation:
```
runtime.call32 at asm_amd64.s:1
runtime.gopanic at panic.go:975
reflect.flag.mustBe at value.go:208
reflect.Value.Call at value.go:319
main.main at testcel.go:57
runtime.main at proc.go:203
runtime.goexit at asm_amd64.s:1373
 - Async stack trace
runtime.rt0_go at asm_amd64.s:220
```

best regards,
ki xu

Tristan Swadell

unread,
Aug 11, 2020, 12:32:08 PM8/11/20
to ki xu, CEL Go Discussion Forum
Excellent, thank you. I'll see what I can do.

-Tristan

Tristan Swadell

unread,
Aug 11, 2020, 5:53:21 PM8/11/20
to ki xu, CEL Go Discussion Forum
Hi Ki Xu,

The CEL internals depend on the global proto registry in order to establish the type and fields of the proto-based descriptor. Since the go sources are being generated via gogoproto, some of the usual linkages which we would expect to be present aren't. I'm going to see what I can do, but it may take a little while to unwind this and provide a fix.

-Tristan

Tristan Swadell

unread,
Aug 11, 2020, 6:59:31 PM8/11/20
to ki xu, CEL Go Discussion Forum
Hi Ki Xu,

Apparently there is a step missing when it comes to registering the gogo protos:

goproto.RegisterFile(
        proto1.FileDescriptor("gogo.proto"))
    goproto.RegisterType(&v1beta1.Event{}, "k8s.io.apiserver.pkg.apis.audit.v1beta1.Event")

After registering the files, you must also register the types you'd like to use, otherwise the standard type resolution used by protobuf reflection won't work properly.

There is also a small change that needs to happen for the CEL internals in order for this to work (https://github.com/google/cel-go/pull/382). Depending on the protobuf syntax, proto2 or proto3, the primitive types are either treated as pointers or values. However, the gogo protogen generates values even for proto2 syntax files. This normally shouldn't make much of a difference, but there is a slight preference for field versus getter method reflection between proto2 and 3 in order to unify the type representation between the two. 

-Tristan

ki xu

unread,
Aug 12, 2020, 3:09:21 AM8/12/20
to CEL Go Discussion Forum
Hi Tristan,

Thanks for the info and really fast response, the patch works on my test. 

best regards,
ki xu
Reply all
Reply to author
Forward
0 new messages