Skip to content

feat(rules): add typed variable definitions (definitions.vars) with <var:name> placeholder#201

Merged
fohte merged 4 commits intomainfrom
fohte/vars-placeholder-design
Mar 13, 2026
Merged

feat(rules): add typed variable definitions (definitions.vars) with <var:name> placeholder#201
fohte merged 4 commits intomainfrom
fohte/vars-placeholder-design

Conversation

@fohte
Copy link
Owner

@fohte fohte commented Mar 13, 2026

Why

  • Match command arguments against a typed list of allowed values in pattern matching

Example

Current:

rules:
# Patterns become long and hard to read as the number of allowed values grows
  - allow: aws ec2 terminate-instances --instance-ids i-abc123|i-def456|i-ghi789

# Path notation differences (./tests/run vs tests/run) cannot be absorbed
  - allow: bash tests/run

Desired:

definitions:
  vars:
    instance-ids:
      values: [i-abc123, i-def456, i-ghi789]
    test-script:
      type: path
      values: [./tests/run]

rules:
  - allow: aws ec2 terminate-instances --instance-ids <var:instance-ids>
  - allow: bash <var:test-script>  # matches both ./tests/run and tests/run

What

  • Add typed variable definitions via definitions.vars, referenced from rule patterns with the <var:name> placeholder
  • Expose matched variables as vars context variable in CEL expressions

Open with Devin

… `<var:name>` placeholder

Pattern matching lacked a way to match command arguments against a
typed list of allowed values. Long alternations (e.g., `a|b|c|d`)
had to be inlined in patterns, and path arguments couldn't be
canonicalized for robust matching across different path forms.

Add `definitions.vars` with typed variable definitions:
- `type: literal` (default): exact string match
- `type: path`: canonicalize both sides before comparison, with
  normalize_path fallback when the file doesn't exist
- `<var:name>` placeholder in rule patterns
- Config validation, merge strategy, and JSON schema
- `vars` context variable in CEL expressions

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@gemini-code-assist
Copy link

Summary of Changes

Hello, 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 introducing a new mechanism for defining and using typed variables within configuration files. This feature addresses the challenge of managing complex rule patterns that involve numerous allowed values or require specific matching logic for path-like arguments. By centralizing variable definitions, it improves the readability and maintainability of rules, making it easier to express sophisticated matching criteria without verbose pattern syntax.

Highlights

  • Typed Variable Definitions: Introduced definitions.vars in the configuration, allowing users to define typed variables with lists of allowed values.
  • Placeholder for Rule Patterns: Added the <var:name> placeholder, enabling rule patterns to reference these defined variables for more flexible and readable matching.
  • Variable Types: Supported literal (exact string match) and path (canonicalized path match) types for variables, enhancing matching behavior for different argument types.
  • CEL Expression Context: Exposed matched variables as a vars context variable in CEL expressions, allowing for dynamic rule evaluation based on captured variable values.
Changelog
  • docs/src/content/docs/configuration/schema.md
    • Updated the definitions section to include variables and added a new section for definitions.vars with details on type and values.
  • docs/src/content/docs/pattern-syntax/overview.md
    • Updated the pattern syntax table to include the new <var:name> placeholder.
  • docs/src/content/docs/pattern-syntax/placeholders.md
    • Added a new section detailing Variable References (<var:name>), including how to define and use them, variable types, path normalization, and restrictions.
    • Updated restrictions for wrapper patterns to include variable references.
  • schema/runok.schema.json
    • Added the vars property to the definitions object.
    • Defined new JSON schemas for VarDefinition and VarType.
  • src/config/model.rs
    • Added vars field to the Definitions struct.
    • Introduced VarType enum and VarDefinition struct to model typed variables.
    • Implemented validation logic to prevent placeholder references within definitions.vars values.
    • Added merge_vars function to handle merging of variable definitions in configuration.
  • src/rules/expr_evaluator.rs
    • Added a vars field to ExprContext to hold matched variables.
    • Included the vars context variable in CEL expression evaluation.
  • src/rules/pattern_matcher/mod.rs
    • Implemented matching logic for the new PatternToken::VarRef.
    • Added a check to disallow VarRef within wrapper patterns.
  • src/rules/pattern_matcher/token_matching.rs
    • Added match_var_ref function to perform matching based on variable type (literal or path).
    • Introduced resolve_var to retrieve variable definitions.
    • Implemented canonicalize_or_normalize for robust path handling.
  • src/rules/pattern_parser.rs
    • Added VarRef variant to the PatternToken enum.
    • Updated parse_placeholder to correctly parse <var:name> into a VarRef token.
  • src/rules/rule_engine.rs
    • Initialized the vars field in build_expr_context.
  • tests/integration/main.rs
    • Added the var_ref_evaluation module to the integration tests.
  • tests/integration/var_ref_evaluation.rs
    • Added new integration tests covering var:name with literal and path types, deny rules, and coexistence with path:name.
