wazuhdevenv provisions and maintains a local Wazuh rule and decoder development environment.
The installable Python CLI owns environment preparation; default Wazuh regression content is distributed independently by wazuh-rule-tests, and logtest communication is provided by wazuhtester.
The tooling is deliberately separated by responsibility:
| Project | Responsibility |
|---|---|
wazuhtester |
reusable Wazuh logtest library, CLI, and pytest plugin |
wazuh-rule-tests |
versioned pytest regression corpus for built-in Wazuh rules |
wazuhcoverage |
runtime Wazuh JSON archive coverage analysis |
wazuhtestgen |
generation of pytest rule-test content |
wazuhdevenv |
environment installation, configuration, managed content, and orchestration |
For CLI use, install wazuhdevenv with an isolated application installer. Before the first PyPI release, install the current main branch directly:
pipx install "git+https://github.com/zbalkan/wazuhdevenv.git@main"After the package is published to PyPI, the stable installation command will be:
pipx install wazuhdevenvA development checkout can be installed with:
python -m pip install -e ".[dev]"The tool supports Linux. WSL is supported because the Wazuh manager and the tool run inside Linux.
Create or enter a project directory and run:
mkdir my-wazuh-rules
cd my-wazuh-rules
wazuhdevenv initAn explicit workspace path is also accepted:
wazuhdevenv init ~/projects/my-wazuh-rulesinit is a one-shot provisioning operation. After a successful initialization, any later init invocation fails immediately using the recorded state; it does not reconcile, repair, switch, or re-provision the environment. It performs the following:
- detects APT, DNF, or YUM;
- installs or verifies Wazuh Manager;
- optionally pins the requested Wazuh version;
- disables the Wazuh package repository after installation;
- creates
rules/,decoders/, andtests/; - creates the workspace
.venv; - installs pytest and the released
wazuhtesterpackage into that venv; - enables JSON archive output required by the development workflow;
- disables unnecessary manager modules used by the old development profile;
- configures the Wazuh
rule_testservice for development throughput; - applies the known rule-60000 Windows EventChannel testing transformation;
- expects a fresh/default Wazuh rules/decoders installation, ignores Wazuh's disposable
local_rules.xmlandlocal_decoder.xmlsamples, and refuses to migrate other existing custom content; - bind-mounts workspace rules and decoders into
/var/ossec/etc; - persists the mounts in
/etc/fstab; - adds the invoking developer to the
wazuhgroup, which is required to use Wazuh tooling without root; - keeps the invoking developer as owner of workspace rules and decoders while granting the
wazuhgroup access; - when
setfaclis available and the filesystem supports ACLs, adds optional default ACLs so future rule and decoder files remain accessible to thewazuhaccount and group; - validates Wazuh configuration using Wazuh's own
-tchecks; - backs up and restores the Wazuh configuration, Windows testing rule, fstab entries, and newly created bind mounts if host configuration fails;
- starts the manager and waits for a stable logtest socket;
- initializes
~/.wazuhdevenv; - downloads and validates the default rule-test corpus whose version exactly matches the installed Wazuh version unless
--skip-corpusis specified; corpus failures are fatal and reported to the user.
The CLI is intended to be run as the developer:
wazuhdevenv initIt invokes sudo only for operations that require system privileges. Do not run the CLI itself with sudo or as root. If init adds your account to the wazuh group, start a new login session before using Wazuh tools without sudo; an already-running shell cannot acquire newly assigned supplementary groups. Default ACLs are only a maintenance helper: they preserve access for future files but do not change file ownership. If setfacl is unavailable or the filesystem rejects ACLs, initialization continues normally.
Do not run init again after it succeeds. A second invocation exits with the recorded workspace, Wazuh home, Wazuh version, and state-file path so the environment can be inspected manually. If only the managed rule-test corpus needs attention, use wazuhdevenv update; init does not act as a repair command.
To require an exact Wazuh version:
wazuhdevenv init --wazuh-version 4.14.8For development before a corpus release is available:
wazuhdevenv init --skip-corpusWazuh installs sample local_rules.xml and local_decoder.xml files. In a workspace provisioned by wazuhdevenv, these samples are not treated as user
content and are never copied into the project. Users can add their own rule or decoder files later, including files with those names if they choose.
User-owned content stays in the project:
my-wazuh-rules/
├── .venv/
├── rules/
├── decoders/
└── tests/
The workspace virtual environment belongs to the project. It is deliberately separate from the private environment used by pipx to run wazuhdevenv.
wazuhdevenv prepares the environment and managed test content. It does not provide a separate test runner; use pytest from the workspace virtual environment.
Run your workspace tests:
.venv/bin/python -m pytest tests --wazuh-require-logtestRun the managed Wazuh regression corpus:
.venv/bin/python -m pytest \
"${WAZUHDEVENV_HOME:-$HOME/.wazuhdevenv}/current-corpus/tests" \
--wazuh-require-logtestRun both together:
.venv/bin/python -m pytest \
tests \
"${WAZUHDEVENV_HOME:-$HOME/.wazuhdevenv}/current-corpus/tests" \
--wazuh-require-logtestThese are ordinary pytest suites, so normal pytest selection, markers, fail-fast options, IDE integration, and plugins remain available without a wazuhdevenv wrapper.
wazuhdevenv coverage reports how many custom rule IDs defined under the initialized workspace's rules/ directory are explicitly referenced by tests under tests/.
wazuhdevenv coverageThe analysis is static and read-only. It recognizes direct rule-ID assertions such as assert response.rule_id == "100100", the equivalent reversed comparison, legacy assertEqual calls, and pytest parametrization where rule_id is one of the parameter columns. Built-in Wazuh rules are intentionally excluded: their regression corpus is maintained separately by wazuh-rule-tests.
Example output:
=== Wazuh Rule Coverage Report ===
Total rules defined: 2
Total test functions: 1
Rules referenced in tests: 1
Coverage: 50.00%
Uncovered Rule IDs:
- 222016
This is different from wazuhcoverage, which analyzes runtime Wazuh JSON archive coverage rather than static test-to-rule coverage.
Tool-managed state defaults to:
~/.wazuhdevenv/
├── state.json
├── current-corpus -> corpora/<active-release>/
├── cache/
├── corpora/
└── logs/
Override the root for CI or disposable environments with:
export WAZUHDEVENV_HOME=/path/to/stateDo not store custom rules, decoders, or project tests under this directory.
wazuhdevenv updateupdate:
- detects the installed Wazuh version;
- reads
wazuh-rule-testsGitHub Release manifests; - selects the corpus whose
versionexactly matches the installed Wazuh version; - downloads the ZIP and its SHA-256 checksum;
- verifies the digest;
- rejects unsafe ZIP paths, symlinks, and special files;
- validates that the external and embedded manifests match;
- extracts into a new versioned corpus directory;
- atomically repoints
current-corpusto the selected corpus; - records the active corpus in
state.json.
Check what would be selected without modifying state:
wazuhdevenv update --checkupdate does not upgrade Wazuh Manager, wazuhdevenv, wazuhtester, or user content. Corpus compatibility is exact: Wazuh 4.14.7 uses corpus 4.14.7; a corpus for another Wazuh version is not selected.
Remove the host integration created by wazuhdevenv with:
wazuhdevenv uninstallThe command is ownership-aware. It removes only state that can be attributed to wazuhdevenv, restores pre-existing Wazuh state where provenance is available, and refuses to overwrite Wazuh configuration that changed after initialization.
For a normal environment created by current versions, teardown first validates the managed mount state, the exact /etc/fstab entries, and package-directory safety before changing host state. When Wazuh Manager was installed by wazuhdevenv, an active bind mount that predates initialization causes a safe refusal before Wazuh is stopped or workspace access is changed. After preflight, the command stops Wazuh Manager, unmounts the managed rules and decoders directories and verifies that they are no longer mount points, removes the matching /etc/fstab entries, verifies that neither package directory nor any content below it is mounted, empties the underlying /var/ossec/etc/rules and /var/ossec/etc/decoders package directories while preserving the directories themselves, restores their expected root:wazuh ownership and 0770 mode (creating them only if missing), uninstalls the wazuh-manager package, and finally removes managed wazuhdevenv state.
Uninstall also:
- unmounts the managed
rulesanddecodersbind mounts; - removes only the exact matching entries added to
/etc/fstab; - removes the developer's
wazuhgroup membership only wheninitadded it; - removes Wazuh-specific default ACL entries and returns files still using the
wazuhgroup to the invoking user's primary group; - removes the workspace
.venvonly whenwazuhdevenvcreated it; - removes the managed
~/.wazuhdevenvstate, caches, corpora, and logs; - removes Wazuh Manager and the tool-owned
/var/ossectree only whenwazuhdevenvinstalled Wazuh; - restores or removes the Wazuh package repository according to its recorded pre-initialization state;
- removes an APT Wazuh keyring when the tool created it and doing so would not break a repository configuration modified after initialization;
- when Wazuh already existed before
init, preserves the package and restores the exact pre-initializationossec.conf, Windows rule file, and service state recorded during provisioning.
User content under rules/, decoders/, and tests/ is always preserved. If a pre-existing workspace virtual environment was present, it is preserved as well.
On successful completion, uninstall prints a final inventory with four sections: Removed, Restored, Preserved, and Remnants. Preflight refusals return an error before teardown begins and therefore do not print a completion inventory. The remnant list is deliberate; the command does not claim to return the host to an unknowable pristine state.
Known intentional remnants include the wazuhdevenv Python or pipx installation itself, which must be removed using the installer that installed the CLI. A small sibling lock file is also retained outside the managed state directory so concurrent commands remain serialized while that directory is deleted. System prerequisite packages installed during provisioning are also retained because they may have acquired other consumers; current state records the exact package names so uninstall can report them. Package-manager cache and metadata changes made by APT, DNF, or YUM are not rolled back.
Workspace permission modes are not reconstructed. Initialization standardizes rule and decoder directories/files to development permissions, currently 0770 and 0660. Uninstall removes Wazuh-specific group/ACL access but does not have enough information to restore arbitrary per-file modes or a pre-initialization non-primary group. Pre-existing/default ACL base and mask entries are preserved. If group membership was removed, already-running login sessions may continue to carry the old supplementary group until a new login session starts.
On RPM-family systems, an RPM signing-key database entry imported during Wazuh repository setup is not removed automatically because its prior ownership cannot be attributed safely. Wazuh system users or groups may also remain if the distribution package's uninstall scripts deliberately retain them; the final report detects and lists those accounts when present.
State created before uninstall provenance tracking is handled conservatively. The command can clean exact managed mounts, fstab entries, and reversible Wazuh configuration changes, but it preserves components whose ownership cannot be proved, including the Wazuh package, user group membership, workspace .venv, and legacy initialization backup files. Those preserved remnants are printed explicitly.
Run the package tests:
python -m pip install -e ".[dev]"
python -m pytestThe unit suite does not alter the host Wazuh installation.
GNU General Public License version 2 only. See LICENSE.