elastic / detection-rules

https://www.elastic.co/guide/en/security/current/detection-engine-overview.html
Other
1.92k stars 492 forks source link

[Bug] Toml Lint Fails on rules with investigate transforms #4033

Closed Mikaayenson closed 3 weeks ago

Mikaayenson commented 1 month ago

Describe the Bug

Realized that we didn't create a subsequent issue to track this bug and only linked it to the meta to refactor. We can probably tackle this sooner vs waiting for the refactor.

### Tasks
- [x] Address the bug (see recommendation below)
- [x] Add a command like `toml-lint` to the `test_cli.bash` so it can be included when we test using `make`

To Reproduce

  1. Select any rule with the investigation transforms.
[[transform.investigate]]
label = "Alerts associated with the user in the last 48h"
relativeFrom = "now-48h/h"
relativeTo = "now"
providers = [
  [
    {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"},
    {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"}
  ]
]
  1. Try to run toml-lint on the rule e.g. python -m detection_rules toml-lint -f rules/windows/command_and_control_common_webservices.toml
  2. See the error.

Expected Behavior

It should format the toml rule without error without crashing.

My recommendation would be to start with the dump_list method to support a list of dictionaries.

def dump_list(self, v):
        """Dump a list more cleanly."""
        if all(isinstance(i, dict) for i in v):
            # Compact inline format for lists of dictionaries
            retval = "["
            retval += ", ".join([self.dump_inline_table(u).strip() for u in v])
            retval += "]"
            return retval

        if any(isinstance(i, list) for i in v) or len(str(v)) > 120:
            # Multi-line format for nested lists or long lists
            retval = "[\n"
            for u in v:
                if isinstance(u, list):
                    retval += "  " + self.dump_list(u) + ",\n"
                elif isinstance(u, dict):
                    retval += "  " + self.dump_inline_table(u) + ",\n"
                else:
                    retval += "  " + self.dump_value(u) + ",\n"
            retval = retval.rstrip(",\n") + "\n]"
            return retval

        # Default to a single-line format if no special formatting is needed
        return self._dump_flat_list(v)

Screenshots

See the original comment.

Desktop - OS

other - explain

Desktop - Version

Any

Additional Context

We use the rule formatter in other areas so we may want to prioritize this.