Development¶
SigmaHQ compatibility gate¶
Engine compatibility is checked against the active rule trees from the
SigmaHQ commit pinned in compatibility/sigmahq-baseline.json. The gate loads
the corpus through the RSigma parser for Windows, Linux, and macOS routing,
then compares verdict and reason counts with the baseline. Parser or compiler
failures, panics, unaccounted skip reasons, unknown unsupported-document
reasons, and count drift fail the test. The emitted
sigma-compatibility.json file is uploaded by CI for machine consumption.
To reproduce the gate locally, check out the pinned SigmaHQ commit and run:
RUSTINEL_EBPF_STUB=1 \
RUSTINEL_SIGMA_CORPUS_DIR=/path/to/sigma \
cargo test --locked --test sigma_corpus_compatibility -- --include-ignored
This test only parses, compiles, and routes rules. Live atomic firing tests and
curated detection packs belong in rustinel-rules and are not run by this
gate.
Build Matrix¶
| Target | Tooling |
|---|---|
| Windows userspace build | Rust 1.92+, Visual Studio Build Tools |
| Linux userspace build | Rust 1.92+ |
| Linux eBPF object build | nightly Rust, rust-src, bpf-linker |
| macOS userspace build | Rust 1.92+, Xcode Command Line Tools |
Fastest Local Build Paths¶
Userspace¶
On Windows, run the final binary from an elevated PowerShell. On Linux, run it as root or with the required eBPF capabilities.
Linux eBPF Build¶
If ebpf/rustinel-ebpf.o already exists, a normal root cargo build embeds it and no nightly eBPF rebuild is needed.
If you need to rebuild the eBPF object from source:
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
cargo install bpf-linker
cd ebpf
cargo +nightly build --release --bin rustinel-ebpf
cp target/bpfel-unknown-none/release/rustinel-ebpf rustinel-ebpf.o
cd ..
build.rs watches ebpf/src, ebpf/Cargo.toml, and ebpf/rustinel-ebpf.o. On Linux builds it embeds either the prebuilt object or a freshly compiled one.
Recommended Dev Runs¶
Windows¶
Linux¶
Linux With eBPF Override¶
Useful when iterating on ebpf/ without rebuilding the full userspace binary:
macOS¶
For normal contributor work, start with cargo check, cargo build, and the
regular test suite. The signed app-bundle path below is only required when you
need live Endpoint Security telemetry on macOS or when preparing a release.
macOS telemetry uses Apple's Endpoint Security framework. Creating an ES client
(es_new_client) requires three things, and each missing piece surfaces a
distinct startup error: running as root (NotPrivileged if not), the
com.apple.developer.endpoint-security.client entitlement (NotEntitled if
missing), and user approval via Full Disk Access / TCC (NotPermitted if not
granted).
Maintainer release builds require Apple to approve the managed Endpoint Security capability. After approval, enable Endpoint Security on the explicit App ID used for the request and download a matching macOS provisioning profile. Install the profile's signing certificate and private key in the login keychain. Confirm that macOS can see the identity:
Build the binary, then create the app-like daemon bundle required for a restricted entitlement:
cargo build --release
scripts/macos/package-app.sh \
--binary target/release/rustinel \
--output target/release/Rustinel.app \
--profile "$HOME/Downloads/rustinel.provisionprofile" \
--identity "Developer ID Application: Example (TEAMID)"
The script derives the bundle identifier from the profile, validates that the
profile authorizes Endpoint Security, embeds it at
Contents/embedded.provisionprofile, adds the profile App ID and Team ID to the
signed entitlements, enables the hardened runtime, and verifies the bundle.
On macOS, YARA-X uses Wasmtime's Pulley interpreter because Endpoint Security
clients cannot use hardened runtime relaxation entitlements for JIT executable
memory.
Grant Rustinel.app Full Disk Access in System Settings, then run:
In another terminal, trigger and inspect the bundled demo:
For a SIP-disabled VM or dedicated test Mac, an ad-hoc bundle can still be created without a profile:
scripts/macos/package-app.sh \
--binary target/release/rustinel \
--output target/release/Rustinel.app \
--adhoc
Do not use the ad-hoc path on a normal SIP-enabled Mac. Release builds require
the Developer ID identity, the Endpoint Security provisioning profile, and a
successful notarization. CI expects MACOS_SIGN_IDENTITY,
MACOS_CERT_P12_BASE64, MACOS_CERT_PASSWORD,
MACOS_PROVISIONING_PROFILE_BASE64, MACOS_NOTARY_APPLE_ID,
MACOS_NOTARY_TEAM_ID, and MACOS_NOTARY_PASSWORD.
Testing¶
Unit and Integration Tests¶
cargo test --locked
cargo test --locked --test pipeline_sigma
cargo test --locked --test yara_disk
cargo test --locked --test yara_memory
Cargo auto-discovers the integration tests in tests/*.rs. The normal suite uses synthetic events and temporary Sigma, YARA, and IOC fixtures, so it does not require administrator/root privileges.
Ignored live tests cover process memory scanning and active-response termination. Build the test target first, then opt in explicitly:
cargo build --locked --example memory_target
cargo test --locked --test yara_memory -- --include-ignored
cargo test --locked --test active_response -- --include-ignored
Those ignored tests may require administrator rights on Windows or a controlled Linux host with permissive process-memory access.
Atomic Detection Gates¶
Pull requests run the rules repository's atomic detection suite against fresh Linux and Windows engine builds. The suite starts each binary with the required privileges, performs safe platform-specific actions, and checks for the alert that each action should produce. The rules checkout is pinned in both CI workflows so changes to detection content are introduced deliberately.
The pull request checks are currently visible but non-blocking while the
short-lived process race is stabilized. The same checks run as blocking jobs
after a push to the default branch. Once the suite is reliable, remove the
conditional continue-on-error setting and require both matrix checks in branch
protection.
Release tags run the same suite against the Linux x86_64, Linux arm64, Windows,
and signed macOS artifacts before publish can run. The Intel macOS leg is
optional because it uses the legacy hosted runner.
Replay Regression Fixture¶
A golden recording guards against a change to normalization, serialization, or matching quietly stopping a rule from firing:
tests/fixtures/replay/
├── windows-powershell-fixture.ps1 benign behavior generator
├── windows-powershell.ndjson the recording
├── windows-powershell.manifest.json its manifest
└── sigma/ the rules it must fire
tests/replay_fixture.rs replays it against those rules on every platform in
ordinary CI (no sensors, no privileges) and asserts both rules fire in the
recorded order. Because it is a Windows capture, it also proves a recording
replays away from the platform that produced it.
To regenerate it:
- On a Windows lab endpoint, run
rustinel capture --output windows-powershell.ndjson. - Run
windows-powershell-fixture.ps1, then stop the capture with Ctrl-C. - Confirm the manifest reads
"status": "complete". - Copy both files into
tests/fixtures/replay/, replacing the previous pair. Never edit a recording by hand: the manifest checksum is verified on every replay and an edited payload is rejected. - Run
cargo test --test replay_fixture.
Development Environment Variables¶
| Variable | Purpose |
|---|---|
RUSTINEL_EBPF_OBJECT |
Absolute path to a compiled .o, used instead of the embedded Linux object |
RUSTINEL_BPF_INTERFACE |
macOS capture interface, when the default en0 is not the active one |
Code Quality¶
Project Structure¶
src/
├── main.rs # CLI entry point and platform bootstrapping
├── config.rs # Config loading and defaults
├── alerts.rs # ECS NDJSON alert sink
├── engine/ # Sigma rule parsing, classification, and evaluation
├── ioc/ # Atomic IOC loading and matching
├── models/ # Event, alert, and ECS data models
├── normalizer/ # Shared event normalization and enrichment
├── reload/ # Hot reload poller and worker
├── response/ # Optional process termination logic
├── scanner/ # YARA compilation and scanning
├── sensor/
│ ├── windows/ # ETW sensor implementation
│ ├── linux/ # eBPF userspace loader and event decoding
│ └── macos/ # Endpoint Security sensor
├── state/ # Process, DNS, SID, and network aggregation state
└── utils/ # Platform-specific helpers
ebpf/
└── src/ # Linux eBPF programs and event ABI definitions
Logging Guidance¶
Use the existing logging contract when adding runtime logs:
trace: high-volume internalsdebug: troubleshooting detailinfo: lifecycle and positive detectionswarnanderror: degraded behavior or failures
If a line can fire on most normal events, it does not belong at debug.