wazuhregex
wazuhregex is a Python package and command-line tool for testing expressions against the regex behavior used by Wazuh 4.x. It lets you validate one pattern against all three regex engines supported by Wazuh rules in one run:
OS_RegexOS_Match(sregex)PCRE2
The project includes:
src/wazuhregex/: importable Python package and command-line implementation.wazuhregex: CLI tester with side-by-side engine results.tests/test_wazuhregex.py: pytest suite containing behavior adapted from Wazuh's C tests.tests/test_engine_edge_cases.py: additional Wazuh 4.x engine boundary and edge-case coverage.
Why this exists
Wazuh rules can use regex engines that differ from common online testers. A pattern that works in a general PCRE-focused tool may fail in OS_Regex or OS_Match, and generic Python regex behavior is not the compatibility target. You can use the original wazuh-regex tool, which is deployed on Wazuh manager servers under /var/ossec/bin/, but that requires access to a manager for simple checks.
This project gives you a local, repeatable way to check Wazuh 4.x behavior before shipping rules.
Features
- Test all 3 Wazuh regex engines from one command.
- Heuristically detect whether the supplied pattern uses OS_Regex, OS_Match, or PCRE2 syntax, mark that engine with
(orig.), and show round-trip-validated alternatives whenever the expression can be represented safely. Plain, non-empty literals have no detected original engine because they are valid in all three. Ambiguous regex syntax defaults to PCRE2. - Case-insensitive emulation for
OS_RegexandOS_Matchbehavior. - Highlighted matches and every match span for each engine.
- Captured groups/substring extraction for
OS_RegexandPCRE2. - Wazuh-specific OS_Regex validation and character classes rather than generic PCRE substitutions.
- Wazuh 4.x PCRE2 defaults, including ASCII shorthand-class behavior unless the pattern explicitly opts into Unicode properties.
- Preserve leading and trailing whitespace on non-empty stdin records. Blank and whitespace-only records are skipped by the CLI.
- Fixed CLI safety limits: at most 20 input lines per run and 100 ms evaluation time per non-empty line.
- Per-engine validation that distinguishes invalid syntax from a valid non-match.
Installation
The application requires Python 3.11 or newer, with Python 3.13 recommended. For command-line use -the recommended installation for most users- use pipx. It installs the application and its dependencies in an isolated environment while exposing the wazuhregex command on your PATH:
pipx install wazuhregex
When multiple Python interpreters are installed, select the recommended version explicitly with pipx install --python python3.13 wazuhregex.
Upgrade or remove the application without affecting other Python tools:
pipx upgrade wazuhregex
pipx uninstall wazuhregex
pipx can also install the application directly from a local checkout:
pipx install --editable .
Contributors should use a virtual environment and install the test dependencies with python -m pip install -e ".[test]".
To import wazuhregex in another Python project, install it into that project's environment with pip. This provides both the library and CLI:
python -m pip install wazuhregex
CLI usage
After installation, use either the console command or module entry point:
wazuhregex '<PATTERN>'
python -m wazuhregex '<PATTERN>'
Then provide input lines via stdin (interactive typing or piping). The CLI accepts at most 20 physical input lines per invocation. Each non-empty line is evaluated in an isolated worker with a 100 ms wall-clock limit; if that limit is exceeded, the worker is terminated and recreated before the next line.
Help/usage output
wazuhregex --help
The help text prints the fixed 20-line and 100 ms limits. The command exits with status 2 for invalid invocation or when input exceeds the 20-line limit.
Example: interactive input
Example: piped input
printf '%s\n' 'sshd: error found in log' 'info: all good' | wazuhregex 'error'
Python API
The primary classes are available directly from the package:
from wazuhregex import Engine, RegexComparer, WazuhRegex
tool = WazuhRegex(r"(\d+)")
is_match, spans = tool.os_regex("30 Agustos 2020")
if is_match:
print(spans) # [(0, 2), (11, 15)]
print(tool.get_substrings()) # ["30", "2020"]
is_match, spans = tool.os_match("Error: disk full")
is_match, spans = tool.pcre2_regex("30 Agustos 2020")
comparer = RegexComparer()
parsed = comparer.parse(r"\d+", Engine.PCRE2)
The 100 ms and 20-line limits belong to the CLI. The direct Python methods remain ordinary library calls.
Running tests
Run all tests:
python -m pytest
Run the main compatibility suite:
python -m pytest tests/test_wazuhregex.py
The tests/test_engine_edge_cases.py suite protects additional boundary behavior that is easy to change accidentally. Tests use Wazuh 4.x behavior as the oracle where it is documented or represented in the Wazuh source/tests; Python-wrapper behavior is not accepted merely because the backend happens to provide it.
Compatibility caveats
The target is Wazuh 4.x, but wazuhregex is an emulator rather than a Python binding to Wazuh's C implementations. Known limitations should therefore be treated narrowly rather than as alternate semantics:
OS_Regexis translated to PCRE2 for execution. Wazuh's native OS_Regex engine deliberately has limited backtracking, whereas PCRE2 can reconsider earlier matches. Complex expressions combining several*or+classes can therefore diverge. Wazuh itself documents this class of difference, including the\p*\d*\s*\w*:example where the native engine does not backtrack after\p*consumes the colon.- Wazuh's legacy OS_Regex and OS_Match implementations operate on byte strings. The Python API uses Unicode strings. The documented ASCII character classes and ASCII case folding are emulated, but spans and captured substrings involving non-ASCII data are Python character offsets rather than native Wazuh byte offsets.
- Wazuh's PCRE2 rule path uses the 8-bit library with default compile options. The Python
pcre2binding forces UTF processing for Pythonstr. The tool compensates for known observable differences such as UCP defaults,\xforms, and\C, but unusual non-ASCII code-unit behavior can still differ from native Wazuh PCRE2. OS_Matchmatch spans are a convenience provided by this project, not part of Wazuh's OS_Match API. A successful negated expression has no positive matching substring and therefore returns an empty span list.- Equivalent-pattern suggestions are intentionally conservative. A missing conversion or an
unknowncomparison means the tool could not prove a safe equivalence; it does not prove the expressions differ for every possible input.
For complex expressions, non-ASCII data, rules that depend on unusual backtracking, or other security-sensitive use, validate the final pattern against the exact Wazuh 4.x manager version used in production. A confirmed divergence should become a regression test before the emulator is changed.
Project status and maintainer policy
This is an independent compatibility tool, not an official Wazuh product. Version 0.2.0 remains alpha while compatibility coverage is expanded and tested against real Wazuh usage.
The project is open-source, but upstream development is owner-maintained. You may use, modify, and fork it under the license, but unsolicited pull requests are not accepted. Bug reports and suggestions may be submitted through the issue tracker and will be considered at the maintainer's discretion. There is no commitment to provide support, response times, fixes, or continued maintenance.
License and third-party material
This project is licensed under the GNU General Public License, version 2 only. See LICENSE for the full terms and THIRD_PARTY_NOTICES.md for the origin and licensing of test material and dependencies.
Building and publishing
Build both the source distribution and wheel, then validate their metadata:
python -m pip install -e ".[build]"
python -m build
python -m twine check dist/*
Publishing is manual. Start .github/workflows/publish.yml with workflow_dispatch from main. The workflow reads the version from pyproject.toml, creates v<version> on the dispatched commit (or verifies that the existing tag already points there), builds and smoke-tests the package, and publishes it through PyPI trusted publishing. No long-lived PyPI token or manually created release tag is required.
Release files for wazuhregex 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wazuhregex-0.2.0.tar.gz | 41.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wazuhregex-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.3 kB
Release files / wazuhregex-0.2.0.tar.gz
| Download URL | wazuhregex-0.2.0.tar.gz |
|---|---|
| Size | 41.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b46e636696eb2d264409ac43fd10f2f69c9fcfd2ee172f7b1a74050ba71c88b
|
|
BLAKE2b-256 checksum How to use checksums |
ae7584ce2cc859aa0f1d1db2e06c6684afc70ab3b24a9c345c08344406bad65a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency logRelease files / wazuhregex-0.2.0-py3-none-any.whl
| Download URL | wazuhregex-0.2.0-py3-none-any.whl |
|---|---|
| Size | 29.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b17b5f1646eb1b81652fef83378a4457421cc6017d8b579c6294bba981976f2
|
|
BLAKE2b-256 checksum How to use checksums |
9438eb04dca0780947abb01eceae48629a4464c1f6a75b3c6d80faf163f47100
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.
Transparency log