Rule Matching

Audience: Customer — this page documents how rules are matched against events.

This page documents how the rule engine evaluates conditions against events to detect violations.


Condition Structure

Each rule has one or more conditions. ALL conditions must match for a violation to be created (AND logic).

{
  "conditions": [
    { "field": "toolInput", "operator": "contains", "value": "SELECT * FROM" },
    { "field": "language", "operator": "equals", "value": "sql" }
  ]
}

In this example, both conditions must be true: the tool input must contain "SELECT * FROM" and the language must be "sql".


Operators

Operator Description Example
equals Exact string match { field: "toolName", operator: "equals", value: "Bash" }
notEquals Not equal { field: "toolSuccess", operator: "notEquals", value: "true" }
contains Substring match (case-insensitive) { field: "toolInput", operator: "contains", value: "password" }
notContains Does not contain (case-insensitive) { field: "toolInput", operator: "notContains", value: "test" }
startsWith Starts with (case-insensitive) { field: "filePath", operator: "startsWith", value: "src/" }
endsWith Ends with (case-insensitive) { field: "filePath", operator: "endsWith", value: ".env" }
regex Regular expression match (case-insensitive) { field: "toolInput", operator: "regex", value: "api[_-]?key\\s*=\\s*['\"]" }
greaterThan Numeric greater than { field: "toolInputSize", operator: "greaterThan", value: 10000 }
lessThan Numeric less than { field: "toolOutputSize", operator: "lessThan", value: 100 }
greaterThanOrEqual Numeric >= { field: "linesAdded", operator: "greaterThanOrEqual", value: 500 }
lessThanOrEqual Numeric <= { field: "toolDuration", operator: "lessThanOrEqual", value: 50 }

Matchable Fields

These fields can be used in condition evaluation:

Field Source Description
toolInput Event Content sent to the tool (stringified)
toolOutput Event Content returned from the tool (stringified)
toolName Event Tool name (Read, Write, Edit, Bash, etc.)
filePath Event Full file path
fileName Derived File name only (last path segment)
fileExtension Derived File extension (lowercase, no dot)
fileDirectory Derived Directory path (everything before file name)
language Event Programming language
toolSuccess Event Boolean — whether tool call succeeded
(any field) Event Any field on the event object via dot notation

Derived Fields

Some fields are computed at match time:

  • fileName — Extracted from filePath (e.g., /src/app/page.tsxpage.tsx)
  • fileExtension — Extracted from filePath (e.g., tsx)
  • fileDirectory — Extracted from filePath (e.g., /src/app)

Regex Matching

Regex conditions use JavaScript RegExp with case-insensitive flag (i):

const regex = new RegExp(condition.value, 'i');
return regex.test(eventValue);

Dev-Safe Filtering

For toolInput and toolOutput fields with regex matching, the engine applies dev-safe filtering:

  1. Test the original value against the regex
  2. If it matches, strip dev-safe patterns and test again
  3. Only count as a match if it still matches after stripping

Dev-safe patterns stripped:

  • http://localhost:PORT
  • http://127.0.0.1:PORT
  • http://0.0.0.0:PORT
  • Bare localhost, 127.0.0.1, 0.0.0.0 references

This prevents false positives for rules about hardcoded URLs — development URLs are not violations.


Line Number Detection

When a violation is found, the engine attempts to identify the specific line number:

  1. Get the content from toolInput or toolOutput
  2. Split into lines
  3. Skip files with fewer than 5 lines (too short for meaningful line detection)
  4. Test each line against the matching condition
  5. Return the 1-based line number of the first match

Line number detection supports contains, equals, startsWith, endsWith, and regex operators.


Correction Detection

When a tool_call event modifies a file that has uncorrected violations:

  1. Query user_rules_violations for uncorrected violations matching the file path
  2. For each violation, look up the original rule's conditions
  3. Re-evaluate the conditions against the new event
  4. If the conditions no longer match, mark the violation as corrected
Event modifies /src/config.ts
   Found uncorrected violation for "Hardcoded API Key" in /src/config.ts
   Re-check: toolInput no longer contains "api_key = 'sk-..."
   Violation marked corrected ✓

Correction detection works for both template and custom rules. The correction is recorded with:

  • corrected: true
  • correctedAt: <timestamp>
  • correctedByEventId: <event-id>

Evaluation Flow

For each event:
  1. Is event type "tool_call"? If not, skip rule checking
  2. Is template cache stale? If yes, refresh
  3. Get user config (stack, disabled templates, plan)
  4. Resolve matchable rules:
     a. Template rules filtered by user's stack categories
     b. Minus disabled templates
     c. Plus always-active templates
     d. Plus custom rules (Enterprise)
  5. For each rule:
     a. Check all conditions (AND logic)
     b. If all match → create violation
     c. Detect line number
  6. Check for corrections on the same file
  7. Mark event as ruleChecked

Example Rules

Security: Hardcoded API Key

{
  "name": "Hardcoded API Key",
  "category": "security",
  "severity": "error",
  "conditions": [
    {
      "field": "toolInput",
      "operator": "regex",
      "value": "(api[_-]?key|secret|token|password)\\s*[:=]\\s*['\"][a-zA-Z0-9_\\-]{20,}['\"]"
    }
  ]
}

TypeScript: Any Type Usage

{
  "name": "Avoid any Type",
  "category": "typescript",
  "severity": "warning",
  "conditions": [
    {
      "field": "toolInput",
      "operator": "regex",
      "value": ":\\s*any\\b"
    },
    {
      "field": "fileExtension",
      "operator": "equals",
      "value": "ts"
    }
  ]
}

React: Missing Key Prop

{
  "name": "Missing Key Prop in List",
  "category": "react",
  "severity": "warning",
  "conditions": [
    {
      "field": "toolInput",
      "operator": "regex",
      "value": "\\.map\\([^)]*=>\\s*<(?!.*\\bkey\\b)"
    }
  ]
}

See Also