cyvest 4.4.0__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.
Potentially problematic release.
This version of cyvest might be problematic. Click here for more details.
- cyvest/__init__.py +38 -0
- cyvest/cli.py +365 -0
- cyvest/cyvest.py +1261 -0
- cyvest/investigation.py +1644 -0
- cyvest/io_rich.py +579 -0
- cyvest/io_schema.py +35 -0
- cyvest/io_serialization.py +459 -0
- cyvest/io_visualization.py +358 -0
- cyvest/keys.py +194 -0
- cyvest/level_score_rules.py +78 -0
- cyvest/levels.py +175 -0
- cyvest/model.py +583 -0
- cyvest/model_enums.py +69 -0
- cyvest/model_schema.py +164 -0
- cyvest/proxies.py +582 -0
- cyvest/score.py +473 -0
- cyvest/shared.py +496 -0
- cyvest/stats.py +316 -0
- cyvest/ulid.py +36 -0
- cyvest-4.4.0.dist-info/METADATA +538 -0
- cyvest-4.4.0.dist-info/RECORD +23 -0
- cyvest-4.4.0.dist-info/WHEEL +4 -0
- cyvest-4.4.0.dist-info/entry_points.txt +3 -0
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)
|