Activity
  • The author, fohte, created this pull request to introduce typed variable definitions and their usage in rule patterns.
  • The changes involve updates across documentation, configuration schema, core logic for parsing and matching, and new integration tests to ensure functionality.
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.

@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 97.23926% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.56%. Comparing base (25c6749) to head (aa25f80).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/rules/pattern_matcher/mod.rs 92.15% 8 Missing ⚠️
src/rules/pattern_matcher/token_matching.rs 95.65% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #201      +/-   ##
==========================================
+ Coverage   89.26%   89.56%   +0.30%     
==========================================
  Files          47       47              
  Lines        9046     9364     +318     
==========================================
+ Hits         8075     8387     +312     
- Misses        971      977       +6     
Flag Coverage Δ
Linux 89.43% <97.23%> (+0.27%) ⬆️
macOS 90.87% <97.23%> (+0.26%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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 typed variable definitions (definitions.vars) to the configuration, enabling the use of <var:name> placeholders in rules for both literal and path-based matching. The changes include updates to the configuration model, JSON schema, pattern parsing, and matching logic, along with new documentation and integration tests. However, the vars field in ExprContext is currently unpopulated, which means matched variables are not exposed to CEL expressions in when clauses. Additionally, several new validation and negative test cases could be refactored into parameterized rstest functions to improve code maintainability and align with repository style guidelines.

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 bugs or issues to report.

Open in Devin Review

fohte added 2 commits March 14, 2026 01:34
Pattern matching with `<var:name>` placeholders only validated whether
a command token was in the allowed values list, but did not capture
the actual matched value. This meant `when` clauses could not inspect
which specific value was matched, limiting conditional deny rules.

Add `MatchCaptures` struct to carry both wildcard and var captures
from pattern matching. Thread a `RefCell<HashMap>` through `match_engine`
to accumulate var captures during recursive matching, then populate
`ExprContext.vars` so CEL expressions can reference captured values.
…ameterized cases

Separate test functions that only differed in input values made it
harder to see that they tested the same invariant. Consolidate
`validate_rejects_var_ref_in_definitions_vars` / `validate_rejects_path_ref_in_definitions_vars`
into a single parameterized `validate_rejects_placeholder_in_definitions_vars`,
and merge three `match_var_ref` negative tests into `match_var_ref_negative_cases`.
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 found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

When pattern matching backtracked (e.g., Optional "with" branch fails
and falls back to "without"), wildcard captures and `after_double_dash`
were properly saved/restored, but `var_captures` was not. This caused
`<var:name>` captures from failed branches to persist, contaminating
the `vars` map passed to `when` clause CEL expressions.

Save and restore `var_captures` at all six backtracking points in
`match_engine`: Wildcard, Alternation (direct and `=`-joined),
FlagWithValue (space-separated and `=`-joined), and Optional.
@fohte fohte merged commit ffee2ec into main Mar 13, 2026
10 checks passed
@fohte fohte deleted the fohte/vars-placeholder-design branch March 13, 2026 17:04
@fohte-bot fohte-bot bot mentioned this pull request Mar 13, 2026
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