Repository navigation
feat(ci): validate the detection and sensor configs - #1427
Merged
Merged
Conversation
Nothing checked Wazuh's rules and ossec.conf, the indexer JSON or Zeek's local.zeek and ja4, so a broken one merged green and failed only on odin or fenrir. check_detection_config.sh parses the XML and JSON, checks the local rule ids are unique and in range, and in the pinned images runs wazuh-analysisd -t and zeek --parse-only. It runs in validate.sh and, via require-no-skip.sh, in CI, which also now runs the vendored ja4 and Sysmon --check. Closes #1426. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L2EweeKAdMf5A1aeFy1anN
Gerrrt
enabled auto-merge (squash)
November 11, 2026 21:24
… an unresolved image
The compose service is wazuh.manager, so image-for.sh found nothing for
wazuh-manager, and docker was handed an empty reference ("invalid
reference format") and reported as wazuh-analysisd rejecting the config.
The step now names the right service, and an image that cannot be
resolved fails as itself. Local runs skipped this step for want of a
docker daemon, which is how it reached CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2EweeKAdMf5A1aeFy1anN
… etc defaults Run with ossec.conf, the rules and agent.conf bind-mounted into an otherwise empty /var/ossec/etc and from the image's working directory, analysisd stopped at "Could not open file 'etc/internal_options.conf'" before reading any of them. The three files are now mounted under /hl, the image's default etc is restored into the container's writable layer when it is not already there, ours are copied over it, and the test runs from /var/ossec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L2EweeKAdMf5A1aeFy1anN
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.
What changed
New
scripts/check_detection_config.sh:local_rules.xml,ossec.confandshared/default/agent.confparse as XML (read inside a wrapper, because Wazuh files may have several top-level elements);local_rules.xml's rule ids are unique and inside the 100100-100199 its header declares; the indexer's two JSON files parse.wazuh-analysisd -tin compose'swazuh-manager, with the three files mounted at/var/ossec/etc/…, andzeek --parse-only local /zeek/site/local.zeekin compose'szeek, withlocal.zeekandja4mounted exactly asstacks/sensor/compose.yamlmounts them. Both run with--network none, and images come fromimage-for.sh.validate.sh(its skip is counted) and into CI throughrequire-no-skip.sh, so a missing daemon fails CI.vendor-ja4.sh --check && vendor-sysmon-config.sh --check. These existed but nothing ran them.scripts/README.md, andrequire-no-skip.sh's list.Why
These are the configs a detection exercise depends on, and before this a broken one broke only on odin or fenrir. Owner decision on finding #8: extend CI to cover them.
Closes #1426.
Not covered, by design: Velociraptor's
init.vql(no offline parser) and the analyst'sscan0-egress.nft(nft -cneeds CAP_NET_ADMIN).Blast radius
CI and
make validateonly. If the docker half is wrong (a mount path, or analysisd needing a file the bare image lacks), the new CI step goes red without anything being deployed, and I'll fix it on this PR.secrets/*.sops.yamlVerification
Static half, run here:
PASS Wazuh XML and indexer JSON: 6 checks(3 XML, 8 rule ids unique and in range, 2 JSON). Fault injection in a throwaway worktree: a duplicated rule id →FAIL … duplicate rule id(s) ['100100']; a removed</rule>→FAIL … not well-formed XML: mismatched tag: line 130.Docker half: SKIP here (no daemon). This PR's CI run is its first real test.
Vendor checks:
vendor-sysmon-config.sh --checkpassed here:vendored sysmon config matches … configs-082cba578667 (15.21).vendor-ja4.sh --checkcouldn't run here, because this container's proxy returned 403 for the GitHub archive download; CI has open network.shellcheck0.11.0 (new script and validate.sh),actionlint1.7.12,zizmor1.32.0 offline andeditorconfig-checker: clean.check_docs.py: passed.make validate: exit 0, 167 PASS, 0 FAIL, 40 SKIP, one more skip than before (this check's docker half). The rest are the same Docker/pipx skips as earlier PRs.make validatepasses (with the skips above)Deployed to the lab and confirmed working (N/A: CI and validate only)
Docs updated (
scripts/README.md)Generated by Claude Code