Skip to content

feat(rules): implement CEL expression evaluator for when-clause conditions#8

Merged
fohte merged 1 commit intomainfrom
fohte/impl-runok-init-cel-evaluator
Feb 10, 2026
Merged

feat(rules): implement CEL expression evaluator for when-clause conditions#8
fohte merged 1 commit intomainfrom
fohte/impl-runok-init-cel-evaluator

Conversation

@fohte
Copy link
Owner

@fohte fohte commented Feb 10, 2026

Why

  • The rule engine requires a way to express conditions beyond command patterns in when clauses, such as checking environment variables, flags, and argument values

What

  • Allow when clauses to evaluate conditional expressions using CEL (Common Expression Language)
    • Access environment variables via env.VAR == 'value'
    • Access parsed flags via flags.name == 'value'
    • Access positional arguments via args[0].startsWith('prefix')
    • Access definitions.paths path lists via paths.sensitive
    • Support &&, ||, ! logical operators
    • Handle invalid expressions with proper error types (Parse, Eval, TypeError)

Open with Devin

…tions

The rule engine needs a way to evaluate conditional expressions (when
clauses) that go beyond simple pattern matching — e.g. checking
environment variables, parsed flags, positional arguments, and path
lists. CEL (Common Expression Language) provides a non-Turing-complete,
safe expression language ideal for this use case.

Add `expr_evaluator` module with:
- `ExprContext` struct providing access to env vars, flags, args, and
  path lists
- `evaluate()` function that compiles and executes CEL expressions
  against the context, returning a boolean result
- Support for `env.VAR`, `flags.name`, `args[0]`, `paths.listname`
  access patterns
- Support for `&&`, `||`, `!` logical operators and string methods
  like `startsWith()`
- Proper error mapping to existing `ExprError` variants (Parse, Eval,
  TypeError)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @fohte, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the rule engine's capabilities by integrating a CEL expression evaluator. This allows when clauses to move beyond simple command patterns, enabling more sophisticated and dynamic conditions based on various contextual data points. The change provides greater flexibility in defining rule triggers and improves the overall adaptability of the rule system.

Highlights

  • CEL Expression Evaluation: Implemented a Common Expression Language (CEL) evaluator to allow for more complex conditional logic in rule when clauses. This enables dynamic checks against environment variables, command-line flags, positional arguments, and predefined path lists.
  • Flexible Contextual Data Access: Introduced ExprContext to provide a structured way to pass environment variables, parsed flags, command arguments, and path lists to the CEL evaluator, making these data points easily accessible within CEL expressions.
  • Robust Error Handling: Integrated comprehensive error handling for CEL expressions, distinguishing between parsing errors, evaluation errors, and type mismatches to provide clear feedback when expressions are invalid or fail during execution.
  • Comprehensive Unit Testing: Added extensive unit tests covering various aspects of the CEL evaluator, including access to different data types (env, flags, args, paths), logical operators, combined conditions, and expected error scenarios.
Changelog
  • Cargo.lock
    • Added numerous new packages required by the cel-interpreter crate and its transitive dependencies.
    • Updated the thiserror dependency for the runok package to version 2.0.18.
    • Introduced thiserror version 1.0.69 as a dependency for cel-interpreter.
  • Cargo.toml
    • Added cel-interpreter = "=0.10.0" as a new dependency.
  • src/rules/expr_evaluator.rs
    • Added a new module expr_evaluator to handle CEL expression parsing and evaluation.
    • Defined ExprContext struct to encapsulate evaluation context (env, flags, args, paths).
    • Implemented the evaluate function to compile and execute CEL expressions against the provided context.
    • Included extensive unit tests for various CEL expression functionalities and error cases.
  • src/rules/mod.rs
    • Exported the new expr_evaluator module.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@fohte fohte merged commit 227252f into main Feb 10, 2026
2 checks passed
@fohte fohte deleted the fohte/impl-runok-init-cel-evaluator branch February 10, 2026 01:12
@fohte-bot fohte-bot bot mentioned this pull request Feb 8, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a powerful feature by integrating a CEL expression evaluator for when clauses. The implementation in src/rules/expr_evaluator.rs is well-structured and accompanied by a comprehensive test suite, which is excellent.

My main feedback is to refactor how variables are added to the CEL context to improve performance and code clarity by avoiding unnecessary data cloning and manual conversions. Using add_variable consistently for all context properties will make the code more efficient and maintainable.

Overall, this is a great addition that significantly enhances the rule engine's capabilities.

Comment on lines +21 to +42
cel_context.add_variable_from_value("env", context.env.clone());

// Convert Option<String> flags to CEL-compatible values.
// None values become null in CEL.
let flags_value: HashMap<String, cel_interpreter::Value> = context
.flags
.iter()
.map(|(k, v)| {
let val = match v {
Some(s) => cel_interpreter::Value::String(s.clone().into()),
None => cel_interpreter::Value::Null,
};
(k.clone(), val)
})
.collect();
cel_context.add_variable_from_value("flags", flags_value);

cel_context.add_variable_from_value("args", context.args.clone());

cel_context
.add_variable("paths", &context.paths)
.map_err(|e| ExprError::Eval(e.to_string()))?;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The context variables env, flags, and args are being cloned and/or manually converted before being added to the CEL context. This can be simplified and made more efficient.

The cel-interpreter crate's add_variable function works with any type that implements serde::Serialize and takes a reference, avoiding unnecessary clones. HashMap<K, V> and Vec<T> (where K, V, T are serializable) both implement Serialize.

For flags, HashMap<String, Option<String>> can be serialized directly, with None values correctly becoming null in the CEL context, which removes the need for manual conversion.

I suggest using add_variable for all context properties for consistency, better performance, and improved readability. This also makes error handling consistent across all variables.

    cel_context
        .add_variable("env", &context.env)
        .map_err(|e| ExprError::Eval(e.to_string()))?;
    cel_context
        .add_variable("flags", &context.flags)
        .map_err(|e| ExprError::Eval(e.to_string()))?;
    cel_context
        .add_variable("args", &context.args)
        .map_err(|e| ExprError::Eval(e.to_string()))?;
    cel_context
        .add_variable("paths", &context.paths)
        .map_err(|e| ExprError::Eval(e.to_string()))?;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant