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
@@ -0,0 +1,145 @@
1
+ """
2
+ Cloud Forensics models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, List, Dict, Any
6
+ from datetime import datetime
7
+ from enum import Enum
8
+ from pydantic import Field
9
+
10
+ from ..base import AIRBaseModel
11
+
12
+
13
+ class CloudVendor(str, Enum):
14
+ """Cloud vendor enumeration."""
15
+ AWS = "aws"
16
+ AZURE = "azure"
17
+ GCP = "gcp"
18
+
19
+
20
+ class CloudAccountStatus(str, Enum):
21
+ """Cloud account status enumeration."""
22
+ CONFIGURED = "configured"
23
+ SYNCING = "syncing"
24
+ FAILED = "failed"
25
+
26
+
27
+ class CloudCredentials(AIRBaseModel):
28
+ """Cloud credentials model."""
29
+
30
+ access_key_id: Optional[str] = Field(default=None, alias="accessKeyId")
31
+ secret_access_key: Optional[str] = Field(default=None, alias="secretAccessKey")
32
+ # Azure credentials
33
+ tenant_id: Optional[str] = Field(default=None, alias="tenantId")
34
+ client_id: Optional[str] = Field(default=None, alias="clientId")
35
+ client_secret: Optional[str] = Field(default=None, alias="clientSecret")
36
+ # GCP credentials
37
+ service_account_key: Optional[str] = Field(default=None, alias="serviceAccountKey")
38
+ project_id: Optional[str] = Field(default=None, alias="projectId")
39
+
40
+
41
+ class CloudAccount(AIRBaseModel):
42
+ """Cloud account model."""
43
+
44
+ id: str = Field(alias="_id")
45
+ cloud_vendor: CloudVendor = Field(alias="cloudVendor")
46
+ organization_id: int = Field(alias="organizationId")
47
+ account_id: str = Field(alias="accountId")
48
+ detected_assets_count: int = Field(default=0, alias="detectedAssetsCount")
49
+ status: CloudAccountStatus
50
+ credentials: CloudCredentials
51
+ account_name: str = Field(alias="accountName")
52
+ last_sync_date: Optional[datetime] = Field(default=None, alias="lastSyncDate")
53
+ errors: List[str] = Field(default_factory=list)
54
+ created_at: datetime = Field(alias="createdAt")
55
+ updated_at: datetime = Field(alias="updatedAt")
56
+
57
+
58
+ class CloudAccountFilter(AIRBaseModel):
59
+ """Filter parameters for cloud accounts."""
60
+
61
+ page_size: Optional[int] = Field(default=10, alias="pageSize")
62
+ page_number: Optional[int] = Field(default=1, alias="pageNumber")
63
+ sort_type: Optional[str] = Field(default="DESC", alias="sortType") # ASC or DESC
64
+ sort_by: Optional[str] = Field(default="createdAt", alias="sortBy") # status, cloudVendor, detectedAssetsCount, lastSyncDate, createdAt
65
+ search_term: Optional[str] = Field(default=None, alias="searchTerm")
66
+ cloud_vendor: Optional[CloudVendor] = Field(default=None, alias="cloudVendor")
67
+ status: Optional[CloudAccountStatus] = Field(default=None)
68
+ organization_ids: Optional[List[int]] = Field(default=None, alias="organizationIds")
69
+
70
+
71
+ class CloudAccountsPaginatedResponse(AIRBaseModel):
72
+ """Paginated response for cloud accounts."""
73
+
74
+ entities: List[CloudAccount]
75
+ filters: List[Dict[str, Any]]
76
+ sortables: List[str]
77
+ total_entity_count: int = Field(alias="totalEntityCount")
78
+ current_page: int = Field(alias="currentPage")
79
+ page_size: int = Field(alias="pageSize")
80
+ previous_page: int = Field(alias="previousPage")
81
+ total_page_count: int = Field(alias="totalPageCount")
82
+ next_page: int = Field(alias="nextPage")
83
+
84
+
85
+ class CreateCloudAccountRequest(AIRBaseModel):
86
+ """Request model for creating cloud accounts."""
87
+
88
+ cloud_vendor: CloudVendor = Field(alias="cloudVendor")
89
+ account_name: str = Field(alias="accountName")
90
+ credentials: CloudCredentials
91
+ organization_id: int = Field(alias="organizationId")
92
+
93
+
94
+ class UpdateCloudAccountRequest(AIRBaseModel):
95
+ """Request model for updating cloud accounts."""
96
+
97
+ account_name: Optional[str] = Field(default=None, alias="accountName")
98
+ credentials: Optional[CloudCredentials] = Field(default=None)
99
+
100
+
101
+ class CloudAccountSyncResult(AIRBaseModel):
102
+ """Cloud account sync result model."""
103
+
104
+ account_id: str = Field(alias="accountId")
105
+ status: str
106
+ assets_discovered: int = Field(default=0, alias="assetsDiscovered")
107
+ sync_started_at: datetime = Field(alias="syncStartedAt")
108
+ sync_completed_at: Optional[datetime] = Field(default=None, alias="syncCompletedAt")
109
+ errors: List[str] = Field(default_factory=list)
110
+
111
+
112
+ class CloudVendorSyncResult(AIRBaseModel):
113
+ """Cloud vendor sync result model."""
114
+
115
+ cloud_vendor: Optional[CloudVendor] = Field(default=None, alias="cloudVendor")
116
+ accounts_synced: int = Field(default=0, alias="accountsSynced")
117
+ total_assets_discovered: int = Field(default=0, alias="totalAssetsDiscovered")
118
+ sync_started_at: Optional[datetime] = Field(default=None, alias="syncStartedAt")
119
+ sync_completed_at: Optional[datetime] = Field(default=None, alias="syncCompletedAt")
120
+ account_results: List[CloudAccountSyncResult] = Field(default_factory=list, alias="accountResults")
121
+
122
+
123
+ class CloudAsset(AIRBaseModel):
124
+ """Cloud asset model."""
125
+
126
+ id: str = Field(alias="_id")
127
+ account_id: str = Field(alias="accountId")
128
+ cloud_vendor: CloudVendor = Field(alias="cloudVendor")
129
+ asset_type: str = Field(alias="assetType")
130
+ asset_name: str = Field(alias="assetName")
131
+ region: Optional[str] = Field(default=None)
132
+ status: str
133
+ tags: Dict[str, str] = Field(default_factory=dict)
134
+ metadata: Dict[str, Any] = Field(default_factory=dict)
135
+ discovered_at: datetime = Field(alias="discoveredAt")
136
+ last_updated: datetime = Field(alias="lastUpdated")
137
+
138
+
139
+ class CloudForensicsExportRequest(AIRBaseModel):
140
+ """Export request model for cloud forensics data."""
141
+
142
+ format: str = Field(default="csv") # csv, json, xlsx
143
+ filters: Optional[CloudAccountFilter] = Field(default=None)
144
+ include_credentials: bool = Field(default=False, alias="includeCredentials")
145
+ include_assets: bool = Field(default=False, alias="includeAssets")
@@ -1,172 +1,171 @@
1
- """
2
- Event Subscription API 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, field_validator
9
-
10
- from ..base import AIRBaseModel, Filter
11
-
12
-
13
- class SubscriptionStatus(str, Enum):
14
- """Event subscription status."""
15
- ACTIVE = "active"
16
- INACTIVE = "inactive"
17
- PENDING = "pending"
18
- FAILED = "failed"
19
-
20
-
21
- class EventType(str, Enum):
22
- """Event types for subscriptions."""
23
- # Real API event names from JSON specification
24
- DEPLOYMENT_TOKEN_REGENERATED = "DeploymentTokenRegeneratedEvent"
25
- TASK_PROCESSING_FAILED = "TaskProcessingFailedEvent"
26
- TASK_PROCESSING_COMPLETED = "TaskProcessingCompletedEvent"
27
- CASE_FILE_SAVED = "CaseFileSavedEvent"
28
-
29
- # Additional common event types (these may exist in the system)
30
- ASSET_CREATED = "AssetCreatedEvent"
31
- ASSET_UPDATED = "AssetUpdatedEvent"
32
- ASSET_DELETED = "AssetDeletedEvent"
33
- CASE_CREATED = "CaseCreatedEvent"
34
- CASE_UPDATED = "CaseUpdatedEvent"
35
- CASE_CLOSED = "CaseClosedEvent"
36
- TASK_STARTED = "TaskStartedEvent"
37
- POLICY_EXECUTED = "PolicyExecutedEvent"
38
- ALERT_TRIGGERED = "AlertTriggeredEvent"
39
-
40
-
41
- class DeliveryMethod(str, Enum):
42
- """Event delivery methods."""
43
- WEBHOOK = "webhook"
44
- EMAIL = "email"
45
- SYSLOG = "syslog"
46
-
47
-
48
- class EventSubscription(AIRBaseModel):
49
- """Event subscription model."""
50
-
51
- id: str = Field(alias="id") # API returns int, but we'll convert to string
52
- name: str
53
- description: Optional[str] = None
54
- event_types: Optional[List[EventType]] = Field(default=[], alias="events") # API: events -> SDK: event_types
55
- delivery_method: Optional[DeliveryMethod] = Field(default=None, alias="deliveryMethod")
56
- endpoint_url: Optional[str] = Field(default=None, alias="url") # API: url -> SDK: endpoint_url
57
- email_addresses: Optional[List[str]] = Field(default=None, alias="emailAddresses")
58
- syslog_server: Optional[str] = Field(default=None, alias="syslogServer")
59
- status: Optional[SubscriptionStatus] = None
60
- active: Optional[bool] = None # API uses active boolean instead of status enum
61
- organization_id: Optional[int] = Field(default=None, alias="organizationId")
62
- created_by: Optional[str] = Field(default=None, alias="createdBy")
63
- created_at: Optional[datetime] = Field(default=None, alias="createdAt")
64
- updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
65
- last_triggered: Optional[datetime] = Field(default=None, alias="lastTriggered")
66
- trigger_count: int = Field(default=0, alias="triggerCount")
67
- retry_count: int = Field(default=3, alias="retryCount")
68
- retry_interval: int = Field(default=300, alias="retryInterval") # seconds
69
- headers: Optional[Dict[str, str]] = None # For webhook headers
70
- authentication: Optional[Dict[str, Any]] = None
71
- filters: Optional[Dict[str, Any]] = None # Event filtering criteria
72
- url: Optional[str] = None # Keep original API field name for backward compatibility
73
- auth_token: Optional[str] = Field(default=None, alias="authToken")
74
-
75
- @field_validator('id', mode='before')
76
- @classmethod
77
- def convert_id_to_string(cls, v):
78
- """Convert ID from int to string as API returns numbers."""
79
- return str(v) if v is not None else v
80
-
81
-
82
- class CreateEventSubscriptionRequest(AIRBaseModel):
83
- """Request model for creating event subscriptions."""
84
-
85
- name: str
86
- description: Optional[str] = None
87
- event_types: List[EventType]
88
- delivery_method: DeliveryMethod
89
- endpoint_url: Optional[str] = None
90
- email_addresses: Optional[List[str]] = None
91
- syslog_server: Optional[str] = None
92
- organization_id: int
93
- retry_count: Optional[int] = 3
94
- retry_interval: Optional[int] = 300
95
- headers: Optional[Dict[str, str]] = None
96
- authentication: Optional[Dict[str, Any]] = None
97
- filters: Optional[Dict[str, Any]] = None
98
-
99
-
100
- class UpdateEventSubscriptionRequest(AIRBaseModel):
101
- """Request model for updating event subscriptions."""
102
-
103
- name: Optional[str] = None
104
- description: Optional[str] = None
105
- event_types: Optional[List[EventType]] = None
106
- delivery_method: Optional[DeliveryMethod] = None
107
- endpoint_url: Optional[str] = None
108
- email_addresses: Optional[List[str]] = None
109
- syslog_server: Optional[str] = None
110
- status: Optional[SubscriptionStatus] = None
111
- retry_count: Optional[int] = None
112
- retry_interval: Optional[int] = None
113
- headers: Optional[Dict[str, str]] = None
114
- authentication: Optional[Dict[str, Any]] = None
115
- filters: Optional[Dict[str, Any]] = None
116
-
117
-
118
- class EventSubscriptionFilter(Filter):
119
- """Filter for event subscription queries."""
120
-
121
- name: Optional[str] = None
122
- event_type: Optional[EventType] = None
123
- delivery_method: Optional[DeliveryMethod] = None
124
- status: Optional[SubscriptionStatus] = None
125
- created_by: Optional[str] = None
126
- is_active: Optional[bool] = None # API uses isActive
127
- url: Optional[str] = None # API supports URL filtering
128
-
129
- def to_params(self) -> Dict[str, Any]:
130
- """Convert filter to API parameters with proper field mapping."""
131
- params = {}
132
-
133
- # Pagination parameters (not in filter namespace)
134
- if self.page_number is not None:
135
- params["pageNumber"] = self.page_number
136
- if self.page_size is not None:
137
- params["pageSize"] = self.page_size
138
- if self.sort_by is not None:
139
- params["sortBy"] = self.sort_by
140
- if self.sort_type is not None:
141
- params["sortType"] = self.sort_type
142
-
143
- # Filter parameters with proper field mapping
144
- field_mappings = {
145
- "search_term": "searchTerm",
146
- "organization_ids": "organizationId", # API expects single organizationId in filter
147
- "name": "name",
148
- "event_type": "eventType",
149
- "delivery_method": "deliveryMethod",
150
- "status": "status",
151
- "created_by": "createdBy",
152
- "is_active": "isActive",
153
- "url": "url"
154
- }
155
-
156
- for field_name, field_value in self.model_dump(exclude_none=True).items():
157
- # Skip pagination/sorting fields as they're handled above
158
- if field_name in ["page_number", "page_size", "sort_by", "sort_type"]:
159
- continue
160
-
161
- if field_value is not None:
162
- api_field_name = field_mappings.get(field_name, field_name)
163
-
164
- # Special handling for organization_ids - use first ID for organizationId filter
165
- if field_name == "organization_ids" and isinstance(field_value, list) and len(field_value) > 0:
166
- params[f"filter[{api_field_name}]"] = str(field_value[0])
167
- elif isinstance(field_value, list):
168
- params[f"filter[{api_field_name}]"] = ",".join(map(str, field_value))
169
- else:
170
- params[f"filter[{api_field_name}]"] = str(field_value)
171
-
1
+ """
2
+ Event Subscription API 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, field_validator
9
+
10
+ from ..base import AIRBaseModel, Filter
11
+
12
+
13
+ class SubscriptionStatus(str, Enum):
14
+ """Event subscription status."""
15
+ ACTIVE = "active"
16
+ INACTIVE = "inactive"
17
+ PENDING = "pending"
18
+ FAILED = "failed"
19
+
20
+
21
+ class EventType(str, Enum):
22
+ """Event types for subscriptions."""
23
+ # Real API event names from JSON specification
24
+ DEPLOYMENT_TOKEN_REGENERATED = "DeploymentTokenRegeneratedEvent"
25
+ TASK_PROCESSING_FAILED = "TaskProcessingFailedEvent"
26
+ TASK_PROCESSING_COMPLETED = "TaskProcessingCompletedEvent"
27
+ CASE_FILE_SAVED = "CaseFileSavedEvent"
28
+
29
+ # Additional event types found in the API
30
+ TASK_FAILED = "TaskFailedEvent" # Found in API response
31
+ ENDPOINT_ONLINE = "EndpointOnlineEvent" # Found in API response
32
+ ENDPOINT_OFFLINE = "EndpointOfflineEvent" # Found in API response
33
+ TASK_COMPLETED = "TaskCompletedEvent" # Found in API response
34
+
35
+ # Additional common event types (these may exist in the system)
36
+ ASSET_CREATED = "AssetCreatedEvent"
37
+ ASSET_UPDATED = "AssetUpdatedEvent"
38
+ ASSET_DELETED = "AssetDeletedEvent"
39
+ CASE_CREATED = "CaseCreatedEvent"
40
+ CASE_UPDATED = "CaseUpdatedEvent"
41
+ CASE_CLOSED = "CaseClosedEvent"
42
+ TASK_STARTED = "TaskStartedEvent"
43
+ POLICY_EXECUTED = "PolicyExecutedEvent"
44
+ ALERT_TRIGGERED = "AlertTriggeredEvent"
45
+
46
+
47
+ class DeliveryMethod(str, Enum):
48
+ """Event delivery methods."""
49
+ WEBHOOK = "webhook"
50
+ EMAIL = "email"
51
+ SYSLOG = "syslog"
52
+
53
+
54
+ class EventSubscription(AIRBaseModel):
55
+ """Event subscription model."""
56
+
57
+ id: str = Field(alias="id") # API returns int, but we'll convert to string
58
+ name: str
59
+ description: Optional[str] = None
60
+ event_types: Optional[List[EventType]] = Field(default=[], alias="events") # API: events -> SDK: event_types
61
+ delivery_method: Optional[DeliveryMethod] = Field(default=None, alias="deliveryMethod")
62
+ endpoint_url: Optional[str] = Field(default=None, alias="url") # API: url -> SDK: endpoint_url
63
+ email_addresses: Optional[List[str]] = Field(default=None, alias="emailAddresses")
64
+ syslog_server: Optional[str] = Field(default=None, alias="syslogServer")
65
+ status: Optional[SubscriptionStatus] = None
66
+ active: Optional[bool] = None # API uses active boolean instead of status enum
67
+ organization_id: Optional[int] = Field(default=None, alias="organizationId")
68
+ created_by: Optional[str] = Field(default=None, alias="createdBy")
69
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
70
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
71
+ last_triggered: Optional[datetime] = Field(default=None, alias="lastTriggered")
72
+ trigger_count: int = Field(default=0, alias="triggerCount")
73
+ retry_count: int = Field(default=3, alias="retryCount")
74
+ retry_interval: int = Field(default=300, alias="retryInterval") # seconds
75
+ headers: Optional[Dict[str, str]] = None # For webhook headers
76
+ authentication: Optional[Dict[str, Any]] = None
77
+ filters: Optional[Dict[str, Any]] = None # Event filtering criteria
78
+ url: Optional[str] = None # Keep original API field name for backward compatibility
79
+ auth_token: Optional[str] = Field(default=None, alias="authToken")
80
+
81
+ @field_validator('id', mode='before')
82
+ @classmethod
83
+ def convert_id_to_string(cls, v):
84
+ """Convert ID from int to string as API returns numbers."""
85
+ return str(v) if v is not None else v
86
+
87
+
88
+ class CreateEventSubscriptionRequest(AIRBaseModel):
89
+ """Request model for creating event subscriptions."""
90
+
91
+ name: str
92
+ description: Optional[str] = None
93
+ event_types: List[EventType]
94
+ delivery_method: DeliveryMethod
95
+ endpoint_url: Optional[str] = None
96
+ email_addresses: Optional[List[str]] = None
97
+ syslog_server: Optional[str] = None
98
+ organization_id: int
99
+ retry_count: Optional[int] = 3
100
+ retry_interval: Optional[int] = 300
101
+ headers: Optional[Dict[str, str]] = None
102
+ authentication: Optional[Dict[str, Any]] = None
103
+ filters: Optional[Dict[str, Any]] = None
104
+
105
+
106
+ class UpdateEventSubscriptionRequest(AIRBaseModel):
107
+ """Request model for updating event subscriptions."""
108
+
109
+ name: Optional[str] = None
110
+ description: Optional[str] = None
111
+ event_types: Optional[List[EventType]] = None
112
+ delivery_method: Optional[DeliveryMethod] = None
113
+ endpoint_url: Optional[str] = None
114
+ email_addresses: Optional[List[str]] = None
115
+ syslog_server: Optional[str] = None
116
+ status: Optional[SubscriptionStatus] = None
117
+ retry_count: Optional[int] = None
118
+ retry_interval: Optional[int] = None
119
+ headers: Optional[Dict[str, str]] = None
120
+ authentication: Optional[Dict[str, Any]] = None
121
+ filters: Optional[Dict[str, Any]] = None
122
+
123
+
124
+ class EventSubscriptionFilter(Filter):
125
+ """Filter for event subscription queries."""
126
+
127
+ # Override the default organization_ids to not use organization filtering
128
+ organization_ids: Optional[List[int]] = None
129
+
130
+ # Add organizationId (singular) as required by the API
131
+ organization_id: Optional[int] = None
132
+
133
+ name: Optional[str] = None
134
+ event_type: Optional[EventType] = None
135
+ delivery_method: Optional[DeliveryMethod] = None
136
+ status: Optional[SubscriptionStatus] = None
137
+ created_by: Optional[str] = None
138
+ is_active: Optional[bool] = None # API uses isActive
139
+ url: Optional[str] = None # API supports URL filtering
140
+
141
+ def to_params(self) -> Dict[str, Any]:
142
+ """Convert filter to API parameters, using organizationId (singular) for event subscriptions."""
143
+ params = {}
144
+
145
+ # Pagination parameters (not in filter namespace)
146
+ if self.page_number is not None:
147
+ params["pageNumber"] = self.page_number
148
+ if self.page_size is not None:
149
+ params["pageSize"] = self.page_size
150
+ if self.sort_by is not None:
151
+ params["sortBy"] = self.sort_by
152
+ if self.sort_type is not None:
153
+ params["sortType"] = self.sort_type
154
+
155
+ # Always add organizationId (required by API) - default to 0 if not set
156
+ organization_id = self.organization_id if self.organization_id is not None else 0
157
+ params["filter[organizationId]"] = str(organization_id)
158
+
159
+ # Filter parameters (in filter namespace) - EXCLUDE organization_ids and organization_id
160
+ for field_name, field_value in self.model_dump(exclude_none=True).items():
161
+ # Skip pagination/sorting fields and organization fields (handled above)
162
+ if field_name in ["page_number", "page_size", "sort_by", "sort_type", "organization_ids", "organization_id"]:
163
+ continue
164
+
165
+ if field_value is not None:
166
+ if isinstance(field_value, list):
167
+ if len(field_value) > 0: # Only add non-empty lists
168
+ params[f"filter[{field_name}]"] = ",".join([str(x) for x in field_value])
169
+ else:
170
+ params[f"filter[{field_name}]"] = str(field_value)
172
171
  return params
@@ -1,66 +1,66 @@
1
- """
2
- Evidence-related data models for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import Optional, List, Dict, Any
6
- from datetime import datetime
7
-
8
- from ..base import AIRBaseModel
9
-
10
-
11
- class EvidencePPC(AIRBaseModel):
12
- """Evidence PPC (Portable Pre-processor Configuration) model for binary file downloads."""
13
-
14
- endpoint_id: str
15
- task_id: str
16
- content: bytes # Binary content of the PPC file
17
- content_type: Optional[str] = None # MIME type of the file
18
- content_length: Optional[int] = None # Size of the file in bytes
19
- filename: Optional[str] = None # Suggested filename
20
-
21
- def save_to_file(self, filepath: str) -> bool:
22
- """Save the PPC content to a file."""
23
- try:
24
- with open(filepath, 'wb') as f:
25
- f.write(self.content)
26
- return True
27
- except Exception:
28
- return False
29
-
30
-
31
- class EvidenceReportFileInfo(AIRBaseModel):
32
- """Evidence report file info model."""
33
-
34
- endpoint_id: str
35
- task_id: str
36
- file_name: Optional[str] = None
37
- file_size: Optional[int] = None
38
- created_at: Optional[datetime] = None
39
- status: Optional[str] = None
40
- # Additional fields from API
41
- file_path: Optional[str] = None # Full path to the file
42
- encoding: Optional[str] = None # File encoding (e.g., "7bit")
43
- mime_type: Optional[str] = None # MIME type (e.g., "application/octet-stream")
44
- file_hash: Optional[str] = None # File hash/checksum
45
- organization_id: Optional[int] = None # Organization ID
46
- is_purged: Optional[bool] = None # Whether file has been purged
47
-
48
-
49
- class EvidenceReport(AIRBaseModel):
50
- """Evidence report model."""
51
-
52
- endpoint_id: str
53
- task_id: str
54
- content: bytes # Binary content of the report file
55
- content_type: Optional[str] = None
56
- content_length: Optional[int] = None
57
- filename: Optional[str] = None
58
-
59
- def save_to_file(self, filepath: str) -> bool:
60
- """Save the report content to a file."""
61
- try:
62
- with open(filepath, 'wb') as f:
63
- f.write(self.content)
64
- return True
65
- except Exception:
1
+ """
2
+ Evidence-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, List, Dict, Any
6
+ from datetime import datetime
7
+
8
+ from ..base import AIRBaseModel
9
+
10
+
11
+ class EvidencePPC(AIRBaseModel):
12
+ """Evidence PPC (Portable Pre-processor Configuration) model for binary file downloads."""
13
+
14
+ endpoint_id: str
15
+ task_id: str
16
+ content: bytes # Binary content of the PPC file
17
+ content_type: Optional[str] = None # MIME type of the file
18
+ content_length: Optional[int] = None # Size of the file in bytes
19
+ filename: Optional[str] = None # Suggested filename
20
+
21
+ def save_to_file(self, filepath: str) -> bool:
22
+ """Save the PPC content to a file."""
23
+ try:
24
+ with open(filepath, 'wb') as f:
25
+ f.write(self.content)
26
+ return True
27
+ except Exception:
28
+ return False
29
+
30
+
31
+ class EvidenceReportFileInfo(AIRBaseModel):
32
+ """Evidence report file info model."""
33
+
34
+ endpoint_id: str
35
+ task_id: str
36
+ file_name: Optional[str] = None
37
+ file_size: Optional[int] = None
38
+ created_at: Optional[datetime] = None
39
+ status: Optional[str] = None
40
+ # Additional fields from API
41
+ file_path: Optional[str] = None # Full path to the file
42
+ encoding: Optional[str] = None # File encoding (e.g., "7bit")
43
+ mime_type: Optional[str] = None # MIME type (e.g., "application/octet-stream")
44
+ file_hash: Optional[str] = None # File hash/checksum
45
+ organization_id: Optional[int] = None # Organization ID
46
+ is_purged: Optional[bool] = None # Whether file has been purged
47
+
48
+
49
+ class EvidenceReport(AIRBaseModel):
50
+ """Evidence report model."""
51
+
52
+ endpoint_id: str
53
+ task_id: str
54
+ content: bytes # Binary content of the report file
55
+ content_type: Optional[str] = None
56
+ content_length: Optional[int] = None
57
+ filename: Optional[str] = None
58
+
59
+ def save_to_file(self, filepath: str) -> bool:
60
+ """Save the report content to a file."""
61
+ try:
62
+ with open(filepath, 'wb') as f:
63
+ f.write(self.content)
64
+ return True
65
+ except Exception:
66
66
  return False