Skip to content

Commit c527510

Browse files
authored
Merge pull request #44 from timescale/feat/athena-correlation-improvements
feat(convert): add CTE-based correlation pre-filtering and sliding window format
2 parents a803512 + 30d67ad commit c527510

5 files changed

Lines changed: 583 additions & 16 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@ name: CI
33
on:
44
push:
55
branches: [main]
6+
paths-ignore:
7+
- "**.md"
8+
- "docs/**"
9+
- "assets/**"
10+
- "LICENSE"
11+
- ".gitignore"
612
pull_request:
713
branches: [main]
14+
paths-ignore:
15+
- "**.md"
16+
- "docs/**"
17+
- "assets/**"
18+
- "LICENSE"
19+
- ".gitignore"
820

921
permissions: {}
1022

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ rsigma convert -r rules/ -t postgres -f view
124124
# Generate TimescaleDB continuous aggregates
125125
rsigma convert -r rules/ -t postgres -p pipelines/ocsf_postgres.yml -f continuous_aggregate
126126

127+
# Custom backend options (table, schema, timestamp field, etc.)
128+
rsigma convert -r rules/ -t postgres -O table=security_logs -O schema=public -O timestamp_field=created_at
129+
130+
# Sliding window correlation format (per-row detection using window functions)
131+
rsigma convert -r rules/ -t postgres -f sliding_window
132+
127133
# List available conversion backends
128134
rsigma list-targets
129135

crates/rsigma-convert/README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,28 @@ for result in &output.queries {
9797
| `view` | `CREATE OR REPLACE VIEW sigma_{id} AS SELECT ...` |
9898
| `timescaledb` | Queries with `time_bucket()` for TimescaleDB optimization |
9999
| `continuous_aggregate` | `CREATE MATERIALIZED VIEW ... WITH (timescaledb.continuous)` |
100+
| `sliding_window` | Correlation queries using window functions for per-row sliding detection |
101+
102+
### SELECT column selection
103+
104+
When a Sigma rule specifies `fields:`, the backend emits `SELECT field1, field2, ...` instead of `SELECT *`. Function calls (e.g. `count(*)`) pass through unchanged, and `field as alias` is supported with both sides quoted independently.
105+
106+
### CLI backend options
107+
108+
Backend configuration can be set via `-O key=value` flags on the CLI, which are wired through to `PostgresBackend::from_options`. Recognized keys: `table`, `schema`, `database`, `timestamp_field`, `json_field`, `case_sensitive_re`.
109+
110+
```bash
111+
rsigma convert -r rules/ -t postgres -O table=security_logs -O schema=public -O timestamp_field=created_at
112+
```
100113

101114
### Custom table, schema, and database
102115

103116
The target table and schema can be set at three levels (highest precedence first):
104117

105118
1. **Rule-level `custom_attributes`**: `postgres.table`, `postgres.schema`, `postgres.database`
106119
2. **Pipeline state**: `set_state` with `key: table`, `key: schema`
107-
3. **Backend defaults**: `PostgresBackend.table`, `.schema`, `.database`
120+
3. **CLI backend options**: `-O table=...`, `-O schema=...`, `-O database=...`
121+
4. **Backend defaults**: `PostgresBackend.table`, `.schema`, `.database`
108122

109123
Example rule with custom attributes:
110124

@@ -235,6 +249,23 @@ The PostgreSQL backend (`PostgresBackend`) leverages native PostgreSQL features
235249

236250
Correlation rules are converted to SQL using `GROUP BY` / `HAVING` for aggregation types (`event_count`, `value_count`, `value_sum`, `value_avg`, `value_percentile`, `value_median`) and CTEs for temporal correlation. Multi-table temporal correlations automatically generate `UNION ALL` CTEs when referenced rules target different tables.
237251

252+
Non-temporal correlations support CTE-based pre-filtering: when the correlation references detection rules that were converted in the same collection, the backend wraps their queries in a `WITH combined_events AS (q1 UNION ALL q2 ...)` CTE so the aggregate only counts events matching the detection logic.
253+
254+
The `sliding_window` output format uses SQL window functions for `event_count` correlations, producing a per-row sliding window that emits every event crossing the threshold:
255+
256+
```sql
257+
WITH combined_events AS (...),
258+
event_counts AS (
259+
SELECT *, COUNT(*) OVER (
260+
PARTITION BY "User"
261+
ORDER BY time
262+
RANGE BETWEEN INTERVAL '300 seconds' PRECEDING AND CURRENT ROW
263+
) AS correlation_event_count
264+
FROM combined_events
265+
)
266+
SELECT * FROM event_counts WHERE correlation_event_count >= 5
267+
```
268+
238269
### Configuration
239270

240271
`PostgresBackend` fields:

0 commit comments

Comments
 (0)