brexhq / substation

Substation is a toolkit for routing, normalizing, and enriching security event and audit logs.
https://substation.readme.io
MIT License
330 stars 21 forks source link

feat: Add Condition Inspector #86

Closed jshlbrd closed 1 year ago

jshlbrd commented 1 year ago

Description

Motivation and Context

We have some use cases for creating complex conditions that mimic this logic:

The simplest way to do this without a breaking change is to make a Condition inspector, which is a meta method similar to the ForEach inspector or the Pipeline processor. The Condition inspector is a condition (operator and inspectors) that can be referenced in other conditions to create the joined logic shown above. For example, the config below copies the value from foo to bar if the logic ( length(foo) > 0 AND foo starts_with "x" ) OR ( length(foo) < 4 AND foo equals "bar" ) is true:

local processors = [
  sub.interfaces.processor.copy(
    settings={ key: 'foo', set_key: 'bar', condition: sub.interfaces.operator.any([
        sub.interfaces.inspector.condition(
          options=sub.interfaces.operator.all([
            sub.patterns.inspector.length.gt_zero(key='foo'),
            sub.patterns.inspector.strings.starts_with(key='foo', expression='x'),
          ]),
        ),
        sub.interfaces.inspector.condition(
          options=sub.interfaces.operator.all([
            sub.interfaces.inspector.length(
              settings={ key: 'foo' },
              options={ type: 'less_than', value: 4 }
            ),
            sub.patterns.inspector.strings.equals(key='foo', expression='bar'),
          ]),
        ),
      ]) },
  )
];

The alternative to this is a breaking change in the conditions' pkg Config struct that takes nested conditions. I'd like to avoid breaking changes till v1.0, but it might be worth considering if the config for that package should change.

How Has This Been Tested?

Added new unit tests.

Types of changes

Checklist: