Building a CEL engine for .NET
Why I wrote Celly — a from-scratch, conformance-passing CEL implementation for .NET — and the protovalidate library that fell out of it
TL;DR — I built Celly, a native C# implementation of Google’s Common Expression Language. It passes 100% of the official conformance suite, and along the way I ended up shipping the first protovalidate library for .NET. It’s on NuGet, and the docs are at bsid.io/celly.
ONE RULE, WRITTEN ONCE user.age >= 18 && user.country in ['US','CA'] EVALUATED AGAINST CHANGING DATA { age: 25, country: 'US' } { age: 16, country: 'US' } { age: 30, country: 'FR' } allow deny deny THE SAME ENGINE RUNS IN Kubernetes Envoy Cloud IAM protovalidate
What’s CEL, and why did I care?
CEL (Common Expression Language) is a small, safe expression language from Google. You’ve used something built on it even if you’ve never heard of it — it’s the language behind Kubernetes admission policies, Envoy’s RBAC rules, Google Cloud IAM conditions, and gRPC’s protovalidate. The idea is simple: let people write expressions like
request.auth.groups.exists(g, g == "admin") || resource.owner == request.auth.subject
as data — strings in a config file — and evaluate them safely at runtime. No arbitrary code execution, guaranteed to terminate, strongly typed.
Why CEL, and not just a scripting language?
Any time you need logic to live outside your compiled code — “which requests are allowed,” “when does this alert fire,” “is this payload valid” — you’ve got a few options, and most of them are traps:
... continue reading