binalyze-air-sdk 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. binalyze_air/__init__.py +77 -0
  2. binalyze_air/apis/__init__.py +27 -0
  3. binalyze_air/apis/authentication.py +27 -0
  4. binalyze_air/apis/auto_asset_tags.py +75 -0
  5. binalyze_air/apis/endpoints.py +22 -0
  6. binalyze_air/apis/event_subscription.py +97 -0
  7. binalyze_air/apis/evidence.py +53 -0
  8. binalyze_air/apis/evidences.py +216 -0
  9. binalyze_air/apis/interact.py +36 -0
  10. binalyze_air/apis/params.py +40 -0
  11. binalyze_air/apis/settings.py +27 -0
  12. binalyze_air/apis/user_management.py +74 -0
  13. binalyze_air/apis/users.py +68 -0
  14. binalyze_air/apis/webhooks.py +231 -0
  15. binalyze_air/base.py +133 -0
  16. binalyze_air/client.py +1338 -0
  17. binalyze_air/commands/__init__.py +146 -0
  18. binalyze_air/commands/acquisitions.py +387 -0
  19. binalyze_air/commands/assets.py +363 -0
  20. binalyze_air/commands/authentication.py +37 -0
  21. binalyze_air/commands/auto_asset_tags.py +231 -0
  22. binalyze_air/commands/baseline.py +396 -0
  23. binalyze_air/commands/cases.py +603 -0
  24. binalyze_air/commands/event_subscription.py +102 -0
  25. binalyze_air/commands/evidences.py +988 -0
  26. binalyze_air/commands/interact.py +58 -0
  27. binalyze_air/commands/organizations.py +221 -0
  28. binalyze_air/commands/policies.py +203 -0
  29. binalyze_air/commands/settings.py +29 -0
  30. binalyze_air/commands/tasks.py +56 -0
  31. binalyze_air/commands/triage.py +360 -0
  32. binalyze_air/commands/user_management.py +126 -0
  33. binalyze_air/commands/users.py +101 -0
  34. binalyze_air/config.py +245 -0
  35. binalyze_air/exceptions.py +50 -0
  36. binalyze_air/http_client.py +306 -0
  37. binalyze_air/models/__init__.py +285 -0
  38. binalyze_air/models/acquisitions.py +251 -0
  39. binalyze_air/models/assets.py +439 -0
  40. binalyze_air/models/audit.py +273 -0
  41. binalyze_air/models/authentication.py +70 -0
  42. binalyze_air/models/auto_asset_tags.py +117 -0
  43. binalyze_air/models/baseline.py +232 -0
  44. binalyze_air/models/cases.py +276 -0
  45. binalyze_air/models/endpoints.py +76 -0
  46. binalyze_air/models/event_subscription.py +172 -0
  47. binalyze_air/models/evidence.py +66 -0
  48. binalyze_air/models/evidences.py +349 -0
  49. binalyze_air/models/interact.py +136 -0
  50. binalyze_air/models/organizations.py +294 -0
  51. binalyze_air/models/params.py +128 -0
  52. binalyze_air/models/policies.py +250 -0
  53. binalyze_air/models/settings.py +84 -0
  54. binalyze_air/models/tasks.py +149 -0
  55. binalyze_air/models/triage.py +143 -0
  56. binalyze_air/models/user_management.py +97 -0
  57. binalyze_air/models/users.py +82 -0
  58. binalyze_air/queries/__init__.py +134 -0
  59. binalyze_air/queries/acquisitions.py +156 -0
  60. binalyze_air/queries/assets.py +105 -0
  61. binalyze_air/queries/audit.py +417 -0
  62. binalyze_air/queries/authentication.py +56 -0
  63. binalyze_air/queries/auto_asset_tags.py +60 -0
  64. binalyze_air/queries/baseline.py +185 -0
  65. binalyze_air/queries/cases.py +293 -0
  66. binalyze_air/queries/endpoints.py +25 -0
  67. binalyze_air/queries/event_subscription.py +55 -0
  68. binalyze_air/queries/evidence.py +140 -0
  69. binalyze_air/queries/evidences.py +280 -0
  70. binalyze_air/queries/interact.py +28 -0
  71. binalyze_air/queries/organizations.py +223 -0
  72. binalyze_air/queries/params.py +115 -0
  73. binalyze_air/queries/policies.py +150 -0
  74. binalyze_air/queries/settings.py +20 -0
  75. binalyze_air/queries/tasks.py +82 -0
  76. binalyze_air/queries/triage.py +231 -0
  77. binalyze_air/queries/user_management.py +83 -0
  78. binalyze_air/queries/users.py +69 -0
  79. binalyze_air_sdk-1.0.1.dist-info/METADATA +635 -0
  80. binalyze_air_sdk-1.0.1.dist-info/RECORD +82 -0
  81. binalyze_air_sdk-1.0.1.dist-info/WHEEL +5 -0
  82. binalyze_air_sdk-1.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,294 @@
