binalyze-air-sdk 1.0.1__py3-none-any.whl → 1.0.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.
- binalyze_air/__init__.py +77 -77
- binalyze_air/apis/__init__.py +67 -27
- binalyze_air/apis/acquisitions.py +107 -0
- binalyze_air/apis/api_tokens.py +49 -0
- binalyze_air/apis/assets.py +161 -0
- binalyze_air/apis/audit_logs.py +26 -0
- binalyze_air/apis/{authentication.py → auth.py} +29 -27
- binalyze_air/apis/auto_asset_tags.py +79 -75
- binalyze_air/apis/backup.py +177 -0
- binalyze_air/apis/baseline.py +46 -0
- binalyze_air/apis/cases.py +225 -0
- binalyze_air/apis/cloud_forensics.py +116 -0
- binalyze_air/apis/event_subscription.py +96 -96
- binalyze_air/apis/evidence.py +249 -53
- binalyze_air/apis/interact.py +153 -36
- binalyze_air/apis/investigation_hub.py +234 -0
- binalyze_air/apis/license.py +104 -0
- binalyze_air/apis/logger.py +83 -0
- binalyze_air/apis/multipart_upload.py +201 -0
- binalyze_air/apis/notifications.py +115 -0
- binalyze_air/apis/organizations.py +267 -0
- binalyze_air/apis/params.py +44 -39
- binalyze_air/apis/policies.py +186 -0
- binalyze_air/apis/preset_filters.py +79 -0
- binalyze_air/apis/recent_activities.py +71 -0
- binalyze_air/apis/relay_server.py +104 -0
- binalyze_air/apis/settings.py +395 -27
- binalyze_air/apis/tasks.py +80 -0
- binalyze_air/apis/triage.py +197 -0
- binalyze_air/apis/user_management.py +183 -74
- binalyze_air/apis/webhook_executions.py +50 -0
- binalyze_air/apis/webhooks.py +322 -230
- binalyze_air/base.py +207 -133
- binalyze_air/client.py +217 -1337
- binalyze_air/commands/__init__.py +175 -145
- binalyze_air/commands/acquisitions.py +661 -387
- binalyze_air/commands/api_tokens.py +55 -0
- binalyze_air/commands/assets.py +324 -362
- binalyze_air/commands/{authentication.py → auth.py} +36 -36
- binalyze_air/commands/auto_asset_tags.py +230 -230
- binalyze_air/commands/backup.py +47 -0
- binalyze_air/commands/baseline.py +32 -396
- binalyze_air/commands/cases.py +609 -602
- binalyze_air/commands/cloud_forensics.py +88 -0
- binalyze_air/commands/event_subscription.py +101 -101
- binalyze_air/commands/evidences.py +918 -988
- binalyze_air/commands/interact.py +172 -58
- binalyze_air/commands/investigation_hub.py +315 -0
- binalyze_air/commands/license.py +183 -0
- binalyze_air/commands/logger.py +126 -0
- binalyze_air/commands/multipart_upload.py +363 -0
- binalyze_air/commands/notifications.py +45 -0
- binalyze_air/commands/organizations.py +200 -221
- binalyze_air/commands/policies.py +175 -203
- binalyze_air/commands/preset_filters.py +55 -0
- binalyze_air/commands/recent_activities.py +32 -0
- binalyze_air/commands/relay_server.py +144 -0
- binalyze_air/commands/settings.py +431 -29
- binalyze_air/commands/tasks.py +95 -56
- binalyze_air/commands/triage.py +224 -360
- binalyze_air/commands/user_management.py +351 -126
- binalyze_air/commands/webhook_executions.py +77 -0
- binalyze_air/config.py +244 -244
- binalyze_air/exceptions.py +49 -49
- binalyze_air/http_client.py +426 -305
- binalyze_air/models/__init__.py +287 -285
- binalyze_air/models/acquisitions.py +365 -250
- binalyze_air/models/api_tokens.py +73 -0
- binalyze_air/models/assets.py +438 -438
- binalyze_air/models/audit.py +247 -272
- binalyze_air/models/audit_logs.py +14 -0
- binalyze_air/models/{authentication.py → auth.py} +69 -69
- binalyze_air/models/auto_asset_tags.py +227 -116
- binalyze_air/models/backup.py +138 -0
- binalyze_air/models/baseline.py +231 -231
- binalyze_air/models/cases.py +275 -275
- binalyze_air/models/cloud_forensics.py +145 -0
- binalyze_air/models/event_subscription.py +170 -171
- binalyze_air/models/evidence.py +65 -65
- binalyze_air/models/evidences.py +367 -348
- binalyze_air/models/interact.py +266 -135
- binalyze_air/models/investigation_hub.py +265 -0
- binalyze_air/models/license.py +150 -0
- binalyze_air/models/logger.py +83 -0
- binalyze_air/models/multipart_upload.py +352 -0
- binalyze_air/models/notifications.py +138 -0
- binalyze_air/models/organizations.py +293 -293
- binalyze_air/models/params.py +153 -127
- binalyze_air/models/policies.py +260 -249
- binalyze_air/models/preset_filters.py +79 -0
- binalyze_air/models/recent_activities.py +70 -0
- binalyze_air/models/relay_server.py +121 -0
- binalyze_air/models/settings.py +538 -84
- binalyze_air/models/tasks.py +215 -149
- binalyze_air/models/triage.py +141 -142
- binalyze_air/models/user_management.py +200 -97
- binalyze_air/models/webhook_executions.py +33 -0
- binalyze_air/queries/__init__.py +121 -133
- binalyze_air/queries/acquisitions.py +155 -155
- binalyze_air/queries/api_tokens.py +46 -0
- binalyze_air/queries/assets.py +186 -105
- binalyze_air/queries/audit.py +400 -416
- binalyze_air/queries/{authentication.py → auth.py} +55 -55
- binalyze_air/queries/auto_asset_tags.py +59 -59
- binalyze_air/queries/backup.py +66 -0
- binalyze_air/queries/baseline.py +21 -185
- binalyze_air/queries/cases.py +292 -292
- binalyze_air/queries/cloud_forensics.py +137 -0
- binalyze_air/queries/event_subscription.py +54 -54
- binalyze_air/queries/evidence.py +139 -139
- binalyze_air/queries/evidences.py +279 -279
- binalyze_air/queries/interact.py +140 -28
- binalyze_air/queries/investigation_hub.py +329 -0
- binalyze_air/queries/license.py +85 -0
- binalyze_air/queries/logger.py +58 -0
- binalyze_air/queries/multipart_upload.py +180 -0
- binalyze_air/queries/notifications.py +71 -0
- binalyze_air/queries/organizations.py +222 -222
- binalyze_air/queries/params.py +154 -115
- binalyze_air/queries/policies.py +149 -149
- binalyze_air/queries/preset_filters.py +60 -0
- binalyze_air/queries/recent_activities.py +44 -0
- binalyze_air/queries/relay_server.py +42 -0
- binalyze_air/queries/settings.py +533 -20
- binalyze_air/queries/tasks.py +125 -81
- binalyze_air/queries/triage.py +230 -230
- binalyze_air/queries/user_management.py +193 -83
- binalyze_air/queries/webhook_executions.py +39 -0
- binalyze_air_sdk-1.0.3.dist-info/METADATA +752 -0
- binalyze_air_sdk-1.0.3.dist-info/RECORD +132 -0
- {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/WHEEL +1 -1
- binalyze_air/apis/endpoints.py +0 -22
- binalyze_air/apis/evidences.py +0 -216
- binalyze_air/apis/users.py +0 -68
- binalyze_air/commands/users.py +0 -101
- binalyze_air/models/endpoints.py +0 -76
- binalyze_air/models/users.py +0 -82
- binalyze_air/queries/endpoints.py +0 -25
- binalyze_air/queries/users.py +0 -69
- binalyze_air_sdk-1.0.1.dist-info/METADATA +0 -635
- binalyze_air_sdk-1.0.1.dist-info/RECORD +0 -82
- {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
binalyze_air/queries/triage.py
CHANGED
@@ -1,231 +1,231 @@
|
|
1
|
-
"""
|
2
|
-
Triage-related queries for the Binalyze AIR SDK.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import List, Optional, Dict, Any
|
6
|
-
|
7
|
-
from ..base import Query
|
8
|
-
from ..models.triage import (
|
9
|
-
TriageRule, TriageTag, TriageFilter, TriageRuleType, TriageSeverity, TriageStatus
|
10
|
-
)
|
11
|
-
from ..http_client import HTTPClient
|
12
|
-
|
13
|
-
|
14
|
-
class ListTriageRulesQuery(Query[List[TriageRule]]):
|
15
|
-
"""Query to list triage rules with optional filtering."""
|
16
|
-
|
17
|
-
def __init__(self, http_client: HTTPClient, filter_params: Optional[TriageFilter] = None, organization_ids: Optional[List[int]] = None):
|
18
|
-
self.http_client = http_client
|
19
|
-
self.filter_params = filter_params or TriageFilter()
|
20
|
-
self.organization_ids = organization_ids or [0]
|
21
|
-
|
22
|
-
def execute(self) -> List[TriageRule]:
|
23
|
-
"""Execute the query to list triage rules."""
|
24
|
-
params = self.filter_params.to_params()
|
25
|
-
|
26
|
-
# Add organization IDs
|
27
|
-
params["filter[organizationIds]"] = ",".join(map(str, self.organization_ids))
|
28
|
-
|
29
|
-
response = self.http_client.get("triages/rules", params=params)
|
30
|
-
|
31
|
-
entities = response.get("result", {}).get("entities", [])
|
32
|
-
|
33
|
-
rules = []
|
34
|
-
for entity_data in entities:
|
35
|
-
mapped_data = {
|
36
|
-
"id": entity_data.get("_id"),
|
37
|
-
"name": entity_data.get("description", ""), # Use description as name
|
38
|
-
"description": entity_data.get("description"),
|
39
|
-
"type": entity_data.get("engine", "yara"), # Use engine as type
|
40
|
-
"rule_content": entity_data.get("rule", ""), # Try "rule" field
|
41
|
-
"enabled": entity_data.get("enabled", True),
|
42
|
-
"severity": entity_data.get("severity", "medium"),
|
43
|
-
"tags": entity_data.get("tags", []),
|
44
|
-
"search_in": entity_data.get("searchIn"), # Map searchIn field
|
45
|
-
"organization_id": entity_data.get("organizationId", 0),
|
46
|
-
"organization_ids": entity_data.get("organizationIds", []), # Map organizationIds array
|
47
|
-
"created_at": entity_data.get("createdAt"),
|
48
|
-
"updated_at": entity_data.get("updatedAt"),
|
49
|
-
"created_by": entity_data.get("createdBy", "Unknown"),
|
50
|
-
"updated_by": entity_data.get("updatedBy"),
|
51
|
-
"match_count": entity_data.get("matchCount", 0),
|
52
|
-
"last_match": entity_data.get("lastMatch"),
|
53
|
-
"deletable": entity_data.get("deletable"), # Map deletable field
|
54
|
-
}
|
55
|
-
|
56
|
-
# Remove None values
|
57
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
58
|
-
|
59
|
-
rules.append(TriageRule(**mapped_data))
|
60
|
-
|
61
|
-
return rules
|
62
|
-
|
63
|
-
|
64
|
-
class GetTriageRuleQuery(Query[TriageRule]):
|
65
|
-
"""Query to get a specific triage rule by ID."""
|
66
|
-
|
67
|
-
def __init__(self, http_client: HTTPClient, rule_id: str):
|
68
|
-
self.http_client = http_client
|
69
|
-
self.rule_id = rule_id
|
70
|
-
|
71
|
-
def execute(self) -> TriageRule:
|
72
|
-
"""Execute the query to get triage rule details."""
|
73
|
-
response = self.http_client.get(f"triages/rules/{self.rule_id}")
|
74
|
-
|
75
|
-
entity_data = response.get("result", {})
|
76
|
-
|
77
|
-
mapped_data = {
|
78
|
-
"id": entity_data.get("_id"),
|
79
|
-
"name": entity_data.get("description", ""), # Use description as name
|
80
|
-
"description": entity_data.get("description"),
|
81
|
-
"type": entity_data.get("engine", "yara"), # Use engine as type
|
82
|
-
"rule_content": entity_data.get("rule", ""), # Try "rule" field
|
83
|
-
"enabled": entity_data.get("enabled", True),
|
84
|
-
"severity": entity_data.get("severity", "medium"),
|
85
|
-
"tags": entity_data.get("tags", []),
|
86
|
-
"search_in": entity_data.get("searchIn"), # Map searchIn field
|
87
|
-
"organization_id": entity_data.get("organizationId", 0),
|
88
|
-
"organization_ids": entity_data.get("organizationIds", []), # Map organizationIds array
|
89
|
-
"created_at": entity_data.get("createdAt"),
|
90
|
-
"updated_at": entity_data.get("updatedAt"),
|
91
|
-
"created_by": entity_data.get("createdBy", "Unknown"),
|
92
|
-
"updated_by": entity_data.get("updatedBy"),
|
93
|
-
"match_count": entity_data.get("matchCount", 0),
|
94
|
-
"last_match": entity_data.get("lastMatch"),
|
95
|
-
"deletable": entity_data.get("deletable"), # Map deletable field
|
96
|
-
}
|
97
|
-
|
98
|
-
# Remove None values
|
99
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
100
|
-
|
101
|
-
return TriageRule(**mapped_data)
|
102
|
-
|
103
|
-
|
104
|
-
class GetTriageResultsQuery(Query[Dict[str, Any]]):
|
105
|
-
"""Query to get triage results for a specific task or rule."""
|
106
|
-
|
107
|
-
def __init__(self, http_client: HTTPClient, task_id: Optional[str] = None, rule_id: Optional[str] = None):
|
108
|
-
self.http_client = http_client
|
109
|
-
self.task_id = task_id
|
110
|
-
self.rule_id = rule_id
|
111
|
-
|
112
|
-
def execute(self) -> Dict[str, Any]:
|
113
|
-
"""Execute the query to get triage results."""
|
114
|
-
params = {}
|
115
|
-
|
116
|
-
if self.task_id:
|
117
|
-
params["taskId"] = self.task_id
|
118
|
-
if self.rule_id:
|
119
|
-
params["ruleId"] = self.rule_id
|
120
|
-
|
121
|
-
response = self.http_client.get("triages/results", params=params)
|
122
|
-
return response.get("result", {})
|
123
|
-
|
124
|
-
|
125
|
-
class GetTriageMatchesQuery(Query[Dict[str, Any]]):
|
126
|
-
"""Query to get triage matches for analysis."""
|
127
|
-
|
128
|
-
def __init__(self, http_client: HTTPClient, endpoint_id: str, task_id: str):
|
129
|
-
self.http_client = http_client
|
130
|
-
self.endpoint_id = endpoint_id
|
131
|
-
self.task_id = task_id
|
132
|
-
|
133
|
-
def execute(self) -> Dict[str, Any]:
|
134
|
-
"""Execute the query to get triage matches."""
|
135
|
-
params = {
|
136
|
-
"endpointId": self.endpoint_id,
|
137
|
-
"taskId": self.task_id
|
138
|
-
}
|
139
|
-
|
140
|
-
response = self.http_client.get("triages/matches", params=params)
|
141
|
-
return response.get("result", {})
|
142
|
-
|
143
|
-
|
144
|
-
class ListTriageTagsQuery(Query[List[TriageTag]]):
|
145
|
-
"""Query to list triage tags."""
|
146
|
-
|
147
|
-
def __init__(self, http_client: HTTPClient, organization_id: Optional[int] = None):
|
148
|
-
self.http_client = http_client
|
149
|
-
self.organization_id = organization_id or 0
|
150
|
-
|
151
|
-
def execute(self) -> List[TriageTag]:
|
152
|
-
"""Execute the query to list triage tags."""
|
153
|
-
# Use singular organizationId as per API documentation
|
154
|
-
params = {"filter[organizationId]": str(self.organization_id)}
|
155
|
-
|
156
|
-
response = self.http_client.get("triages/tags", params=params)
|
157
|
-
|
158
|
-
# Handle different response formats: direct list or wrapped in result
|
159
|
-
if isinstance(response, list):
|
160
|
-
# Direct list response format
|
161
|
-
entities = response
|
162
|
-
elif isinstance(response, dict):
|
163
|
-
# Wrapped response format - check if result is list or dict
|
164
|
-
result_data = response.get("result", [])
|
165
|
-
if isinstance(result_data, list):
|
166
|
-
# result is a direct list of entities
|
167
|
-
entities = result_data
|
168
|
-
elif isinstance(result_data, dict):
|
169
|
-
# result is a dict with entities inside
|
170
|
-
entities = result_data.get("entities", [])
|
171
|
-
else:
|
172
|
-
entities = []
|
173
|
-
|
174
|
-
# Fallback: if no entities found, try direct entities field
|
175
|
-
if not entities and "entities" in response:
|
176
|
-
entities = response.get("entities", [])
|
177
|
-
else:
|
178
|
-
# Unknown format
|
179
|
-
entities = []
|
180
|
-
|
181
|
-
tags = []
|
182
|
-
for entity_data in entities:
|
183
|
-
# Ensure entity_data is a dictionary
|
184
|
-
if not isinstance(entity_data, dict):
|
185
|
-
continue
|
186
|
-
|
187
|
-
mapped_data = {
|
188
|
-
"id": entity_data.get("id") or entity_data.get("_id"), # Handle both id and _id
|
189
|
-
"name": entity_data.get("name"),
|
190
|
-
"description": entity_data.get("description"),
|
191
|
-
"color": entity_data.get("color", "#3498db"),
|
192
|
-
"created_at": entity_data.get("createdAt"),
|
193
|
-
"created_by": entity_data.get("createdBy", "Unknown"), # Provide default for required field
|
194
|
-
"organization_id": entity_data.get("organizationId", 0),
|
195
|
-
"usage_count": entity_data.get("usageCount") or entity_data.get("count", 0), # Handle both count and usageCount
|
196
|
-
}
|
197
|
-
|
198
|
-
# Remove None values but keep defaults for required fields
|
199
|
-
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
200
|
-
|
201
|
-
tags.append(TriageTag(**mapped_data))
|
202
|
-
|
203
|
-
return tags
|
204
|
-
|
205
|
-
|
206
|
-
class ListTriageProfilesQuery(Query[List[Dict[str, Any]]]):
|
207
|
-
"""Query to list triage profiles."""
|
208
|
-
|
209
|
-
def __init__(self, http_client: HTTPClient, organization_id: Optional[int] = None):
|
210
|
-
self.http_client = http_client
|
211
|
-
self.organization_id = organization_id or 0
|
212
|
-
|
213
|
-
def execute(self) -> List[Dict[str, Any]]:
|
214
|
-
"""Execute the query to list triage profiles."""
|
215
|
-
params = {"filter[organizationId]": str(self.organization_id)}
|
216
|
-
|
217
|
-
response = self.http_client.get("triages/profiles", params=params)
|
218
|
-
return response.get("result", {}).get("entities", [])
|
219
|
-
|
220
|
-
|
221
|
-
class GetTriageProfileQuery(Query[Dict[str, Any]]):
|
222
|
-
"""Query to get a specific triage profile by ID."""
|
223
|
-
|
224
|
-
def __init__(self, http_client: HTTPClient, profile_id: str):
|
225
|
-
self.http_client = http_client
|
226
|
-
self.profile_id = profile_id
|
227
|
-
|
228
|
-
def execute(self) -> Dict[str, Any]:
|
229
|
-
"""Execute the query to get triage profile details."""
|
230
|
-
response = self.http_client.get(f"triages/profiles/{self.profile_id}")
|
1
|
+
"""
|
2
|
+
Triage-related queries for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
|
7
|
+
from ..base import Query
|
8
|
+
from ..models.triage import (
|
9
|
+
TriageRule, TriageTag, TriageFilter, TriageRuleType, TriageSeverity, TriageStatus
|
10
|
+
)
|
11
|
+
from ..http_client import HTTPClient
|
12
|
+
|
13
|
+
|
14
|
+
class ListTriageRulesQuery(Query[List[TriageRule]]):
|
15
|
+
"""Query to list triage rules with optional filtering."""
|
16
|
+
|
17
|
+
def __init__(self, http_client: HTTPClient, filter_params: Optional[TriageFilter] = None, organization_ids: Optional[List[int]] = None):
|
18
|
+
self.http_client = http_client
|
19
|
+
self.filter_params = filter_params or TriageFilter()
|
20
|
+
self.organization_ids = organization_ids or [0]
|
21
|
+
|
22
|
+
def execute(self) -> List[TriageRule]:
|
23
|
+
"""Execute the query to list triage rules."""
|
24
|
+
params = self.filter_params.to_params()
|
25
|
+
|
26
|
+
# Add organization IDs
|
27
|
+
params["filter[organizationIds]"] = ",".join(map(str, self.organization_ids))
|
28
|
+
|
29
|
+
response = self.http_client.get("triages/rules", params=params)
|
30
|
+
|
31
|
+
entities = response.get("result", {}).get("entities", [])
|
32
|
+
|
33
|
+
rules = []
|
34
|
+
for entity_data in entities:
|
35
|
+
mapped_data = {
|
36
|
+
"id": entity_data.get("_id"),
|
37
|
+
"name": entity_data.get("description", ""), # Use description as name
|
38
|
+
"description": entity_data.get("description"),
|
39
|
+
"type": entity_data.get("engine", "yara"), # Use engine as type
|
40
|
+
"rule_content": entity_data.get("rule", ""), # Try "rule" field
|
41
|
+
"enabled": entity_data.get("enabled", True),
|
42
|
+
"severity": entity_data.get("severity", "medium"),
|
43
|
+
"tags": entity_data.get("tags", []),
|
44
|
+
"search_in": entity_data.get("searchIn"), # Map searchIn field
|
45
|
+
"organization_id": entity_data.get("organizationId", 0),
|
46
|
+
"organization_ids": entity_data.get("organizationIds", []), # Map organizationIds array
|
47
|
+
"created_at": entity_data.get("createdAt"),
|
48
|
+
"updated_at": entity_data.get("updatedAt"),
|
49
|
+
"created_by": entity_data.get("createdBy", "Unknown"),
|
50
|
+
"updated_by": entity_data.get("updatedBy"),
|
51
|
+
"match_count": entity_data.get("matchCount", 0),
|
52
|
+
"last_match": entity_data.get("lastMatch"),
|
53
|
+
"deletable": entity_data.get("deletable"), # Map deletable field
|
54
|
+
}
|
55
|
+
|
56
|
+
# Remove None values
|
57
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
58
|
+
|
59
|
+
rules.append(TriageRule(**mapped_data))
|
60
|
+
|
61
|
+
return rules
|
62
|
+
|
63
|
+
|
64
|
+
class GetTriageRuleQuery(Query[TriageRule]):
|
65
|
+
"""Query to get a specific triage rule by ID."""
|
66
|
+
|
67
|
+
def __init__(self, http_client: HTTPClient, rule_id: str):
|
68
|
+
self.http_client = http_client
|
69
|
+
self.rule_id = rule_id
|
70
|
+
|
71
|
+
def execute(self) -> TriageRule:
|
72
|
+
"""Execute the query to get triage rule details."""
|
73
|
+
response = self.http_client.get(f"triages/rules/{self.rule_id}")
|
74
|
+
|
75
|
+
entity_data = response.get("result", {})
|
76
|
+
|
77
|
+
mapped_data = {
|
78
|
+
"id": entity_data.get("_id"),
|
79
|
+
"name": entity_data.get("description", ""), # Use description as name
|
80
|
+
"description": entity_data.get("description"),
|
81
|
+
"type": entity_data.get("engine", "yara"), # Use engine as type
|
82
|
+
"rule_content": entity_data.get("rule", ""), # Try "rule" field
|
83
|
+
"enabled": entity_data.get("enabled", True),
|
84
|
+
"severity": entity_data.get("severity", "medium"),
|
85
|
+
"tags": entity_data.get("tags", []),
|
86
|
+
"search_in": entity_data.get("searchIn"), # Map searchIn field
|
87
|
+
"organization_id": entity_data.get("organizationId", 0),
|
88
|
+
"organization_ids": entity_data.get("organizationIds", []), # Map organizationIds array
|
89
|
+
"created_at": entity_data.get("createdAt"),
|
90
|
+
"updated_at": entity_data.get("updatedAt"),
|
91
|
+
"created_by": entity_data.get("createdBy", "Unknown"),
|
92
|
+
"updated_by": entity_data.get("updatedBy"),
|
93
|
+
"match_count": entity_data.get("matchCount", 0),
|
94
|
+
"last_match": entity_data.get("lastMatch"),
|
95
|
+
"deletable": entity_data.get("deletable"), # Map deletable field
|
96
|
+
}
|
97
|
+
|
98
|
+
# Remove None values
|
99
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
100
|
+
|
101
|
+
return TriageRule(**mapped_data)
|
102
|
+
|
103
|
+
|
104
|
+
class GetTriageResultsQuery(Query[Dict[str, Any]]):
|
105
|
+
"""Query to get triage results for a specific task or rule."""
|
106
|
+
|
107
|
+
def __init__(self, http_client: HTTPClient, task_id: Optional[str] = None, rule_id: Optional[str] = None):
|
108
|
+
self.http_client = http_client
|
109
|
+
self.task_id = task_id
|
110
|
+
self.rule_id = rule_id
|
111
|
+
|
112
|
+
def execute(self) -> Dict[str, Any]:
|
113
|
+
"""Execute the query to get triage results."""
|
114
|
+
params = {}
|
115
|
+
|
116
|
+
if self.task_id:
|
117
|
+
params["taskId"] = self.task_id
|
118
|
+
if self.rule_id:
|
119
|
+
params["ruleId"] = self.rule_id
|
120
|
+
|
121
|
+
response = self.http_client.get("triages/results", params=params)
|
122
|
+
return response.get("result", {})
|
123
|
+
|
124
|
+
|
125
|
+
class GetTriageMatchesQuery(Query[Dict[str, Any]]):
|
126
|
+
"""Query to get triage matches for analysis."""
|
127
|
+
|
128
|
+
def __init__(self, http_client: HTTPClient, endpoint_id: str, task_id: str):
|
129
|
+
self.http_client = http_client
|
130
|
+
self.endpoint_id = endpoint_id
|
131
|
+
self.task_id = task_id
|
132
|
+
|
133
|
+
def execute(self) -> Dict[str, Any]:
|
134
|
+
"""Execute the query to get triage matches."""
|
135
|
+
params = {
|
136
|
+
"endpointId": self.endpoint_id,
|
137
|
+
"taskId": self.task_id
|
138
|
+
}
|
139
|
+
|
140
|
+
response = self.http_client.get("triages/matches", params=params)
|
141
|
+
return response.get("result", {})
|
142
|
+
|
143
|
+
|
144
|
+
class ListTriageTagsQuery(Query[List[TriageTag]]):
|
145
|
+
"""Query to list triage tags."""
|
146
|
+
|
147
|
+
def __init__(self, http_client: HTTPClient, organization_id: Optional[int] = None):
|
148
|
+
self.http_client = http_client
|
149
|
+
self.organization_id = organization_id or 0
|
150
|
+
|
151
|
+
def execute(self) -> List[TriageTag]:
|
152
|
+
"""Execute the query to list triage tags."""
|
153
|
+
# Use singular organizationId as per API documentation
|
154
|
+
params = {"filter[organizationId]": str(self.organization_id)}
|
155
|
+
|
156
|
+
response = self.http_client.get("triages/tags", params=params)
|
157
|
+
|
158
|
+
# Handle different response formats: direct list or wrapped in result
|
159
|
+
if isinstance(response, list):
|
160
|
+
# Direct list response format
|
161
|
+
entities = response
|
162
|
+
elif isinstance(response, dict):
|
163
|
+
# Wrapped response format - check if result is list or dict
|
164
|
+
result_data = response.get("result", [])
|
165
|
+
if isinstance(result_data, list):
|
166
|
+
# result is a direct list of entities
|
167
|
+
entities = result_data
|
168
|
+
elif isinstance(result_data, dict):
|
169
|
+
# result is a dict with entities inside
|
170
|
+
entities = result_data.get("entities", [])
|
171
|
+
else:
|
172
|
+
entities = []
|
173
|
+
|
174
|
+
# Fallback: if no entities found, try direct entities field
|
175
|
+
if not entities and "entities" in response:
|
176
|
+
entities = response.get("entities", [])
|
177
|
+
else:
|
178
|
+
# Unknown format
|
179
|
+
entities = []
|
180
|
+
|
181
|
+
tags = []
|
182
|
+
for entity_data in entities:
|
183
|
+
# Ensure entity_data is a dictionary
|
184
|
+
if not isinstance(entity_data, dict):
|
185
|
+
continue
|
186
|
+
|
187
|
+
mapped_data = {
|
188
|
+
"id": entity_data.get("id") or entity_data.get("_id"), # Handle both id and _id
|
189
|
+
"name": entity_data.get("name"),
|
190
|
+
"description": entity_data.get("description"),
|
191
|
+
"color": entity_data.get("color", "#3498db"),
|
192
|
+
"created_at": entity_data.get("createdAt"),
|
193
|
+
"created_by": entity_data.get("createdBy", "Unknown"), # Provide default for required field
|
194
|
+
"organization_id": entity_data.get("organizationId", 0),
|
195
|
+
"usage_count": entity_data.get("usageCount") or entity_data.get("count", 0), # Handle both count and usageCount
|
196
|
+
}
|
197
|
+
|
198
|
+
# Remove None values but keep defaults for required fields
|
199
|
+
mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
|
200
|
+
|
201
|
+
tags.append(TriageTag(**mapped_data))
|
202
|
+
|
203
|
+
return tags
|
204
|
+
|
205
|
+
|
206
|
+
class ListTriageProfilesQuery(Query[List[Dict[str, Any]]]):
|
207
|
+
"""Query to list triage profiles."""
|
208
|
+
|
209
|
+
def __init__(self, http_client: HTTPClient, organization_id: Optional[int] = None):
|
210
|
+
self.http_client = http_client
|
211
|
+
self.organization_id = organization_id or 0
|
212
|
+
|
213
|
+
def execute(self) -> List[Dict[str, Any]]:
|
214
|
+
"""Execute the query to list triage profiles."""
|
215
|
+
params = {"filter[organizationId]": str(self.organization_id)}
|
216
|
+
|
217
|
+
response = self.http_client.get("triages/profiles", params=params)
|
218
|
+
return response.get("result", {}).get("entities", [])
|
219
|
+
|
220
|
+
|
221
|
+
class GetTriageProfileQuery(Query[Dict[str, Any]]):
|
222
|
+
"""Query to get a specific triage profile by ID."""
|
223
|
+
|
224
|
+
def __init__(self, http_client: HTTPClient, profile_id: str):
|
225
|
+
self.http_client = http_client
|
226
|
+
self.profile_id = profile_id
|
227
|
+
|
228
|
+
def execute(self) -> Dict[str, Any]:
|
229
|
+
"""Execute the query to get triage profile details."""
|
230
|
+
response = self.http_client.get(f"triages/profiles/{self.profile_id}")
|
231
231
|
return response.get("result", {})
|