binalyze-air-sdk 1.0.2__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.
Files changed (142) hide show
  1. binalyze_air/__init__.py +77 -77
  2. binalyze_air/apis/__init__.py +67 -27
  3. binalyze_air/apis/acquisitions.py +107 -0
  4. binalyze_air/apis/api_tokens.py +49 -0
  5. binalyze_air/apis/assets.py +161 -0
  6. binalyze_air/apis/audit_logs.py +26 -0
  7. binalyze_air/apis/{authentication.py → auth.py} +29 -27
  8. binalyze_air/apis/auto_asset_tags.py +79 -75
  9. binalyze_air/apis/backup.py +177 -0
  10. binalyze_air/apis/baseline.py +46 -0
  11. binalyze_air/apis/cases.py +225 -0
  12. binalyze_air/apis/cloud_forensics.py +116 -0
  13. binalyze_air/apis/event_subscription.py +96 -96
  14. binalyze_air/apis/evidence.py +249 -53
  15. binalyze_air/apis/interact.py +153 -36
  16. binalyze_air/apis/investigation_hub.py +234 -0
  17. binalyze_air/apis/license.py +104 -0
  18. binalyze_air/apis/logger.py +83 -0
  19. binalyze_air/apis/multipart_upload.py +201 -0
  20. binalyze_air/apis/notifications.py +115 -0
  21. binalyze_air/apis/organizations.py +267 -0
  22. binalyze_air/apis/params.py +44 -39
  23. binalyze_air/apis/policies.py +186 -0
  24. binalyze_air/apis/preset_filters.py +79 -0
  25. binalyze_air/apis/recent_activities.py +71 -0
  26. binalyze_air/apis/relay_server.py +104 -0
  27. binalyze_air/apis/settings.py +395 -27
  28. binalyze_air/apis/tasks.py +80 -0
  29. binalyze_air/apis/triage.py +197 -0
  30. binalyze_air/apis/user_management.py +183 -74
  31. binalyze_air/apis/webhook_executions.py +50 -0
  32. binalyze_air/apis/webhooks.py +322 -230
  33. binalyze_air/base.py +207 -133
  34. binalyze_air/client.py +217 -1337
  35. binalyze_air/commands/__init__.py +175 -145
  36. binalyze_air/commands/acquisitions.py +661 -387
  37. binalyze_air/commands/api_tokens.py +55 -0
  38. binalyze_air/commands/assets.py +324 -362
  39. binalyze_air/commands/{authentication.py → auth.py} +36 -36
  40. binalyze_air/commands/auto_asset_tags.py +230 -230
  41. binalyze_air/commands/backup.py +47 -0
  42. binalyze_air/commands/baseline.py +32 -396
  43. binalyze_air/commands/cases.py +609 -602
  44. binalyze_air/commands/cloud_forensics.py +88 -0
  45. binalyze_air/commands/event_subscription.py +101 -101
  46. binalyze_air/commands/evidences.py +918 -988
  47. binalyze_air/commands/interact.py +172 -58
  48. binalyze_air/commands/investigation_hub.py +315 -0
  49. binalyze_air/commands/license.py +183 -0
  50. binalyze_air/commands/logger.py +126 -0
  51. binalyze_air/commands/multipart_upload.py +363 -0
  52. binalyze_air/commands/notifications.py +45 -0
  53. binalyze_air/commands/organizations.py +200 -221
  54. binalyze_air/commands/policies.py +175 -203
  55. binalyze_air/commands/preset_filters.py +55 -0
  56. binalyze_air/commands/recent_activities.py +32 -0
  57. binalyze_air/commands/relay_server.py +144 -0
  58. binalyze_air/commands/settings.py +431 -29
  59. binalyze_air/commands/tasks.py +95 -56
  60. binalyze_air/commands/triage.py +224 -360
  61. binalyze_air/commands/user_management.py +351 -126
  62. binalyze_air/commands/webhook_executions.py +77 -0
  63. binalyze_air/config.py +244 -244
  64. binalyze_air/exceptions.py +49 -49
  65. binalyze_air/http_client.py +426 -305
  66. binalyze_air/models/__init__.py +287 -285
  67. binalyze_air/models/acquisitions.py +365 -250
  68. binalyze_air/models/api_tokens.py +73 -0
  69. binalyze_air/models/assets.py +438 -438
  70. binalyze_air/models/audit.py +247 -272
  71. binalyze_air/models/audit_logs.py +14 -0
  72. binalyze_air/models/{authentication.py → auth.py} +69 -69
  73. binalyze_air/models/auto_asset_tags.py +227 -116
  74. binalyze_air/models/backup.py +138 -0
  75. binalyze_air/models/baseline.py +231 -231
  76. binalyze_air/models/cases.py +275 -275
  77. binalyze_air/models/cloud_forensics.py +145 -0
  78. binalyze_air/models/event_subscription.py +170 -171
  79. binalyze_air/models/evidence.py +65 -65
  80. binalyze_air/models/evidences.py +367 -348
  81. binalyze_air/models/interact.py +266 -135
  82. binalyze_air/models/investigation_hub.py +265 -0
  83. binalyze_air/models/license.py +150 -0
  84. binalyze_air/models/logger.py +83 -0
  85. binalyze_air/models/multipart_upload.py +352 -0
  86. binalyze_air/models/notifications.py +138 -0
  87. binalyze_air/models/organizations.py +293 -293
  88. binalyze_air/models/params.py +153 -127
  89. binalyze_air/models/policies.py +260 -249
  90. binalyze_air/models/preset_filters.py +79 -0
  91. binalyze_air/models/recent_activities.py +70 -0
  92. binalyze_air/models/relay_server.py +121 -0
  93. binalyze_air/models/settings.py +538 -84
  94. binalyze_air/models/tasks.py +215 -149
  95. binalyze_air/models/triage.py +141 -142
  96. binalyze_air/models/user_management.py +200 -97
  97. binalyze_air/models/webhook_executions.py +33 -0
  98. binalyze_air/queries/__init__.py +121 -133
  99. binalyze_air/queries/acquisitions.py +155 -155
  100. binalyze_air/queries/api_tokens.py +46 -0
  101. binalyze_air/queries/assets.py +186 -105
  102. binalyze_air/queries/audit.py +400 -416
  103. binalyze_air/queries/{authentication.py → auth.py} +55 -55
  104. binalyze_air/queries/auto_asset_tags.py +59 -59
  105. binalyze_air/queries/backup.py +66 -0
  106. binalyze_air/queries/baseline.py +21 -185
  107. binalyze_air/queries/cases.py +292 -292
  108. binalyze_air/queries/cloud_forensics.py +137 -0
  109. binalyze_air/queries/event_subscription.py +54 -54
  110. binalyze_air/queries/evidence.py +139 -139
  111. binalyze_air/queries/evidences.py +279 -279
  112. binalyze_air/queries/interact.py +140 -28
  113. binalyze_air/queries/investigation_hub.py +329 -0
  114. binalyze_air/queries/license.py +85 -0
  115. binalyze_air/queries/logger.py +58 -0
  116. binalyze_air/queries/multipart_upload.py +180 -0
  117. binalyze_air/queries/notifications.py +71 -0
  118. binalyze_air/queries/organizations.py +222 -222
  119. binalyze_air/queries/params.py +154 -115
  120. binalyze_air/queries/policies.py +149 -149
  121. binalyze_air/queries/preset_filters.py +60 -0
  122. binalyze_air/queries/recent_activities.py +44 -0
  123. binalyze_air/queries/relay_server.py +42 -0
  124. binalyze_air/queries/settings.py +533 -20
  125. binalyze_air/queries/tasks.py +125 -81
  126. binalyze_air/queries/triage.py +230 -230
  127. binalyze_air/queries/user_management.py +193 -83
  128. binalyze_air/queries/webhook_executions.py +39 -0
  129. binalyze_air_sdk-1.0.3.dist-info/METADATA +752 -0
  130. binalyze_air_sdk-1.0.3.dist-info/RECORD +132 -0
  131. {binalyze_air_sdk-1.0.2.dist-info → binalyze_air_sdk-1.0.3.dist-info}/WHEEL +1 -1
  132. binalyze_air/apis/endpoints.py +0 -22
  133. binalyze_air/apis/evidences.py +0 -216
  134. binalyze_air/apis/users.py +0 -68
  135. binalyze_air/commands/users.py +0 -101
  136. binalyze_air/models/endpoints.py +0 -76
  137. binalyze_air/models/users.py +0 -82
  138. binalyze_air/queries/endpoints.py +0 -25
  139. binalyze_air/queries/users.py +0 -69
  140. binalyze_air_sdk-1.0.2.dist-info/METADATA +0 -706
  141. binalyze_air_sdk-1.0.2.dist-info/RECORD +0 -82
  142. {binalyze_air_sdk-1.0.2.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
@@ -1,363 +1,325 @@
1
- """
2
- Asset-related commands for the Binalyze AIR SDK.
3
- Fixed to match API documentation exactly.
4
- """
5
-
6
- from typing import List, Union, Optional, Dict, Any
7
-
8
- from ..base import Command
9
- from ..models.assets import AssetFilter
10
- from ..http_client import HTTPClient
11
-
12
-
13
- class RebootAssetsCommand(Command[Dict[str, Any]]):
14
- """Command to reboot assets by filter - FIXED to match API documentation."""
15
-
16
- def __init__(
17
- self,
18
- http_client: HTTPClient,
19
- asset_filter: AssetFilter
20
- ):
21
- self.http_client = http_client
22
- self.asset_filter = asset_filter
23
-
24
- def execute(self) -> Dict[str, Any]:
25
- """Execute the reboot command with correct payload structure."""
26
- # Use the correct payload structure as per API documentation
27
- payload = {
28
- "filter": self.asset_filter.to_filter_dict()
29
- }
30
-
31
- # FIXED: Correct endpoint URL (confirmed from API docs)
32
- return self.http_client.post("assets/tasks/reboot", json_data=payload)
33
-
34
-
35
- class ShutdownAssetsCommand(Command[Dict[str, Any]]):
36
- """Command to shutdown assets by filter - FIXED to match API documentation."""
37
-
38
- def __init__(
39
- self,
40
- http_client: HTTPClient,
41
- asset_filter: AssetFilter
42
- ):
43
- self.http_client = http_client
44
- self.asset_filter = asset_filter
45
-
46
- def execute(self) -> Dict[str, Any]:
47
- """Execute the shutdown command with correct payload structure."""
48
- payload = {
49
- "filter": self.asset_filter.to_filter_dict()
50
- }
51
-
52
- # FIXED: Correct endpoint URL (following same pattern as reboot)
53
- return self.http_client.post("assets/tasks/shutdown", json_data=payload)
54
-
55
-
56
- class IsolateAssetsCommand(Command[Dict[str, Any]]):
57
- """Command to isolate assets by filter - FIXED to match API documentation."""
58
-
59
- def __init__(
60
- self,
61
- http_client: HTTPClient,
62
- asset_filter: AssetFilter,
63
- isolation_settings: Optional[Dict[str, Any]] = None
64
- ):
65
- self.http_client = http_client
66
- self.asset_filter = asset_filter
67
- self.isolation_settings = isolation_settings or {}
68
-
69
- def execute(self) -> Dict[str, Any]:
70
- """Execute the isolation command with correct payload structure."""
71
- payload = {
72
- "enabled": True, # Required field for isolation
73
- "filter": self.asset_filter.to_filter_dict()
74
- }
75
-
76
- # Add isolation settings if provided
77
- if self.isolation_settings:
78
- payload.update(self.isolation_settings)
79
-
80
- # FIXED: Correct endpoint URL and payload
81
- return self.http_client.post("assets/tasks/isolation", json_data=payload)
82
-
83
-
84
- class UnisolateAssetsCommand(Command[Dict[str, Any]]):
85
- """Command to unisolate (remove isolation from) assets - FIXED to match API documentation."""
86
-
87
- def __init__(
88
- self,
89
- http_client: HTTPClient,
90
- asset_filter: AssetFilter
91
- ):
92
- self.http_client = http_client
93
- self.asset_filter = asset_filter
94
-
95
- def execute(self) -> Dict[str, Any]:
96
- """Execute the unisolate command with correct payload structure."""
97
- payload = {
98
- "enabled": False, # Disable isolation for unisolate
99
- "filter": self.asset_filter.to_filter_dict()
100
- }
101
-
102
- # FIXED: Correct endpoint URL and payload
103
- return self.http_client.post("assets/tasks/isolation", json_data=payload)
104
-
105
-
106
- class LogRetrievalCommand(Command[Dict[str, Any]]):
107
- """Command to retrieve logs from assets - FIXED endpoint URL and payload structure."""
108
-
109
- def __init__(
110
- self,
111
- http_client: HTTPClient,
112
- asset_filter: AssetFilter,
113
- log_settings: Optional[Dict[str, Any]] = None
114
- ):
115
- self.http_client = http_client
116
- self.asset_filter = asset_filter
117
- self.log_settings = log_settings or {}
118
-
119
- def execute(self) -> Dict[str, Any]:
120
- """Execute the log retrieval command with correct endpoint and payload."""
121
- payload = {
122
- "filter": self.asset_filter.to_filter_dict()
123
- }
124
-
125
- # Add log retrieval settings if provided
126
- if self.log_settings:
127
- payload.update(self.log_settings)
128
-
129
- # FIXED: Correct endpoint URL to match API specification
130
- return self.http_client.post("assets/tasks/retrieve-logs", json_data=payload)
131
-
132
-
133
- class VersionUpdateCommand(Command[Dict[str, Any]]):
134
- """Command to update version on assets - FIXED to match API documentation."""
135
-
136
- def __init__(
137
- self,
138
- http_client: HTTPClient,
139
- asset_filter: AssetFilter,
140
- update_settings: Optional[Dict[str, Any]] = None
141
- ):
142
- self.http_client = http_client
143
- self.asset_filter = asset_filter
144
- self.update_settings = update_settings or {}
145
-
146
- def execute(self) -> Dict[str, Any]:
147
- """Execute the version update command with correct payload structure."""
148
- payload = {
149
- "filter": self.asset_filter.to_filter_dict()
150
- }
151
-
152
- # Add version update settings if provided
153
- if self.update_settings:
154
- payload.update(self.update_settings)
155
-
156
- # FIXED: Correct endpoint URL (following tasks pattern)
157
- return self.http_client.post("assets/tasks/version-update", json_data=payload)
158
-
159
-
160
- class UninstallAssetsCommand(Command[Dict[str, Any]]):
161
- """Command to uninstall assets without purging data - FIXED endpoint URL and HTTP method."""
162
-
163
- def __init__(
164
- self,
165
- http_client: HTTPClient,
166
- asset_filter: AssetFilter
167
- ):
168
- self.http_client = http_client
169
- self.asset_filter = asset_filter
170
-
171
- def execute(self) -> Dict[str, Any]:
172
- """Execute the uninstall command with correct endpoint, HTTP method and payload structure."""
173
- payload = {
174
- "filter": self.asset_filter.to_filter_dict()
175
- }
176
-
177
- # FIXED: Correct endpoint URL and HTTP method (DELETE, not POST)
178
- return self.http_client.delete("assets/uninstall-without-purge", json_data=payload)
179
-
180
-
181
- class PurgeAndUninstallAssetsCommand(Command[Dict[str, Any]]):
182
- """Command to purge and uninstall assets - FIXED endpoint URL and HTTP method."""
183
-
184
- def __init__(
185
- self,
186
- http_client: HTTPClient,
187
- asset_filter: AssetFilter
188
- ):
189
- self.http_client = http_client
190
- self.asset_filter = asset_filter
191
-
192
- def execute(self) -> Dict[str, Any]:
193
- """Execute the purge and uninstall command with correct endpoint, HTTP method and payload."""
194
- payload = {
195
- "filter": self.asset_filter.to_filter_dict()
196
- }
197
-
198
- # FIXED: Correct endpoint URL and HTTP method (DELETE, not POST)
199
- return self.http_client.delete("assets/purge-and-uninstall", json_data=payload)
200
-
201
-
202
- class AddTagsToAssetsCommand(Command[Dict[str, Any]]):
203
- """Command to add tags to assets - FIXED endpoint URL and payload structure."""
204
-
205
- def __init__(
206
- self,
207
- http_client: HTTPClient,
208
- asset_filter: AssetFilter,
209
- tags: List[str]
210
- ):
211
- self.http_client = http_client
212
- self.asset_filter = asset_filter
213
- self.tags = tags
214
-
215
- def execute(self) -> Dict[str, Any]:
216
- """Execute the add tags command with correct endpoint and payload structure."""
217
- payload = {
218
- "filter": self.asset_filter.to_filter_dict(),
219
- "tags": self.tags
220
- }
221
-
222
- # FIXED: Correct endpoint URL (from API documentation)
223
- return self.http_client.post("assets/tags", json_data=payload)
224
-
225
-
226
- class RemoveTagsFromAssetsCommand(Command[Dict[str, Any]]):
227
- """Command to remove tags from assets - FIXED endpoint URL and HTTP method."""
228
-
229
- def __init__(
230
- self,
231
- http_client: HTTPClient,
232
- asset_filter: AssetFilter,
233
- tags: List[str]
234
- ):
235
- self.http_client = http_client
236
- self.asset_filter = asset_filter
237
- self.tags = tags
238
-
239
- def execute(self) -> Dict[str, Any]:
240
- """Execute the remove tags command with correct endpoint, HTTP method and payload structure."""
241
- payload = {
242
- "filter": self.asset_filter.to_filter_dict(),
243
- "tags": self.tags
244
- }
245
-
246
- # FIXED: Correct endpoint URL and HTTP method (DELETE, not POST)
247
- return self.http_client.delete("assets/tags", json_data=payload)
248
-
249
-
250
- # Convenience functions for backward compatibility
251
- def create_asset_filter_from_endpoint_ids(
252
- endpoint_ids: Union[str, List[str]],
253
- organization_ids: Optional[List[Union[int, str]]] = None
254
- ) -> AssetFilter:
255
- """Create an AssetFilter from endpoint IDs for backward compatibility."""
256
- if isinstance(endpoint_ids, str):
257
- endpoint_ids = [endpoint_ids]
258
-
259
- org_ids = [int(org_id) for org_id in (organization_ids or [0])]
260
-
261
- return AssetFilter(
262
- included_endpoint_ids=endpoint_ids,
263
- organization_ids=org_ids,
264
- managed_status=["managed"] # Default to managed assets
265
- )
266
-
267
-
268
- # Backward compatibility command classes that use endpoint IDs directly
269
- class IsolateAssetsByIdCommand(Command[Dict[str, Any]]):
270
- """Legacy command to isolate assets by endpoint IDs - uses correct API structure."""
271
-
272
- def __init__(
273
- self,
274
- http_client: HTTPClient,
275
- endpoint_ids: Union[str, List[str]],
276
- organization_ids: Optional[List[Union[int, str]]] = None
277
- ):
278
- self.http_client = http_client
279
- asset_filter = create_asset_filter_from_endpoint_ids(endpoint_ids, organization_ids)
280
- self.command = IsolateAssetsCommand(http_client, asset_filter)
281
-
282
- def execute(self) -> Dict[str, Any]:
283
- """Execute through the correct filter-based command."""
284
- return self.command.execute()
285
-
286
-
287
- class UnisolateAssetsByIdCommand(Command[Dict[str, Any]]):
288
- """Legacy command to unisolate assets by endpoint IDs - uses correct API structure."""
289
-
290
- def __init__(
291
- self,
292
- http_client: HTTPClient,
293
- endpoint_ids: Union[str, List[str]],
294
- organization_ids: Optional[List[Union[int, str]]] = None
295
- ):
296
- self.http_client = http_client
297
- asset_filter = create_asset_filter_from_endpoint_ids(endpoint_ids, organization_ids)
298
- self.command = UnisolateAssetsCommand(http_client, asset_filter)
299
-
300
- def execute(self) -> Dict[str, Any]:
301
- """Execute through the correct filter-based command."""
302
- return self.command.execute()
303
-
304
-
305
- class RebootAssetsByIdCommand(Command[Dict[str, Any]]):
306
- """Legacy command to reboot assets by endpoint IDs - uses correct API structure."""
307
-
308
- def __init__(
309
- self,
310
- http_client: HTTPClient,
311
- endpoint_ids: Union[str, List[str]],
312
- organization_ids: Optional[List[Union[int, str]]] = None
313
- ):
314
- self.http_client = http_client
315
- asset_filter = create_asset_filter_from_endpoint_ids(endpoint_ids, organization_ids)
316
- self.command = RebootAssetsCommand(http_client, asset_filter)
317
-
318
- def execute(self) -> Dict[str, Any]:
319
- """Execute through the correct filter-based command."""
320
- return self.command.execute()
321
-
322
-
323
- class ShutdownAssetsByIdCommand(Command[Dict[str, Any]]):
324
- """Legacy command to shutdown assets by endpoint IDs - uses correct API structure."""
325
-
326
- def __init__(
327
- self,
328
- http_client: HTTPClient,
329
- endpoint_ids: Union[str, List[str]],
330
- organization_ids: Optional[List[Union[int, str]]] = None
331
- ):
332
- self.http_client = http_client
333
- asset_filter = create_asset_filter_from_endpoint_ids(endpoint_ids, organization_ids)
334
- self.command = ShutdownAssetsCommand(http_client, asset_filter)
335
-
336
- def execute(self) -> Dict[str, Any]:
337
- """Execute through the correct filter-based command."""
338
- return self.command.execute()
339
-
340
-
341
- # Export the main corrected classes
342
- __all__ = [
343
- # Main corrected commands
344
- 'RebootAssetsCommand',
345
- 'ShutdownAssetsCommand',
346
- 'IsolateAssetsCommand',
347
- 'UnisolateAssetsCommand',
348
- 'LogRetrievalCommand',
349
- 'VersionUpdateCommand',
350
- 'UninstallAssetsCommand',
351
- 'PurgeAndUninstallAssetsCommand',
352
- 'AddTagsToAssetsCommand',
353
- 'RemoveTagsFromAssetsCommand',
354
-
355
- # Legacy compatibility commands
356
- 'IsolateAssetsByIdCommand',
357
- 'UnisolateAssetsByIdCommand',
358
- 'RebootAssetsByIdCommand',
359
- 'ShutdownAssetsByIdCommand',
360
-
361
- # Utility functions
362
- 'create_asset_filter_from_endpoint_ids'
1
+ """
2
+ Asset-related commands for the Binalyze AIR SDK.
3
+ Fixed to match API documentation exactly.
4
+ """
5
+
6
+ from typing import List, Union, Optional, Dict, Any
7
+
8
+ from ..base import Command
9
+ from ..models.assets import AssetFilter
10
+ from ..http_client import HTTPClient
11
+
12
+
13
+ class RebootAssetsCommand(Command[Dict[str, Any]]):
14
+ """Command to reboot assets by filter - FIXED to match API documentation."""
15
+
16
+ def __init__(
17
+ self,
18
+ http_client: HTTPClient,
19
+ asset_filter: AssetFilter
20
+ ):
21
+ self.http_client = http_client
22
+ self.asset_filter = asset_filter
23
+
24
+ def execute(self) -> Dict[str, Any]:
25
+ """Execute the reboot command with correct payload structure."""
26
+ # Use the correct payload structure as per API documentation
27
+ payload = {
28
+ "filter": self.asset_filter.to_filter_dict()
29
+ }
30
+
31
+ # FIXED: Correct endpoint URL (confirmed from API docs)
32
+ return self.http_client.post("assets/tasks/reboot", json_data=payload)
33
+
34
+
35
+ class ShutdownAssetsCommand(Command[Dict[str, Any]]):
36
+ """Command to shutdown assets by filter - FIXED to match API documentation."""
37
+
38
+ def __init__(
39
+ self,
40
+ http_client: HTTPClient,
41
+ asset_filter: AssetFilter
42
+ ):
43
+ self.http_client = http_client
44
+ self.asset_filter = asset_filter
45
+
46
+ def execute(self) -> Dict[str, Any]:
47
+ """Execute the shutdown command with correct payload structure."""
48
+ payload = {
49
+ "filter": self.asset_filter.to_filter_dict()
50
+ }
51
+
52
+ # FIXED: Correct endpoint URL (following same pattern as reboot)
53
+ return self.http_client.post("assets/tasks/shutdown", json_data=payload)
54
+
55
+
56
+ class IsolateAssetsCommand(Command[Dict[str, Any]]):
57
+ """Command to isolate assets by filter - FIXED to match API documentation."""
58
+
59
+ def __init__(
60
+ self,
61
+ http_client: HTTPClient,
62
+ asset_filter: AssetFilter,
63
+ isolation_settings: Optional[Dict[str, Any]] = None
64
+ ):
65
+ self.http_client = http_client
66
+ self.asset_filter = asset_filter
67
+ self.isolation_settings = isolation_settings or {}
68
+
69
+ def execute(self) -> Dict[str, Any]:
70
+ """Execute the isolation command with correct payload structure."""
71
+ payload = {
72
+ "enabled": True, # Required field for isolation
73
+ "filter": self.asset_filter.to_filter_dict()
74
+ }
75
+
76
+ # Add isolation settings if provided
77
+ if self.isolation_settings:
78
+ payload.update(self.isolation_settings)
79
+
80
+ # FIXED: Correct endpoint URL and payload
81
+ return self.http_client.post("assets/tasks/isolation", json_data=payload)
82
+
83
+
84
+ class UnisolateAssetsCommand(Command[Dict[str, Any]]):
85
+ """Command to unisolate (remove isolation from) assets - FIXED to match API documentation."""
86
+
87
+ def __init__(
88
+ self,
89
+ http_client: HTTPClient,
90
+ asset_filter: AssetFilter
91
+ ):
92
+ self.http_client = http_client
93
+ self.asset_filter = asset_filter
94
+
95
+ def execute(self) -> Dict[str, Any]:
96
+ """Execute the unisolate command with correct payload structure."""
97
+ payload = {
98
+ "enabled": False, # Disable isolation for unisolate
99
+ "filter": self.asset_filter.to_filter_dict()
100
+ }
101
+
102
+ # FIXED: Correct endpoint URL and payload
103
+ return self.http_client.post("assets/tasks/isolation", json_data=payload)
104
+
105
+
106
+ class LogRetrievalCommand(Command[Dict[str, Any]]):
107
+ """Command to retrieve logs from assets - FIXED endpoint URL and payload structure."""
108
+
109
+ def __init__(
110
+ self,
111
+ http_client: HTTPClient,
112
+ asset_filter: AssetFilter,
113
+ log_settings: Optional[Dict[str, Any]] = None
114
+ ):
115
+ self.http_client = http_client
116
+ self.asset_filter = asset_filter
117
+ self.log_settings = log_settings or {}
118
+
119
+ def execute(self) -> Dict[str, Any]:
120
+ """Execute the log retrieval command with correct endpoint and payload."""
121
+ payload = {
122
+ "filter": self.asset_filter.to_filter_dict()
123
+ }
124
+
125
+ # Add log retrieval settings if provided
126
+ if self.log_settings:
127
+ payload.update(self.log_settings)
128
+
129
+ # FIXED: Correct endpoint URL to match API specification
130
+ return self.http_client.post("assets/tasks/retrieve-logs", json_data=payload)
131
+
132
+
133
+ class VersionUpdateCommand(Command[Dict[str, Any]]):
134
+ """Command to update version on assets - FIXED to match API documentation."""
135
+
136
+ def __init__(
137
+ self,
138
+ http_client: HTTPClient,
139
+ asset_filter: AssetFilter,
140
+ update_settings: Optional[Dict[str, Any]] = None
141
+ ):
142
+ self.http_client = http_client
143
+ self.asset_filter = asset_filter
144
+ self.update_settings = update_settings or {}
145
+
146
+ def execute(self) -> Dict[str, Any]:
147
+ """Execute the version update command with correct payload structure."""
148
+ payload = {
149
+ "filter": self.asset_filter.to_filter_dict()
150
+ }
151
+
152
+ # Add version update settings if provided
153
+ if self.update_settings:
154
+ payload.update(self.update_settings)
155
+
156
+ # FIXED: Correct endpoint URL (following tasks pattern)
157
+ return self.http_client.post("assets/tasks/version-update", json_data=payload)
158
+
159
+
160
+ class UninstallAssetsCommand(Command[Dict[str, Any]]):
161
+ """Command to uninstall assets without purging data - FIXED endpoint URL and HTTP method."""
162
+
163
+ def __init__(
164
+ self,
165
+ http_client: HTTPClient,
166
+ asset_filter: AssetFilter
167
+ ):
168
+ self.http_client = http_client
169
+ self.asset_filter = asset_filter
170
+
171
+ def execute(self) -> Dict[str, Any]:
172
+ """Execute the uninstall command with correct endpoint, HTTP method and payload structure."""
173
+ payload = {
174
+ "filter": self.asset_filter.to_filter_dict()
175
+ }
176
+
177
+ # FIXED: Correct endpoint URL and HTTP method (DELETE, not POST)
178
+ return self.http_client.delete("assets/uninstall-without-purge", json_data=payload)
179
+
180
+
181
+ class PurgeAndUninstallAssetsCommand(Command[Dict[str, Any]]):
182
+ """Command to purge and uninstall assets - FIXED endpoint URL and HTTP method."""
183
+
184
+ def __init__(
185
+ self,
186
+ http_client: HTTPClient,
187
+ asset_filter: AssetFilter
188
+ ):
189
+ self.http_client = http_client
190
+ self.asset_filter = asset_filter
191
+
192
+ def execute(self) -> Dict[str, Any]:
193
+ """Execute the purge and uninstall command with correct endpoint, HTTP method and payload."""
194
+ payload = {
195
+ "filter": self.asset_filter.to_filter_dict()
196
+ }
197
+
198
+ # FIXED: Correct endpoint URL and HTTP method (DELETE, not POST)
199
+ return self.http_client.delete("assets/purge-and-uninstall", json_data=payload)
200
+
201
+
202
+ class AddTagsToAssetsCommand(Command[Dict[str, Any]]):
203
+ """Command to add tags to assets - FIXED endpoint URL and payload structure."""
204
+
205
+ def __init__(
206
+ self,
207
+ http_client: HTTPClient,
208
+ asset_filter: AssetFilter,
209
+ tags: List[str]
210
+ ):
211
+ self.http_client = http_client
212
+ self.asset_filter = asset_filter
213
+ self.tags = tags
214
+
215
+ def execute(self) -> Dict[str, Any]:
216
+ """Execute the add tags command with correct endpoint and payload structure."""
217
+ payload = {
218
+ "filter": self.asset_filter.to_filter_dict(),
219
+ "tags": self.tags
220
+ }
221
+
222
+ # FIXED: Correct endpoint URL (from API documentation)
223
+ return self.http_client.post("assets/tags", json_data=payload)
224
+
225
+
226
+ class RemoveTagsFromAssetsCommand(Command[Dict[str, Any]]):
227
+ """Command to remove tags from assets by filter - FIXED to match API documentation."""
228
+
229
+ def __init__(
230
+ self,
231
+ http_client: HTTPClient,
232
+ asset_filter: AssetFilter,
233
+ tags: List[str]
234
+ ):
235
+ self.http_client = http_client
236
+ self.asset_filter = asset_filter
237
+ self.tags = tags
238
+
239
+ def execute(self) -> Dict[str, Any]:
240
+ """Execute the remove tags command with correct payload structure."""
241
+ payload = {
242
+ "filter": self.asset_filter.to_filter_dict(),
243
+ "tags": self.tags
244
+ }
245
+
246
+ # FIXED: Correct endpoint URL and HTTP method
247
+ return self.http_client.delete("assets/tags", json_data=payload)
248
+
249
+
250
+ class DeleteAssetTagByIdCommand(Command[Dict[str, Any]]):
251
+ """Command to delete an asset tag by ID."""
252
+
253
+ def __init__(self, http_client: HTTPClient, organization_id: int, tag_id: str):
254
+ self.http_client = http_client
255
+ self.organization_id = organization_id
256
+ self.tag_id = tag_id
257
+
258
+ def execute(self) -> Dict[str, Any]:
259
+ """Execute the delete asset tag command."""
260
+ return self.http_client.delete(f"asset-tags/{self.organization_id}/{self.tag_id}")
261
+
262
+
263
+ class DeleteAssetTagsByOrganizationIdCommand(Command[Dict[str, Any]]):
264
+ """Command to delete asset tags by organization ID."""
265
+
266
+ def __init__(self, http_client: HTTPClient, organization_id: int):
267
+ self.http_client = http_client
268
+ self.organization_id = organization_id
269
+
270
+ def execute(self) -> Dict[str, Any]:
271
+ """Execute the delete asset tags by organization ID command."""
272
+ return self.http_client.delete(f"asset-tags/{self.organization_id}/all")
273
+
274
+
275
+ # Convenience functions for backward compatibility
276
+ def create_asset_filter_from_endpoint_ids(
277
+ endpoint_ids: Union[str, List[str]],
278
+ organization_ids: Optional[List[Union[int, str]]] = None
279
+ ) -> AssetFilter:
280
+ """
281
+ Create an AssetFilter from endpoint IDs - helper function.
282
+
283
+ Args:
284
+ endpoint_ids: Single endpoint ID or list of endpoint IDs
285
+ organization_ids: Optional list of organization IDs
286
+
287
+ Returns:
288
+ AssetFilter: Configured filter object
289
+ """
290
+ # Convert single endpoint ID to list
291
+ if isinstance(endpoint_ids, str):
292
+ endpoint_ids = [endpoint_ids]
293
+
294
+ # Set default organization IDs if not provided and convert to integers
295
+ if organization_ids is None:
296
+ org_ids = [0]
297
+ else:
298
+ org_ids = [int(org_id) for org_id in organization_ids]
299
+
300
+ # Create and return the filter
301
+ return AssetFilter(
302
+ included_endpoint_ids=endpoint_ids,
303
+ organization_ids=org_ids
304
+ )
305
+
306
+
307
+ # Export the main corrected classes
308
+ __all__ = [
309
+ # Main corrected commands
310
+ 'RebootAssetsCommand',
311
+ 'ShutdownAssetsCommand',
312
+ 'IsolateAssetsCommand',
313
+ 'UnisolateAssetsCommand',
314
+ 'LogRetrievalCommand',
315
+ 'VersionUpdateCommand',
316
+ 'UninstallAssetsCommand',
317
+ 'PurgeAndUninstallAssetsCommand',
318
+ 'AddTagsToAssetsCommand',
319
+ 'RemoveTagsFromAssetsCommand',
320
+ 'DeleteAssetTagByIdCommand',
321
+ 'DeleteAssetTagsByOrganizationIdCommand',
322
+
323
+ # Utility functions
324
+ 'create_asset_filter_from_endpoint_ids'
363
325
  ]