1
+ """
2
+ Organization-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Optional, Dict, Any, Union
6
+ from datetime import datetime
7
+ from enum import Enum
8
+ from pydantic import Field
9
+
10
+ from ..base import AIRBaseModel, Filter
11
+
12
+
13
+ class OrganizationStatus(str, Enum):
14
+ """Organization status."""
15
+ ACTIVE = "active"
16
+ SUSPENDED = "suspended"
17
+ INACTIVE = "inactive"
18
+
19
+
20
+ class UserRoleType(str, Enum):
21
+ """User role type in organization."""
22
+ ADMIN = "admin"
23
+ USER = "user"
24
+ VIEWER = "viewer"
25
+ ANALYST = "analyst"
26
+
27
+
28
+ class FilterOption(AIRBaseModel):
29
+ """Filter option model for API response metadata."""
30
+
31
+ name: str
32
+ type: str # text, select, etc.
33
+ options: List[Any] = []
34
+ filter_url: Optional[str] = Field(default=None, alias="filterUrl")
35
+
36
+
37
+ class Organization(AIRBaseModel):
38
+ """Organization model with complete field mapping."""
39
+
40
+ id: int = Field(alias="_id")
41
+ name: str
42
+ note: Optional[str] = None
43
+ owner: Optional[str] = None
44
+ is_default: bool = Field(default=False, alias="isDefault")
45
+ shareable_deployment_enabled: bool = Field(default=True, alias="shareableDeploymentEnabled")
46
+ deployment_token: Optional[str] = Field(default=None, alias="deploymentToken")
47
+ contact: Dict[str, Any] = {}
48
+ total_endpoints: int = Field(default=0, alias="totalEndpoints")
49
+ tags: List[str] = []
50
+ statistics: Optional[Dict[str, Any]] = None # Organization statistics
51
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
52
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
53
+
54
+
55
+ class UserProfile(AIRBaseModel):
56
+ """User profile information."""
57
+
58
+ name: Optional[str] = None
59
+ surname: Optional[str] = None
60
+ department: Optional[str] = None
61
+
62
+
63
+ class UserGroup(AIRBaseModel):
64
+ """User group information."""
65
+
66
+ id: str
67
+ name: str
68
+ organization_ids: List[int] = Field(default=[], alias="organizationIds")
69
+
70
+
71
+ class UserRole(AIRBaseModel):
72
+ """User role information with full privileges."""
73
+
74
+ id: str = Field(alias="_id")
75
+ name: str
76
+ tag: str
77
+ created_by: str = Field(alias="createdBy")
78
+ privileges: List[str] = []
79
+ privilege_types: List[str] = Field(default=[], alias="privilegeTypes")
80
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
81
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
82
+
83
+
84
+ class OrganizationUser(AIRBaseModel):
85
+ """Enhanced organization user model with complete field mapping."""
86
+
87
+ # Core fields
88
+ id: str = Field(alias="_id")
89
+ email: str
90
+ username: str
91
+ strategy: Optional[str] = None
92
+
93
+ # Profile information
94
+ profile: Optional[UserProfile] = None
95
+
96
+ # Role and permission information
97
+ roles: List[UserRole] = []
98
+ groups: List[UserGroup] = []
99
+
100
+ # Organization and permission data
101
+ organization_ids: Optional[Union[str, List[int]]] = Field(default=None, alias="organizationIds") # Can be "ALL" or list
102
+
103
+ # Boolean flags
104
+ has_password: bool = Field(default=False, alias="hasPassword")
105
+ tfa_enabled: bool = Field(default=False, alias="tfaEnabled")
106
+ is_authorized_for_all_organizations: bool = Field(default=False, alias="isAuthorizedForAllOrganizations")
107
+ is_global_admin: bool = Field(default=False, alias="isGlobalAdmin")
108
+ is_organization_admin: bool = Field(default=False, alias="isOrganizationAdmin")
109
+ is_not_in_organizations: bool = Field(default=False, alias="isNotInOrganizations")
110
+
111
+ # Timestamps
112
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
113
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
114
+
115
+ # Legacy fields for backward compatibility
116
+ first_name: Optional[str] = None
117
+ last_name: Optional[str] = None
118
+ role: Optional[str] = None
119
+ organization_id: Optional[int] = None
120
+ last_login: Optional[datetime] = None
121
+ is_active: bool = True
122
+ permissions: List[str] = []
123
+
124
+
125
+ class OrganizationUsersPaginatedResponse(AIRBaseModel):
126
+ """Complete paginated response for organization users endpoint."""
127
+
128
+ entities: List[OrganizationUser]
129
+ filters: List[FilterOption] = []
130
+ sortables: List[str] = []
131
+ total_entity_count: int = Field(default=0, alias="totalEntityCount")
132
+ current_page: int = Field(default=1, alias="currentPage")
133
+ page_size: int = Field(default=10, alias="pageSize")
134
+ previous_page: int = Field(default=0, alias="previousPage")
135
+ total_page_count: int = Field(default=1, alias="totalPageCount")
136
+ next_page: int = Field(default=2, alias="nextPage")
137
+
138
+
139
+ class OrganizationRole(AIRBaseModel):
140
+ """Organization role model."""
141
+
142
+ id: str
143
+ name: str
144
+ description: Optional[str] = None
145
+ organization_id: int
146
+ permissions: List[str] = []
147
+ created_at: Optional[datetime] = None
148
+ updated_at: Optional[datetime] = None
149
+ created_by: Optional[str] = None
150
+ is_system: bool = False
151
+ user_count: int = 0
152
+
153
+
154
+ class OrganizationLicense(AIRBaseModel):
155
+ """Organization license model."""
156
+
157
+ id: str
158
+ organization_id: int
159
+ license_type: str
160
+ total_licenses: int = 0
161
+ used_licenses: int = 0
162
+ valid_from: Optional[datetime] = None
163
+ valid_until: Optional[datetime] = None
164
+ features: List[str] = []
165
+ is_active: bool = True
166
+
167
+
168
+ class OrganizationSettings(AIRBaseModel):
169
+ """Organization settings model."""
170
+
171
+ organization_id: int
172
+ retention_policy: Dict[str, Any] = {}
173
+ security_settings: Dict[str, Any] = {}
174
+ notification_settings: Dict[str, Any] = {}
175
+ api_settings: Dict[str, Any] = {}
176
+ custom_settings: Dict[str, Any] = {}
177
+
178
+
179
+ class OrganizationFilter(Filter):
180
+ """Filter for organization queries with complete parameter support."""
181
+
182
+ name: Optional[str] = None
183
+ search_term: Optional[str] = None
184
+
185
+ def to_params(self) -> Dict[str, Any]:
186
+ """Convert filter to API parameters."""
187
+ params = {}
188
+ if self.name:
189
+ params["filter[name]"] = self.name
190
+ if self.search_term:
191
+ params["filter[searchTerm]"] = self.search_term
192
+ return params
193
+
194
+
195
+ class OrganizationsPaginatedResponse(AIRBaseModel):
196
+ """Complete paginated response for organizations list endpoint."""
197
+
198
+ entities: List[Organization]
199
+ filters: List[FilterOption] = []
200
+ sortables: List[str] = []
201
+ total_entity_count: int = Field(default=0, alias="totalEntityCount")
202
+ current_page: int = Field(default=1, alias="currentPage")
203
+ page_size: int = Field(default=10, alias="pageSize")
204
+ previous_page: int = Field(default=0, alias="previousPage")
205
+ total_page_count: int = Field(default=1, alias="totalPageCount")
206
+ next_page: int = Field(default=2, alias="nextPage")
207
+
208
+
209
+ # Request models for organization operations
210
+ class CreateOrganizationRequest(AIRBaseModel):
211
+ """Create organization request model with complete field mapping."""
212
+
213
+ name: str
214
+ shareable_deployment_enabled: bool = Field(default=True, alias="shareableDeploymentEnabled")
215
+ note: Optional[str] = None
216
+ contact: Optional[Dict[str, Any]] = None
217
+ tags: Optional[List[str]] = None
218
+
219
+
220
+ class UpdateOrganizationRequest(AIRBaseModel):
221
+ """Update organization request model with complete field mapping."""
222
+
223
+ name: Optional[str] = None
224
+ note: Optional[str] = None
225
+ owner: Optional[str] = None # Added missing owner field
226
+ contact: Optional[Dict[str, Any]] = None
227
+ tags: Optional[List[str]] = None
228
+
229
+
230
+ class AddUserToOrganizationRequest(AIRBaseModel):
231
+ """Add user to organization request model."""
232
+
233
+ user_id: str
234
+ email: str
235
+ username: str
236
+ role: Optional[str] = None
237
+
238
+
239
+ class AssignUsersToOrganizationRequest(AIRBaseModel):
240
+ """Assign multiple users to organization request model."""
241
+
242
+ user_ids: List[str] = Field(alias="userIds")
243
+
244
+
245
+ class AddTagsToOrganizationRequest(AIRBaseModel):
246
+ """Add tags to organization request model."""
247
+
248
+ tags: List[str]
249
+
250
+
251
+ class DeleteTagsFromOrganizationRequest(AIRBaseModel):
252
+ """Delete tags from organization request model."""
253
+
254
+ tags: List[str]
255
+
256
+
257
+ class UpdateShareableDeploymentSettingsRequest(AIRBaseModel):
258
+ """Update shareable deployment settings request model."""
259
+
260
+ status: bool
261
+
262
+
263
+ class UpdateDeploymentTokenRequest(AIRBaseModel):
264
+ """Update deployment token request model."""
265
+
266
+ # Empty request body - the API generates a new token automatically
267
+ pass
268
+
269
+
270
+ class CheckOrganizationNameExistsResponse(AIRBaseModel):
271
+ """Response model for checking if organization name exists."""
272
+
273
+ success: bool
274
+ result: bool
275
+ status_code: int = Field(alias="statusCode")
276
+ errors: List[str] = []
277
+
278
+
279
+ class ShareableDeploymentInfoResponse(AIRBaseModel):
280
+ """Response model for shareable deployment information."""
281
+
282
+ success: bool
283
+ result: Optional[Dict[str, Any]] = None
284
+ status_code: int = Field(alias="statusCode")
285
+ errors: List[str] = []
286
+
287
+
288
+ class DeploymentTokenUpdateResponse(AIRBaseModel):
289
+ """Response model for deployment token update."""
290
+
291
+ success: bool
292
+ result: Optional[Dict[str, str]] = None # Contains new token
293
+ status_code: int = Field(alias="statusCode")
294
+ errors: List[str] = []
@@ -0,0 +1,128 @@
1
+ """
2
+ Params API models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Optional, Dict, Any
6
+ from enum import Enum
7
+ from pydantic import Field
8
+
9
+ from ..base import AIRBaseModel
10
+
11
+
12
+ class ArtifactType(str, Enum):
13
+ """Acquisition artifact types."""
14
+ FILE = "file"
15
+ REGISTRY = "registry"
16
+ MEMORY = "memory"
17
+ NETWORK = "network"
18
+ PROCESS = "process"
19
+ EVENT_LOG = "event_log"
20
+ PREFETCH = "prefetch"
21
+ BROWSER = "browser"
22
+ SYSTEM = "system"
23
+
24
+
25
+ class ArtifactCategory(str, Enum):
26
+ """Artifact categories."""
27
+ FORENSICS = "forensics"
28
+ MALWARE = "malware"
29
+ NETWORK = "network"
30
+ SYSTEM = "system"
31
+ BROWSER = "browser"
32
+ EMAIL = "email"
33
+ CHAT = "chat"
34
+ CLOUD = "cloud"
35
+
36
+
37
+ class Platform(str, Enum):
38
+ """Supported platforms."""
39
+ WINDOWS = "windows"
40
+ LINUX = "linux"
41
+ DARWIN = "darwin"
42
+ MACOS = "macos"
43
+
44
+
45
+ class AcquisitionArtifact(AIRBaseModel):
46
+ """Acquisition artifact model based on API response structure."""
47
+
48
+ name: str
49
+ desc: str = Field(alias="desc")
50
+ type: str = Field(alias="type")
51
+
52
+ # Additional fields for SDK processing
53
+ group: Optional[str] = None
54
+ platform: Optional[str] = None
55
+
56
+
57
+ class EDiscoveryPattern(AIRBaseModel):
58
+ """E-Discovery pattern model based on API response structure."""
59
+
60
+ name: str
61
+ pattern: str
62
+
63
+ # Additional fields for SDK processing
64
+ category: Optional[str] = None
65
+
66
+
67
+ class AcquisitionEvidence(AIRBaseModel):
68
+ """Acquisition evidence model based on API response structure."""
69
+
70
+ name: str
71
+ desc: str = Field(alias="desc")
72
+ type: str = Field(alias="type")
73
+
74
+ # Additional fields for SDK processing
75
+ group: Optional[str] = None
76
+ platform: Optional[str] = None
77
+
78
+
79
+ class DroneAnalyzer(AIRBaseModel):
80
+ """Drone analyzer model with proper field mapping."""
81
+
82
+ id: str = Field(alias="Id")
83
+ name: str = Field(alias="Name")
84
+ default_enabled: bool = Field(alias="DefaultEnabled")
85
+ platforms: List[str] = Field(default=[], alias="Platforms")
86
+ o_ses: List[str] = Field(default=[], alias="OSes")
87
+
88
+ # Computed properties can be added as methods if needed
89
+
90
+
91
+ # API Response wrapper models for structured responses
92
+ class AcquisitionArtifactGroup(AIRBaseModel):
93
+ """Group of acquisition artifacts."""
94
+
95
+ group: str
96
+ items: List[AcquisitionArtifact]
97
+
98
+
99
+ class AcquisitionArtifactsResponse(AIRBaseModel):
100
+ """Full response structure for acquisition artifacts."""
101
+
102
+ windows: List[AcquisitionArtifactGroup] = []
103
+ linux: List[AcquisitionArtifactGroup] = []
104
+ macos: List[AcquisitionArtifactGroup] = []
105
+ aix: List[AcquisitionArtifactGroup] = []
106
+
107
+
108
+ class EDiscoveryCategory(AIRBaseModel):
109
+ """E-Discovery pattern category."""
110
+
111
+ category: str
112
+ applications: List[EDiscoveryPattern]
113
+
114
+
115
+ class AcquisitionEvidenceGroup(AIRBaseModel):
116
+ """Group of acquisition evidences."""
117
+
118
+ group: str
119
+ items: List[AcquisitionEvidence]
120
+
121
+
122
+ class AcquisitionEvidencesResponse(AIRBaseModel):
123
+ """Full response structure for acquisition evidences."""
124
+
125
+ windows: List[AcquisitionEvidenceGroup] = []
126
+ linux: List[AcquisitionEvidenceGroup] = []
127
+ macos: List[AcquisitionEvidenceGroup] = []
128
+ aix: List[AcquisitionEvidenceGroup] = []
@@ -0,0 +1,250 @@
1
+ """
2
+ Policy-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Optional, Dict, Any
6
+ from datetime import datetime
7
+ from enum import Enum
8
+ from pydantic import Field
9
+
10
+ from ..base import AIRBaseModel, Filter, PaginatedResponse
11
+
12
+
13
+ class PolicyType(str, Enum):
14
+ """Policy type."""
15
+ ACQUISITION = "acquisition"
16
+ SECURITY = "security"
17
+ COMPLIANCE = "compliance"
18
+ CUSTOM = "custom"
19
+
20
+
21
+ class PolicyStatus(str, Enum):
22
+ """Policy status."""
23
+ ACTIVE = "active"
24
+ INACTIVE = "inactive"
25
+ DRAFT = "draft"
26
+
27
+
28
+ class PolicyCondition(AIRBaseModel):
29
+ """Policy condition model based on API structure."""
30
+
31
+ # For leaf conditions
32
+ field: Optional[str] = None
33
+ operator: Optional[str] = None
34
+ value: Optional[Any] = None
35
+
36
+ # For nested conditions (when this is a group)
37
+ conditions: Optional[List['PolicyCondition']] = None
38
+
39
+
40
+ class PolicyAction(AIRBaseModel):
41
+ """Policy action model."""
42
+
43
+ type: str
44
+ parameters: Dict[str, Any] = {}
45
+ enabled: bool = True
46
+
47
+
48
+ class PolicyRule(AIRBaseModel):
49
+ """Policy rule model."""
50
+
51
+ id: str
52
+ name: str
53
+ description: Optional[str] = None
54
+ conditions: List[PolicyCondition] = []
55
+ actions: List[PolicyAction] = []
56
+ enabled: bool = True
57
+ priority: int = 0
58
+
59
+
60
+ class PolicyFilterStructure(AIRBaseModel):
61
+ """Policy filter model based on API structure."""
62
+
63
+ operator: str
64
+ conditions: List[PolicyCondition]
65
+
66
+
67
+ class PolicyCpuSettings(AIRBaseModel):
68
+ """Policy CPU settings."""
69
+
70
+ limit: int
71
+
72
+
73
+ class PolicySaveToSettings(AIRBaseModel):
74
+ """Policy save-to settings for a platform."""
75
+
76
+ location: str
77
+ path: Optional[str] = None
78
+ repository_id: Optional[str] = Field(default=None, alias="repositoryId")
79
+ use_most_free_volume: bool = Field(default=True, alias="useMostFreeVolume")
80
+ volume: Optional[str] = None
81
+ tmp: Optional[str] = None
82
+
83
+
84
+ class PolicySaveTo(AIRBaseModel):
85
+ """Policy save-to settings for all platforms."""
86
+
87
+ windows: Optional[PolicySaveToSettings] = None
88
+ linux: Optional[PolicySaveToSettings] = None
89
+ macos: Optional[PolicySaveToSettings] = None
90
+
91
+
92
+ class PolicyEncryption(AIRBaseModel):
93
+ """Policy encryption settings."""
94
+
95
+ enabled: bool
96
+ password: Optional[str] = None
97
+
98
+
99
+ class PolicyCompression(AIRBaseModel):
100
+ """Policy compression settings."""
101
+
102
+ enabled: bool
103
+ encryption: Optional[PolicyEncryption] = None
104
+
105
+
106
+ class PolicySendTo(AIRBaseModel):
107
+ """Policy send-to settings."""
108
+
109
+ location: str
110
+ repository_id: Optional[str] = Field(default=None, alias="repositoryId")
111
+
112
+
113
+ class Policy(AIRBaseModel):
114
+ """Policy model based on API response structure."""
115
+
116
+ id: str = Field(alias="_id")
117
+ name: str
118
+ organization_ids: List[int] = Field(default=[], alias="organizationIds")
119
+ default: Optional[bool] = None
120
+ order: Optional[int] = None
121
+ created_by: Optional[str] = Field(default=None, alias="createdBy")
122
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
123
+
124
+ # Policy configuration
125
+ filter: Optional[PolicyFilterStructure] = None
126
+ cpu: Optional[PolicyCpuSettings] = None
127
+ save_to: Optional[PolicySaveTo] = Field(default=None, alias="saveTo")
128
+ send_to: Optional[PolicySendTo] = Field(default=None, alias="sendTo")
129
+ compression: Optional[PolicyCompression] = None
130
+
131
+ # Optional fields that may be present
132
+ bandwidth: Optional[Dict[str, Any]] = None
133
+ disk_space: Optional[Dict[str, Any]] = Field(default=None, alias="diskSpace")
134
+ triage_local_drives_only: Optional[Dict[str, Any]] = Field(default=None, alias="triageLocalDrivesOnly")
135
+ isolation_allowed_ips: Optional[List[str]] = Field(default=None, alias="isolationAllowedIps")
136
+ isolation_allowed_processes: Optional[List[str]] = Field(default=None, alias="isolationAllowedProcesses")
137
+
138
+
139
+ class PolicyPriority(AIRBaseModel):
140
+ """Policy priority update model."""
141
+
142
+ id: str = Field(alias="_id")
143
+ order: int
144
+
145
+
146
+ class PolicyMatchStats(AIRBaseModel):
147
+ """Policy match statistics model."""
148
+
149
+ total_matches: int = Field(alias="totalMatches")
150
+ policy_matches: List[Dict[str, Any]] = Field(default=[], alias="policyMatches")
151
+
152
+
153
+ class PolicyAssignment(AIRBaseModel):
154
+ """Policy assignment model."""
155
+
156
+ id: str
157
+ policy_id: str
158
+ endpoint_id: str
159
+ assigned_at: Optional[datetime] = None
160
+ assigned_by: str
161
+ status: str = "active"
162
+
163
+
164
+ class PolicyExecution(AIRBaseModel):
165
+ """Policy execution result model."""
166
+
167
+ id: str
168
+ policy_id: str
169
+ endpoint_id: str
170
+ executed_at: Optional[datetime] = None
171
+ status: str
172
+ result: Dict[str, Any] = {}
173
+ errors: List[str] = []
174
+ duration: Optional[int] = None
175
+
176
+
177
+ class CreatePolicyRequest(AIRBaseModel):
178
+ """Request model for creating a policy."""
179
+
180
+ name: str
181
+ organization_ids: List[int] = Field(alias="organizationIds")
182
+ filter: PolicyFilterStructure
183
+ cpu: PolicyCpuSettings
184
+ save_to: PolicySaveTo = Field(alias="saveTo")
185
+ send_to: PolicySendTo = Field(alias="sendTo")
186
+ compression: PolicyCompression
187
+
188
+ # Optional fields
189
+ bandwidth: Optional[Dict[str, Any]] = None
190
+ disk_space: Optional[Dict[str, Any]] = Field(default=None, alias="diskSpace")
191
+ triage_local_drives_only: Optional[Dict[str, Any]] = Field(default=None, alias="triageLocalDrivesOnly")
192
+ isolation_allowed_ips: Optional[List[str]] = Field(default=None, alias="isolationAllowedIps")
193
+ isolation_allowed_processes: Optional[List[str]] = Field(default=None, alias="isolationAllowedProcesses")
194
+
195
+
196
+ class UpdatePolicyRequest(AIRBaseModel):
197
+ """Request model for updating a policy."""
198
+
199
+ name: Optional[str] = None
200
+ organization_ids: Optional[List[int]] = Field(default=None, alias="organizationIds")
201
+ filter: Optional[PolicyFilterStructure] = None
202
+ cpu: Optional[PolicyCpuSettings] = None
203
+ save_to: Optional[PolicySaveTo] = Field(default=None, alias="saveTo")
204
+ send_to: Optional[PolicySendTo] = Field(default=None, alias="sendTo")
205
+ compression: Optional[PolicyCompression] = None
206
+
207
+ # Optional fields
208
+ bandwidth: Optional[Dict[str, Any]] = None
209
+ disk_space: Optional[Dict[str, Any]] = Field(default=None, alias="diskSpace")
210
+ triage_local_drives_only: Optional[Dict[str, Any]] = Field(default=None, alias="triageLocalDrivesOnly")
211
+ isolation_allowed_ips: Optional[List[str]] = Field(default=None, alias="isolationAllowedIps")
212
+ isolation_allowed_processes: Optional[List[str]] = Field(default=None, alias="isolationAllowedProcesses")
213
+
214
+
215
+ class UpdatePoliciesPrioritiesRequest(AIRBaseModel):
216
+ """Request model for updating policy priorities."""
217
+
218
+ policies: List[PolicyPriority]
219
+
220
+
221
+ class PolicyFilter(Filter):
222
+ """Filter for policy queries."""
223
+
224
+ organization_ids: Optional[List[int]] = None
225
+
226
+ def to_params(self) -> Dict[str, Any]:
227
+ """Convert filter to query parameters."""
228
+ params = {}
229
+ if self.organization_ids:
230
+ params["filter[organizationIds]"] = ",".join(map(str, self.organization_ids))
231
+ return params
232
+
233
+
234
+ class PoliciesPaginatedResponse(PaginatedResponse[Policy]):
235
+ """Paginated response for policies."""
236
+
237
+ # Add field aliases for pagination fields
238
+ total_entity_count: int = Field(alias="totalEntityCount")
239
+ current_page: int = Field(alias="currentPage")
240
+ page_size: int = Field(alias="pageSize")
241
+ total_page_count: int = Field(alias="totalPageCount")
242
+
243
+
244
+ class AssignPolicyRequest(AIRBaseModel):
245
+ """Request model for assigning policy to endpoints."""
246
+
247
+ policy_id: str
248
+ endpoint_ids: List[str] = []
249
+ organization_ids: List[int] = []
250
+ filter_params: Optional[Dict[str, Any]] = None