Add Sigma rule-logic evaluator + --check-rule#13
Merged
Conversation
Implements the core of the merged design doc: evaluate a command against a Sigma rule's detection/condition logic with three-valued (Kleene) logic. Synthesizes an event (CommandLine/Image/OriginalFileName) from the parsed command; fields it can't see (ParentImage, hashes, registry) make the rule INDETERMINATE rather than a false claim. - src/sigma_eval.rs: field-match modifiers (contains/startswith/endswith/ all + wildcard globs), search forms (fields/list-of-maps/keywords), a recursive-descent condition parser (and/or/not/N-of/all-of/them), and FIRES/NO-FIRE/INDETERMINATE verdicts with missing-field reporting. - --check-rule <RULE.yml>: per-command verdicts against one rule. - +7 tests (39 total). Next: wire into --sigma for --coverage-gaps.
There was a problem hiding this comment.
Pull request overview
Adds a Sigma rule-logic evaluator to opseclint so a command line can be evaluated against a Sigma rule’s actual detection:/condition: logic using three-valued (Kleene) outcomes (FIRES / NO-FIRE / INDETERMINATE), and exposes it via a new --check-rule CLI mode.
Changes:
- Introduces
src/sigma_eval.rsimplementing Sigma detection parsing + condition evaluation with three-valued logic. - Adds
--check-rule <RULE.yml>mode to evaluate each parsed command in the input against a single Sigma rule and print per-line outcomes. - Documents the new mode and updates the project roadmap in
README.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/sigma_eval.rs | New Sigma detection/condition parser + three-valued evaluator with unit tests. |
| src/main.rs | New --check-rule CLI option and execution path to run the evaluator as a distinct mode. |
| README.md | Adds usage/docs for --check-rule and marks the evaluator feature as complete. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+460
to
+464
| let terns: Vec<Ternary> = matching_ids(pat, searches) | ||
| .iter() | ||
| .filter_map(|id| searches.get(*id)) | ||
| .map(|s| eval_search(s, event)) | ||
| .collect(); |
Comment on lines
+75
to
+76
| #[arg(long, value_name = "RULE.yml")] | ||
| check_rule: Option<String>, |
|
|
||
| Beyond technique-tag matching, opseclint can evaluate a command against a Sigma | ||
| rule's actual `detection:`/`condition:` logic and report, per command, whether it | ||
| **FIRES**, **NO-FIRE**s, or is **INDETERMINATE** — the last meaning the rule keys |
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.
Implements the core of the merged design doc: evaluate a command against a Sigma rule's real
detection:/condition:logic, not just its ATT&CK technique tag.The idea: opseclint has a command line, not a full host event, so it synthesizes the fields it can legitimately know (
CommandLine,Image,OriginalFileName) and evaluates with three-valued (Kleene) logic —FIRES/NO-FIRE/INDETERMINATE. A rule keyed on a field a static analyzer can't see (e.g.ParentImage, a hash) is INDETERMINATE (with the missing field named), so it abstains honestly rather than making a false claim.What's in it (
src/sigma_eval.rs):contains/startswith/endswith/all+*/?globs); unsupported modifiers (re/cidr/base64) → INDETERMINATEconditionparser:and/or/not/parens/N of/all of/them--check-rule <RULE.yml>CLI surface; verified end-to-end against a real Sigma rule+7 tests (39 total), fmt/clippy clean. Next step (separate PR): wire the evaluator into
--sigmaenrichment and add--coverage-gaps.