1"""`BestChecker`."""
2
3import logging
4
5from suricata_check.checkers.interface import CheckerInterface
6from suricata_check.utils.checker import (
7 get_rule_option,
8 is_rule_option_set,
9 is_rule_suboption_set,
10)
11from suricata_check.utils.checker_typing import ISSUES_TYPE, Issue, Rule
12
13
[docs]
14class BestChecker(CheckerInterface):
15 """The `BestChecker` contains several checks for best practices to improve the experience of Suricata rules for everyone.
16
17 Codes C100-C110 report on missing fields that should be set.
18 """
19
20 codes = {
21 "C100": {"severity": logging.INFO},
22 "C101": {"severity": logging.INFO},
23 "C102": {"severity": logging.INFO},
24 }
25
26 def _check_rule(
27 self: "BestChecker",
28 rule: Rule,
29 ) -> ISSUES_TYPE:
30 issues: ISSUES_TYPE = []
31
32 if not (
33 is_rule_option_set(rule, "noalert")
34 or is_rule_suboption_set(rule, "flowbits", "noalert")
35 ) and not is_rule_option_set(rule, "target"):
36 issues.append(
37 Issue(
38 code="C100",
39 message="""\
40The rule does not use the `target` Suricata meta option.
41Consider adding the `target` option to specify which IP address is the target of the attack.\
42""",
43 ),
44 )
45
46 if not is_rule_suboption_set(rule, "metadata", "created_at"):
47 issues.append(
48 Issue(
49 code="C101",
50 message="""\
51The rule does not use set the `created_at` metadata option.
52Consider adding the `created_at` metadata option to inform users of the recency of this signature.\
53""",
54 ),
55 )
56
57 if (
58 is_rule_option_set(rule, "rev")
59 and int(get_rule_option(rule, "rev")) > 1 # type: ignore reportArgumentType
60 and not is_rule_suboption_set(rule, "metadata", "updated_at")
61 ):
62 issues.append(
63 Issue(
64 code="C102",
65 message="""\
66The rule does not use set the `updated_at` metadata option while it has been revised since creation.
67Consider adding the `updated_at` metadata option to inform users of the recency of this signature.\
68""",
69 ),
70 )
71
72 return issues