feat(rules): support redirects and pipe variables in when clauses#203
feat(rules): support redirects and pipe variables in when clauses#203
redirects and pipe variables in when clauses#203Conversation
The `when` clause could only reference env, flags, args, and paths, making it impossible to write rules based on shell redirect operators or pipeline position. This prevented use cases like requiring output redirects for noisy commands or blocking `curl | sh` patterns. Add two new context variables available in CEL `when` expressions: - `redirects`: list of redirect operators (type, operator, target, descriptor) attached to the command - `pipe`: object with stdin/stdout bools indicating pipeline position Extract redirect/pipe metadata from the tree-sitter AST during command parsing via `extract_commands_with_metadata`, thread it through evaluate_compound -> evaluate_command_inner -> build_expr_context, and register as CEL variables. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello, 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 extends the capabilities of rule evaluation by exposing shell-level constructs like redirects and pipes to the Highlights
Changelog
Using Gemini Code AssistThe 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
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 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
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #203 +/- ##
==========================================
+ Coverage 89.53% 89.57% +0.04%
==========================================
Files 49 49
Lines 9574 9808 +234
==========================================
+ Hits 8572 8786 +214
- Misses 1002 1022 +20
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The `>|` operator in the docs markdown table contained an unescaped pipe character, breaking the table rendering. Pipeline unit tests were separate functions instead of parameterized cases, violating the repository's rstest style guide. Escape `|` in the operator table and consolidate pipeline tests into a single `#[rstest]` parameterized test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tadata evaluate_command() always passed empty redirects and default PipeInfo to evaluate_command_inner(), so `when` clauses referencing `redirects` or `pipe` always saw empty values for single commands. This meant rules like `when: 'redirects.exists(r, r.type == "output")'` never matched when evaluated through the evaluate_command path. Fix evaluate_command() to extract metadata via extract_commands_with_metadata() for single commands, and add evaluate_command_with_metadata() for callers (like the adapter) that already have pre-extracted metadata. Update the adapter to use extract_commands_with_metadata() and pass the metadata through.
When extract_commands_with_metadata() failed (e.g., SyntaxError from malformed input), the fallback was changed from vec![command.clone()] to vec![], which hit the commands.is_empty() branch and returned default_action() without evaluating any rules. This could silently allow commands that should be denied. Restore the original behavior: on parse failure, fall back to an ExtractedCommand containing the raw command with empty metadata.
The note stated that redirects are only populated through evaluate_compound, but evaluate_command now also extracts and passes redirect/pipe metadata for single commands.
…ipe-when-variables # Conflicts: # docs/src/content/docs/rule-evaluation/when-clause.md # src/rules/expr_evaluator.rs # src/rules/rule_engine.rs
The pipeline handler computed PipeInfo based solely on the child's index position, ignoring the parent pipe context. For nested pipelines like `cmd1 | (cmd2 | cmd3)`, cmd2 would get stdin=false instead of stdin=true, causing when clauses like `pipe.stdin` to incorrectly evaluate to false. Compose parent and local pipe context with logical OR so that nested pipeline commands inherit the outer pipeline's position.
Why
whenclauses cannot reference redirect (>,>>,2>&1) or pipe (|) information for rule evaluationwhenexpressionscurl | sh)What
redirectsandpipeavailable inwhenexpressionsredirects: list of redirect operators attached to the command (type, operator, target, descriptor)pipe: pipeline position of the command (stdin, stdout)