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,273 @@
1
+ """
2
+ Audit-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
+
9
+ from ..base import AIRBaseModel, Filter
10
+
11
+
12
+ class AuditLevel(str, Enum):
13
+ """Audit log level."""
14
+ INFO = "info"
15
+ WARNING = "warning"
16
+ ERROR = "error"
17
+ CRITICAL = "critical"
18
+
19
+
20
+ class AuditCategory(str, Enum):
21
+ """Audit event category."""
22
+ AUTHENTICATION = "authentication"
23
+ AUTHORIZATION = "authorization"
24
+ DATA_ACCESS = "data_access"
25
+ SYSTEM_CHANGE = "system_change"
26
+ USER_ACTION = "user_action"
27
+ API_CALL = "api_call"
28
+ POLICY_EXECUTION = "policy_execution"
29
+ TASK_EXECUTION = "task_execution"
30
+
31
+
32
+ class AuditAction(str, Enum):
33
+ """Audit action type."""
34
+ CREATE = "create"
35
+ READ = "read"
36
+ UPDATE = "update"
37
+ DELETE = "delete"
38
+ EXECUTE = "execute"
39
+ LOGIN = "login"
40
+ LOGOUT = "logout"
41
+ DOWNLOAD = "download"
42
+ UPLOAD = "upload"
43
+
44
+
45
+ class AuditLog(AIRBaseModel):
46
+ """Audit log model."""
47
+
48
+ id: str
49
+ timestamp: datetime
50
+ user_id: Optional[str] = None
51
+ username: Optional[str] = None
52
+ organization_id: int = 0
53
+ category: AuditCategory
54
+ action: AuditAction
55
+ resource_type: str
56
+ resource_id: Optional[str] = None
57
+ resource_name: Optional[str] = None
58
+ level: AuditLevel = AuditLevel.INFO
59
+ message: str
60
+ details: Dict[str, Any] = {}
61
+ ip_address: Optional[str] = None
62
+ user_agent: Optional[str] = None
63
+ session_id: Optional[str] = None
64
+ correlation_id: Optional[str] = None
65
+ success: bool = True
66
+ error_code: Optional[str] = None
67
+ duration: Optional[int] = None # milliseconds
68
+ tags: List[str] = []
69
+
70
+
71
+ class AuditSummary(AIRBaseModel):
72
+ """Audit summary model."""
73
+
74
+ organization_id: int
75
+ date: datetime
76
+ total_events: int = 0
77
+ successful_events: int = 0
78
+ failed_events: int = 0
79
+ authentication_events: int = 0
80
+ authorization_events: int = 0
81
+ data_access_events: int = 0
82
+ system_change_events: int = 0
83
+ user_action_events: int = 0
84
+ api_call_events: int = 0
85
+ unique_users: int = 0
86
+ unique_ips: int = 0
87
+ top_users: List[Dict[str, Any]] = []
88
+ top_actions: List[Dict[str, Any]] = []
89
+ error_summary: List[Dict[str, Any]] = []
90
+
91
+
92
+ class AuditUserActivity(AIRBaseModel):
93
+ """User activity audit model."""
94
+
95
+ user_id: str
96
+ username: str
97
+ organization_id: int
98
+ date: datetime
99
+ login_count: int = 0
100
+ action_count: int = 0
101
+ failed_login_count: int = 0
102
+ last_login: Optional[datetime] = None
103
+ last_action: Optional[datetime] = None
104
+ unique_ips: List[str] = []
105
+ actions_by_category: Dict[str, int] = {}
106
+ risk_score: float = 0.0
107
+
108
+
109
+ class AuditSystemEvent(AIRBaseModel):
110
+ """System event audit model."""
111
+
112
+ id: str
113
+ timestamp: datetime
114
+ event_type: str
115
+ severity: AuditLevel
116
+ component: str
117
+ message: str
118
+ details: Dict[str, Any] = {}
119
+ organization_id: int = 0
120
+ resolved: bool = False
121
+ resolved_by: Optional[str] = None
122
+ resolved_at: Optional[datetime] = None
123
+
124
+
125
+ class AuditLogsFilter(Filter):
126
+ """Filter for audit logs queries - matches NEW API specification exactly (POST with JSON body)."""
127
+
128
+ # Search and identification
129
+ search_term: Optional[str] = None
130
+ name: Optional[str] = None
131
+
132
+ # Audit log specific filters
133
+ type: Optional[str] = None # audit log type filter (changed from List[str] to str)
134
+ performed_by: Optional[str] = None # user who performed the action
135
+ endpoint_name: Optional[str] = None # endpoint name filter
136
+
137
+ # NEW PARAMETERS from updated API spec
138
+ event_source: Optional[str] = None # NEW: event source filter
139
+ occurred_at: Optional[str] = None # NEW: timestamp filter
140
+ data_filter: Optional[str] = None # NEW: data filtering capability
141
+
142
+ # Organization parameters - changed to single int instead of list
143
+ organization_ids: Optional[int] = None # Changed from List[int] to int (API expects single number)
144
+ all_organizations: Optional[bool] = None # true/false
145
+
146
+ def to_json_body(self) -> Dict[str, Any]:
147
+ """Convert filter to JSON body for POST request - NEW API FORMAT."""
148
+ body = {}
149
+
150
+ # Pagination parameters (top level in body)
151
+ if self.page_number is not None:
152
+ body["pageNumber"] = self.page_number
153
+ if self.page_size is not None:
154
+ body["pageSize"] = self.page_size
155
+ if self.sort_by is not None:
156
+ body["sortBy"] = self.sort_by
157
+ if self.sort_type is not None:
158
+ body["sortType"] = self.sort_type
159
+
160
+ # Filter object (nested in body)
161
+ filter_obj = {}
162
+
163
+ if self.search_term is not None:
164
+ filter_obj["searchTerm"] = self.search_term
165
+ if self.name is not None:
166
+ filter_obj["name"] = self.name
167
+ if self.type is not None:
168
+ filter_obj["type"] = self.type
169
+ if self.performed_by is not None:
170
+ filter_obj["performedBy"] = self.performed_by
171
+ if self.endpoint_name is not None:
172
+ filter_obj["endpointName"] = self.endpoint_name
173
+
174
+ # NEW PARAMETERS
175
+ if self.event_source is not None:
176
+ filter_obj["eventSource"] = self.event_source
177
+ if self.occurred_at is not None:
178
+ filter_obj["occurredAt"] = self.occurred_at
179
+ if self.data_filter is not None:
180
+ filter_obj["dataFilter"] = self.data_filter
181
+
182
+ # Organization parameters
183
+ if self.organization_ids is not None:
184
+ filter_obj["organizationIds"] = self.organization_ids
185
+ if self.all_organizations is not None:
186
+ filter_obj["allOrganizations"] = self.all_organizations
187
+
188
+ # Only add filter object if it has content
189
+ if filter_obj:
190
+ body["filter"] = filter_obj
191
+
192
+ return body
193
+
194
+ def to_params(self) -> Dict[str, Any]:
195
+ """DEPRECATED: Convert filter to query parameters - kept for backward compatibility."""
196
+ # Keep the old method for backward compatibility but mark as deprecated
197
+ import warnings
198
+ warnings.warn(
199
+ "to_params() is deprecated for audit logs. Use to_json_body() for new POST-based API.",
200
+ DeprecationWarning,
201
+ stacklevel=2
202
+ )
203
+
204
+ params = {}
205
+
206
+ # Pagination parameters (not in filter namespace) - only if set
207
+ if self.page_number is not None:
208
+ params["pageNumber"] = self.page_number
209
+ if self.page_size is not None:
210
+ params["pageSize"] = self.page_size
211
+ if self.sort_by is not None:
212
+ params["sortBy"] = self.sort_by
213
+ if self.sort_type is not None:
214
+ params["sortType"] = self.sort_type
215
+
216
+ # Add audit-specific filter parameters (use API field names)
217
+ if self.search_term is not None:
218
+ params["filter[searchTerm]"] = self.search_term
219
+ if self.name is not None:
220
+ params["filter[name]"] = self.name
221
+ if self.type is not None:
222
+ params["filter[type]"] = self.type
223
+ if self.performed_by is not None:
224
+ params["filter[performedBy]"] = self.performed_by
225
+ if self.endpoint_name is not None:
226
+ params["filter[endpointName]"] = self.endpoint_name
227
+ if self.organization_ids is not None:
228
+ params["filter[organizationIds]"] = str(self.organization_ids)
229
+ if self.all_organizations is not None:
230
+ params["filter[allOrganizations]"] = "true" if self.all_organizations else "false"
231
+
232
+ return params
233
+
234
+
235
+ class AuditFilter(Filter):
236
+ """Filter for audit queries."""
237
+
238
+ user_id: Optional[str] = None
239
+ username: Optional[str] = None
240
+ category: Optional[List[AuditCategory]] = None
241
+ action: Optional[List[AuditAction]] = None
242
+ level: Optional[List[AuditLevel]] = None
243
+ resource_type: Optional[str] = None
244
+ resource_id: Optional[str] = None
245
+ ip_address: Optional[str] = None
246
+ success: Optional[bool] = None
247
+ start_date: Optional[datetime] = None
248
+ end_date: Optional[datetime] = None
249
+ tags: Optional[List[str]] = None
250
+ correlation_id: Optional[str] = None
251
+
252
+
253
+ class AuditExportRequest(AIRBaseModel):
254
+ """Request model for exporting audit logs."""
255
+
256
+ filter_params: AuditFilter
257
+ format: str = "json" # json, csv, excel
258
+ include_details: bool = True
259
+ organization_ids: List[int] = []
260
+
261
+
262
+ class AuditRetentionPolicy(AIRBaseModel):
263
+ """Audit retention policy model."""
264
+
265
+ organization_id: int
266
+ retention_days: int = 365
267
+ auto_archive: bool = True
268
+ archive_location: Optional[str] = None
269
+ compress_archives: bool = True
270
+ delete_after_archive: bool = False
271
+ created_at: Optional[datetime] = None
272
+ updated_at: Optional[datetime] = None
273
+ created_by: str
@@ -0,0 +1,70 @@
1
+ """
2
+ Authentication-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, List, Dict, Any
6
+ from datetime import datetime
7
+ from pydantic import Field
8
+
9
+ from ..base import AIRBaseModel
10
+
11
+
12
+ class UserProfile(AIRBaseModel):
13
+ """User profile information."""
14
+ name: Optional[str] = None
15
+ surname: Optional[str] = None
16
+ department: Optional[str] = None
17
+
18
+
19
+ class UserRole(AIRBaseModel):
20
+ """User role information."""
21
+ id: Optional[str] = Field(alias="_id", default=None)
22
+ name: str
23
+ tag: str
24
+ created_at: Optional[str] = Field(alias="createdAt", default=None)
25
+ updated_at: Optional[str] = Field(alias="updatedAt", default=None)
26
+ created_by: Optional[str] = Field(alias="createdBy", default=None)
27
+ privilege_types: List[str] = Field(alias="privilegeTypes", default_factory=list)
28
+
29
+
30
+ class User(AIRBaseModel):
31
+ """User model."""
32
+
33
+ id: str = Field(alias="_id")
34
+ username: str
35
+ email: str
36
+ organization_ids: Optional[str] = Field(alias="organizationIds", default=None) # Can be "ALL"
37
+ strategy: Optional[str] = None
38
+ profile: Optional[UserProfile] = None
39
+ privileges: List[str] = Field(default_factory=list)
40
+ roles: List[UserRole] = Field(default_factory=list)
41
+ tfa_enabled: bool = Field(alias="tfaEnabled", default=False)
42
+ created_at: Optional[str] = Field(alias="createdAt", default=None)
43
+ updated_at: Optional[str] = Field(alias="updatedAt", default=None)
44
+ has_password: bool = Field(alias="hasPassword", default=False)
45
+ photo: Optional[str] = None
46
+ groups: List[Any] = Field(default_factory=list)
47
+ user_flow_user_signature: Optional[str] = Field(alias="userFlowUserSignature", default=None)
48
+ user_flow_group_signature: Optional[str] = Field(alias="userFlowGroupSignature", default=None)
49
+
50
+
51
+ class AuthStatus(AIRBaseModel):
52
+ """Authentication status model - matches actual API response."""
53
+
54
+ # The API doesn't return authenticated field, we derive it from success
55
+ authenticated: bool = True # Default to True since if we get a response, we're authenticated
56
+ user: Optional[User] = None
57
+
58
+
59
+ class LoginRequest(AIRBaseModel):
60
+ """Login request model."""
61
+
62
+ username: str
63
+ password: str
64
+
65
+
66
+ class LoginResponse(AIRBaseModel):
67
+ """Login response model."""
68
+
69
+ access_token: str = Field(alias="accessToken")
70
+ refresh_token: str = Field(alias="refreshToken")
@@ -0,0 +1,117 @@
1
+ """
2
+ Auto Asset Tags-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, List, Dict, Any
6
+ from datetime import datetime
7
+ from pydantic import Field
8
+ from pydantic import ConfigDict
9
+
10
+ from ..base import AIRBaseModel, Filter
11
+
12
+
13
+ class AutoAssetTag(AIRBaseModel):
14
+ """Auto asset tag model."""
15
+
16
+ id: str = Field(alias="_id")
17
+ tag: str
18
+ linux_conditions: Optional[Dict[str, Any]] = Field(alias="linuxConditions", default=None)
19
+ windows_conditions: Optional[Dict[str, Any]] = Field(alias="windowsConditions", default=None)
20
+ macos_conditions: Optional[Dict[str, Any]] = Field(alias="macosConditions", default=None)
21
+ organization_ids: Optional[List[int]] = Field(alias="organizationIds", default_factory=list)
22
+ created_at: Optional[datetime] = Field(alias="createdAt", default=None)
23
+ updated_at: Optional[datetime] = Field(alias="updatedAt", default=None)
24
+ created_by: Optional[str] = Field(alias="createdBy", default=None)
25
+ updated_by: Optional[str] = Field(alias="updatedBy", default=None)
26
+
27
+
28
+ class CreateAutoAssetTagRequest(AIRBaseModel):
29
+ """Create auto asset tag request model."""
30
+
31
+ model_config = ConfigDict(populate_by_name=True)
32
+
33
+ tag: str
34
+ linux_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="linuxConditions")
35
+ windows_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="windowsConditions")
36
+ macos_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="macosConditions")
37
+ organization_ids: List[int] = Field(default_factory=list, alias="organizationIds")
38
+
39
+
40
+ class UpdateAutoAssetTagRequest(AIRBaseModel):
41
+ """Update auto asset tag request model."""
42
+
43
+ model_config = ConfigDict(populate_by_name=True)
44
+
45
+ tag: Optional[str] = None
46
+ linux_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="linuxConditions")
47
+ windows_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="windowsConditions")
48
+ macos_conditions: Optional[Dict[str, Any]] = Field(default=None, alias="macosConditions")
49
+
50
+
51
+ class StartTaggingRequest(AIRBaseModel):
52
+ """Start tagging process request model."""
53
+
54
+ filter: Dict[str, Any]
55
+ schedulerConfig: Dict[str, Any]
56
+
57
+
58
+ class TaggingResult(AIRBaseModel):
59
+ """Tagging process result model."""
60
+
61
+ taskId: str
62
+ message: str
63
+ processedTags: int
64
+ affectedAssets: int
65
+
66
+
67
+ class TaggingTask(AIRBaseModel):
68
+ """Individual tagging task result from start tagging API."""
69
+
70
+ task_id: str = Field(alias="_id")
71
+ name: str = Field(alias="name")
72
+
73
+
74
+ class TaggingResponse(AIRBaseModel):
75
+ """Response from start tagging API containing list of tasks."""
76
+
77
+ tasks: List[TaggingTask] = []
78
+
79
+ @classmethod
80
+ def from_api_result(cls, result_list: List[Dict[str, Any]]) -> 'TaggingResponse':
81
+ """Create TaggingResponse from API result list."""
82
+ if not isinstance(result_list, list):
83
+ raise ValueError("API result must be a list")
84
+
85
+ tasks = [TaggingTask(**task) for task in result_list]
86
+ return cls(tasks=tasks)
87
+
88
+ @property
89
+ def task_count(self) -> int:
90
+ """Get the number of tasks created."""
91
+ return len(self.tasks)
92
+
93
+ def get_task_ids(self) -> List[str]:
94
+ """Get list of all task IDs."""
95
+ return [task.task_id for task in self.tasks]
96
+
97
+
98
+ class AutoAssetTagFilter(Filter):
99
+ """Filter for auto asset tag queries."""
100
+
101
+ tag: Optional[str] = None
102
+ organization_ids: Optional[List[int]] = None
103
+ search_term: Optional[str] = None
104
+
105
+ def to_params(self) -> Dict[str, Any]:
106
+ """Convert filter to API parameters with proper field name mapping."""
107
+ params = super().to_params()
108
+
109
+ # Convert organization_ids to organizationIds for API compatibility
110
+ if "filter[organization_ids]" in params:
111
+ params["filter[organizationIds]"] = params.pop("filter[organization_ids]")
112
+
113
+ # Convert search_term to searchTerm for API compatibility
114
+ if "filter[search_term]" in params:
115
+ params["filter[searchTerm]"] = params.pop("filter[search_term]")
116
+
117
+ return params
@@ -0,0 +1,232 @@
1
+ """
2
+ Baseline-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
11
+
12
+
13
+ class BaselineStatus(str, Enum):
14
+ """Baseline status."""
15
+ ACTIVE = "active"
16
+ INACTIVE = "inactive"
17
+ CREATING = "creating"
18
+ FAILED = "failed"
19
+
20
+
21
+ class BaselineType(str, Enum):
22
+ """Baseline type."""
23
+ SYSTEM = "system"
24
+ SECURITY = "security"
25
+ CUSTOM = "custom"
26
+ COMPLIANCE = "compliance"
27
+
28
+
29
+ class ComparisonStatus(str, Enum):
30
+ """Comparison status."""
31
+ PENDING = "pending"
32
+ RUNNING = "running"
33
+ COMPLETED = "completed"
34
+ FAILED = "failed"
35
+
36
+
37
+ class ChangeType(str, Enum):
38
+ """Type of change detected."""
39
+ ADDED = "added"
40
+ REMOVED = "removed"
41
+ MODIFIED = "modified"
42
+ MOVED = "moved"
43
+
44
+
45
+ class BaselineItem(AIRBaseModel):
46
+ """Individual baseline item."""
47
+
48
+ id: str
49
+ path: str
50
+ item_type: str # file, registry, service, process, etc.
51
+ hash: Optional[str] = None
52
+ size: Optional[int] = None
53
+ permissions: Optional[str] = None
54
+ owner: Optional[str] = None
55
+ created_at: Optional[datetime] = None
56
+ modified_at: Optional[datetime] = None
57
+ attributes: Dict[str, Any] = {}
58
+ metadata: Dict[str, Any] = {}
59
+
60
+
61
+ class Baseline(AIRBaseModel):
62
+ """Baseline model."""
63
+
64
+ id: str = Field(alias="_id")
65
+ name: str
66
+ description: Optional[str] = None
67
+ type: BaselineType
68
+ status: BaselineStatus = BaselineStatus.CREATING
69
+ endpoint_id: str = Field(alias="endpointId")
70
+ endpoint_name: str = Field(alias="endpointName")
71
+ organization_id: int = Field(default=0, alias="organizationId")
72
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
73
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
74
+ created_by: str = Field(alias="createdBy")
75
+ item_count: int = Field(default=0, alias="itemCount")
76
+ file_count: int = Field(default=0, alias="fileCount")
77
+ registry_count: int = Field(default=0, alias="registryCount")
78
+ service_count: int = Field(default=0, alias="serviceCount")
79
+ process_count: int = Field(default=0, alias="processCount")
80
+ network_connection_count: int = Field(default=0, alias="networkConnectionCount")
81
+ tags: List[str] = []
82
+ profile_id: Optional[str] = Field(default=None, alias="profileId")
83
+ profile_name: Optional[str] = Field(default=None, alias="profileName")
84
+ last_comparison: Optional[datetime] = Field(default=None, alias="lastComparison")
85
+ comparison_count: int = Field(default=0, alias="comparisonCount")
86
+
87
+
88
+ class BaselineProfile(AIRBaseModel):
89
+ """Baseline profile model."""
90
+
91
+ id: str = Field(alias="_id")
92
+ name: str
93
+ description: Optional[str] = None
94
+ organization_id: int = Field(default=0, alias="organizationId")
95
+ include_files: bool = Field(default=True, alias="includeFiles")
96
+ include_registry: bool = Field(default=True, alias="includeRegistry")
97
+ include_services: bool = Field(default=True, alias="includeServices")
98
+ include_processes: bool = Field(default=False, alias="includeProcesses")
99
+ include_network: bool = Field(default=False, alias="includeNetwork")
100
+ file_patterns: List[str] = Field(default=[], alias="filePatterns")
101
+ exclude_patterns: List[str] = Field(default=[], alias="excludePatterns")
102
+ registry_keys: List[str] = Field(default=[], alias="registryKeys")
103
+ custom_checks: List[Dict[str, Any]] = Field(default=[], alias="customChecks")
104
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
105
+ updated_at: Optional[datetime] = Field(default=None, alias="updatedAt")
106
+ created_by: str = Field(alias="createdBy")
107
+ is_default: bool = Field(default=False, alias="isDefault")
108
+ usage_count: int = Field(default=0, alias="usageCount")
109
+
110
+
111
+ class BaselineChange(AIRBaseModel):
112
+ """Baseline change detection model."""
113
+
114
+ id: str = Field(alias="_id")
115
+ comparison_id: str = Field(alias="comparisonId")
116
+ change_type: ChangeType = Field(alias="changeType")
117
+ item_type: str = Field(alias="itemType")
118
+ path: str
119
+ old_value: Optional[Dict[str, Any]] = Field(default=None, alias="oldValue")
120
+ new_value: Optional[Dict[str, Any]] = Field(default=None, alias="newValue")
121
+ severity: str = "medium" # low, medium, high, critical
122
+ category: str
123
+ description: str
124
+ detected_at: datetime = Field(alias="detectedAt")
125
+ risk_score: float = Field(default=0.0, alias="riskScore")
126
+
127
+
128
+ class BaselineComparison(AIRBaseModel):
129
+ """Baseline comparison result model."""
130
+
131
+ id: str = Field(alias="_id")
132
+ baseline_id: str = Field(alias="baselineId")
133
+ baseline_name: str = Field(alias="baselineName")
134
+ endpoint_id: str = Field(alias="endpointId")
135
+ endpoint_name: str = Field(alias="endpointName")
136
+ status: ComparisonStatus
137
+ started_at: Optional[datetime] = Field(default=None, alias="startedAt")
138
+ completed_at: Optional[datetime] = Field(default=None, alias="completedAt")
139
+ duration: Optional[int] = None # seconds
140
+ total_changes: int = Field(default=0, alias="totalChanges")
141
+ added_items: int = Field(default=0, alias="addedItems")
142
+ removed_items: int = Field(default=0, alias="removedItems")
143
+ modified_items: int = Field(default=0, alias="modifiedItems")
144
+ moved_items: int = Field(default=0, alias="movedItems")
145
+ high_risk_changes: int = Field(default=0, alias="highRiskChanges")
146
+ medium_risk_changes: int = Field(default=0, alias="mediumRiskChanges")
147
+ low_risk_changes: int = Field(default=0, alias="lowRiskChanges")
148
+ changes: List[BaselineChange] = []
149
+ organization_id: int = Field(default=0, alias="organizationId")
150
+ triggered_by: str = Field(alias="triggeredBy")
151
+ error_message: Optional[str] = Field(default=None, alias="errorMessage")
152
+
153
+
154
+ class BaselineSchedule(AIRBaseModel):
155
+ """Baseline comparison schedule model."""
156
+
157
+ id: str = Field(alias="_id")
158
+ baseline_id: str = Field(alias="baselineId")
159
+ name: str
160
+ enabled: bool = True
161
+ frequency: str # daily, weekly, monthly
162
+ time_of_day: str = Field(alias="timeOfDay") # HH:MM format
163
+ day_of_week: Optional[int] = Field(default=None, alias="dayOfWeek") # 0-6, Monday=0
164
+ day_of_month: Optional[int] = Field(default=None, alias="dayOfMonth") # 1-31
165
+ next_run: Optional[datetime] = Field(default=None, alias="nextRun")
166
+ last_run: Optional[datetime] = Field(default=None, alias="lastRun")
167
+ created_at: Optional[datetime] = Field(default=None, alias="createdAt")
168
+ created_by: str = Field(alias="createdBy")
169
+ notification_enabled: bool = Field(default=True, alias="notificationEnabled")
170
+ notification_threshold: int = Field(default=10, alias="notificationThreshold") # minimum changes to notify
171
+
172
+
173
+ class BaselineFilter(Filter):
174
+ """Filter for baseline queries."""
175
+
176
+ name: Optional[str] = None
177
+ type: Optional[List[BaselineType]] = None
178
+ status: Optional[List[BaselineStatus]] = None
179
+ endpoint_id: Optional[str] = None
180
+ endpoint_name: Optional[str] = None
181
+ created_by: Optional[str] = None
182
+ tags: Optional[List[str]] = None
183
+ profile_id: Optional[str] = None
184
+ has_recent_comparison: Optional[bool] = None
185
+
186
+
187
+ class CreateBaselineRequest(AIRBaseModel):
188
+ """Request model for creating a baseline."""
189
+
190
+ name: str
191
+ description: Optional[str] = None
192
+ type: BaselineType = BaselineType.SYSTEM
193
+ endpoint_id: str
194
+ profile_id: Optional[str] = None
195
+ tags: List[str] = []
196
+ organization_id: int = 0
197
+
198
+
199
+ class UpdateBaselineRequest(AIRBaseModel):
200
+ """Request model for updating a baseline."""
201
+
202
+ name: Optional[str] = None
203
+ description: Optional[str] = None
204
+ status: Optional[BaselineStatus] = None
205
+ tags: Optional[List[str]] = None
206
+
207
+
208
+ class CreateBaselineProfileRequest(AIRBaseModel):
209
+ """Request model for creating a baseline profile."""
210
+
211
+ name: str
212
+ description: Optional[str] = None
213
+ include_files: bool = True
214
+ include_registry: bool = True
215
+ include_services: bool = True
216
+ include_processes: bool = False
217
+ include_network: bool = False
218
+ file_patterns: List[str] = []
219
+ exclude_patterns: List[str] = []
220
+ registry_keys: List[str] = []
221
+ custom_checks: List[Dict[str, Any]] = []
222
+ organization_id: int = 0
223
+
224
+
225
+ class CompareBaselineRequest(AIRBaseModel):
226
+ """Request model for comparing baselines."""
227
+
228
+ baseline_id: str
229
+ endpoint_ids: Optional[List[str]] = None # If None, use baseline's endpoint
230
+ profile_id: Optional[str] = None # Override baseline's profile
231
+ include_low_risk: bool = True
232
+ generate_report: bool = True