cyvest 0.1.0__py3-none-any.whl → 5.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cyvest/levels.py ADDED
@@ -0,0 +1,175 @@
1
+ """
2
+ Level enumeration and scoring logic for Cyvest.
3
+
4
+ This module defines the security level classification system and the algorithm
5
+ for determining levels from scores.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from decimal import Decimal
11
+ from enum import Enum
12
+
13
+ # Ordering mapping for Level comparisons
14
+ _LEVEL_ORDER = {
15
+ "NONE": 0,
16
+ "TRUSTED": 1,
17
+ "INFO": 2,
18
+ "SAFE": 3,
19
+ "NOTABLE": 4,
20
+ "SUSPICIOUS": 5,
21
+ "MALICIOUS": 6,
22
+ }
23
+
24
+
25
+ class Level(str, Enum):
26
+ """
27
+ Security level classification for checks, observables, and threat intelligence.
28
+
29
+ Levels are ordered from lowest (NONE) to highest (MALICIOUS) severity.
30
+ """
31
+
32
+ NONE = "NONE"
33
+ TRUSTED = "TRUSTED"
34
+ INFO = "INFO"
35
+ SAFE = "SAFE"
36
+ NOTABLE = "NOTABLE"
37
+ SUSPICIOUS = "SUSPICIOUS"
38
+ MALICIOUS = "MALICIOUS"
39
+
40
+ def __lt__(self, other: object) -> bool:
41
+ if not isinstance(other, Level):
42
+ return NotImplemented
43
+ return _LEVEL_ORDER[self.value] < _LEVEL_ORDER[other.value]
44
+
45
+ def __eq__(self, other: object) -> bool:
46
+ if not isinstance(other, Level):
47
+ return NotImplemented
48
+ return self.value == other.value
49
+
50
+ def __le__(self, other: object) -> bool:
51
+ if not isinstance(other, Level):
52
+ return NotImplemented
53
+ return _LEVEL_ORDER[self.value] <= _LEVEL_ORDER[other.value]
54
+
55
+ def __gt__(self, other: object) -> bool:
56
+ if not isinstance(other, Level):
57
+ return NotImplemented
58
+ return _LEVEL_ORDER[self.value] > _LEVEL_ORDER[other.value]
59
+
60
+ def __ge__(self, other: object) -> bool:
61
+ if not isinstance(other, Level):
62
+ return NotImplemented
63
+ return _LEVEL_ORDER[self.value] >= _LEVEL_ORDER[other.value]
64
+
65
+ def __hash__(self) -> int:
66
+ return hash(self.value)
67
+
68
+ def __str__(self) -> str:
69
+ return self.value
70
+
71
+ def __repr__(self) -> str:
72
+ return f"Level.{self.name}"
73
+
74
+
75
+ def normalize_level(level: Level | str) -> Level:
76
+ """
77
+ Normalize a level input to the Level enum.
78
+
79
+ Accepts either a Level enum instance or a case-insensitive string name
80
+ corresponding to a Level member.
81
+
82
+ Args:
83
+ level: Level enum or string representation (e.g., "malicious")
84
+
85
+ Returns:
86
+ The corresponding Level enum member
87
+
88
+ Raises:
89
+ ValueError: If the string does not match a Level name
90
+ TypeError: If the input type is unsupported
91
+ """
92
+ if isinstance(level, Level):
93
+ return level
94
+ if isinstance(level, str):
95
+ try:
96
+ return Level[level.upper()]
97
+ except KeyError as exc:
98
+ raise ValueError(f"Invalid level name: {level}") from exc
99
+ raise TypeError(f"Expected Level or str for level, got {type(level).__name__}")
100
+
101
+
102
+ def get_level_from_score(score: Decimal) -> Level:
103
+ """
104
+ Calculate the security level from a numeric score.
105
+
106
+ Algorithm:
107
+ - score < 0.0 -> TRUSTED
108
+ - score == 0.0 -> INFO
109
+ - score < 3.0 -> NOTABLE
110
+ - score < 5.0 -> SUSPICIOUS
111
+ - score >= 5.0 -> MALICIOUS
112
+
113
+ Args:
114
+ score: The numeric score to evaluate
115
+
116
+ Returns:
117
+ The appropriate Level based on the score
118
+ """
119
+ if score < Decimal("0.0"):
120
+ return Level.TRUSTED
121
+ if score == Decimal("0.0"):
122
+ return Level.INFO
123
+ if score < Decimal("3.0"):
124
+ return Level.NOTABLE
125
+ if score < Decimal("5.0"):
126
+ return Level.SUSPICIOUS
127
+ if score >= Decimal("5.0"):
128
+ return Level.MALICIOUS
129
+ return Level.NONE
130
+
131
+
132
+ # Color mapping for display purposes
133
+ LEVEL_COLORS = {
134
+ Level.NONE: "white",
135
+ Level.TRUSTED: "green",
136
+ Level.INFO: "cyan",
137
+ Level.SAFE: "bright_green",
138
+ Level.NOTABLE: "yellow",
139
+ Level.SUSPICIOUS: "orange3",
140
+ Level.MALICIOUS: "red",
141
+ }
142
+
143
+
144
+ def get_color_level(level: Level | str) -> str:
145
+ """
146
+ Get the color associated with a level for display purposes.
147
+
148
+ Args:
149
+ level: Level enum or level name string
150
+
151
+ Returns:
152
+ Color name for rich console display
153
+ """
154
+ if isinstance(level, str):
155
+ try:
156
+ level = normalize_level(level)
157
+ except (TypeError, ValueError):
158
+ return "white"
159
+ return LEVEL_COLORS.get(level, "white")
160
+
161
+
162
+ def get_color_score(score: Decimal | float) -> str:
163
+ """
164
+ Get the color associated with a score for display purposes.
165
+
166
+ Args:
167
+ score: The numeric score
168
+
169
+ Returns:
170
+ Color name for rich console display
171
+ """
172
+ if not isinstance(score, Decimal):
173
+ score = Decimal(str(score))
174
+ level = get_level_from_score(score)
175
+ return get_color_level(level)