Metadata-Version: 2.4
Name: sigmawarden
Version: 0.1.0
Summary: Lints a folder of Sigma detection rules for the mistakes that don't show up until someone tries to deploy them
Author: Zephryx
License: MIT
Project-URL: Homepage, https://github.com/zephryxsec/SigmaWarden
Project-URL: Issues, https://github.com/zephryxsec/SigmaWarden/issues
Keywords: sigma,detection-engineering,siem,dfir,linter
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# SigmaWarden

A linter for [Sigma](https://github.com/SigmaHQ/sigma) detection rules. Points
`sigmawarden lint` at a folder and it flags the mistakes that don't show up
until someone actually tries to deploy the rule — a `logsource` that doesn't
match anything real, a `condition` referencing a selection you renamed and
forgot to update, a `falsepositives` field nobody filled in, an ATT&CK
technique tag with a digit transposed.

I built this after the third time I shipped a rule to my own
[detections](https://zephryx.in/detections/) page with an empty
`falsepositives` list, because I'd written the detection logic, felt done, and
closed the file. None of those mistakes break the YAML. They just mean the
rule looks finished and isn't.

## Install

```bash
pip install sigmawarden
```

Or from source:

```bash
git clone https://github.com/zephryxsec/SigmaWarden
cd SigmaWarden
pip install -e .
```

Python 3.9+, one runtime dependency (PyYAML). No network calls at lint time —
the ATT&CK technique list and the logsource reference are both bundled.

## Usage

```bash
sigmawarden lint ./rules
```

```
rules/dcsync.yml
  warning SW011  missing 'falsepositives'

rules/kerberoasting.yml
  error   SW010  condition 'selction and not 1 of filter_*' references 'selction', which isn't defined in 'detection'

rules/golden-ticket.yml
  warning SW016  tag 'attack.t1003.099' — T1003.099 isn't a current ATT&CK technique ID (typo, or it's been deprecated/revoked since this reference was last updated)

3 rule(s) across 3 file(s) — 1 error(s), 2 warning(s), 0 info
```

Exit code is `1` if anything at `error` severity turned up, `0` otherwise.
Point it at a single file instead of a directory if that's all you want
checked.

```bash
sigmawarden lint ./rules --strict            # also fail on warnings
sigmawarden lint ./rules --format json        # for CI / other tooling to consume
sigmawarden lint ./rules --ignore SW011,SW016 # skip specific checks
sigmawarden lint ./rules --min-severity error # only show what would fail --strict... plus this
sigmawarden new-id                            # print a fresh UUID for a rule's `id:` field
```

Custom taxonomy — internal log sources, a vendor product not in the bundled
reference — won't trip false positives forever. Point `--extra-logsource` at
a JSON file shaped like `sigmawarden/data/logsource_reference.json` (only the
keys you need) and it's merged in.

## Checks

| Code | Severity | What it means |
| --- | --- | --- |
| SW001 | error | missing `title` |
| SW002 | error | missing `id` |
| SW003 | warning | `id` isn't a UUID |
| SW004 | error | `logsource` missing, or none of product/category/service set |
| SW005 | warning | `logsource.product` isn't recognized |
| SW006 | warning | `logsource.category` isn't recognized |
| SW007 | info | `logsource.service` isn't recognized for that product |
| SW008 | error | `detection` missing or empty |
| SW009 | error | `detection` has no `condition` |
| SW010 | error | `condition` references a selection that isn't defined |
| SW011 | warning | `falsepositives` missing or empty |
| SW012 | info | `falsepositives` is just `Unknown` |
| SW013 | warning | `level` isn't one of Sigma's five values |
| SW014 | warning | `status` isn't one of Sigma's five values |
| SW015 | error | an `attack.tXXXX` tag is malformed |
| SW016 | warning | an `attack.tXXXX` tag isn't a known technique ID |
| SW017 | error | two rules in the scanned set share an `id` |
| SW018 | error | a correlation rule's `correlation.rules` is missing or empty |

Correlation-type rules (a `correlation:` block instead of `detection:`) are
recognized and skip the logsource/detection checks — they're a different
Sigma object, not a malformed regular rule. Aggregation expressions after a
`|` in a condition (`selection | count() by field > 5`) are parsed as what
they are, not as undefined selections.

## CI

```yaml
- name: Lint Sigma rules
  run: |
    pip install sigmawarden
    sigmawarden lint ./rules --strict
```

## On the bundled reference data

`sigmawarden/data/attack_techniques.json` is extracted from MITRE's
[attack-stix-data](https://github.com/mitre-attack/attack-stix-data)
(Enterprise ATT&CK, revoked/deprecated techniques excluded) — regenerate it
with `python scripts/update_attack_data.py` when a new ATT&CK release adds or
retires techniques. `sigmawarden/data/logsource_reference.json` is curated
from the SigmaHQ rule corpus, not a formal spec — `logsource` is an
intentionally open taxonomy, so SW005–SW007 are warnings, not errors, and
`--extra-logsource` exists for exactly this reason.

## Contributing

Issues and PRs welcome. If you're adding a check, keep it in `checks.py` as
an independent function that yields `Finding`s — no shared state with the
others — and add a fixture under `tests/fixtures/` that would trip it.

## License

MIT — see [LICENSE](LICENSE).
