-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CEL expressions #112
Comments
The envoy attriubutes are available through a WASM-ABI, which in rust, and for Envoy, looks like pub fn get_property(path: Vec<&str>) -> Result<Option<Bytes>, Status> There is no way to add all the attributes to the CEL context and make then available to expressions directly. So the question is about how to make envoy attributes (and I underline Envoy here) on the CEL expressions. Approach 1: CEL functions to the rescuepredicates:
- "get_property(request.url_path).startsWith('/get')" Here. we have defined a custom function PROS: we can do this now Approach 2: CEL Lazy values Or CEL dynamic valuesI came across these two RFE on the cel-rust repo:
I would say both would enable us to implement CEL expressions in a clean way, i.e. predicates:
- "request.url_path.startsWith('/get')" PROS: Clean and straightforward
|
There is a third option, which is what actually happens today already: parse the expression and replace member navigation in the AST directly. Today, when you have a condition that says Also, there is more work that I think should happen as part of this: align authorino & limitador's lingo (or at least at the Kuadrant level). I was thinking having the so-called |
Also, I think having option 1, probably more like |
I like the function option. I don't believe adding this precludes us from allowing |
And this is NOT public API here. We can absolutely replace |
I think I have a contingency plan here: just have everything become cel expressions (but the
|
Something like this? From https://docs.rs/cel-parser/0.7.1/cel_parser/ast/struct.ExpressionReferences.html let expression = parse("foo.bar == true").unwrap();
let references = expression.references();
assert_eq!(vec!["foo"], references.variables()); Interesting idea... could work. But we would need the entire variable instead of the first level. As in the example |
Interesting about EDIT: we are already doing that for auth service https://github.com/Kuadrant/wasm-shim/blob/main/src/service/auth.rs#L55 Makes sense to me |
So here's how this looks like: let exp = cel_parser::parse(
"request.headers.all(n, n in auth.allowedHeaders) && auth.identity.secure" // our predicate
).unwrap();
let mut all = Vec::default();
properties(&exp, &mut all, &mut Vec::default()); // gets all member navigation from the AST
assert_eq!(all[0], vec!["request", "headers"]);
assert_eq!(all[1], vec!["auth", "allowedHeaders"]);
assert_eq!(all[2], vec!["auth", "identity", "secure"]);
assert_eq!(all.len(), 3); So the idea is to use that This is from an actual passing test locally. Am now working on the second part, which is lazily populating all that data. |
Also, on that front, I wasn't up to date:
We are NOT having |
Yes, using a |
@alexsnaps I was thinking on start working on this issue. It is being unassigned, but I feel you already started. What's the current state? |
Yeah, I'm on it, should be done by EOD |
Looking forward to seeing the implementation of properties(&exp, &mut all, &mut Vec::default()); |
In rebase hell, but... I won't have you wait any longer ;) fn properties<'e>(
exp: &'e Expression,
all: &mut Vec<Vec<&'e str>>,
path: &mut Vec<&'e str>,
) {
match exp {
Expression::Arithmetic(e1, _, e2)
| Expression::Relation(e1, _, e2)
| Expression::Ternary(e1, _, e2)
| Expression::Or(e1, e2)
| Expression::And(e1, e2) => {
properties(e1, all, path);
properties(e2, all, path);
}
Expression::Unary(_, e) => {
properties(e, all, path);
}
Expression::Member(e, a) => {
if let Member::Attribute(attr) = &**a {
path.insert(0, attr.as_str())
}
properties(e, all, path);
}
Expression::FunctionCall(name, target, args) => {
if let Some(target) = target {
properties(target, all, path);
}
for e in args {
properties(e, all, path);
}
}
Expression::List(e) => {
for e in e {
properties(e, all, path);
}
}
Expression::Map(v) => {
for (e1, e2) in v {
properties(e1, all, path);
properties(e2, all, path);
}
}
Expression::Atom(_) => {}
Expression::Ident(v) => {
if path.len() > 0 {
path.insert(0, v.as_str());
all.push(path.clone());
path.clear();
}
}
}
} |
From https://github.com/clarkmcc/cel-rust/blob/master/parser/src/ast.rs#L155-L203, I see. Looks like a good RFE for the Expression public API in the https://github.com/clarkmcc/cel-rust/ so we do not need to maintain this ;) |
Yeah... that's been an on-going discussion again lately... tho, really unsure how the "laziness problem" is best tackled from the interpreter's perspective. Plus there is bunch of work that I think should happen before that, e.g. proper protobuf interop. Which, for one would be a huge benefit to us, but would probably also impact how to best go about this... anyways... problem for future us, let's focus on our release for now 😛 |
Currently, conditions, matches (or whatever you want to call them), are expressed as a
PatternExpressions
Which in configuration looks like:
The ask here is to leverage the Common Expression Language to implement predicates that evaluate to
bool
.Something like
Note that data type on the configuration: CEL expressions will be strings that need to be parsed.
The text was updated successfully, but these errors were encountered: