cel-go
moduleThis package is not in the latest version of its module.
Details
Validgo.mod file
The Go module system was introduced in Go 1.11 and is the official dependency management solution for Go.
Redistributable license
Redistributable licenses place minimal restrictions on how software can be used, modified, and redistributed.
Tagged version
Modules with tagged versions give importers more predictable builds.
Stable version
When a project reaches major version v1 it is considered stable.
- Learn more about best practices
Repository
Links
README¶
Common Expression Language
The Common Expression Language (CEL) is a non-Turing complete language designedfor simplicity, speed, safety, and portability. CEL's C-likesyntax looksnearly identical to equivalent expressions in C++, Go, Java, and TypeScript.
// Check whether a resource name starts with a group name.resource.name.startsWith("/groups/" + auth.claims.group)// Determine whether the request is in the permitted time window.request.time - resource.age < duration("24h")// Check whether all resource names in a list match a given filter.auth.claims.email_verified && resources.all(r, r.startsWith(auth.claims.email))A CEL "program" is a single expression. The examples have been tagged asjava,go, andtypescript within the markdown to showcase the commonalityof the syntax.
CEL is ideal for lightweight expression evaluation when a fully sandboxedscripting language is too resource intensive. To get started, try theCodelab.
Overview
Determine the variables and functions you want to provide to CEL. Parse andcheck an expression to make sure it's valid. Then evaluate the output ASTagainst some input. Checking is optional, but strongly encouraged.
Environment Setup
Let's exposename andgroup variables to CEL using thecel.Variableenvironment option:
import "github.com/google/cel-go/cel"env, err := cel.NewEnv( cel.Variable("name", cel.StringType), cel.Variable("group", cel.StringType),)That's it. The environment is ready to be used for parsing and type-checking.CEL supports all the usual primitive types in addition to lists, maps, as wellas first-class support for JSON and Protocol Buffers.
Parse and Check
The parsing phase indicates whether the expression is syntactically valid andexpands any macros present within the environment. Parsing and checking aremore computationally expensive than evaluation, and it is recommended thatexpressions be parsed and checked ahead of time.
The parse and check phases are combined for convenience into theCompilestep:
ast, issues := env.Compile(`name.startsWith("/groups/" + group)`)if issues != nil && issues.Err() != nil { log.Fatalf("type-check error: %s", issues.Err())}prg, err := env.Program(ast)if err != nil { log.Fatalf("program construction error: %s", err)}Thecel.Program generated at the end of parse and check is stateless,thread-safe, and cachable.
Type-checking is an optional, but strongly encouraged step that can reject somesemantically invalid expressions using static analysis. Additionally, the checkproduces metadata which can improve function invocation performance and objectfield selection at evaluation-time.
Macros
Macros are optional but enabled by default. Macros were introduced tosupport optional CEL features that might not be desired in all use caseswithout the syntactic burden and complexity such features might desire ifthey were part of the core CEL syntax. Macros are expanded at parse time andtheir expansions are type-checked at check time.
For example, when macros are enabled it is possible to support boundediteration / fold operators. The macrosall,exists,exists_one,filter,andmap are particularly useful for evaluating a single predicate againstlist and map values.
// Ensure all tweets are less than 140 charstweets.all(t, t.size() <= 140)Thehas macro is useful for unifying field presence testing logic acrossprotobuf types and dynamic (JSON-like) types.
// Test whether the field is a non-default value if proto-based, or defined// in the JSON case.has(message.field)Both cases traditionally require special syntax at the language level, butthese features are exposed via macros in CEL.
Evaluate
Now, evaluate for fun and profit. The evaluation is thread-safe and side-effectfree. Many different inputs can be sent to the samecel.Program and if fieldsare present in the input, but not referenced in the expression, they areignored.
// The `out` var contains the output of a successful evaluation.// The `details' var would contain intermediate evaluation state if enabled as// a cel.ProgramOption. This can be useful for visualizing how the `out` value// was arrive at.out, details, err := prg.Eval(map[string]interface{}{ "name": "/groups/acme.co/documents/secret-stuff", "group": "acme.co"})fmt.Println(out) // 'true'Partial State
What ifname hadn't been supplied? CEL is designed for this case. Indistributed apps it is not uncommon to have edge caches and central services.If possible, evaluation should happen at the edge, but it isn't always possibleto know the full state required for all values and functions present in theCEL expression.
To improve the odds of successful evaluation with partial state, CEL usescommutative logical operators&&,||. If an error or unknown value (not thesame thing) is encountered on the left-hand side, the right hand side isevaluated also to determine the outcome. While it is possible to implementevaluation with partial state without this feature, this method was chosenbecause it aligns with the semantics of SQL evaluation and because it's morerobust to evaluation against dynamic data types such as JSON inputs.
In the following truth-table, the symbols<x> and<y> represent error orunknown values, with the? indicating that the branch is not taken due toshort-circuiting. When the result is<x, y> this means that the both argsare possibly relevant to the result.
| Expression | Result |
|---|---|
false && ? | false |
true && false | false |
<x> && false | false |
true && true | true |
true && <x> | <x> |
<x> && true | <x> |
<x> && <y> | <x, y> |
true || ? | true |
false || true | true |
<x> || true | true |
false || false | false |
false || <x> | <x> |
<x> || false | <x> |
<x> || <y> | <x, y> |
In the cases where unknowns are expected,cel.EvalOptions(cel.OptTrackState)should be enabled. Thedetails value returned byEval() will contain theintermediate evaluation values and can be provided to theinterpreter.Prunefunction to generate a residual expression. e.g.:
// Residual when `name` omitted:name.startsWith("/groups/acme.co")This technique can be useful when there are variables that are expensive tocompute unless they are absolutely needed. This functionality will be thefocus of many future improvements, so keep an eye out for more goodness here!
Errors
Parse and check errors have friendly error messages with pointers to where theissues occur in source:
ERROR: <input>:1:40: undefined field 'undefined' | TestAllTypes{single_int32: 1, undefined: 2} | .......................................^`,Both the parsed and checked expressions contain source position informationabout each node that appears in the output AST. This information can be usedto determine error locations at evaluation time as well.
Install
CEL-Go supportsmodules and uses semantic versioning. For more infosee theGo Modules docs.
And of course, there is always the option to build from source directly.
Common Questions
Why not JavaScript, Lua, or WASM?
JavaScript and Lua are rich languages that require sandboxing to executesafely. Sandboxing is costly and factors into the "what will I let usersevaluate?" question heavily when the answer is anything more than O(n)complexity.
CEL evaluates linearly with respect to the size of the expression and the inputbeing evaluated when macros are disabled. The only functions beyond thebuilt-ins that may be invoked are provided by the host environment. Whileextension functions may be more complex, this is a choice by the applicationembedding CEL.
But, why not WASM? WASM is an excellent choice for certain applications andis far superior to embedded JavaScript and Lua, but it does not have supportfor garbage collection and non-primitive object types require semi-expensivecalls across modules. In most cases CEL will be faster and just as portablefor its intended use case, though for node.js and web-based execution CELtoo may offer a WASM evaluator with direct to WASM compilation.
Do I need to Parseand Check?
Checking is an optional, but strongly suggested step in CEL expressionvalidation. It is sufficient in some cases to simply parse and rely on theruntime bindings and error handling to do the right thing.
Where can I learn more about the language?
- See theCEL Spec for the specification and conformance test suite.
- Ask for support on theCEL Go Discuss Google group.
Where can I learn more about the internals?
- SeeGoDoc to learn how to integrate CEL into services written in Go.
- See theCEL C++ toolchain (under development) for information about howto integrate CEL evaluation into other environments.
How can I contribute?
- SeeCONTRIBUTING.md to get started.
- UseGitHub Issues to request features or report bugs.
Some tests don't work withgo test?
A handful of tests rely onBazel. In particular dynamic proto supportat check time and the conformance test driver require Bazel to coordinatethe test inputs:
bazel test ...License
Released under theApache License.
Directories¶
| Path | Synopsis |
|---|---|
Package cel defines the top-level interface for the Common Expression Language (CEL). | Package cel defines the top-level interface for the Common Expression Language (CEL). |
Package checker defines functions to type-checked a parsed expression against a set of identifier and function declarations. | Package checker defines functions to type-checked a parsed expression against a set of identifier and function declarations. |
decls Package decls provides helpers for creating variable and function declarations. | Package decls provides helpers for creating variable and function declarations. |
codelabmodule | |
Package common defines types and utilities common to expression parsing, checking, and interpretation | Package common defines types and utilities common to expression parsing, checking, and interpretation |
ast Package ast declares data structures useful for parsed and checked abstract syntax trees | Package ast declares data structures useful for parsed and checked abstract syntax trees |
containers Package containers defines types and functions for resolving qualified names within a namespace or type provided to CEL. | Package containers defines types and functions for resolving qualified names within a namespace or type provided to CEL. |
debug Package debug provides tools to print a parsed expression graph and adorn each expression element with additional metadata. | Package debug provides tools to print a parsed expression graph and adorn each expression element with additional metadata. |
decls Package decls contains function and variable declaration structs and helper methods. | Package decls contains function and variable declaration structs and helper methods. |
env Package env provides a representation of a CEL environment. | Package env provides a representation of a CEL environment. |
functions Package functions defines the standard builtin functions supported by the interpreter | Package functions defines the standard builtin functions supported by the interpreter |
operators Package operators defines the internal function names of operators. | Package operators defines the internal function names of operators. |
overloads Package overloads defines the internal overload identifiers for function and operator overloads. | Package overloads defines the internal overload identifiers for function and operator overloads. |
runes Package runes provides interfaces and utilities for working with runes. | Package runes provides interfaces and utilities for working with runes. |
stdlib Package stdlib contains all of the standard library function declarations and definitions for CEL. | Package stdlib contains all of the standard library function declarations and definitions for CEL. |
types Package types contains the types, traits, and utilities common to all components of expression handling. | Package types contains the types, traits, and utilities common to all components of expression handling. |
types/pb Package pb reflects over protocol buffer descriptors to generate objects that simplify type, enum, and field lookup. | Package pb reflects over protocol buffer descriptors to generate objects that simplify type, enum, and field lookup. |
types/ref Package ref contains the reference interfaces used throughout the types components. | Package ref contains the reference interfaces used throughout the types components. |
types/traits Package traits defines interfaces that a type may implement to participate in operator overloads and function dispatch. | Package traits defines interfaces that a type may implement to participate in operator overloads and function dispatch. |
Package ext contains CEL extension libraries where each library defines a related set of constants, functions, macros, or other configuration settings which may not be covered by the core CEL spec. | Package ext contains CEL extension libraries where each library defines a related set of constants, functions, macros, or other configuration settings which may not be covered by the core CEL spec. |
Package interpreter provides functions to evaluate parsed expressions with the option to augment the evaluation with inputs and functions supplied at evaluation time. | Package interpreter provides functions to evaluate parsed expressions with the option to augment the evaluation with inputs and functions supplied at evaluation time. |
functions Package functions defines the standard builtin functions supported by the interpreter and as declared within the checker#StandardDeclarations. | Package functions defines the standard builtin functions supported by the interpreter and as declared within the checker#StandardDeclarations. |
Package parser declares an expression parser with support for macro expansion. | Package parser declares an expression parser with support for macro expansion. |
gen Package gen contains all of the ANTLR-generated sources used by the cel-go parser. | Package gen contains all of the ANTLR-generated sources used by the cel-go parser. |
policymodule | |
replmodule | |
appenginemodule | |
servermodule | |
Package test provides a YAML-serializable test suite for CEL tests. | Package test provides a YAML-serializable test suite for CEL tests. |
bench Package bench defines a structure for benchmarked tests against custom CEL environments. | Package bench defines a structure for benchmarked tests against custom CEL environments. |
toolsmodule |