Skip to content
zbalkanPublic

About

RuleVis is a powerful analysis tool that transforms your Wazuh ruleset into a dynamic, interactive force-directed graph. It helps you visualize the complex relationships between rules, identify critical dependencies, discover structural issues, and analyze the distribution of your rule IDs.

Topics

Resources

Stars

27 stars

Watchers

3 watching

Forks

Repository files navigation

RuleVis: Interactive Wazuh Rule Graph Explorer

RuleVis is a powerful analysis tool that transforms your Wazuh ruleset into a dynamic, interactive force-directed graph. It helps you visualize the complex relationships between rules, identify critical dependencies, discover structural issues, and analyze the distribution of your rule IDs.

This tool is designed for security engineers, SOC analysts, and Wazuh administrators who need to understand, maintain, and develop complex custom rulesets.

General View of RuleVis

Features

  • Interactive Graph Visualization: Renders your entire ruleset as a graph using D3.js and HTML Canvas for high performance.
  • Dependency Analysis: Clearly shows parent-child relationships (if_sid, if_group, etc.) with directed edges.
  • Correlation Risk Warnings: Flag load-order-dependent group references and possible SID/group-history interference in Wazuh 4.14.10, with node-level explanations and a link to upstream issue #41279. These are scan-based risk indicators, not confirmed runtime failures.
  • Node Expansion: Interactively expand nodes to reveal their parent or child dependencies on demand.
  • Detailed Rule Information: Click on any rule to see its full description, groups, and a complete list of its parents and children.
  • Condition Path Analysis: Open a large condition-analysis view for atomic or temporal rules, inspect direct parents, and expand each resolved root-to-rule path as a flattened table with condition provenance.
  • Powerful Search: Instantly find and focus on any rule by its ID.
  • Graph Statistics Panel: Get at-a-glance insights into your ruleset with statistics like:
    • Top 5 rules with the most direct children (foundational rules).
    • Top 5 rules with the highest impact (most total descendants).
    • Top 5 rules with the most complex dependencies.
    • A list of isolated rules.
    • Cycles in the rules
  • Rule ID Heatmap: Visualize the entire rule ID space from 0 to 100,000+ to see which ID ranges are heavily used and which are available for custom rules.
  • Keyboard Shortcuts: Pause the simulation (Space), close panels (Esc), and more for an efficient workflow.
  • Focus: By default, when a node is highlighted, any node except for the selected node and its neighbords are dimmed. That allows better focus minimizing visual complexity.

The Problem It Solves

Wazuh's rule engine builds a complex, tree-like structure in memory. While powerful, this structure is invisible to the user. It can be difficult to:

  • Understand the full impact of changing a single rule.
  • Find redundant rules or overly complex dependency chains.
  • Identify structural issues like circular dependencies, which can impact performance.
  • Know which ID ranges are safe to use for new custom rules.

RuleVis makes these invisible structures visible, turning abstract XML files into a tangible, explorable map.

Installation

Using pipx (recommended)

pipx install rulevis

Using pip (for testing)

pip install rulevis

Using source

  1. Clone the repository:

    git clone https://github.com/zbalkan/rulevis.git
    cd rulevis
  2. Create and activate a Python virtual environment:

    python -m venv .venv
    source .venv/bin/activate

    Or for Windows

    python -m venv .venv
    source .venv\Scripts\activate.ps1
  3. Install dependencies:

    pip install -r requirements.txt

Usage

The tool is run from the command line. You must provide the path to the directory (or directories) containing your Wazuh rule XML files.

rulevis --path /var/ossec/ruleset/rules,/var/ossec/etc/rules

Arguments:

  • --path, -p: (Required) A comma-separated list of paths to your Wazuh rule directories. This should include both the default rules and your custom rules.
  • -h, --help: Show the help message.

