Skip to content

feat(ci): validate the detection and sensor configs - #1427

Merged
Gerrrt merged 4 commits into
mainfrom
fix/check-detection-config
Nov 11, 2026
Merged

Gerrrt merged 4 commits into
mainfrom
fix/check-detection-config

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Nov 11, 2026

Copy link
Copy Markdown
Owner

What changed

New scripts/check_detection_config.sh:

  • Static (python3, everywhere): local_rules.xml, ossec.conf and shared/default/agent.conf parse 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.
  • Pinned images (docker): wazuh-analysisd -t in compose's wazuh-manager, with the three files mounted at /var/ossec/etc/…, and zeek --parse-only local /zeek/site/local.zeek in compose's zeek, with local.zeek and ja4 mounted exactly as stacks/sensor/compose.yaml mounts them. Both run with --network none, and images come from image-for.sh.
  • Wired into validate.sh (its skip is counted) and into CI through require-no-skip.sh, so a missing daemon fails CI.
  • New CI step: vendor-ja4.sh --check && vendor-sysmon-config.sh --check. These existed but nothing ran them.
  • Rows in scripts/README.md, and require-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's scan0-egress.nft (nft -c needs CAP_NET_ADMIN).

Blast radius

CI and make validate only. 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.

  • No change to network segmentation or firewall rules
  • No new port published to a VLAN that could not already reach the service
  • No credential added outside secrets/*.sops.yaml

Verification

  • 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 --check passed here: vendored sysmon config matches … configs-082cba578667 (15.21). vendor-ja4.sh --check couldn't run here, because this container's proxy returned 403 for the GitHub archive download; CI has open network.

  • shellcheck 0.11.0 (new script and validate.sh), actionlint 1.7.12, zizmor 1.32.0 offline and editorconfig-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 validate passes (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

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
Copilot AI balanced review requested due to automatic review settings November 11, 2026 20:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Gerrrt
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
@Gerrrt
Gerrrt merged commit 57d6e44 into main Nov 11, 2026
8 checks passed
@Gerrrt
Gerrrt deleted the fix/check-detection-config branch November 11, 2026 23:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing validates the detection and sensor configs (Wazuh rules/ossec.conf, Zeek scripts, vendored ja4/Sysmon)

3 participants