binalyze-air-sdk 1.0.1__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 -0
- binalyze_air/apis/__init__.py +27 -0
- binalyze_air/apis/authentication.py +27 -0
- binalyze_air/apis/auto_asset_tags.py +75 -0
- binalyze_air/apis/endpoints.py +22 -0
- binalyze_air/apis/event_subscription.py +97 -0
- binalyze_air/apis/evidence.py +53 -0
- binalyze_air/apis/evidences.py +216 -0
- binalyze_air/apis/interact.py +36 -0
- binalyze_air/apis/params.py +40 -0
- binalyze_air/apis/settings.py +27 -0
- binalyze_air/apis/user_management.py +74 -0
- binalyze_air/apis/users.py +68 -0
- binalyze_air/apis/webhooks.py +231 -0
- binalyze_air/base.py +133 -0
- binalyze_air/client.py +1338 -0
- binalyze_air/commands/__init__.py +146 -0
- binalyze_air/commands/acquisitions.py +387 -0
- binalyze_air/commands/assets.py +363 -0
- binalyze_air/commands/authentication.py +37 -0
- binalyze_air/commands/auto_asset_tags.py +231 -0
- binalyze_air/commands/baseline.py +396 -0
- binalyze_air/commands/cases.py +603 -0
- binalyze_air/commands/event_subscription.py +102 -0
- binalyze_air/commands/evidences.py +988 -0
- binalyze_air/commands/interact.py +58 -0
- binalyze_air/commands/organizations.py +221 -0
- binalyze_air/commands/policies.py +203 -0
- binalyze_air/commands/settings.py +29 -0
- binalyze_air/commands/tasks.py +56 -0
- binalyze_air/commands/triage.py +360 -0
- binalyze_air/commands/user_management.py +126 -0
- binalyze_air/commands/users.py +101 -0
- binalyze_air/config.py +245 -0
- binalyze_air/exceptions.py +50 -0
- binalyze_air/http_client.py +306 -0
- binalyze_air/models/__init__.py +285 -0
- binalyze_air/models/acquisitions.py +251 -0
- binalyze_air/models/assets.py +439 -0
- binalyze_air/models/audit.py +273 -0
- binalyze_air/models/authentication.py +70 -0
- binalyze_air/models/auto_asset_tags.py +117 -0
- binalyze_air/models/baseline.py +232 -0
- binalyze_air/models/cases.py +276 -0
- binalyze_air/models/endpoints.py +76 -0
- binalyze_air/models/event_subscription.py +172 -0
- binalyze_air/models/evidence.py +66 -0
- binalyze_air/models/evidences.py +349 -0
- binalyze_air/models/interact.py +136 -0
- binalyze_air/models/organizations.py +294 -0
- binalyze_air/models/params.py +128 -0
- binalyze_air/models/policies.py +250 -0
- binalyze_air/models/settings.py +84 -0
- binalyze_air/models/tasks.py +149 -0
- binalyze_air/models/triage.py +143 -0
- binalyze_air/models/user_management.py +97 -0
- binalyze_air/models/users.py +82 -0
- binalyze_air/queries/__init__.py +134 -0
- binalyze_air/queries/acquisitions.py +156 -0
- binalyze_air/queries/assets.py +105 -0
- binalyze_air/queries/audit.py +417 -0
- binalyze_air/queries/authentication.py +56 -0
- binalyze_air/queries/auto_asset_tags.py +60 -0
- binalyze_air/queries/baseline.py +185 -0
- binalyze_air/queries/cases.py +293 -0
- binalyze_air/queries/endpoints.py +25 -0
- binalyze_air/queries/event_subscription.py +55 -0
- binalyze_air/queries/evidence.py +140 -0
- binalyze_air/queries/evidences.py +280 -0
- binalyze_air/queries/interact.py +28 -0
- binalyze_air/queries/organizations.py +223 -0
- binalyze_air/queries/params.py +115 -0
- binalyze_air/queries/policies.py +150 -0
- binalyze_air/queries/settings.py +20 -0
- binalyze_air/queries/tasks.py +82 -0
- binalyze_air/queries/triage.py +231 -0
- binalyze_air/queries/user_management.py +83 -0
- binalyze_air/queries/users.py +69 -0
- binalyze_air_sdk-1.0.1.dist-info/METADATA +635 -0
- binalyze_air_sdk-1.0.1.dist-info/RECORD +82 -0
- binalyze_air_sdk-1.0.1.dist-info/WHEEL +5 -0
- binalyze_air_sdk-1.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,273 @@
|
|
1
|
+
"""
|
2
|
+
Audit-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
|
9
|
+
from ..base import AIRBaseModel, Filter
|
10
|
+
|
11
|
+
|
12
|
+
class AuditLevel(str, Enum):
|
13
|
+
"""Audit log level."""
|
14
|
+
INFO = "info"
|
15
|
+
WARNING = "warning"
|
16
|
+
ERROR = "error"
|
17
|
+
CRITICAL = "critical"
|
18
|
+
|
19
|
+
|
20
|
+
class AuditCategory(str, Enum):
|
21
|
+
"""Audit event category."""
|
22
|
+
AUTHENTICATION = "authentication"
|
23
|
+
AUTHORIZATION = "authorization"
|
24
|
+
DATA_ACCESS = "data_access"
|
25
|
+
SYSTEM_CHANGE = "system_change"
|
26
|
+
USER_ACTION = "user_action"
|
27
|
+
API_CALL = "api_call"
|
28
|
+
POLICY_EXECUTION = "policy_execution"
|
29
|
+
TASK_EXECUTION = "task_execution"
|
30
|
+
|
31
|
+
|
32
|
+
class AuditAction(str, Enum):
|
33
|
+
"""Audit action type."""
|
34
|
+
CREATE = "create"
|
35
|
+
READ = "read"
|
36
|
+
UPDATE = "update"
|
37
|
+
DELETE = "delete"
|
38
|
+
EXECUTE = "execute"
|
39
|
+
LOGIN = "login"
|
40
|
+
LOGOUT = "logout"
|
41
|
+
DOWNLOAD = "download"
|
42
|
+
UPLOAD = "upload"
|
43
|
+
|
44
|
+
|
45
|
+
class AuditLog(AIRBaseModel):
|
46
|
+
"""Audit log model."""
|
47
|
+
|
48
|
+
id: str
|
49
|
+
timestamp: datetime
|
50
|
+
user_id: Optional[str] = None
|
51
|
+
username: Optional[str] = None
|
52
|
+
organization_id: int = 0
|
53
|
+
category: AuditCategory
|
54
|
+
action: AuditAction
|
55
|
+
resource_type: str
|
56
|
+
resource_id: Optional[str] = None
|
57
|
+
resource_name: Optional[str] = None
|
58
|
+
level: AuditLevel = AuditLevel.INFO
|
59
|
+
message: str
|
60
|
+
details: Dict[str, Any] = {}
|
61
|
+
ip_address: Optional[str] = None
|
62
|
+
user_agent: Optional[str] = None
|
63
|
+
session_id: Optional[str] = None
|
64
|
+
correlation_id: Optional[str] = None
|
65
|
+
success: bool = True
|
66
|
+
error_code: Optional[str] = None
|
67
|
+
duration: Optional[int] = None # milliseconds
|
68
|
+
tags: List[str] = []
|
69
|
+
|
70
|
+
|
71
|
+
class AuditSummary(AIRBaseModel):
|
72
|
+
"""Audit summary model."""
|
73
|
+
|
74
|
+
organization_id: int
|
75
|
+
date: datetime
|
76
|
+
total_events: int = 0
|
77
|
+
successful_events: int = 0
|
78
|
+
failed_events: int = 0
|
79
|
+
authentication_events: int = 0
|
80
|
+
authorization_events: int = 0
|
81
|
+
data_access_events: int = 0
|
82
|
+
system_change_events: int = 0
|
83
|
+
user_action_events: int = 0
|
84
|
+
api_call_events: int = 0
|
85
|
+
unique_users: int = 0
|
86
|
+
unique_ips: int = 0
|
87
|
+
top_users: List[Dict[str, Any]] = []
|
88
|
+
top_actions: List[Dict[str, Any]] = []
|
89
|
+
error_summary: List[Dict[str, Any]] = []
|
90
|
+
|
91
|
+
|
92
|
+
class AuditUserActivity(AIRBaseModel):
|
93
|
+
"""User activity audit model."""
|
94
|
+
|
95
|
+
user_id: str
|
96
|
+
username: str
|
97
|
+
organization_id: int
|
98
|
+
date: datetime
|
99
|
+
login_count: int = 0
|
100
|
+
action_count: int = 0
|
101
|
+
failed_login_count: int = 0
|
102
|
+
last_login: Optional[datetime] = None
|
103
|
+
last_action: Optional[datetime] = None
|
104
|
+
unique_ips: List[str] = []
|
105
|
+
actions_by_category: Dict[str, int] = {}
|
106
|
+
risk_score: float = 0.0
|
107
|
+
|
108
|
+
|
109
|
+
class AuditSystemEvent(AIRBaseModel):
|
110
|
+
"""System event audit model."""
|
111
|
+
|
112
|
+
id: str
|
113
|
+
timestamp: datetime
|
114
|
+
event_type: str
|
115
|
+
severity: AuditLevel
|
116
|
+
component: str
|
117
|
+
message: str
|
118
|
+
details: Dict[str, Any] = {}
|
119
|
+
organization_id: int = 0
|
120
|
+
resolved: bool = False
|
121
|
+
resolved_by: Optional[str] = None
|
122
|
+
resolved_at: Optional[datetime] = None
|
123
|
+
|
124
|
+
|
125
|
+
class AuditLogsFilter(Filter):
|
126
|
+
"""Filter for audit logs queries - matches NEW API specification exactly (POST with JSON body)."""
|
127
|
+
|
128
|
+
# Search and identification
|
129
|
+
search_term: Optional[str] = None
|
130
|
+
name: Optional[str] = None
|
131
|
+
|
132
|
+
# Audit log specific filters
|
133
|
+
type: Optional[str] = None # audit log type filter (changed from List[str] to str)
|
134
|
+
performed_by: Optional[str] = None # user who performed the action
|
135
|
+
endpoint_name: Optional[str] = None # endpoint name filter
|
136
|
+
|
137
|
+
# NEW PARAMETERS from updated API spec
|
138
|
+
event_source: Optional[str] = None # NEW: event source filter
|
139
|
+
occurred_at: Optional[str] = None # NEW: timestamp filter
|
140
|
+
data_filter: Optional[str] = None # NEW: data filtering capability
|
141
|
+
|
142
|
+
# Organization parameters - changed to single int instead of list
|
143
|
+
organization_ids: Optional[int] = None # Changed from List[int] to int (API expects single number)
|
144
|
+
all_organizations: Optional[bool] = None # true/false
|
145
|
+
|
146
|
+
def to_json_body(self) -> Dict[str, Any]:
|
147
|
+
"""Convert filter to JSON body for POST request - NEW API FORMAT."""
|
148
|
+
body = {}
|
149
|
+
|
150
|
+
# Pagination parameters (top level in body)
|
151
|
+
if self.page_number is not None:
|
152
|
+
body["pageNumber"] = self.page_number
|
153
|
+
if self.page_size is not None:
|
154
|
+
body["pageSize"] = self.page_size
|
155
|
+
if self.sort_by is not None:
|
156
|
+
body["sortBy"] = self.sort_by
|
157
|
+
if self.sort_type is not None:
|
158
|
+
body["sortType"] = self.sort_type
|
159
|
+
|
160
|
+
# Filter object (nested in body)
|
161
|
+
filter_obj = {}
|
162
|
+
|
163
|
+
if self.search_term is not None:
|
164
|
+
filter_obj["searchTerm"] = self.search_term
|
165
|
+
if self.name is not None:
|
166
|
+
filter_obj["name"] = self.name
|
167
|
+
if self.type is not None:
|
168
|
+
filter_obj["type"] = self.type
|
169
|
+
if self.performed_by is not None:
|
170
|
+
filter_obj["performedBy"] = self.performed_by
|
171
|
+
if self.endpoint_name is not None:
|
172
|
+
filter_obj["endpointName"] = self.endpoint_name
|
173
|
+
|
174
|
+
# NEW PARAMETERS
|
175
|
+
if self.event_source is not None:
|
176
|
+
filter_obj["eventSource"] = self.event_source
|
177
|
+
if self.occurred_at is not None:
|
178
|
+
filter_obj["occurredAt"] = self.occurred_at
|
179
|
+
if self.data_filter is not None:
|
180
|
+
filter_obj["dataFilter"] = self.data_filter
|
181
|
+
|
182
|
+
# Organization parameters
|
183
|
+
if self.organization_ids is not None:
|
184
|
+
filter_obj["organizationIds"] = self.organization_ids
|
185
|
+
if self.all_organizations is not None:
|
186
|
+
filter_obj["allOrganizations"] = self.all_organizations
|
187
|
+
|
188
|
+
# Only add filter object if it has content
|
189
|
+
if filter_obj:
|
190
|
+
body["filter"] = filter_obj
|
191
|
+
|
192
|
+
return body
|
193
|
+
|
194
|
+
def to_params(self) -> Dict[str, Any]:
|
195
|
+
"""DEPRECATED: Convert filter to query parameters - kept for backward compatibility."""
|
196
|
+
# Keep the old method for backward compatibility but mark as deprecated
|
197
|
+
import warnings
|
198
|
+
warnings.warn(
|
199
|
+
"to_params() is deprecated for audit logs. Use to_json_body() for new POST-based API.",
|
200
|
+
DeprecationWarning,
|
201
|
+
stacklevel=2
|
202
|
+
)
|
203
|
+
|
204
|
+
params = {}
|
205
|
+
|
206
|
+
# Pagination parameters (not in filter namespace) - only if set
|
207
|
+
if self.page_number is not None:
|
208
|
+
params["pageNumber"] = self.page_number
|
209
|
+
if self.page_size is not None:
|
210
|
+
params["pageSize"] = self.page_size
|
211
|
+
if self.sort_by is not None:
|
212
|
+
params["sortBy"] = self.sort_by
|
213
|
+
if self.sort_type is not None:
|
214
|
+
params["sortType"] = self.sort_type
|
215
|
+
|
216
|
+
# Add audit-specific filter parameters (use API field names)
|
217
|
+
if self.search_term is not None:
|
218
|
+
params["filter[searchTerm]"] = self.search_term
|
219
|
+
if self.name is not None:
|
220
|
+
params["filter[name]"] = self.name
|
221
|
+
if self.type is not None:
|
222
|
+
params["filter[type]"] = self.type
|
223
|
+
if self.performed_by is not None:
|
224
|
+
params["filter[performedBy]"] = self.performed_by
|
225
|
+
if self.endpoint_name is not None:
|
226
|
+
params["filter[endpointName]"] = self.endpoint_name
|
227
|
+
if self.organization_ids is not None:
|
228
|
+
params["filter[organizationIds]"] = str(self.organization_ids)
|
229
|
+
if self.all_organizations is not None:
|
230
|
+
params["filter[allOrganizations]"] = "true" if self.all_organizations else "false"
|
231
|
+
|
232
|
+
return params
|
233
|
+
|
234
|
+
|
235
|
+
class AuditFilter(Filter):
|
236
|
+
"""Filter for audit queries."""
|
237
|
+
|
238
|
+
user_id: Optional[str] = None
|
239
|
+
username: Optional[str] = None
|
240
|
+
category: Optional[List[AuditCategory]] = None
|
241
|
+
action: Optional[List[AuditAction]] = None
|
242
|
+
level: Optional[List[AuditLevel]] = None
|
243
|
+
resource_type: Optional[str] = None
|
244
|
+
resource_id: Optional[str] = None
|
245
|
+
ip_address: Optional[str] = None
|
246
|
+
success: Optional[bool] = None
|
247
|
+
start_date: Optional[datetime] = None
|
248
|
+
end_date: Optional[datetime] = None
|
249
|
+
tags: Optional[List[str]] = None
|
250
|
+
correlation_id: Optional[str] = None
|
251
|
+
|
252
|
+
|
253
|
+
class AuditExportRequest(AIRBaseModel):
|
254
|
+
"""Request model for exporting audit logs."""
|
255
|
+
|
256
|
+
filter_params: AuditFilter
|
257
|
+
format: str = "json" # json, csv, excel
|
258
|
+
include_details: bool = True
|
259
|
+
organization_ids: List[int] = []
|
260
|
+
|
261
|
+
|
262
|
+
class AuditRetentionPolicy(AIRBaseModel):
|
263
|
+
"""Audit retention policy model."""
|
264
|
+
|
265
|
+
organization_id: int
|
266
|
+
retention_days: int = 365
|
267
|
+
auto_archive: bool = True
|
268
|
+
archive_location: Optional[str] = None
|
269
|
+
compress_archives: bool = True
|
270
|
+
delete_after_archive: bool = False
|
271
|
+
created_at: Optional[datetime] = None
|
272
|
+
updated_at: Optional[datetime] = None
|
273
|
+
created_by: str
|
@@ -0,0 +1,70 @@
|
|
1
|
+
"""
|
2
|
+
Authentication-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Optional, List, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from pydantic import Field
|
8
|
+
|
9
|
+
from ..base import AIRBaseModel
|
10
|
+
|
11
|
+
|
12
|
+
class UserProfile(AIRBaseModel):
|
13
|
+
"""User profile information."""
|
14
|
+
name: Optional[str] = None
|
15
|
+
surname: Optional[str] = None
|
16
|
+
department: Optional[str] = None
|
17
|
+
|
18
|
+
|
19
|
+
class UserRole(AIRBaseModel):
|
20
|
+
"""User role information."""
|
21
|
+
id: Optional[str] = Field(alias="_id", default=None)
|
22
|
+
name: str
|
23
|
+
tag: str
|
24
|
+
created_at: Optional[str] = Field(alias="createdAt", default=None)
|
25
|
+
updated_at: Optional[str] = Field(alias="updatedAt", default=None)
|
26
|
+
created_by: Optional[str] = Field(alias="createdBy", default=None)
|
27
|
+
privilege_types: List[str] = Field(alias="privilegeTypes", default_factory=list)
|
28
|
+
|
29
|
+
|
30
|
+
class User(AIRBaseModel):
|
31
|
+
"""User model."""
|
32
|
+
|
33
|
+
id: str = Field(alias="_id")
|
34
|
+
username: str
|
35
|
+
email: str
|
36
|
+
organization_ids: Optional[str] = Field(alias="organizationIds", default=None) # Can be "ALL"
|
37
|
+
strategy: Optional[str] = None
|
38
|
+
profile: Optional[UserProfile] = None
|
39
|
+
privileges: List[str] = Field(default_factory=list)
|
40
|
+
roles: List[UserRole] = Field(default_factory=list)
|
41
|
+
tfa_enabled: bool = Field(alias="tfaEnabled", default=False)
|
42
|
+
created_at: Optional[str] = Field(alias="createdAt", default=None)
|
43
|
+
updated_at: Optional[str] = Field(alias="updatedAt", default=None)
|
44
|
+
has_password: bool = Field(alias="hasPassword", default=False)
|
45
|
+
photo: Optional[str] = None
|
46
|
+
groups: List[Any] = Field(default_factory=list)
|
47
|
+
user_flow_user_signature: Optional[str] = Field(alias="userFlowUserSignature", default=None)
|
48
|
+
user_flow_group_signature: Optional[str] = Field(alias="userFlowGroupSignature", default=None)
|
49
|
+
|
50
|
+
|
51
|
+
class AuthStatus(AIRBaseModel):
|
52
|
+
"""Authentication status model - matches actual API response."""
|
53
|
+
|
54
|
+
# The API doesn't return authenticated field, we derive it from success
|
55
|
+
authenticated: bool = True # Default to True since if we get a response, we're authenticated
|
56
|
+
user: Optional[User] = None
|
57
|
+
|
58
|
+
|
59
|
+
class LoginRequest(AIRBaseModel):
|
60
|
+
"""Login request model."""
|
61
|
+
|
62
|
+
username: str
|
63
|
+
password: str
|
64
|
+
|
65
|
+
|
66
|
+
class LoginResponse(AIRBaseModel):
|
67
|
+
"""Login response model."""
|
68
|
+
|
69
|
+
access_token: str = Field(alias="accessToken")
|
70
|
+
refresh_token: str = Field(alias="refreshToken")
|
@@ -0,0 +1,117 @@
|
|
1
|
+
"""
|
2
|
+
Auto Asset Tags-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Optional, List, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from pydantic import Field
|
8
|
+
from pydantic import ConfigDict
|
9
|
+
|
10
|
+
from ..base import AIRBaseModel, Filter
|
11
|
+
|
12
|
+
|
13
|
+
class AutoAssetTag(AIRBaseModel):
|
14
|
+
"""Auto asset tag model."""
|
15
|
+
|
16
|
+
id: str = Field(alias="_id")
|
17
|
+
tag: str
|
18
|
+
linux_conditions: Optional[Dict[str, Any]] = Field(alias="linuxConditions", default=None)
|
19
|
+
windows_conditions: Optional[Dict[str, Any]] = Field(alias="windowsConditions", default=None)
|
20
|
+
macos_conditions: Optional[Dict[str, Any]] = Field(alias="macosConditions", default=None)
|
21
|
+
organization_ids: Optional[List[int]] = Field(alias="organizationIds", default_factory=list)
|
22
|
+
created_at: Optional[datetime] = Field(alias="createdAt", default=None)
|
23
|
+
updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
|
24
|
+
created_by: Optional[str] = Field(alias="createdBy", default=None)
|
25
|
+
updated_by: Optional[str] = Field(alias="updatedBy", default=None)
|
26
|
+
|
27
|
+
|
28
|
+
class CreateAutoAssetTagRequest(AIRBaseModel):
|
29
|
+
"""Create auto asset tag request model."""
|
30
|
+
|
31
|
+
model_config = ConfigDict(populate_by_name=True)
|
32
|
+
|
33
|
+
tag: str
|
34
|
+
linux_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="linuxConditions")
|
35
|
+
windows_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="windowsConditions")
|
36
|
+
macos_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="macosConditions")
|
37
|
+
organization_ids: List[int] = Field(default_factory=list, alias="organizationIds")
|
38
|
+
|
39
|
+
|
40
|
+
class UpdateAutoAssetTagRequest(AIRBaseModel):
|
41
|
+
"""Update auto asset tag request model."""
|
42
|
+
|
43
|
+
model_config = ConfigDict(populate_by_name=True)
|
44
|
+
|
45
|
+
tag: Optional[str] = None
|
46
|
+
linux_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="linuxConditions")
|
47
|
+
windows_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="windowsConditions")
|
48
|
+
macos_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="macosConditions")
|
49
|
+
|
50
|
+
|
51
|
+
class StartTaggingRequest(AIRBaseModel):
|
52
|
+
"""Start tagging process request model."""
|
53
|
+
|
54
|
+
filter: Dict[str, Any]
|
55
|
+
schedulerConfig: Dict[str, Any]
|
56
|
+
|
57
|
+
|
58
|
+
class TaggingResult(AIRBaseModel):
|
59
|
+
"""Tagging process result model."""
|
60
|
+
|
61
|
+
taskId: str
|
62
|
+
message: str
|
63
|
+
processedTags: int
|
64
|
+
affectedAssets: int
|
65
|
+
|
66
|
+
|
67
|
+
class TaggingTask(AIRBaseModel):
|
68
|
+
"""Individual tagging task result from start tagging API."""
|
69
|
+
|
70
|
+
task_id: str = Field(alias="_id")
|
71
|
+
name: str = Field(alias="name")
|
72
|
+
|
73
|
+
|
74
|
+
class TaggingResponse(AIRBaseModel):
|
75
|
+
"""Response from start tagging API containing list of tasks."""
|
76
|
+
|
77
|
+
tasks: List[TaggingTask] = []
|
78
|
+
|
79
|
+
@classmethod
|
80
|
+
def from_api_result(cls, result_list: List[Dict[str, Any]]) -> 'TaggingResponse':
|
81
|
+
"""Create TaggingResponse from API result list."""
|
82
|
+
if not isinstance(result_list, list):
|
83
|
+
raise ValueError("API result must be a list")
|
84
|
+
|
85
|
+
tasks = [TaggingTask(**task) for task in result_list]
|
86
|
+
return cls(tasks=tasks)
|
87
|
+
|
88
|
+
@property
|
89
|
+
def task_count(self) -> int:
|
90
|
+
"""Get the number of tasks created."""
|
91
|
+
return len(self.tasks)
|
92
|
+
|
93
|
+
def get_task_ids(self) -> List[str]:
|
94
|
+
"""Get list of all task IDs."""
|
95
|
+
return [task.task_id for task in self.tasks]
|
96
|
+
|
97
|
+
|
98
|
+
class AutoAssetTagFilter(Filter):
|
99
|
+
"""Filter for auto asset tag queries."""
|
100
|
+
|
101
|
+
tag: Optional[str] = None
|
102
|
+
organization_ids: Optional[List[int]] = None
|
103
|
+
search_term: Optional[str] = None
|
104
|
+
|
105
|
+
def to_params(self) -> Dict[str, Any]:
|
106
|
+
"""Convert filter to API parameters with proper field name mapping."""
|
107
|
+
params = super().to_params()
|
108
|
+
|
109
|
+
# Convert organization_ids to organizationIds for API compatibility
|
110
|
+
if "filter[organization_ids]" in params:
|
111
|
+
params["filter[organizationIds]"] = params.pop("filter[organization_ids]")
|
112
|
+
|
113
|
+
# Convert search_term to searchTerm for API compatibility
|
114
|
+
if "filter[search_term]" in params:
|
115
|
+
params["filter[searchTerm]"] = params.pop("filter[search_term]")
|
116
|
+
|
117
|
+
return params
|
@@ -0,0 +1,232 @@
|
|
1
|
+
"""
|
2
|
+
Baseline-related data models for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from datetime import datetime
|
7
|
+
from enum import Enum
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from ..base import AIRBaseModel, Filter
|
11
|
+
|
12
|
+
|
13
|
+
class BaselineStatus(str, Enum):
|
14
|
+
"""Baseline status."""
|
15
|
+
ACTIVE = "active"
|
16
|
+
INACTIVE = "inactive"
|
17
|
+
CREATING = "creating"
|
18
|
+
FAILED = "failed"
|
19
|
+
|
20
|
+
|
21
|
+
class BaselineType(str, Enum):
|
22
|
+
"""Baseline type."""
|
23
|
+
SYSTEM = "system"
|
24
|
+
SECURITY = "security"
|
25
|
+
CUSTOM = "custom"
|
26
|
+
COMPLIANCE = "compliance"
|
27
|
+
|
28
|
+
|
29
|
+
class ComparisonStatus(str, Enum):
|
30
|
+
"""Comparison status."""
|
31
|
+
PENDING = "pending"
|
32
|
+
RUNNING = "running"
|
33
|
+
COMPLETED = "completed"
|
34
|
+
FAILED = "failed"
|
35
|
+
|
36
|
+
|
37
|
+
class ChangeType(str, Enum):
|
38
|
+
"""Type of change detected."""
|
39
|
+
ADDED = "added"
|
40
|
+
REMOVED = "removed"
|
41
|
+
MODIFIED = "modified"
|
42
|
+
MOVED = "moved"
|
43
|
+
|
44
|
+
|
45
|
+
class BaselineItem(AIRBaseModel):
|
46
|
+
"""Individual baseline item."""
|
47
|
+
|
48
|
+
id: str
|
49
|
+
path: str
|
50
|
+
item_type: str # file, registry, service, process, etc.
|
51
|
+
hash: Optional[str] = None
|
52
|
+
size: Optional[int] = None
|
53
|
+
permissions: Optional[str] = None
|
54
|
+
owner: Optional[str] = None
|
55
|
+
created_at: Optional[datetime] = None
|
56
|
+
modified_at: Optional[datetime] = None
|
57
|
+
attributes: Dict[str, Any] = {}
|
58
|
+
metadata: Dict[str, Any] = {}
|
59
|
+
|
60
|
+
|
61
|
+
class Baseline(AIRBaseModel):
|
62
|
+
"""Baseline model."""
|
63
|
+
|
64
|
+
id: str = Field(alias="_id")
|
65
|
+
name: str
|
66
|
+
description: Optional[str] = None
|
67
|
+
type: BaselineType
|
68
|
+
status: BaselineStatus = BaselineStatus.CREATING
|
69
|
+
endpoint_id: str = Field(alias="endpointId")
|
70
|
+
endpoint_name: str = Field(alias="endpointName")
|
71
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
72
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
73
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
74
|
+
created_by: str = Field(alias="createdBy")
|
75
|
+
item_count: int = Field(default=0, alias="itemCount")
|
76
|
+
file_count: int = Field(default=0, alias="fileCount")
|
77
|
+
registry_count: int = Field(default=0, alias="registryCount")
|
78
|
+
service_count: int = Field(default=0, alias="serviceCount")
|
79
|
+
process_count: int = Field(default=0, alias="processCount")
|
80
|
+
network_connection_count: int = Field(default=0, alias="networkConnectionCount")
|
81
|
+
tags: List[str] = []
|
82
|
+
profile_id: Optional[str] = Field(default=None, alias="profileId")
|
83
|
+
profile_name: Optional[str] = Field(default=None, alias="profileName")
|
84
|
+
last_comparison: Optional[datetime] = Field(default=None, alias="lastComparison")
|
85
|
+
comparison_count: int = Field(default=0, alias="comparisonCount")
|
86
|
+
|
87
|
+
|
88
|
+
class BaselineProfile(AIRBaseModel):
|
89
|
+
"""Baseline profile model."""
|
90
|
+
|
91
|
+
id: str = Field(alias="_id")
|
92
|
+
name: str
|
93
|
+
description: Optional[str] = None
|
94
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
95
|
+
include_files: bool = Field(default=True, alias="includeFiles")
|
96
|
+
include_registry: bool = Field(default=True, alias="includeRegistry")
|
97
|
+
include_services: bool = Field(default=True, alias="includeServices")
|
98
|
+
include_processes: bool = Field(default=False, alias="includeProcesses")
|
99
|
+
include_network: bool = Field(default=False, alias="includeNetwork")
|
100
|
+
file_patterns: List[str] = Field(default=[], alias="filePatterns")
|
101
|
+
exclude_patterns: List[str] = Field(default=[], alias="excludePatterns")
|
102
|
+
registry_keys: List[str] = Field(default=[], alias="registryKeys")
|
103
|
+
custom_checks: List[Dict[str, Any]] = Field(default=[], alias="customChecks")
|
104
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
105
|
+
updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
|
106
|
+
created_by: str = Field(alias="createdBy")
|
107
|
+
is_default: bool = Field(default=False, alias="isDefault")
|
108
|
+
usage_count: int = Field(default=0, alias="usageCount")
|
109
|
+
|
110
|
+
|
111
|
+
class BaselineChange(AIRBaseModel):
|
112
|
+
"""Baseline change detection model."""
|
113
|
+
|
114
|
+
id: str = Field(alias="_id")
|
115
|
+
comparison_id: str = Field(alias="comparisonId")
|
116
|
+
change_type: ChangeType = Field(alias="changeType")
|
117
|
+
item_type: str = Field(alias="itemType")
|
118
|
+
path: str
|
119
|
+
old_value: Optional[Dict[str, Any]] = Field(default=None, alias="oldValue")
|
120
|
+
new_value: Optional[Dict[str, Any]] = Field(default=None, alias="newValue")
|
121
|
+
severity: str = "medium" # low, medium, high, critical
|
122
|
+
category: str
|
123
|
+
description: str
|
124
|
+
detected_at: datetime = Field(alias="detectedAt")
|
125
|
+
risk_score: float = Field(default=0.0, alias="riskScore")
|
126
|
+
|
127
|
+
|
128
|
+
class BaselineComparison(AIRBaseModel):
|
129
|
+
"""Baseline comparison result model."""
|
130
|
+
|
131
|
+
id: str = Field(alias="_id")
|
132
|
+
baseline_id: str = Field(alias="baselineId")
|
133
|
+
baseline_name: str = Field(alias="baselineName")
|
134
|
+
endpoint_id: str = Field(alias="endpointId")
|
135
|
+
endpoint_name: str = Field(alias="endpointName")
|
136
|
+
status: ComparisonStatus
|
137
|
+
started_at: Optional[datetime] = Field(default=None, alias="startedAt")
|
138
|
+
completed_at: Optional[datetime] = Field(default=None, alias="completedAt")
|
139
|
+
duration: Optional[int] = None # seconds
|
140
|
+
total_changes: int = Field(default=0, alias="totalChanges")
|
141
|
+
added_items: int = Field(default=0, alias="addedItems")
|
142
|
+
removed_items: int = Field(default=0, alias="removedItems")
|
143
|
+
modified_items: int = Field(default=0, alias="modifiedItems")
|
144
|
+
moved_items: int = Field(default=0, alias="movedItems")
|
145
|
+
high_risk_changes: int = Field(default=0, alias="highRiskChanges")
|
146
|
+
medium_risk_changes: int = Field(default=0, alias="mediumRiskChanges")
|
147
|
+
low_risk_changes: int = Field(default=0, alias="lowRiskChanges")
|
148
|
+
changes: List[BaselineChange] = []
|
149
|
+
organization_id: int = Field(default=0, alias="organizationId")
|
150
|
+
triggered_by: str = Field(alias="triggeredBy")
|
151
|
+
error_message: Optional[str] = Field(default=None, alias="errorMessage")
|
152
|
+
|
153
|
+
|
154
|
+
class BaselineSchedule(AIRBaseModel):
|
155
|
+
"""Baseline comparison schedule model."""
|
156
|
+
|
157
|
+
id: str = Field(alias="_id")
|
158
|
+
baseline_id: str = Field(alias="baselineId")
|
159
|
+
name: str
|
160
|
+
enabled: bool = True
|
161
|
+
frequency: str # daily, weekly, monthly
|
162
|
+
time_of_day: str = Field(alias="timeOfDay") # HH:MM format
|
163
|
+
day_of_week: Optional[int] = Field(default=None, alias="dayOfWeek") # 0-6, Monday=0
|
164
|
+
day_of_month: Optional[int] = Field(default=None, alias="dayOfMonth") # 1-31
|
165
|
+
next_run: Optional[datetime] = Field(default=None, alias="nextRun")
|
166
|
+
last_run: Optional[datetime] = Field(default=None, alias="lastRun")
|
167
|
+
created_at: Optional[datetime] = Field(default=None, alias="createdAt")
|
168
|
+
created_by: str = Field(alias="createdBy")
|
169
|
+
notification_enabled: bool = Field(default=True, alias="notificationEnabled")
|
170
|
+
notification_threshold: int = Field(default=10, alias="notificationThreshold") # minimum changes to notify
|
171
|
+
|
172
|
+
|
173
|
+
class BaselineFilter(Filter):
|
174
|
+
"""Filter for baseline queries."""
|
175
|
+
|
176
|
+
name: Optional[str] = None
|
177
|
+
type: Optional[List[BaselineType]] = None
|
178
|
+
status: Optional[List[BaselineStatus]] = None
|
179
|
+
endpoint_id: Optional[str] = None
|
180
|
+
endpoint_name: Optional[str] = None
|
181
|
+
created_by: Optional[str] = None
|
182
|
+
tags: Optional[List[str]] = None
|
183
|
+
profile_id: Optional[str] = None
|
184
|
+
has_recent_comparison: Optional[bool] = None
|
185
|
+
|
186
|
+
|
187
|
+
class CreateBaselineRequest(AIRBaseModel):
|
188
|
+
"""Request model for creating a baseline."""
|
189
|
+
|
190
|
+
name: str
|
191
|
+
description: Optional[str] = None
|
192
|
+
type: BaselineType = BaselineType.SYSTEM
|
193
|
+
endpoint_id: str
|
194
|
+
profile_id: Optional[str] = None
|
195
|
+
tags: List[str] = []
|
196
|
+
organization_id: int = 0
|
197
|
+
|
198
|
+
|
199
|
+
class UpdateBaselineRequest(AIRBaseModel):
|
200
|
+
"""Request model for updating a baseline."""
|
201
|
+
|
202
|
+
name: Optional[str] = None
|
203
|
+
description: Optional[str] = None
|
204
|
+
status: Optional[BaselineStatus] = None
|
205
|
+
tags: Optional[List[str]] = None
|
206
|
+
|
207
|
+
|
208
|
+
class CreateBaselineProfileRequest(AIRBaseModel):
|
209
|
+
"""Request model for creating a baseline profile."""
|
210
|
+
|
211
|
+
name: str
|
212
|
+
description: Optional[str] = None
|
213
|
+
include_files: bool = True
|
214
|
+
include_registry: bool = True
|
215
|
+
include_services: bool = True
|
216
|
+
include_processes: bool = False
|
217
|
+
include_network: bool = False
|
218
|
+
file_patterns: List[str] = []
|
219
|
+
exclude_patterns: List[str] = []
|
220
|
+
registry_keys: List[str] = []
|
221
|
+
custom_checks: List[Dict[str, Any]] = []
|
222
|
+
organization_id: int = 0
|
223
|
+
|
224
|
+
|
225
|
+
class CompareBaselineRequest(AIRBaseModel):
|
226
|
+
"""Request model for comparing baselines."""
|
227
|
+
|
228
|
+
baseline_id: str
|
229
|
+
endpoint_ids: Optional[List[str]] = None # If None, use baseline's endpoint
|
230
|
+
profile_id: Optional[str] = None # Override baseline's profile
|
231
|
+
include_low_risk: bool = True
|
232
|
+
generate_report: bool = True
|