1"""`MandatoryChecker`."""
2
3import logging
4from types import MappingProxyType
5
6from suricata_check.checkers.interface import CheckerInterface
7from suricata_check.utils.checker import (
8 get_rule_suboptions,
9 is_rule_option_set,
10)
11from suricata_check.utils.checker_typing import ISSUES_TYPE, Issue
12from suricata_check.utils.regex import FLOW_OPTIONS
13from suricata_check.utils.rule import Rule
14
15
[docs]
16class MandatoryChecker(CheckerInterface):
17 """The `MandatoryChecker` contains several checks based on the Suricata syntax that are critical.
18
19 Codes M000-M009 report on mandatory rule syntax violations.
20 """
21
22 codes = MappingProxyType(
23 {
24 "M000": {"severity": logging.ERROR},
25 "M001": {"severity": logging.ERROR},
26 "M002": {"severity": logging.ERROR},
27 },
28 )
29
30 def _check_rule(
31 self: "MandatoryChecker",
32 rule: Rule,
33 ) -> ISSUES_TYPE:
34 issues: ISSUES_TYPE = []
35
36 if not is_rule_option_set(rule, "msg"):
37 issues.append(
38 Issue(
39 code="M000",
40 message="The rule did not specify a msg, which is a mandatory field.",
41 ),
42 )
43
44 if not is_rule_option_set(rule, "sid"):
45 issues.append(
46 Issue(
47 code="M001",
48 message="The rule did not specify a sid, which is a mandatory field.",
49 ),
50 )
51
52 for suboption, _ in get_rule_suboptions(rule, "flow"):
53 if suboption not in FLOW_OPTIONS:
54 issues.append(
55 Issue(
56 code="M002",
57 message=f"""\
58The rule uses invalid `flow` option: {suboption}.
59Each `flow` suboption must be a valid Suricata flow option ({", ".join(FLOW_OPTIONS)}).\
60""",
61 ),
62 )
63
64 return issues