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.
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.1.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.1.dist-info/METADATA +0 -635
  141. binalyze_air_sdk-1.0.1.dist-info/RECORD +0 -82
  142. {binalyze_air_sdk-1.0.1.dist-info → binalyze_air_sdk-1.0.3.dist-info}/top_level.txt +0 -0
@@ -1,251 +1,366 @@
1
- """
2
- Acquisition-related data models for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import List, Optional, Dict, Any
6
- from datetime import datetime
7
-
8
- from ..base import AIRBaseModel, Filter
9
-
10
-
11
- class NetworkCaptureConfig(AIRBaseModel):
12
- """Network capture configuration."""
13
-
14
- enabled: bool = False
15
- duration: int = 60
16
- pcap: Dict[str, bool] = {"enabled": False}
17
- network_flow: Dict[str, bool] = {"enabled": False}
18
-
19
-
20
- class EDiscoveryPattern(AIRBaseModel):
21
- """eDiscovery pattern model."""
22
-
23
- pattern: str
24
- category: str
25
-
26
-
27
- class SaveLocationConfig(AIRBaseModel):
28
- """Save location configuration."""
29
-
30
- location: str
31
- use_most_free_volume: bool = False
32
- repository_id: Optional[str] = None
33
- path: str
34
- volume: Optional[str] = None
35
- tmp: str
36
- direct_collection: bool = False
37
-
38
-
39
- class TaskConfig(AIRBaseModel):
40
- """Task configuration."""
41
-
42
- choice: str
43
- save_to: Dict[str, SaveLocationConfig]
44
- cpu: Dict[str, int] = {"limit": 50}
45
- compression: Dict[str, Any] = {
46
- "enabled": False,
47
- "encryption": {"enabled": False, "password": ""}
48
- }
49
-
50
-
51
- class DroneConfig(AIRBaseModel):
52
- """Drone configuration."""
53
-
54
- auto_pilot: bool = False
55
- enabled: bool = False
56
- analyzers: List[str] = []
57
- keywords: List[str] = []
58
-
59
-
60
- class FilterConfig(AIRBaseModel):
61
- """Filter configuration for acquisition tasks - matches API specification exactly."""
62
-
63
- # Basic search and identification
64
- search_term: Optional[str] = None
65
- name: Optional[str] = None
66
- ip_address: Optional[str] = None
67
- group_id: Optional[str] = None
68
- group_full_path: Optional[str] = None
69
- label: Optional[str] = None # NEW - Missing from API spec
70
-
71
- # Status filters (arrays as per API)
72
- managed_status: List[str] = []
73
- isolation_status: List[str] = []
74
- platform: List[str] = []
75
- issue: Optional[str] = None # API expects string, not array
76
- online_status: List[str] = []
77
-
78
- # Tags and policies
79
- tags: List[str] = []
80
- version: Optional[str] = None
81
- policy: Optional[str] = None
82
-
83
- # Endpoint targeting
84
- included_endpoint_ids: List[str] = []
85
- excluded_endpoint_ids: List[str] = []
86
-
87
- # Organization and case
88
- organization_ids: List[int] = [] # Required by API
89
- case_id: Optional[str] = None # NEW - Missing from API spec
90
-
91
- # Date/time filters
92
- last_seen: Optional[str] = None # NEW - Missing from API spec (ISO 8601 format)
93
-
94
- # Cloud provider filters
95
- aws_regions: Optional[List[str]] = None # NEW - Missing from API spec
96
- azure_regions: Optional[List[str]] = None # NEW - Missing from API spec
97
-
98
-
99
- class AcquisitionProfilePlatformDetails(AIRBaseModel):
100
- """Platform-specific acquisition profile details."""
101
-
102
- evidence_list: List[str] = []
103
- artifact_list: Optional[List[str]] = None
104
- custom_content_profiles: List[Any] = []
105
- network_capture: Optional[NetworkCaptureConfig] = None
106
-
107
-
108
- class AcquisitionProfile(AIRBaseModel):
109
- """Acquisition profile model."""
110
-
111
- id: str
112
- name: str
113
- organization_ids: List[int] = []
114
- created_at: Optional[datetime] = None
115
- updated_at: Optional[datetime] = None
116
- created_by: str
117
- deletable: bool = True
118
- artifacts: List[str] = [] # Added for test compatibility
119
-
120
- # Additional fields from API response
121
- average_time: Optional[int] = None
122
- last_used_at: Optional[datetime] = None
123
- last_used_by: Optional[str] = None
124
- has_event_log_records_evidence: Optional[bool] = None
125
-
126
-
127
- class AcquisitionProfileDetails(AcquisitionProfile):
128
- """Detailed acquisition profile with platform configurations."""
129
-
130
- windows: Optional[AcquisitionProfilePlatformDetails] = None
131
- linux: Optional[AcquisitionProfilePlatformDetails] = None
132
- macos: Optional[AcquisitionProfilePlatformDetails] = None
133
- aix: Optional[AcquisitionProfilePlatformDetails] = None
134
- e_discovery: Optional[Dict[str, List[EDiscoveryPattern]]] = None
135
- settings: Optional[Dict[str, Any]] = None # Added for test compatibility
136
-
137
-
138
- class EndpointVolumeConfig(AIRBaseModel):
139
- """Endpoint and volume configuration for disk image acquisition."""
140
-
141
- endpoint_id: str
142
- volumes: List[str] = []
143
-
144
-
145
- class DiskImageOptions(AIRBaseModel):
146
- """Disk image options."""
147
-
148
- chunk_size: int
149
- chunk_count: int
150
- start_offset: int
151
- endpoints: List[EndpointVolumeConfig] = []
152
-
153
-
154
- class AcquisitionTaskRequest(AIRBaseModel):
155
- """Acquisition task request."""
156
-
157
- case_id: str
158
- drone_config: DroneConfig
159
- task_config: TaskConfig
160
- acquisition_profile_id: str
161
- filter: FilterConfig
162
-
163
-
164
- class ImageAcquisitionTaskRequest(AIRBaseModel):
165
- """Image acquisition task request."""
166
-
167
- case_id: Optional[str] = None
168
- task_config: TaskConfig
169
- disk_image_options: DiskImageOptions
170
- filter: FilterConfig
171
-
172
-
173
- class CreateAcquisitionProfileRequest(AIRBaseModel):
174
- """Create acquisition profile request."""
175
-
176
- name: str
177
- organization_ids: List[int] = []
178
- windows: Optional[AcquisitionProfilePlatformDetails] = None
179
- linux: Optional[AcquisitionProfilePlatformDetails] = None
180
- macos: Optional[AcquisitionProfilePlatformDetails] = None
181
- aix: Optional[AcquisitionProfilePlatformDetails] = None
182
- e_discovery: Optional[Dict[str, List[EDiscoveryPattern]]] = None
183
- description: Optional[str] = None # Added for test compatibility
184
- artifacts: List[str] = [] # Added for test compatibility
185
-
186
-
187
- # Simplified request models for testing
188
- class CreateAcquisitionRequest(AIRBaseModel):
189
- """Simplified acquisition request for testing."""
190
-
191
- filter: Dict[str, Any]
192
- profileId: str
193
- name: Optional[str] = None
194
-
195
-
196
- class CreateImageAcquisitionRequest(AIRBaseModel):
197
- """Simplified image acquisition request for testing."""
198
-
199
- filter: Dict[str, Any]
200
- name: Optional[str] = None
201
- fullDisk: bool = False
202
- repository_id: Optional[str] = None
203
- volumes: Optional[List[str]] = None
204
-
205
-
206
- class AcquisitionFilter(Filter):
207
- """Filter for acquisition profile queries - matches API specification exactly."""
208
-
209
- # Search and identification
210
- search_term: Optional[str] = None
211
- name: Optional[str] = None
212
-
213
- # Organization parameters
214
- organization_ids: Optional[List[int]] = None # Required by API
215
- all_organizations: Optional[bool] = None # true/false
216
-
217
- # Profile metadata (for backwards compatibility)
218
- created_by: Optional[str] = None
219
- deletable: Optional[bool] = None
220
-
221
- def to_params(self) -> Dict[str, Any]:
222
- """Convert filter to API parameters."""
223
- params = {}
224
-
225
- # Pagination parameters (not in filter namespace) - only if set
226
- if self.page_number is not None:
227
- params["pageNumber"] = self.page_number
228
- if self.page_size is not None:
229
- params["pageSize"] = self.page_size
230
- if self.sort_by is not None:
231
- params["sortBy"] = self.sort_by
232
- if self.sort_type is not None:
233
- params["sortType"] = self.sort_type
234
-
235
- # Add acquisition-specific filter parameters (use API field names)
236
- if self.search_term is not None:
237
- params["filter[searchTerm]"] = self.search_term
238
- if self.name is not None:
239
- params["filter[name]"] = self.name
240
- if self.organization_ids is not None:
241
- params["filter[organizationIds]"] = ",".join(map(str, self.organization_ids))
242
- if self.all_organizations is not None:
243
- params["filter[allOrganizations]"] = "true" if self.all_organizations else "false"
244
-
245
- # Backwards compatibility fields (not in API spec but may be used)
246
- if self.created_by is not None:
247
- params["filter[createdBy]"] = self.created_by
248
- if self.deletable is not None:
249
- params["filter[deletable]"] = "true" if self.deletable else "false"
250
-
1
+ """
2
+ Acquisition-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 pydantic import Field
8
+
9
+ from ..base import AIRBaseModel, Filter
10
+
11
+
12
+ class NetworkCaptureConfig(AIRBaseModel):
13
+ """Network capture configuration - matches API specification exactly."""
14
+
15
+ enabled: bool = False
16
+ duration: int = 60
17
+ pcap: Dict[str, bool] = {"enabled": False}
18
+ networkFlow: Dict[str, bool] = {"enabled": False} # API uses camelCase
19
+
20
+
21
+ class EDiscoveryPattern(AIRBaseModel):
22
+ """eDiscovery pattern model."""
23
+
24
+ pattern: str
25
+ category: str
26
+
27
+
28
+ class EDiscoveryConfig(AIRBaseModel):
29
+ """eDiscovery configuration matching API specification exactly."""
30
+
31
+ patterns: List[EDiscoveryPattern] = []
32
+
33
+ def model_dump(self, **kwargs):
34
+ """Override to serialize patterns under 'edPatterns' key for API."""
35
+ data = super().model_dump(**kwargs)
36
+ if 'patterns' in data:
37
+ data['edPatterns'] = data.pop('patterns')
38
+ return data
39
+
40
+
41
+ class SaveLocationConfig(AIRBaseModel):
42
+ """Save location configuration."""
43
+
44
+ location: str
45
+ use_most_free_volume: bool = False
46
+ repository_id: Optional[str] = None
47
+ path: str
48
+ volume: Optional[str] = None
49
+ tmp: str = "tmp"
50
+ direct_collection: bool = False
51
+
52
+
53
+ class TaskConfig(AIRBaseModel):
54
+ """Task configuration."""
55
+
56
+ choice: str
57
+ save_to: Dict[str, SaveLocationConfig]
58
+ cpu: Dict[str, int] = {"limit": 50}
59
+ bandwidth: Optional[Dict[str, int]] = None
60
+ compression: Dict[str, Any] = {
61
+ "enabled": False,
62
+ "encryption": {"enabled": False, "password": ""}
63
+ }
64
+
65
+
66
+ class DroneConfig(AIRBaseModel):
67
+ """Drone configuration."""
68
+
69
+ auto_pilot: bool = False
70
+ enabled: bool = False
71
+ analyzers: List[str] = []
72
+ keywords: List[str] = []
73
+
74
+
75
+ class FilterConfig(AIRBaseModel):
76
+ """Filter configuration for acquisition tasks - matches API specification exactly."""
77
+
78
+ # Basic search and identification
79
+ search_term: Optional[str] = None
80
+ name: Optional[str] = None
81
+ ip_address: Optional[str] = None
82
+ group_id: Optional[str] = None
83
+ group_full_path: Optional[str] = None
84
+ label: Optional[str] = None # NEW - Missing from API spec
85
+
86
+ # Status filters (arrays as per API)
87
+ managed_status: List[str] = []
88
+ isolation_status: List[str] = []
89
+ platform: List[str] = []
90
+ issue: Optional[str] = None # API expects string, not array
91
+ online_status: List[str] = []
92
+
93
+ # Tags and policies
94
+ tags: List[str] = []
95
+ version: Optional[str] = None
96
+ policy: Optional[str] = None
97
+
98
+ # Endpoint targeting
99
+ included_endpoint_ids: List[str] = []
100
+ excluded_endpoint_ids: List[str] = []
101
+
102
+ # Organization and case
103
+ organization_ids: List[int] = [] # Required by API
104
+ case_id: Optional[str] = None # NEW - Missing from API spec
105
+
106
+ # Date/time filters
107
+ last_seen: Optional[str] = None # NEW - Missing from API spec (ISO 8601 format)
108
+
109
+ # Cloud provider filters
110
+ aws_regions: Optional[List[str]] = None # NEW - Missing from API spec
111
+ azure_regions: Optional[List[str]] = None # NEW - Missing from API spec
112
+
113
+
114
+ class AcquisitionProfilePlatformDetails(AIRBaseModel):
115
+ """Platform-specific acquisition profile details - matches API specification exactly."""
116
+
117
+ evidenceList: List[str] = [] # API uses camelCase
118
+ artifactList: Optional[List[str]] = None # API uses camelCase
119
+ customContentProfiles: List[Any] = [] # API uses camelCase
120
+ osQueries: List[str] = [] # FIXED: Added missing required field
121
+ networkCapture: Optional[NetworkCaptureConfig] = None # API uses camelCase
122
+
123
+ # Windows-specific fields
124
+ eventLogRecordsConfig: Optional[Dict[str, List[str]]] = None # FIXED: Added for Windows platform
125
+
126
+ @classmethod
127
+ def create_windows_config(cls, evidence_list: Optional[List[str]] = None, artifact_list: Optional[List[str]] = None) -> "AcquisitionProfilePlatformDetails":
128
+ """Create a proper Windows platform configuration with all required fields."""
129
+ return cls(
130
+ evidenceList=evidence_list or [], # FIXED: Empty by default
131
+ artifactList=artifact_list or [], # FIXED: Empty by default
132
+ customContentProfiles=[],
133
+ osQueries=[],
134
+ networkCapture=NetworkCaptureConfig(
135
+ enabled=False,
136
+ duration=600,
137
+ pcap={"enabled": False},
138
+ networkFlow={"enabled": False}
139
+ ),
140
+ eventLogRecordsConfig={"types": []}
141
+ )
142
+
143
+ @classmethod
144
+ def create_linux_config(cls, evidence_list: Optional[List[str]] = None, artifact_list: Optional[List[str]] = None) -> "AcquisitionProfilePlatformDetails":
145
+ """Create a proper Linux platform configuration with all required fields."""
146
+ return cls(
147
+ evidenceList=evidence_list or [], # FIXED: Empty by default
148
+ artifactList=artifact_list or [], # FIXED: Empty by default
149
+ customContentProfiles=[],
150
+ osQueries=[],
151
+ networkCapture=NetworkCaptureConfig(
152
+ enabled=False,
153
+ duration=600,
154
+ pcap={"enabled": False},
155
+ networkFlow={"enabled": False}
156
+ )
157
+ )
158
+
159
+ @classmethod
160
+ def create_macos_config(cls, evidence_list: Optional[List[str]] = None, artifact_list: Optional[List[str]] = None) -> "AcquisitionProfilePlatformDetails":
161
+ """Create a proper macOS platform configuration with all required fields."""
162
+ return cls(
163
+ evidenceList=evidence_list or [], # FIXED: Empty by default
164
+ artifactList=artifact_list or [], # FIXED: Empty by default
165
+ customContentProfiles=[],
166
+ osQueries=[],
167
+ networkCapture=NetworkCaptureConfig(
168
+ enabled=False,
169
+ duration=600,
170
+ pcap={"enabled": False},
171
+ networkFlow={"enabled": False}
172
+ )
173
+ )
174
+
175
+
176
+ class AcquisitionProfileAIXDetails(AIRBaseModel):
177
+ """AIX-specific acquisition profile details - AIX doesn't support osQueries or networkCapture."""
178
+
179
+ evidenceList: List[str] = [] # API uses camelCase
180
+ artifactList: Optional[List[str]] = None # API uses camelCase
181
+ customContentProfiles: List[Any] = [] # API uses camelCase
182
+ # Note: AIX doesn't have osQueries, networkCapture, or eventLogRecordsConfig
183
+
184
+ @classmethod
185
+ def create_aix_config(cls, evidence_list: Optional[List[str]] = None, artifact_list: Optional[List[str]] = None) -> "AcquisitionProfileAIXDetails":
186
+ """Create a proper AIX platform configuration with all required fields."""
187
+ return cls(
188
+ evidenceList=evidence_list or [], # FIXED: Empty by default
189
+ artifactList=artifact_list or [], # FIXED: Empty by default
190
+ customContentProfiles=[],
191
+ # Note: AIX doesn't have osQueries or networkCapture
192
+ )
193
+
194
+
195
+ class AcquisitionProfile(AIRBaseModel):
196
+ """Acquisition profile model."""
197
+
198
+ id: str
199
+ name: str
200
+ organization_ids: List[int] = []
201
+ created_at: Optional[datetime] = None
202
+ updated_at: Optional[datetime] = None
203
+ created_by: str
204
+ deletable: bool = True
205
+ artifacts: List[str] = [] # Added for test compatibility
206
+
207
+ # Additional fields from API response
208
+ average_time: Optional[int] = None
209
+ last_used_at: Optional[datetime] = None
210
+ last_used_by: Optional[str] = None
211
+ has_event_log_records_evidence: Optional[bool] = None
212
+
213
+
214
+ class AcquisitionProfileDetails(AcquisitionProfile):
215
+ """Detailed acquisition profile with platform configurations."""
216
+
217
+ windows: Optional[AcquisitionProfilePlatformDetails] = None
218
+ linux: Optional[AcquisitionProfilePlatformDetails] = None
219
+ macos: Optional[AcquisitionProfilePlatformDetails] = None
220
+ aix: Optional[AcquisitionProfilePlatformDetails] = None
221
+ e_discovery: Optional[Dict[str, List[EDiscoveryPattern]]] = None
222
+ settings: Optional[Dict[str, Any]] = None # Added for test compatibility
223
+
224
+
225
+ class EndpointVolumeConfig(AIRBaseModel):
226
+ """Endpoint and volume configuration for disk image acquisition."""
227
+
228
+ endpointId: str # API uses camelCase
229
+ volumes: List[str] = []
230
+
231
+
232
+ class DiskImageOptions(AIRBaseModel):
233
+ """Disk image options - API field names in camelCase."""
234
+
235
+ chunkSize: int # API uses camelCase
236
+ chunkCount: int = 0 # API uses camelCase
237
+ startOffset: int # API uses camelCase
238
+ imageType: str = "dd" # API uses camelCase
239
+ singleFile: bool = False # API uses camelCase
240
+ endpoints: List[EndpointVolumeConfig] = []
241
+
242
+
243
+ class SchedulerConfig(AIRBaseModel):
244
+ """Scheduler configuration for acquisition tasks."""
245
+
246
+ when: str = "now"
247
+ timezone_type: Optional[str] = None
248
+ timezone: Optional[str] = None
249
+ start_date: Optional[int] = None
250
+ recurrence: Optional[str] = None
251
+ repeat_every: Optional[int] = None
252
+ repeat_on_week: Optional[List[str]] = None
253
+ repeat_on_month: Optional[int] = None
254
+ end_repeat_type: Optional[str] = None
255
+ end_date: Optional[int] = None
256
+ limit: Optional[int] = None
257
+
258
+
259
+ class AcquisitionTaskRequest(AIRBaseModel):
260
+ """Acquisition task request."""
261
+
262
+ case_id: str
263
+ drone_config: DroneConfig
264
+ task_config: TaskConfig
265
+ acquisition_profile_id: str
266
+ filter: FilterConfig
267
+
268
+
269
+ class ImageAcquisitionTaskRequest(AIRBaseModel):
270
+ """Image acquisition task request."""
271
+
272
+ case_id: Optional[str] = None
273
+ task_config: TaskConfig
274
+ disk_image_options: DiskImageOptions
275
+ filter: FilterConfig
276
+ scheduler_config: SchedulerConfig = SchedulerConfig()
277
+
278
+
279
+ class CreateAcquisitionProfileRequest(AIRBaseModel):
280
+ """Create acquisition profile request - matches API specification exactly."""
281
+
282
+ name: str
283
+ organizationIds: List[int] = [0] # FIXED: Default to [0] instead of []
284
+ windows: AcquisitionProfilePlatformDetails # Required by API
285
+ linux: AcquisitionProfilePlatformDetails # Required by API
286
+ macos: AcquisitionProfilePlatformDetails # Required by API
287
+ aix: AcquisitionProfileAIXDetails # FIXED: Use AIX-specific model
288
+ eDiscovery: EDiscoveryConfig = EDiscoveryConfig(patterns=[
289
+ EDiscoveryPattern(pattern="**/*.7z", category="Archives")
290
+ ]) # API requires this field to be non-empty
291
+
292
+
293
+ # Simplified request models for testing
294
+ class CreateAcquisitionRequest(AIRBaseModel):
295
+ """Simplified acquisition request for testing."""
296
+
297
+ filter: Dict[str, Any]
298
+ profileId: str
299
+ name: Optional[str] = None
300
+
301
+
302
+ class CreateImageAcquisitionRequest(AIRBaseModel):
303
+ """Simplified image acquisition request for testing - FIXED with required fields."""
304
+
305
+ filter: Dict[str, Any]
306
+ name: Optional[str] = None
307
+ fullDisk: bool = False
308
+ repository_id: Optional[str] = None
309
+ volumes: Optional[List[str]] = None
310
+
311
+ # FIXED: Add required fields for image acquisition
312
+ case_id: Optional[str] = None
313
+ task_config: Optional[Dict[str, Any]] = None
314
+ disk_image_options: Optional[Dict[str, Any]] = None
315
+ scheduler_config: Optional[Dict[str, Any]] = None
316
+
317
+ # API expects imageFormat for disk image type (e.g., dd, e01)
318
+ image_format: Optional[str] = Field(default=None, alias="imageFormat")
319
+
320
+
321
+ class AcquisitionFilter(Filter):
322
+ """Filter for acquisition profile queries - matches API specification exactly."""
323
+
324
+ # Search and identification
325
+ search_term: Optional[str] = None
326
+ name: Optional[str] = None
327
+
328
+ # Organization parameters
329
+ organization_ids: Optional[List[int]] = None # Required by API
330
+ all_organizations: Optional[bool] = None # true/false
331
+
332
+ # Profile metadata (for backwards compatibility)
333
+ created_by: Optional[str] = None
334
+ deletable: Optional[bool] = None
335
+
336
+ def to_params(self) -> Dict[str, Any]:
337
+ """Convert filter to API parameters."""
338
+ params = {}
339
+
340
+ # Pagination parameters (not in filter namespace) - only if set
341
+ if self.page_number is not None:
342
+ params["pageNumber"] = self.page_number
343
+ if self.page_size is not None:
344
+ params["pageSize"] = self.page_size
345
+ if self.sort_by is not None:
346
+ params["sortBy"] = self.sort_by
347
+ if self.sort_type is not None:
348
+ params["sortType"] = self.sort_type
349
+
350
+ # Add acquisition-specific filter parameters (use API field names)
351
+ if self.search_term is not None:
352
+ params["filter[searchTerm]"] = self.search_term
353
+ if self.name is not None:
354
+ params["filter[name]"] = self.name
355
+ if self.organization_ids is not None:
356
+ params["filter[organizationIds]"] = ",".join([str(x) for x in self.organization_ids])
357
+ if self.all_organizations is not None:
358
+ params["filter[allOrganizations]"] = "true" if self.all_organizations else "false"
359
+
360
+ # Backwards compatibility fields (not in API spec but may be used)
361
+ if self.created_by is not None:
362
+ params["filter[createdBy]"] = self.created_by
363
+ if self.deletable is not None:
364
+ params["filter[deletable]"] = "true" if self.deletable else "false"
365
+
251
366
  return params