Once executed, the script will:

  1. Parse all .xml files in the specified paths.
  2. Build a graph model of the rule relationships.
  3. Pre-calculate statistics and heatmap data.
  4. Start a local web server.
  5. Automatically open the tool in your default web browser.

Key Features in Action

Graph Statistics

Quickly identify the most important and complex rules in your entire ruleset. Click on any rule in the list to instantly navigate to it in the main graph.

Statistics Panel

Rule ID Heatmap

Get a bird's-eye view of your rule ID landscape. Dark gray blocks are unused and available for your custom rules, while brighter red blocks indicate heavily populated ranges. This is invaluable for planning and organizing a large custom ruleset.

Heatmap View

Condition Path Analysis

Analyze Conditions opens a large modal rather than extending the rule-details panel. The modal shows metadata for the selected rule (level, description, groups, MITRE ATT&CK IDs, and source file), lists its direct parent relationships, and resolves each graph path from the virtual root to the selected rule. Every path is collapsed by default and expands into a flattened condition table that keeps the originating rule for every condition. Relationship selectors such as if_sid, if_group, if_matched_sid, and if_matched_group are represented by the resolved path and are omitted from the flattened condition rows. Condition attributes are rendered inline with the condition name, leaving Origin | Condition | Value for atomic tables and Origin | Scope | Condition | Value for temporal tables.

For atomic rules, RuleVis follows atomic parent relationships and keeps alternative parent branches as separate paths rather than merging them into one condition set. When the same dynamic field is constrained repeatedly along a path, RuleVis performs a conservative simplification only when both expressions are exact anchored literal alternatives such as ^root$|^admin$. A broader earlier condition can be marked subsumed, a broader later condition redundant, and disjoint exact alternatives contradictory. Subsumed and redundant rows remain visible with strike-through so the derivation is still auditable. General regexes and negated fields are left unchanged rather than guessed. RuleVis also includes declared if_level relationships in these paths. They represent level-threshold dependencies from the source analysis, not verified Wazuh runtime attachments; the experimental occurrence evaluator independently reconstructs load-time attachments.

For temporal rules, the same path view also follows historical if_matched_sid and if_matched_group relationships. Temporal tables add a Scope column:

  • historical_source identifies predicates belonging to declared active historical-search sources (subject to actual rule acceptance and event-history state);
  • declared_only identifies ancestor conditions reachable only through a shadowed historical selector; these paths do not represent an active historical search;
  • current_event identifies predicates applied on the current-event side of the path;
  • temporal identifies correlation conditions on the selected temporal rule, such as frequency and timeframe.

Wazuh 4.14.10 chooses historical SID search over historical group search when both selectors are declared and the SID is nonzero. RuleVis retains the shadowed if_matched_group relationship for source inspection and labels it shadowed by if_matched_sid. Its ancestry has the declared_only scope rather than being presented as a historical event source. This selector decision alone does not prove runtime rule acceptance.

The clock shape is intentionally classified only by the presence of the frequency or timeframe rule attributes. Condition analysis is independent from that visual heuristic: temporal constructs such as if_matched_*, check_diff, or if_fts are still retained and analyzed even when they do not make the node a clock.

Technical Overview

The project is composed of four main Python modules and a JavaScript frontend:

  1. generator.py: Parses Wazuh XML rule files and builds the networkx.MultiDiGraph, including rule metadata, relationship provenance, and extracted atomic/temporal conditions.
  2. conditions.py: Enumerates root-to-rule relationship paths and flattens the effective condition rows for atomic and temporal analysis.
  3. analyzer.py: Loads the graph and calculates structural statistics and rule-ID heatmap data.
  4. visualizer.py: Serves the Flask UI and APIs for graph navigation, condition analysis, statistics, and heatmap data.
  5. graph.js: Implements the D3 force simulation, Canvas graph rendering, side panels, heatmap interaction, and condition-analysis modal.

Experimental Source-Faithful Assessment

