Conversation
intent(rules): expose every value of repeated and aliased flags to `when` clauses so security policies can inspect all of them at once (e.g. `gh api graphql -f query=mutation...`, `curl -d @/etc/passwd`, `docker run -v /etc/shadow:...`). decision(rules): introduce a new `definitions.flag_groups` block plus a `<flag:name>` pattern placeholder rather than overloading the existing `flags` map. The placeholder collects every occurrence of any aliased flag and surfaces them through a new `flag_groups[name]` CEL variable whose values are always lists, matching how clap/cobra/argparse expose multi-value flags. rejected(rules): extend the existing `flags` map with mixed string/list values — type-inconsistent variables are bug-prone in CEL. rejected(rules): convert `flags` itself to lists — breaking change that invalidates every existing `when: flags.X == ...` rule. constraint(rules): CEL `has()` macro does not support bracket notation, so `flag_groups[name]` is always seeded with empty lists for every group declared in `definitions.flag_groups`. This guarantees that `flag_groups["name"]` never raises an undeclared-reference error. learned(rules): the matching engine's `should_consume_as_value` heuristic refuses to consume a trailing wildcard as a flag value (because that would leave nothing for the wildcard to match). For `<flag:name>` we bypass this heuristic — the placeholder is unambiguously a flag-with-value construct, so the next lex token is always its value. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #278 +/- ##
==========================================
+ Coverage 89.50% 89.55% +0.04%
==========================================
Files 52 52
Lines 10731 11010 +279
==========================================
+ Hits 9605 9860 +255
- Misses 1126 1150 +24
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:
|
intent(docs): unblock the docs site CI build that was failing with "invalid hash" link validation errors on the new flag_groups section. learned(docs): Starlight slugifies `### \`flag_groups\` -- Captured ...` to `flag_groups--captured-...` (collapsing the surrounding spaces into a single dash on each side, leaving exactly two dashes around `--`). My initial cross-references included four dashes which the link validator rejected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
intent(test): consolidate the three validation-error tests in `flag_group_evaluation.rs` and the four `flag_groups` CEL access tests in `expr_evaluator.rs` into single `#[rstest]` parameterized functions, matching CLAUDE.md's testing convention. Devin Review flagged both as duplicated test bodies that differ only in input/expected values. intent(docs): document that the `<flag:name>` placeholder also recognizes `=`-joined short flags (e.g. `-f=value`), not just `--field=value`. Gemini Code Assist pointed out the omission was confusing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…flag gap intent(rules): close two follow-up gaps in the new `<flag:name>` feature before merging — one was a silent miscompile risk, the other a missing reminder for future contributors. decision(rules/parser): error out when `<flag:name>` appears inside an Optional group `[...]`. The matcher's `optional_flags_absent` only knows about `FlagWithValue` aliases, so it cannot tell that grouped flags are still present in the command tokens — taking the "absent" path would silently drop captured values and produce an incorrect match. Failing fast at parse time is safer than supporting it half-heartedly. decision(rules/matcher, config/model): document the bool-flag limitation with TODO comments next to the matcher arm and the `definitions.flag_groups` field. The original spec deferred boolean flag support, and committing the constraint inline keeps the gap visible to future contributors instead of relying on the PR description. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
intent(test): teach the matcher-level test helper `build_schema_from_pattern` about `FlagGroupRef` so unit tests using `<flag:name>` build the same value-flag schema the production `rule_engine::build_flag_schema` does. Without it, `parse_command` would mis-tokenize `-f query=hello` as a boolean flag plus a positional `query=hello`, silently breaking any matcher-level test exercising the new placeholder. intent(docs): add the missing PR link to the `flag_groups` release-notes heading per CLAUDE.md's release-notes format requirement. learned(test): the matcher submodule keeps its own copy of the schema- building helpers, so production refactors that touch `rule_engine::collect_value_flags` need to be mirrored here too. Added a `flag_group_ref_matching` rstest case that would have caught this gap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
whenclauses cannot inspect every value of a repeated or aliased flaggh api graphql -f query=mutation{...} -f variables={}should expose all-fvalues to detect mutationscurl -d @/etc/passwd -d "innocent=data"should fire when even one value sends a sensitive filedocker run -v /etc/shadow:/leak:ro -v ./app:/appshould expose every--volumemount, not just the last oneflagsmap is last-wins: when the same flag appears multiple times, only one value survives-fand--fieldland under separate keys (flags.fvsflags["field"]), so awhenclause cannot check them as a single setWhat
definitions.flag_groupsto declare named groups of aliased flags<flag:name>placeholder that matches any flag in a named groupflag_groups[name]CEL variable, always as a listflag_groups[name]is always a list, even when only one value matches, so CEL macros (exists,all,size) work uniformlydefinitions.flag_groupsis seeded as an empty list[]even when the matched rule did not capture any value, soflag_groups["name"]never raises an undeclared-reference error<flag:undefined>is rejected at config load time as a validation errorflagsmap and<var:name>/<path:name>placeholders are unchanged (additive, non-breaking)