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
@@ -1,75 +1,79 @@
|
|
1
|
-
"""
|
2
|
-
Auto Asset Tags API for the Binalyze AIR SDK.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import List, Optional, Dict, Any, Union
|
6
|
-
|
7
|
-
from ..http_client import HTTPClient
|
8
|
-
from ..models.auto_asset_tags import (
|
9
|
-
AutoAssetTag, AutoAssetTagFilter, CreateAutoAssetTagRequest, UpdateAutoAssetTagRequest,
|
10
|
-
StartTaggingRequest, TaggingResponse
|
11
|
-
)
|
12
|
-
from ..queries.auto_asset_tags import ListAutoAssetTagsQuery, GetAutoAssetTagQuery
|
13
|
-
from ..commands.auto_asset_tags import (
|
14
|
-
CreateAutoAssetTagCommand, UpdateAutoAssetTagCommand, DeleteAutoAssetTagCommand,
|
15
|
-
StartTaggingCommand
|
16
|
-
)
|
17
|
-
|
18
|
-
|
19
|
-
class AutoAssetTagsAPI:
|
20
|
-
"""Auto Asset Tags API with CQRS pattern - separated queries and commands."""
|
21
|
-
|
22
|
-
def __init__(self, http_client: HTTPClient):
|
23
|
-
self.http_client = http_client
|
24
|
-
|
25
|
-
# QUERIES (Read operations)
|
26
|
-
def list(self, filter_params: Optional[AutoAssetTagFilter] = None) -> List[AutoAssetTag]:
|
27
|
-
"""List auto asset tags with optional filtering."""
|
28
|
-
query = ListAutoAssetTagsQuery(self.http_client, filter_params)
|
29
|
-
return query.execute()
|
30
|
-
|
31
|
-
def get(self, tag_id: str) -> AutoAssetTag:
|
32
|
-
"""Get a specific auto asset tag by ID."""
|
33
|
-
query = GetAutoAssetTagQuery(self.http_client, tag_id)
|
34
|
-
return query.execute()
|
35
|
-
|
36
|
-
def get_by_id(self, tag_id: str) -> AutoAssetTag:
|
37
|
-
"""Get a specific auto asset tag by ID - alias for get."""
|
38
|
-
return self.get(tag_id)
|
39
|
-
|
40
|
-
# COMMANDS (Write operations)
|
41
|
-
def create(self, request: Union[CreateAutoAssetTagRequest, Dict[str, Any]]) -> AutoAssetTag:
|
42
|
-
"""Create a new auto asset tag."""
|
43
|
-
command = CreateAutoAssetTagCommand(self.http_client, request)
|
44
|
-
return command.execute()
|
45
|
-
|
46
|
-
def update(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
command
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
return
|
71
|
-
|
72
|
-
def
|
73
|
-
"""
|
74
|
-
|
75
|
-
|
1
|
+
"""
|
2
|
+
Auto Asset Tags API for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any, Union
|
6
|
+
|
7
|
+
from ..http_client import HTTPClient
|
8
|
+
from ..models.auto_asset_tags import (
|
9
|
+
AutoAssetTag, AutoAssetTagFilter, CreateAutoAssetTagRequest, UpdateAutoAssetTagRequest,
|
10
|
+
StartTaggingRequest, TaggingResponse
|
11
|
+
)
|
12
|
+
from ..queries.auto_asset_tags import ListAutoAssetTagsQuery, GetAutoAssetTagQuery
|
13
|
+
from ..commands.auto_asset_tags import (
|
14
|
+
CreateAutoAssetTagCommand, UpdateAutoAssetTagCommand, DeleteAutoAssetTagCommand,
|
15
|
+
StartTaggingCommand
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
class AutoAssetTagsAPI:
|
20
|
+
"""Auto Asset Tags API with CQRS pattern - separated queries and commands."""
|
21
|
+
|
22
|
+
def __init__(self, http_client: HTTPClient):
|
23
|
+
self.http_client = http_client
|
24
|
+
|
25
|
+
# QUERIES (Read operations)
|
26
|
+
def list(self, filter_params: Optional[AutoAssetTagFilter] = None) -> List[AutoAssetTag]:
|
27
|
+
"""List auto asset tags with optional filtering."""
|
28
|
+
query = ListAutoAssetTagsQuery(self.http_client, filter_params)
|
29
|
+
return query.execute()
|
30
|
+
|
31
|
+
def get(self, tag_id: str) -> AutoAssetTag:
|
32
|
+
"""Get a specific auto asset tag by ID."""
|
33
|
+
query = GetAutoAssetTagQuery(self.http_client, tag_id)
|
34
|
+
return query.execute()
|
35
|
+
|
36
|
+
def get_by_id(self, tag_id: str) -> AutoAssetTag:
|
37
|
+
"""Get a specific auto asset tag by ID - alias for get."""
|
38
|
+
return self.get(tag_id)
|
39
|
+
|
40
|
+
# COMMANDS (Write operations)
|
41
|
+
def create(self, request: Union[CreateAutoAssetTagRequest, Dict[str, Any]]) -> AutoAssetTag:
|
42
|
+
"""Create a new auto asset tag."""
|
43
|
+
command = CreateAutoAssetTagCommand(self.http_client, request)
|
44
|
+
return command.execute()
|
45
|
+
|
46
|
+
def update(
|
47
|
+
self,
|
48
|
+
tag_id_or_data: Union[str, Dict[str, Any]],
|
49
|
+
request: Optional[Union[UpdateAutoAssetTagRequest, Dict[str, Any]]] = None
|
50
|
+
) -> AutoAssetTag:
|
51
|
+
"""Update an existing auto asset tag."""
|
52
|
+
# Handle both signatures: update(tag_id, request) and update(data_dict)
|
53
|
+
if isinstance(tag_id_or_data, str) and request is not None:
|
54
|
+
# Traditional signature: update(tag_id, request)
|
55
|
+
command = UpdateAutoAssetTagCommand(self.http_client, tag_id_or_data, request)
|
56
|
+
elif isinstance(tag_id_or_data, dict):
|
57
|
+
# Dict signature: update(data_dict) where data_dict contains 'id'
|
58
|
+
tag_id = tag_id_or_data.get('id')
|
59
|
+
if not tag_id:
|
60
|
+
raise ValueError("Tag ID must be provided in data dict or as separate parameter")
|
61
|
+
command = UpdateAutoAssetTagCommand(self.http_client, tag_id, tag_id_or_data)
|
62
|
+
else:
|
63
|
+
raise ValueError("Invalid arguments for update")
|
64
|
+
|
65
|
+
return command.execute()
|
66
|
+
|
67
|
+
def delete(self, tag_id: str) -> Dict[str, Any]:
|
68
|
+
"""Delete an auto asset tag."""
|
69
|
+
command = DeleteAutoAssetTagCommand(self.http_client, tag_id)
|
70
|
+
return command.execute()
|
71
|
+
|
72
|
+
def delete_by_id(self, tag_id: str) -> Dict[str, Any]:
|
73
|
+
"""Delete an auto asset tag by ID - alias for delete."""
|
74
|
+
return self.delete(tag_id)
|
75
|
+
|
76
|
+
def start_tagging(self, request: Union[StartTaggingRequest, Dict[str, Any]]) -> TaggingResponse:
|
77
|
+
"""Start the tagging process for auto asset tags."""
|
78
|
+
command = StartTaggingCommand(self.http_client, request)
|
79
|
+
return command.execute()
|
@@ -0,0 +1,177 @@
|
|
1
|
+
"""
|
2
|
+
Backup API for the Binalyze AIR SDK.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Optional, Dict, Any, List
|
6
|
+
from datetime import datetime
|
7
|
+
|
8
|
+
from ..http_client import HTTPClient
|
9
|
+
from ..models.backup import (
|
10
|
+
BackupHistoryResponse, BackupFilter, BackupNowRequest,
|
11
|
+
BackupStatus, BackupSource, BackupLocation, BackupStats
|
12
|
+
)
|
13
|
+
from ..queries.backup import (
|
14
|
+
GetBackupHistoryQuery, GetBackupDownloadQuery
|
15
|
+
)
|
16
|
+
from ..commands.backup import (
|
17
|
+
BackupNowCommand, DeleteBackupCommand
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
class BackupAPI:
|
22
|
+
"""Backup API with CQRS pattern - separated queries and commands."""
|
23
|
+
|
24
|
+
def __init__(self, http_client: HTTPClient):
|
25
|
+
self.http_client = http_client
|
26
|
+
|
27
|
+
# QUERIES (Read operations)
|
28
|
+
def get_history(self, filter_params: Optional[BackupFilter] = None) -> BackupHistoryResponse:
|
29
|
+
"""Get backup history with optional filtering."""
|
30
|
+
query = GetBackupHistoryQuery(self.http_client, filter_params)
|
31
|
+
return query.execute()
|
32
|
+
|
33
|
+
def download_backup(self, backup_id: str) -> Dict[str, Any]:
|
34
|
+
"""Download a backup by ID."""
|
35
|
+
query = GetBackupDownloadQuery(self.http_client, backup_id)
|
36
|
+
return query.execute()
|
37
|
+
|
38
|
+
# COMMANDS (Write operations)
|
39
|
+
def backup_now(self, request: BackupNowRequest) -> Dict[str, Any]:
|
40
|
+
"""Create an immediate backup."""
|
41
|
+
command = BackupNowCommand(self.http_client, request)
|
42
|
+
return command.execute()
|
43
|
+
|
44
|
+
def delete_backup(self, backup_id: str) -> Dict[str, Any]:
|
45
|
+
"""Delete a backup by ID."""
|
46
|
+
command = DeleteBackupCommand(self.http_client, backup_id)
|
47
|
+
return command.execute()
|
48
|
+
|
49
|
+
# Convenience methods
|
50
|
+
def backup_all_endpoints(self, organization_ids: Optional[List[int]] = None) -> Dict[str, Any]:
|
51
|
+
"""Create a backup of all endpoints."""
|
52
|
+
request = BackupNowRequest(organizationIds=organization_ids)
|
53
|
+
return self.backup_now(request)
|
54
|
+
|
55
|
+
def backup_specific_endpoints(self, endpoint_ids: List[str],
|
56
|
+
organization_ids: Optional[List[int]] = None) -> Dict[str, Any]:
|
57
|
+
"""Create a backup of specific endpoints."""
|
58
|
+
request = BackupNowRequest(
|
59
|
+
includedEndpointIds=endpoint_ids,
|
60
|
+
organizationIds=organization_ids
|
61
|
+
)
|
62
|
+
return self.backup_now(request)
|
63
|
+
|
64
|
+
def get_recent_backups(self, days: int = 7) -> BackupHistoryResponse:
|
65
|
+
"""Get recent backups from the last N days."""
|
66
|
+
end_date = datetime.utcnow()
|
67
|
+
start_date = datetime.utcnow().replace(day=end_date.day - days)
|
68
|
+
|
69
|
+
filter_params = BackupFilter(
|
70
|
+
startDate=start_date,
|
71
|
+
endDate=end_date,
|
72
|
+
sortBy="startDate",
|
73
|
+
sortType="DESC"
|
74
|
+
)
|
75
|
+
return self.get_history(filter_params)
|
76
|
+
|
77
|
+
def get_failed_backups(self) -> BackupHistoryResponse:
|
78
|
+
"""Get all failed backups."""
|
79
|
+
filter_params = BackupFilter(
|
80
|
+
status=BackupStatus.FAILED,
|
81
|
+
sortBy="startDate",
|
82
|
+
sortType="DESC"
|
83
|
+
)
|
84
|
+
return self.get_history(filter_params)
|
85
|
+
|
86
|
+
def get_in_progress_backups(self) -> BackupHistoryResponse:
|
87
|
+
"""Get all in-progress backups."""
|
88
|
+
filter_params = BackupFilter(
|
89
|
+
status=BackupStatus.IN_PROGRESS,
|
90
|
+
sortBy="startDate",
|
91
|
+
sortType="DESC"
|
92
|
+
)
|
93
|
+
return self.get_history(filter_params)
|
94
|
+
|
95
|
+
def get_user_backups(self, username: str) -> BackupHistoryResponse:
|
96
|
+
"""Get backups created by a specific user."""
|
97
|
+
filter_params = BackupFilter(
|
98
|
+
username=username,
|
99
|
+
source=BackupSource.USER,
|
100
|
+
sortBy="startDate",
|
101
|
+
sortType="DESC"
|
102
|
+
)
|
103
|
+
return self.get_history(filter_params)
|
104
|
+
|
105
|
+
def get_scheduled_backups(self) -> BackupHistoryResponse:
|
106
|
+
"""Get backups created by scheduler."""
|
107
|
+
filter_params = BackupFilter(
|
108
|
+
source=BackupSource.SCHEDULER,
|
109
|
+
sortBy="startDate",
|
110
|
+
sortType="DESC"
|
111
|
+
)
|
112
|
+
return self.get_history(filter_params)
|
113
|
+
|
114
|
+
def get_backup_stats(self) -> BackupStats:
|
115
|
+
"""Get backup statistics summary."""
|
116
|
+
# Get all backup history to calculate stats
|
117
|
+
all_backups = self.get_history(BackupFilter(pageSize=1000))
|
118
|
+
|
119
|
+
stats = BackupStats()
|
120
|
+
stats.total_backups = len(all_backups.entities)
|
121
|
+
|
122
|
+
total_duration = 0
|
123
|
+
backup_count_with_duration = 0
|
124
|
+
|
125
|
+
for backup in all_backups.entities:
|
126
|
+
# Count by status
|
127
|
+
if backup.status == BackupStatus.SUCCEEDED:
|
128
|
+
stats.successful_backups += 1
|
129
|
+
elif backup.status == BackupStatus.FAILED:
|
130
|
+
stats.failed_backups += 1
|
131
|
+
elif backup.status == BackupStatus.IN_PROGRESS:
|
132
|
+
stats.in_progress_backups += 1
|
133
|
+
|
134
|
+
# Sum total size
|
135
|
+
if backup.size:
|
136
|
+
stats.total_size_bytes += backup.size
|
137
|
+
|
138
|
+
# Calculate average backup time
|
139
|
+
if backup.start_date and backup.end_date:
|
140
|
+
duration = (backup.end_date - backup.start_date).total_seconds() / 60
|
141
|
+
total_duration += duration
|
142
|
+
backup_count_with_duration += 1
|
143
|
+
|
144
|
+
# Track last backup date
|
145
|
+
if not stats.last_backup_date or backup.start_date > stats.last_backup_date:
|
146
|
+
stats.last_backup_date = backup.start_date
|
147
|
+
|
148
|
+
# Calculate average backup time
|
149
|
+
if backup_count_with_duration > 0:
|
150
|
+
stats.average_backup_time_minutes = total_duration / backup_count_with_duration
|
151
|
+
|
152
|
+
return stats
|
153
|
+
|
154
|
+
def cleanup_old_backups(self, days_to_keep: int = 30) -> List[str]:
|
155
|
+
"""Delete backups older than specified days and return deleted backup IDs."""
|
156
|
+
cutoff_date = datetime.utcnow().replace(day=datetime.utcnow().day - days_to_keep)
|
157
|
+
|
158
|
+
filter_params = BackupFilter(
|
159
|
+
endDate=cutoff_date,
|
160
|
+
status=BackupStatus.SUCCEEDED,
|
161
|
+
sortBy="startDate",
|
162
|
+
sortType="ASC",
|
163
|
+
pageSize=1000
|
164
|
+
)
|
165
|
+
|
166
|
+
old_backups = self.get_history(filter_params)
|
167
|
+
deleted_ids = []
|
168
|
+
|
169
|
+
for backup in old_backups.entities:
|
170
|
+
try:
|
171
|
+
self.delete_backup(backup.id)
|
172
|
+
deleted_ids.append(backup.id)
|
173
|
+
except Exception:
|
174
|
+
# Continue with other backups if one fails
|
175
|
+
continue
|
176
|
+
|
177
|
+
return deleted_ids
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""
|
2
|
+
Baseline API for the Binalyze AIR SDK using CQRS pattern.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from ..http_client import HTTPClient
|
7
|
+
from ..commands.baseline import (
|
8
|
+
AcquireBaselineByFilterCommand,
|
9
|
+
CompareBaselineByEndpointCommand,
|
10
|
+
)
|
11
|
+
from ..queries.baseline import (
|
12
|
+
GetBaselineComparisonReportQuery,
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
class BaselineAPI:
|
17
|
+
"""Baseline API with CQRS pattern - separated queries and commands."""
|
18
|
+
|
19
|
+
def __init__(self, http_client: HTTPClient):
|
20
|
+
self.http_client = http_client
|
21
|
+
|
22
|
+
# COMMANDS (Write operations)
|
23
|
+
def acquire_by_filter(self, filter_data: Dict[str, Any], case_id: Optional[str] = None) -> Dict[str, Any]:
|
24
|
+
"""Acquire baselines by asset filter criteria."""
|
25
|
+
payload = {
|
26
|
+
"filter": filter_data,
|
27
|
+
"caseId": case_id
|
28
|
+
}
|
29
|
+
|
30
|
+
command = AcquireBaselineByFilterCommand(self.http_client, payload)
|
31
|
+
return command.execute()
|
32
|
+
|
33
|
+
def compare_by_endpoint(self, endpoint_id: str, baseline_task_ids: List[str]) -> Dict[str, Any]:
|
34
|
+
"""Compare baseline acquisition tasks by endpoint ID."""
|
35
|
+
payload = {
|
36
|
+
"endpointId": endpoint_id,
|
37
|
+
"taskIds": baseline_task_ids
|
38
|
+
}
|
39
|
+
|
40
|
+
command = CompareBaselineByEndpointCommand(self.http_client, payload)
|
41
|
+
return command.execute()
|
42
|
+
|
43
|
+
def get_comparison_report(self, endpoint_id: str, task_id: str) -> Dict[str, Any]:
|
44
|
+
"""Get comparison report by endpoint ID and task ID."""
|
45
|
+
query = GetBaselineComparisonReportQuery(self.http_client, endpoint_id, task_id)
|
46
|
+
return query.execute()
|
@@ -0,0 +1,225 @@
|
|
1
|
+
"""
|
2
|
+
Cases API for the Binalyze AIR SDK using CQRS pattern.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import List, Optional, Dict, Any
|
6
|
+
from ..http_client import HTTPClient
|
7
|
+
from ..models.cases import (
|
8
|
+
Case, CaseActivity, CaseEndpoint, CaseTask, User, CaseFilter, CaseActivityFilter,
|
9
|
+
CreateCaseRequest, UpdateCaseRequest, CaseNote, CaseEndpointFilter, CaseTaskFilter, CaseUserFilter
|
10
|
+
)
|
11
|
+
from ..models.assets import AssetFilter
|
12
|
+
from ..queries.cases import (
|
13
|
+
ListCasesQuery,
|
14
|
+
GetCaseQuery,
|
15
|
+
GetCaseActivitiesQuery,
|
16
|
+
GetCaseEndpointsQuery,
|
17
|
+
GetCaseTasksQuery,
|
18
|
+
GetCaseUsersQuery,
|
19
|
+
CheckCaseNameQuery,
|
20
|
+
)
|
21
|
+
from ..commands.cases import (
|
22
|
+
CreateCaseCommand,
|
23
|
+
UpdateCaseCommand,
|
24
|
+
CloseCaseCommand,
|
25
|
+
OpenCaseCommand,
|
26
|
+
ArchiveCaseCommand,
|
27
|
+
ChangeCaseOwnerCommand,
|
28
|
+
RemoveEndpointsFromCaseCommand,
|
29
|
+
RemoveTaskAssignmentFromCaseCommand,
|
30
|
+
ImportTaskAssignmentsToCaseCommand,
|
31
|
+
AddNoteToCaseCommand,
|
32
|
+
UpdateNoteToCaseCommand,
|
33
|
+
DeleteNoteToCaseCommand,
|
34
|
+
ExportCaseNotesCommand,
|
35
|
+
ExportCasesCommand,
|
36
|
+
ExportCaseEndpointsCommand,
|
37
|
+
ExportCaseActivitiesCommand,
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
class CasesAPI:
|
42
|
+
"""Cases API with CQRS pattern - separated queries and commands."""
|
43
|
+
|
44
|
+
def __init__(self, http_client: HTTPClient):
|
45
|
+
self.http_client = http_client
|
46
|
+
|
47
|
+
# QUERIES (Read operations)
|
48
|
+
def list(self, filter_params: Optional[CaseFilter] = None, organization_ids: Optional[List[int]] = None) -> List[Case]:
|
49
|
+
"""List cases with optional filtering."""
|
50
|
+
query = ListCasesQuery(self.http_client, filter_params, organization_ids)
|
51
|
+
return query.execute()
|
52
|
+
|
53
|
+
def get(self, case_id: str) -> Case:
|
54
|
+
"""Get a specific case by ID."""
|
55
|
+
query = GetCaseQuery(self.http_client, case_id)
|
56
|
+
return query.execute()
|
57
|
+
|
58
|
+
def get_activities(self, case_id: str, filter_params: Optional[CaseActivityFilter] = None) -> List[CaseActivity]:
|
59
|
+
"""Get activities for a specific case with optional filtering, pagination, and sorting."""
|
60
|
+
query = GetCaseActivitiesQuery(self.http_client, case_id, filter_params)
|
61
|
+
return query.execute()
|
62
|
+
|
63
|
+
def get_endpoints(
|
64
|
+
self, case_id: str, filter_params: Optional[CaseEndpointFilter] = None, organization_ids: Optional[List[int]] = None
|
65
|
+
) -> List[CaseEndpoint]:
|
66
|
+
"""Get endpoints for a specific case with comprehensive filtering support.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
case_id: The case ID to get endpoints for
|
70
|
+
filter_params: Optional CaseEndpointFilter with comprehensive filtering options
|
71
|
+
organization_ids: Optional list of organization IDs (for backward compatibility)
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
List of CaseEndpoint objects
|
75
|
+
|
76
|
+
Note: If both filter_params and organization_ids are provided, organization_ids in filter_params takes precedence.
|
77
|
+
"""
|
78
|
+
# Handle backward compatibility
|
79
|
+
if filter_params is None:
|
80
|
+
filter_params = CaseEndpointFilter()
|
81
|
+
|
82
|
+
# If organization_ids is provided and not set in filter_params, use it
|
83
|
+
if organization_ids is not None and filter_params.organization_ids is None:
|
84
|
+
filter_params.organization_ids = organization_ids
|
85
|
+
|
86
|
+
query = GetCaseEndpointsQuery(self.http_client, case_id, filter_params)
|
87
|
+
return query.execute()
|
88
|
+
|
89
|
+
def get_tasks(
|
90
|
+
self, case_id: str, filter_params: Optional[CaseTaskFilter] = None, organization_ids: Optional[List[int]] = None
|
91
|
+
) -> List[CaseTask]:
|
92
|
+
"""Get tasks for a specific case with comprehensive filtering support.
|
93
|
+
|
94
|
+
Args:
|
95
|
+
case_id: The case ID to get tasks for
|
96
|
+
filter_params: Optional CaseTaskFilter with comprehensive filtering options
|
97
|
+
organization_ids: Optional list of organization IDs (for backward compatibility)
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
List of CaseTask objects
|
101
|
+
|
102
|
+
Note: If both filter_params and organization_ids are provided, organization_ids in filter_params takes precedence.
|
103
|
+
"""
|
104
|
+
# Handle backward compatibility
|
105
|
+
if filter_params is None:
|
106
|
+
filter_params = CaseTaskFilter()
|
107
|
+
|
108
|
+
# If organization_ids is provided and not set in filter_params, use it
|
109
|
+
if organization_ids is not None and filter_params.organization_ids is None:
|
110
|
+
filter_params.organization_ids = organization_ids
|
111
|
+
|
112
|
+
query = GetCaseTasksQuery(self.http_client, case_id, filter_params)
|
113
|
+
return query.execute()
|
114
|
+
|
115
|
+
def get_users(
|
116
|
+
self, case_id: str, filter_params: Optional[CaseUserFilter] = None, organization_ids: Optional[List[int]] = None
|
117
|
+
) -> List[User]:
|
118
|
+
"""Get users for a specific case with comprehensive filtering support.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
case_id: The case ID to get users for
|
122
|
+
filter_params: Optional CaseUserFilter with comprehensive filtering options
|
123
|
+
organization_ids: Optional list of organization IDs (for backward compatibility)
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
List of User objects
|
127
|
+
|
128
|
+
Note: If both filter_params and organization_ids are provided, organization_ids in filter_params takes precedence.
|
129
|
+
"""
|
130
|
+
# Handle backward compatibility
|
131
|
+
if filter_params is None:
|
132
|
+
filter_params = CaseUserFilter()
|
133
|
+
|
134
|
+
# If organization_ids is provided and not set in filter_params, use it
|
135
|
+
if organization_ids is not None and filter_params.organization_ids is None:
|
136
|
+
filter_params.organization_ids = organization_ids
|
137
|
+
|
138
|
+
query = GetCaseUsersQuery(self.http_client, case_id, filter_params)
|
139
|
+
return query.execute()
|
140
|
+
|
141
|
+
def check_name(self, name: str) -> bool:
|
142
|
+
"""Check if a case name is available."""
|
143
|
+
query = CheckCaseNameQuery(self.http_client, name)
|
144
|
+
return query.execute()
|
145
|
+
|
146
|
+
# COMMANDS (Write operations)
|
147
|
+
def create(self, case_data: CreateCaseRequest) -> Case:
|
148
|
+
"""Create a new case."""
|
149
|
+
command = CreateCaseCommand(self.http_client, case_data)
|
150
|
+
return command.execute()
|
151
|
+
|
152
|
+
def update(self, case_id: str, update_data: UpdateCaseRequest) -> Case:
|
153
|
+
"""Update an existing case."""
|
154
|
+
command = UpdateCaseCommand(self.http_client, case_id, update_data)
|
155
|
+
return command.execute()
|
156
|
+
|
157
|
+
def close(self, case_id: str) -> Case:
|
158
|
+
"""Close a case."""
|
159
|
+
command = CloseCaseCommand(self.http_client, case_id)
|
160
|
+
return command.execute()
|
161
|
+
|
162
|
+
def open(self, case_id: str) -> Case:
|
163
|
+
"""Open a case."""
|
164
|
+
command = OpenCaseCommand(self.http_client, case_id)
|
165
|
+
return command.execute()
|
166
|
+
|
167
|
+
def archive(self, case_id: str) -> Case:
|
168
|
+
"""Archive a case."""
|
169
|
+
command = ArchiveCaseCommand(self.http_client, case_id)
|
170
|
+
return command.execute()
|
171
|
+
|
172
|
+
def change_owner(self, case_id: str, new_owner_id: str) -> Case:
|
173
|
+
"""Change case owner."""
|
174
|
+
command = ChangeCaseOwnerCommand(self.http_client, case_id, new_owner_id)
|
175
|
+
return command.execute()
|
176
|
+
|
177
|
+
def remove_endpoints(self, case_id: str, filter_params: AssetFilter) -> Dict[str, Any]:
|
178
|
+
"""Remove endpoints from a case."""
|
179
|
+
command = RemoveEndpointsFromCaseCommand(self.http_client, case_id, filter_params)
|
180
|
+
return command.execute()
|
181
|
+
|
182
|
+
def remove_task_assignment(self, case_id: str, task_assignment_id: str) -> Dict[str, Any]:
|
183
|
+
"""Remove task assignment from a case."""
|
184
|
+
command = RemoveTaskAssignmentFromCaseCommand(self.http_client, case_id, task_assignment_id)
|
185
|
+
return command.execute()
|
186
|
+
|
187
|
+
def import_task_assignments(self, case_id: str, task_assignment_ids: List[str]) -> Dict[str, Any]:
|
188
|
+
"""Import task assignments to a case."""
|
189
|
+
command = ImportTaskAssignmentsToCaseCommand(self.http_client, case_id, task_assignment_ids)
|
190
|
+
return command.execute()
|
191
|
+
|
192
|
+
def add_note(self, case_id: str, note_value: str) -> CaseNote:
|
193
|
+
"""Add a note to a case."""
|
194
|
+
command = AddNoteToCaseCommand(self.http_client, case_id, note_value)
|
195
|
+
return command.execute()
|
196
|
+
|
197
|
+
def update_note(self, case_id: str, note_id: str, note_value: str) -> CaseNote:
|
198
|
+
"""Update a note in a case."""
|
199
|
+
command = UpdateNoteToCaseCommand(self.http_client, case_id, note_id, note_value)
|
200
|
+
return command.execute()
|
201
|
+
|
202
|
+
def delete_note(self, case_id: str, note_id: str) -> Dict[str, Any]:
|
203
|
+
"""Delete a note from a case."""
|
204
|
+
command = DeleteNoteToCaseCommand(self.http_client, case_id, note_id)
|
205
|
+
return command.execute()
|
206
|
+
|
207
|
+
def export_notes(self, case_id: str) -> Dict[str, Any]:
|
208
|
+
"""Export case notes as a file download (ZIP/CSV format)."""
|
209
|
+
command = ExportCaseNotesCommand(self.http_client, case_id)
|
210
|
+
return command.execute()
|
211
|
+
|
212
|
+
def export_cases(self, filter_params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
213
|
+
"""Export cases as a CSV file download."""
|
214
|
+
command = ExportCasesCommand(self.http_client, filter_params)
|
215
|
+
return command.execute()
|
216
|
+
|
217
|
+
def export_endpoints(self, case_id: str, filter_params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
218
|
+
"""Export case endpoints as a CSV file download with optional filtering."""
|
219
|
+
command = ExportCaseEndpointsCommand(self.http_client, case_id, filter_params)
|
220
|
+
return command.execute()
|
221
|
+
|
222
|
+
def export_activities(self, case_id: str, filter_params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
223
|
+
"""Export case activities as a CSV file download with optional filtering and pagination."""
|
224
|
+
command = ExportCaseActivitiesCommand(self.http_client, case_id, filter_params)
|
225
|
+
return command.execute()
|