The experimental assessment pipeline is deliberately separate from the visualization graph and UI. It preserves Wazuh rule declarations in load order, reconstructs Wazuh 4.14.10 runtime rule occurrences, evaluates an explicitly supplied finite event domain with exact bitsets, classifies the resulting reachability/shadowing/drop behavior, and can serialize a stable JSON report. project_occurrence_relationships() additionally reduces the runtime occurrence tree to logical rule-to-rule attachments with multiplicity counts for comparison against the declared visualization graph; it is not used by the UI.

The pipeline is:

Rule XML
  -> RuleCatalog
  -> EvaluationBuilder
  -> runtime occurrence DAG
  -> BitsetAssessor
  -> AssessmentClassifier
  -> AssessmentReport
  -> deterministic JSON

This is not yet a symbolic compiler for arbitrary Wazuh predicates, and it is not connected to the web UI. See Source-Faithful Assessment for the semantics, finding definitions, complexity model, benchmark command, and current limitations.

Here’s a ready-to-paste README subsection that explains rulevis logging clearly and professionally for your users. It assumes the per-user setup you’ve implemented.


Logging

rulevis automatically writes diagnostic and operational logs to a user-specific location. Logs are plain text encoded in UTF-8 and include timestamps, module names, and severity levels. The application creates its log directory if it does not exist.

Platform Log file location Example path
Windows %LocalAppData%\rulevis\Logs\rulevis.log C:\Users\<user>\AppData\Local\rulevis\Logs\rulevis.log
macOS ~/Library/Logs/rulevis/rulevis.log /Users/<user>/Library/Logs/rulevis/rulevis.log
Linux / BSD $XDG_STATE_HOME/rulevis/rulevis.log or fallback ~/.local/share/rulevis/logs/rulevis.log /home/<user>/.local/state/rulevis/rulevis.log

rulevis follows the XDG Base Directory specification on Unix-like systems and Windows conventions under %LocalAppData%.

The log file records informational messages, warnings, and errors emitted during execution. You can safely delete it; a new one will be created automatically on the next run.

Group relationship interpretation

Temporal relationships have two meanings in analysisd. When if_matched_sid or if_matched_group supplies the only structural parent, the loader synthesizes if_sid or if_group for placement, while retaining the original if_matched_* condition for historical-event registration. RuleVis now marks those synthesized structural edges explicitly in rule details. A temporal group source uses OSMatch to register event-history references; structural if_group placement uses OS_WordMatch. These may select different rules.

RuleVis displays declared if_group, if_level, and if_matched_group dependencies even when their parents would not have been available at the point the child was encountered in RuleVis's file scan. The temporal if_matched_group selector uses Wazuh's OSMatch semantics, including negation, alternatives, and anchoring; ordinary if_group instead uses OS_WordMatch. The rule details label those relationships not a candidate in scanned load order. The same annotation is used for declared if_level dependencies. Other links are candidates, not verified runtime attachments. The scan uses sorted XML files and may differ from the manager's configured rule-loading order. Source-faithful runtime occurrence reconstruction remains a separate experimental subsystem.

Notes

RuleVis represents declared <if_level> dependencies alongside if_sid, if_group, if_matched_sid, and if_matched_group. For if_level, the candidate annotation reflects a parent rule's encoded load-time priority at the point the child is scanned. The declared dependency graph intentionally preserves later or superseded matches; it is not identical to analysisd's ordered RuleNode occurrence tree. Implicit category-based placement and occurrence multiplicity remain exclusive to the experimental evaluator.

The <if_fts> condition represents first-time-seen state rather than a parent-child graph relationship, so it is retained for condition analysis but does not create a graph edge.

About

RuleVis is a powerful analysis tool that transforms your Wazuh ruleset into a dynamic, interactive force-directed graph. It helps you visualize the complex relationships between rules, identify critical dependencies, discover structural issues, and analyze the distribution of your rule IDs.

Topics

Resources

Stars

27 stars

Watchers

3 watching

Forks

Used by

Contributors

Languages