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/base.py
CHANGED
@@ -1,133 +1,207 @@
|
|
1
|
-
"""
|
2
|
-
Base classes for CQRS implementation in the AIR SDK.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from abc import ABC, abstractmethod
|
6
|
-
from typing import Any, Dict, List, Optional, TypeVar, Generic
|
7
|
-
from pydantic import BaseModel as PydanticBaseModel, ConfigDict
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
if self.
|
84
|
-
params["
|
85
|
-
if self.
|
86
|
-
params["
|
87
|
-
if self.
|
88
|
-
params["
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
params[f"filter[{field_name}]"] = str(field_value)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
self.
|
125
|
-
self.
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
1
|
+
"""
|
2
|
+
Base classes for CQRS implementation in the AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from abc import ABC, abstractmethod
|
6
|
+
from typing import Any, Dict, List, Optional, TypeVar, Generic, Union
|
7
|
+
from pydantic import BaseModel as PydanticBaseModel, ConfigDict, Field
|
8
|
+
from datetime import datetime
|
9
|
+
|
10
|
+
T = TypeVar("T")
|
11
|
+
|
12
|
+
|
13
|
+
class Query(Generic[T], ABC):
|
14
|
+
"""Base class for all queries (read operations)."""
|
15
|
+
|
16
|
+
@abstractmethod
|
17
|
+
def execute(self) -> T:
|
18
|
+
"""Execute the query and return the result."""
|
19
|
+
pass
|
20
|
+
|
21
|
+
|
22
|
+
class Command(Generic[T], ABC):
|
23
|
+
"""Base class for all commands (write operations)."""
|
24
|
+
|
25
|
+
@abstractmethod
|
26
|
+
def execute(self) -> T:
|
27
|
+
"""Execute the command and return the result."""
|
28
|
+
pass
|
29
|
+
|
30
|
+
|
31
|
+
class AIRBaseModel(PydanticBaseModel):
|
32
|
+
"""Base Pydantic model with common configurations."""
|
33
|
+
|
34
|
+
model_config = ConfigDict(
|
35
|
+
use_enum_values=True,
|
36
|
+
validate_assignment=True,
|
37
|
+
arbitrary_types_allowed=True,
|
38
|
+
populate_by_name=True # Allow using both field names and aliases
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
class PaginatedResponse(AIRBaseModel, Generic[T]):
|
43
|
+
"""Generic paginated response model."""
|
44
|
+
|
45
|
+
entities: List[T]
|
46
|
+
total_entity_count: int
|
47
|
+
current_page: int
|
48
|
+
page_size: int
|
49
|
+
total_page_count: int
|
50
|
+
previous_page: Optional[int] = None
|
51
|
+
next_page: Optional[int] = None
|
52
|
+
|
53
|
+
|
54
|
+
class APIResponse(AIRBaseModel, Generic[T]):
|
55
|
+
"""Generic API response model."""
|
56
|
+
|
57
|
+
success: bool
|
58
|
+
result: T
|
59
|
+
status_code: int
|
60
|
+
errors: List[str] = []
|
61
|
+
|
62
|
+
|
63
|
+
class Filter(AIRBaseModel):
|
64
|
+
"""Base filter model for queries with pagination and sorting support."""
|
65
|
+
|
66
|
+
# Basic filter fields
|
67
|
+
search_term: Optional[str] = None
|
68
|
+
organization_ids: Optional[List[int]] = None
|
69
|
+
|
70
|
+
# Pagination parameters (match API documentation exactly) - no defaults
|
71
|
+
page_number: Optional[int] = Field(default=None, alias="pageNumber")
|
72
|
+
page_size: Optional[int] = Field(default=None, alias="pageSize")
|
73
|
+
|
74
|
+
# Sorting parameters (match API documentation exactly) - no defaults
|
75
|
+
sort_by: Optional[str] = Field(default=None, alias="sortBy")
|
76
|
+
sort_type: Optional[str] = Field(default=None, alias="sortType")
|
77
|
+
|
78
|
+
def to_params(self) -> Dict[str, Any]:
|
79
|
+
"""Convert filter to API parameters."""
|
80
|
+
params = {}
|
81
|
+
|
82
|
+
# Pagination parameters (not in filter namespace) - only if set
|
83
|
+
if self.page_number is not None:
|
84
|
+
params["pageNumber"] = self.page_number
|
85
|
+
if self.page_size is not None:
|
86
|
+
params["pageSize"] = self.page_size
|
87
|
+
if self.sort_by is not None:
|
88
|
+
params["sortBy"] = self.sort_by
|
89
|
+
if self.sort_type is not None:
|
90
|
+
params["sortType"] = self.sort_type
|
91
|
+
|
92
|
+
# Filter parameters (in filter namespace)
|
93
|
+
for field_name, field_value in self.model_dump(exclude_none=True).items():
|
94
|
+
# Skip pagination/sorting fields as they're handled above
|
95
|
+
if field_name in ["page_number", "page_size", "sort_by", "sort_type"]:
|
96
|
+
continue
|
97
|
+
|
98
|
+
if field_value is not None:
|
99
|
+
if isinstance(field_value, list):
|
100
|
+
params[f"filter[{field_name}]"] = ",".join([str(x) for x in field_value])
|
101
|
+
else:
|
102
|
+
params[f"filter[{field_name}]"] = str(field_value)
|
103
|
+
return params
|
104
|
+
|
105
|
+
|
106
|
+
class PaginatedList(list):
|
107
|
+
"""List-like container that carries pagination metadata.
|
108
|
+
This allows SDK query methods to return a normal iterable while still
|
109
|
+
exposing additional pagination attributes such as total_entity_count.
|
110
|
+
The class simply subclasses ``list`` and adds attributes during
|
111
|
+
construction. All standard list operations remain intact.
|
112
|
+
"""
|
113
|
+
def __init__(
|
114
|
+
self,
|
115
|
+
iterable=None,
|
116
|
+
*,
|
117
|
+
total_entity_count: int | None = None,
|
118
|
+
current_page: int | None = None,
|
119
|
+
page_size: int | None = None,
|
120
|
+
total_page_count: int | None = None,
|
121
|
+
) -> None:
|
122
|
+
super().__init__(iterable or [])
|
123
|
+
# Store metadata for caller introspection
|
124
|
+
self.total_entity_count = total_entity_count
|
125
|
+
self.current_page = current_page
|
126
|
+
self.page_size = page_size
|
127
|
+
self.total_page_count = total_page_count
|
128
|
+
|
129
|
+
# Optional: pretty representation including meta for debugging
|
130
|
+
def __repr__(self) -> str: # noqa: D401
|
131
|
+
meta = (
|
132
|
+
f" total={self.total_entity_count} page={self.current_page} "
|
133
|
+
f"size={self.page_size} pages={self.total_page_count}"
|
134
|
+
)
|
135
|
+
return f"PaginatedList({list.__repr__(self)},{meta})"
|
136
|
+
|
137
|
+
|
138
|
+
# Utility functions for common SDK operations
|
139
|
+
def ensure_organization_ids(organization_ids: Optional[Union[List[int], int]], default_org_id: int = 0) -> List[int]:
|
140
|
+
"""
|
141
|
+
Ensure organization IDs are properly formatted for API requests.
|
142
|
+
|
143
|
+
Many AIR API endpoints require organizationIds parameter to be non-empty.
|
144
|
+
This utility ensures consistent handling across all SDK components.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
organization_ids: Organization ID(s) - can be None, int, or List[int]
|
148
|
+
default_org_id: Default organization ID to use if none provided
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
List[int]: Non-empty list of organization IDs
|
152
|
+
|
153
|
+
Raises:
|
154
|
+
ValueError: If organization_ids is explicitly empty list
|
155
|
+
"""
|
156
|
+
if organization_ids is None:
|
157
|
+
return [default_org_id]
|
158
|
+
|
159
|
+
if isinstance(organization_ids, int):
|
160
|
+
return [organization_ids]
|
161
|
+
|
162
|
+
if isinstance(organization_ids, list):
|
163
|
+
if len(organization_ids) == 0:
|
164
|
+
# API requires non-empty organizationIds - use default
|
165
|
+
return [default_org_id]
|
166
|
+
return organization_ids
|
167
|
+
|
168
|
+
# Fallback for other types
|
169
|
+
return [default_org_id]
|
170
|
+
|
171
|
+
|
172
|
+
def format_organization_ids_param(organization_ids: Optional[Union[List[int], int]],
|
173
|
+
param_name: str = "filter[organizationIds]",
|
174
|
+
default_org_id: int = 0) -> Dict[str, str]:
|
175
|
+
"""
|
176
|
+
Format organization IDs for API request parameters.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
organization_ids: Organization ID(s) to format
|
180
|
+
param_name: Parameter name to use (default: "filter[organizationIds]")
|
181
|
+
default_org_id: Default organization ID if none provided
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Dict with formatted parameter
|
185
|
+
"""
|
186
|
+
validated_ids = ensure_organization_ids(organization_ids, default_org_id)
|
187
|
+
return {param_name: ",".join([str(x) for x in validated_ids])}
|
188
|
+
|
189
|
+
|
190
|
+
def format_single_organization_id_param(organization_id: Optional[int],
|
191
|
+
param_name: str = "filter[organizationId]",
|
192
|
+
default_org_id: int = 0) -> Dict[str, str]:
|
193
|
+
"""
|
194
|
+
Format single organization ID for API request parameters.
|
195
|
+
|
196
|
+
Some APIs (like Recent Activities) use singular organizationId instead of plural.
|
197
|
+
|
198
|
+
Args:
|
199
|
+
organization_id: Single organization ID
|
200
|
+
param_name: Parameter name to use (default: "filter[organizationId]")
|
201
|
+
default_org_id: Default organization ID if none provided
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
Dict with formatted parameter
|
205
|
+
"""
|
206
|
+
final_id = organization_id if organization_id is not None else default_org_id
|
207
|
+
return {param_name: str(final_id)}
|