Production-grade Abstract Syntax Tree parser for IDS rules (Suricata/Snort) with comprehensive validation and serialization support
Project description
surinort-ast
Production-grade AST parser and analysis toolkit for Suricata/Snort rules
Overview
surinort-ast is a Python toolkit to parse, validate, serialize, and analyze IDS/IPS rules from Suricata, Snort2, and Snort3. It provides a typed AST, CLI workflows, and machine-readable outputs including JSON and SARIF 2.1.0.
Key Features
| Feature | Description |
|---|---|
| Typed AST | Full Pydantic-backed AST for headers, options, and metadata |
| Multi-dialect | Suricata, Snort2, and Snort3 support |
| Validation | Syntax/semantic diagnostics with severity levels |
| Serialization | JSON and protobuf support |
| SARIF 2.1.0 | Parse/validate/analysis findings export for Code Scanning |
| CLI + Library | Use as command-line tool or Python package |
| Coverage/Optimization Analysis | Built-in analyzers for coverage and optimization insights |
| Streaming Mode | Memory-efficient parsing for large rule sets |
Supported Outputs
AST Data JSON, protobuf
Diagnostics Human-readable tables, SARIF 2.1.0
Analysis Text reports, SARIF 2.1.0 findings
CI Integration SARIF artifact + GitHub Code Scanning upload
Installation
From PyPI (Recommended)
pip install surinort-ast
From Source
git clone https://github.com/seifreed/surinort-ast.git
cd surinort-ast
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e .
Optional Extras
pip install "surinort-ast[all]"
pip install "surinort-ast[serialization]"
pip install "surinort-ast[analysis]"
pip install "surinort-ast[cli-enhanced]"
Quick Start
# Parse rule file
surinort parse rules/local.rules
# Validate with strict mode
surinort validate rules/local.rules --strict
# Export parse findings to SARIF
surinort parse rules/local.rules --format sarif -o parse-results.sarif
Usage
Command Line Interface
# Parse to JSON
surinort parse rules/local.rules --json -o rules.json
# Validate and export SARIF
surinort validate rules/local.rules --format sarif -o validate-results.sarif
# Stats and coverage findings in SARIF
surinort stats rules/local.rules --format sarif -o stats-results.sarif
Available Options (Main Commands)
| Command | Description |
|---|---|
surinort parse |
Parse rules (text, json, sarif) |
surinort validate |
Validate rules with optional strict mode and SARIF output |
surinort stats |
Rule statistics and optional SARIF coverage findings |
surinort fmt |
Canonical formatting for rule files |
surinort to-json |
Convert rules to JSON |
surinort from-json |
Convert JSON back to rule text |
surinort schema |
Print AST JSON schema |
SARIF Flags
| Option | Description |
|---|---|
--format sarif |
Print SARIF content as command output |
--sarif-out <file> |
Write SARIF report while keeping default output mode |
-o, --output <file> |
Write primary output to file |
Python Library
Basic Usage
from surinort_ast import parse_rule, validate_rule, to_json
rule = parse_rule('alert tcp any any -> any 80 (msg:"HTTP"; sid:1;)')
diags = validate_rule(rule)
print(to_json(rule))
for diag in diags:
print(diag.level, diag.code, diag.message)
SARIF API Usage
from surinort_ast import (
diagnostics_to_sarif,
parse_file,
validate_rule,
)
rules = parse_file("rules/local.rules")
diagnostics = []
for rule in rules:
diagnostics.extend(validate_rule(rule))
sarif = diagnostics_to_sarif(diagnostics, default_file_path="rules/local.rules")
with open("results.sarif", "w", encoding="utf-8") as f:
f.write(sarif)
Additional SARIF Helpers
from surinort_ast import (
coverage_report_to_sarif,
optimization_results_to_sarif,
to_sarif,
)
CI and GitHub Code Scanning (SARIF)
The project CI now supports SARIF generation and upload:
- Generate
results.sariffrom real validation diagnostics. - Upload SARIF as workflow artifact.
- Upload SARIF to GitHub Code Scanning.
Minimal workflow example:
- name: Generate SARIF report
run: |
python - <<'PY'
from pathlib import Path
from surinort_ast import diagnostics_to_sarif, parse_file, validate_rule
fixture_path = Path("tests/fixtures/simple_rules.txt")
rules = parse_file(fixture_path)
diagnostics = []
for rule in rules:
diagnostics.extend(validate_rule(rule))
Path("results.sarif").write_text(
diagnostics_to_sarif(diagnostics, default_file_path=str(fixture_path)),
encoding="utf-8",
)
PY
- name: Upload SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Requirements
- Python 3.11+
- See pyproject.toml for dependencies and extras
Contributing
Contributions are welcome.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support the Project
If this project is useful in your workflows, you can support development:
License
This project is licensed under the GPL-3.0-or-later license. See LICENSE.
Attribution
- Author: Marc Rivero López | @seifreed
- Repository: github.com/seifreed/surinort-ast
Built for practical IDS/IPS rule engineering and security automation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file surinort_ast-2.0.1.tar.gz.
File metadata
- Download URL: surinort_ast-2.0.1.tar.gz
- Upload date:
- Size: 416.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efa37797cb922810419cdeba6520235d1208748451070b7b5572d405d0c04e38
|
|
| MD5 |
bae8509b085994768437ddc706a47d15
|
|
| BLAKE2b-256 |
990b55fc5061d6a1fc814a239a2c6671342eb834374eccc5771ff17ec2b4aaa5
|
Provenance
The following attestation bundles were made for surinort_ast-2.0.1.tar.gz:
Publisher:
release.yml on seifreed/surinort-ast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
surinort_ast-2.0.1.tar.gz -
Subject digest:
efa37797cb922810419cdeba6520235d1208748451070b7b5572d405d0c04e38 - Sigstore transparency entry: 1223866386
- Sigstore integration time:
-
Permalink:
seifreed/surinort-ast@16f079672319fe87f34cd74851441016dd2a2189 -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@16f079672319fe87f34cd74851441016dd2a2189 -
Trigger Event:
push
-
Statement type:
File details
Details for the file surinort_ast-2.0.1-py3-none-any.whl.
File metadata
- Download URL: surinort_ast-2.0.1-py3-none-any.whl
- Upload date:
- Size: 251.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adcdf2fa0a0e2f947ce8e57d5ad299025b7583f51ed34ae7b31e275d5f612cfc
|
|
| MD5 |
4ed21bfa7eb6fabd96c269c155a40f28
|
|
| BLAKE2b-256 |
40592b8ed14ccc7185248281a398a186fcede799dbb0ba79fbb2095478aceb3b
|
Provenance
The following attestation bundles were made for surinort_ast-2.0.1-py3-none-any.whl:
Publisher:
release.yml on seifreed/surinort-ast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
surinort_ast-2.0.1-py3-none-any.whl -
Subject digest:
adcdf2fa0a0e2f947ce8e57d5ad299025b7583f51ed34ae7b31e275d5f612cfc - Sigstore transparency entry: 1223866414
- Sigstore integration time:
-
Permalink:
seifreed/surinort-ast@16f079672319fe87f34cd74851441016dd2a2189 -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/seifreed
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@16f079672319fe87f34cd74851441016dd2a2189 -
Trigger Event:
push
-
Statement type: