Contributing to rsigma
Contributing to rsigma
Thank you for considering a contribution to rsigma! This document covers the basics of setting up a development environment, running tests, and submitting changes.
Getting Started
Prerequisites
- Rust toolchain (MSRV: 1.96.0). Install via rustup; opening the repository installs the pinned toolchain from
rust-toolchain.toml. - Docker (optional, required for integration tests that use testcontainers).
- Node.js 20+ (optional, only for building the documentation site under
docs/; not needed for the Rust workspace).
Building
cargo build --workspace
Running Tests
# Unit and integration tests
cargo test --workspace
# Clippy lints (must pass with zero warnings)
cargo clippy --workspace --all-targets --all-features -- -D warnings
# Formatting check
cargo fmt --all -- --check
# Dependency audit
cargo deny check
Development Workflow
Rust toolchain updates
The compiler used for development, CI, release artifacts, and the minimum supported Rust version move together. Keep Cargo.toml, rust-toolchain.toml, the Dockerfile builder tag, the README badge, and this prerequisite on the same exact X.Y.Z version. Update the Docker digest for that exact image tag, run scripts/check-toolchain-version.sh and every pre-push gate, and ship the compatibility change in its own pull request.
Branching
- Feature branches:
feat/<name> - Fix branches:
fix/<name> - Target
mainfor all PRs.
Commit Messages
Use Conventional Commits style:
feat(parser): add support for temporal_ordered correlationfix(convert): prevent SQL injection in identifier interpolationtest: add snapshot tests for parser ASTci: add cargo-deny job to audit workflow
Pull Requests
- Keep PRs focused on a single concern.
- Reference any related issue numbers.
- Ensure CI is green before requesting review.
- New public API surface should include rustdoc with examples.
- New features should include tests. Prefer integration tests for cross-crate behavior and unit tests for isolated logic.
Code Quality
cargo fmtandcargo clippymust pass with zero warnings.cargo deny checkmust pass (licenses, advisories, bans, sources).- Do not add
unsafecode without justification and a safety comment. - Avoid
.unwrap()in library crates. Use?or return descriptive errors..unwrap()is acceptable in tests.
Testing
- Unit tests live in
#[cfg(test)]modules alongside the code they test. - Integration tests go under
crates/<crate>/tests/. - Snapshot tests use insta. Run
cargo insta reviewafter updating snapshots. - Fuzz targets live in
fuzz/fuzz_targets/. Add a fuzz target for any new untrusted input surface. - Benchmarks use Criterion and live in
benches/.
Backend engine tests
Conversion backends are tested by running their queries in the real engines. Each case in crates/rsigma-convert/tests/engines/cases/ is a Sigma rule with sample events and the indexes of the events it must match:
description: What the case checks.
rule: { ... } # a Sigma rule
events: [ ... ] # one map per event
matches: [0, 2] # indexes of the events the rule must match
pipeline: | # optional: processing pipeline YAML applied before the engine's own pipelines
...
unsupported: [lynxdb] # optional: engines whose backend must reject the rule
known_failures: # optional: engine label to a confirmed defect
postgres-jsonb:
type: match-mismatch
reason: why the result is wrong
actual: [1]
The engine labels are eval, postgres-jsonb, postgres-columns, lynxdb, fibratus, fibratus-nomacros, and test-pysigma. Known failures use type: match-mismatch with the exact matched indexes, type: engine-error with a required error substring, or type: output-difference with the exact rsigma and reference queries. A failure that changes outcome or starts passing fails the test, so a fix must update or remove its entry. Prefer cases that probe edge behavior (missing fields, escapes, grouping, case) over happy paths.
The eval run is part of cargo test. The engine runs are #[ignore]d and need extra tooling:
# Docker: PostgreSQL 18 (both modes), LynxDB built from its release, pySigma's test backend
cargo test -p rsigma-convert --test engine_postgres -- --ignored
cargo test -p rsigma-convert --test engine_lynxdb -- --ignored
cargo test -p rsigma-convert --test engine_test_backend -- --ignored
# Windows with Go: the Fibratus filter engine
cargo test -p rsigma-convert --test engine_fibratus -- --ignored
The PostgreSQL and LynxDB runs also check SigmaHQ rules whose conditions need grouping. For each rule that uses only plain string matches they build events from the rule’s own values, take the expected matches from engine eval, and require the engine to agree (PostgreSQL in both modes). LynxDB only takes rules whose values avoid characters it renders or matches wrongly. Point them at a SigmaHQ checkout to run them. Without one they are skipped locally and fail in CI:
RSIGMA_SIGMA_CORPUS=/path/to/sigma cargo test -p rsigma-convert --test engine_postgres -- --ignored
RSIGMA_SIGMA_CORPUS=/path/to/sigma cargo test -p rsigma-convert --test engine_lynxdb -- --ignored
In CI each engine has its own workflow (.github/workflows/engine-*.yml) that runs only when its backend, its harness, the shared cases, or the conversion core changes.
Documentation
Two surfaces must stay in sync with what each release ships:
- Crate READMEs (
README.mdat the workspace root, pluscrates/<crate>/README.md) — for any public API or behavior change. The root README documents runtime/security features (Docker hardening, signature verification, supported features). - The docmd site under
docs/— the primary user-facing documentation surface, published athttps://rsigma.io/. The whole docmd project (config,package.json, local plugin, assets, and Markdown underdocs/content/) lives indocs/. A PR that adds or changes:- A user-facing capability → add or update the relevant
docs/content/guide/<topic>.mdpage and an entry indocs/docmd.config.jsnavigation (under the appropriate User Guide sub-category) - A CLI subcommand or flag → update the matching
docs/content/cli/<group>/<command>.mdpage (e.g.docs/content/cli/engine/daemon.md) - A daemon config key → update
docs/content/cli/engine/daemon.mdand any cross-referenced guide page - A public library API surface → update the matching
docs/content/library/<crate>.mdpage - A Prometheus metric, HTTP endpoint, environment variable, lint rule, feature flag, or backend → update the corresponding
docs/content/reference/<topic>.mdpage
- A user-facing capability → add or update the relevant
The site publishes from main, so docs for a change that is not in a release yet must say so. Tag the page of a new command or feature on the line below its H1, a new section on the line below its heading, and a new flag, key, or table row at the end of its description, with {{ added "unreleased" }}. Docs that only describe already-released behavior need no tag. The release PR replaces every {{ added "unreleased" }} with {{ added "X.Y.Z" }} for the version being cut. The docs plugin renders the tag as a link to that version’s release notes and fails the build on a version that is not in CHANGELOG.md. Keep section headings free of tags so their anchors stay stable.
From docs/, run npm install once, then npm run docs:build and npm run docs:validate before pushing docs changes; .github/workflows/docs.yml enforces both on every PR.
A CHANGELOG.md entry under ## [X.Y.Z] - YYYY-MM-DD is part of the release commit (the same content gets copied to the GitHub Release body). For features with public-API impact, the release notes mention the affected README and docs/ pages so reviewers can sanity-check the doc sync.
Architecture
rsigma is a Cargo workspace with the following crates:
| Crate | Purpose |
|---|---|
rsigma-parser |
YAML parsing, AST, linting, auto-fix |
rsigma-eval |
Rule compilation, matching engine, correlation |
rsigma-convert |
Backend conversion (PostgreSQL, LynxDB, Fibratus) |
rsigma-runtime |
Streaming I/O, daemon engine, input adapters |
rsigma-mcp |
Model Context Protocol server exposing rsigma to AI agents |
rsigma-cli |
CLI binary (validate, lint, convert, daemon) |
rsigma-lsp |
Language Server Protocol implementation |
rstix |
STIX 2.1 library: typed objects, bundle parse/stream, semantic validation (TAXII client planned) |
License
By contributing, you agree that your contributions will be licensed under the MIT License.
For the project’s development workflow conventions (branching, testing, releases, supply-chain hygiene), see CONTRIBUTING.md.