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
@@ -1,70 +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")
1
+ """
2
+ Auth-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
70
  refresh_token: str = Field(alias="refreshToken")
@@ -1,117 +1,228 @@
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
-
1
+ """
2
+ Auto Asset Tags-related data models for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, List, Dict, Any, Union
6
+ from datetime import datetime
7
+ from pydantic import Field
8
+ from pydantic import ConfigDict
9
+ from enum import Enum
10
+
11
+ from ..base import AIRBaseModel, Filter
12
+
13
+
14
+ class ConditionField(str, Enum):
15
+ """Valid condition fields for auto asset tags."""
16
+ HOSTNAME = "hostname"
17
+ IP_ADDRESS = "ip-address"
18
+ SUBNET = "subnet"
19
+ OSQUERY = "osquery"
20
+ PROCESS = "process"
21
+ FILE = "file"
22
+ DIRECTORY = "directory"
23
+
24
+
25
+ class ConditionOperator(str, Enum):
26
+ """Valid condition operators for auto asset tags."""
27
+ RUNNING = "running"
28
+ EXIST = "exist"
29
+ IS = "is"
30
+ CONTAINS = "contains"
31
+ STARTS_WITH = "starts-with"
32
+ ENDS_WITH = "ends-with"
33
+ IN_RANGE = "in-range"
34
+ HAS_RESULT = "has-result"
35
+ NOT_RUNNING = "not-running"
36
+ NOT_EXIST = "not-exist"
37
+ HAS_NO_RESULT = "has-no-result"
38
+
39
+
40
+ class LogicalOperator(str, Enum):
41
+ """Valid logical operators for condition groups."""
42
+ AND = "and"
43
+ OR = "or"
44
+
45
+
46
+ class AutoAssetTagCondition(AIRBaseModel):
47
+ """Individual condition for auto asset tag."""
48
+
49
+ field: ConditionField
50
+ operator: ConditionOperator
51
+ value: str
52
+
53
+
54
+ class AutoAssetTagConditionGroup(AIRBaseModel):
55
+ """Group of conditions with logical operator."""
56
+
57
+ operator: LogicalOperator
58
+ conditions: List[AutoAssetTagCondition]
59
+
60
+
61
+ class AutoAssetTagConditions(AIRBaseModel):
62
+ """Platform-specific conditions structure."""
63
+
64
+ operator: LogicalOperator
65
+ conditions: List[AutoAssetTagConditionGroup]
66
+
67
+
68
+ class AutoAssetTag(AIRBaseModel):
69
+ """Auto asset tag model - handles actual API response format."""
70
+
71
+ id: str = Field(alias="_id")
72
+ tag: str
73
+ linuxConditions: Optional[Union[AutoAssetTagConditions, Dict[str, Any]]] = None
74
+ windowsConditions: Optional[Union[AutoAssetTagConditions, Dict[str, Any]]] = None
75
+ macosConditions: Optional[Union[AutoAssetTagConditions, Dict[str, Any]]] = None
76
+ organizationIds: Optional[List[int]] = Field(default_factory=list)
77
+ createdAt: Optional[datetime] = None
78
+ updatedAt: Optional[datetime] = None
79
+ createdBy: Optional[str] = None
80
+ updatedBy: Optional[str] = None
81
+ conditionIdCounter: Optional[int] = None # API includes this field
82
+
83
+
84
+ class CreateAutoAssetTagRequest(AIRBaseModel):
85
+ """Create auto asset tag request model - matches API specification exactly."""
86
+
87
+ model_config = ConfigDict(populate_by_name=True)
88
+
89
+ tag: str
90
+ linuxConditions: AutoAssetTagConditions # Required by API
91
+ windowsConditions: AutoAssetTagConditions # Required by API
92
+ macosConditions: AutoAssetTagConditions # Required by API
93
+ organizationIds: List[int] = Field(default_factory=list)
94
+
95
+ def model_dump(self, **kwargs):
96
+ """Exclude None values from serialization to prevent API validation errors."""
97
+ # Set exclude_none=True if not explicitly set
98
+ if 'exclude_none' not in kwargs:
99
+ kwargs['exclude_none'] = True
100
+ return super().model_dump(**kwargs)
101
+
102
+
103
+ class UpdateAutoAssetTagRequest(AIRBaseModel):
104
+ """Update auto asset tag request model."""
105
+
106
+ model_config = ConfigDict(populate_by_name=True)
107
+
108
+ tag: Optional[str] = None
109
+ linuxConditions: Optional[AutoAssetTagConditions] = None
110
+ windowsConditions: Optional[AutoAssetTagConditions] = None
111
+ macosConditions: Optional[AutoAssetTagConditions] = None
112
+ organizationIds: Optional[List[int]] = Field(default_factory=list)
113
+
114
+ def model_dump(self, **kwargs):
115
+ """Exclude None values from serialization to prevent API validation errors."""
116
+ # Set exclude_none=True if not explicitly set
117
+ if 'exclude_none' not in kwargs:
118
+ kwargs['exclude_none'] = True
119
+ return super().model_dump(**kwargs)
120
+
121
+
122
+ class StartTaggingSchedulerConfig(AIRBaseModel):
123
+ """Scheduler configuration for start tagging."""
124
+
125
+ when: str # "now" or "scheduled"
126
+ timezoneType: Optional[str] = None # "asset" or "custom" - required if scheduled
127
+ timezone: Optional[str] = None # required if scheduled and custom timezone
128
+ startDate: Optional[int] = None # unix timestamp - required if scheduled
129
+ recurrence: Optional[str] = None # "onetime", "daily", "weekly", "monthly" - required if scheduled
130
+ repeatEvery: Optional[int] = None # required if scheduled and daily/monthly
131
+ repeatOnWeek: Optional[List[str]] = None # required if scheduled and weekly
132
+ repeatOnMonth: Optional[int] = None # required if scheduled and monthly
133
+ endRepeatType: Optional[str] = None # "never", "date", "occurrence" - required if scheduled
134
+ endDate: Optional[int] = None # unix timestamp - required if end repeat type is date
135
+ limit: Optional[int] = None # required if end repeat type is occurrence
136
+
137
+
138
+ class StartTaggingFilter(AIRBaseModel):
139
+ """Filter for start tagging process - matches API specification exactly."""
140
+
141
+ organizationIds: List[int] # Required
142
+ searchTerm: Optional[str] = ""
143
+ name: Optional[str] = ""
144
+ ipAddress: Optional[str] = ""
145
+ groupId: Optional[str] = ""
146
+ groupFullPath: Optional[str] = ""
147
+ label: Optional[str] = ""
148
+ lastSeen: Optional[str] = ""
149
+ managedStatus: List[str] = [] # "unmanaged", "managed", "off-network"
150
+ isolationStatus: List[str] = [] # "isolating", "isolated", "unisolating", "unisolated"
151
+ platform: List[str] = [] # "windows", "linux", "darwin"
152
+ issue: Optional[str] = "" # "unreachable", "old-version", "update-required"
153
+ onlineStatus: List[str] = [] # "online", "offline"
154
+ tags: List[str] = []
155
+ version: Optional[str] = ""
156
+ policy: Optional[str] = ""
157
+ includedEndpointIds: List[str] = []
158
+ excludedEndpointIds: List[str] = []
159
+ caseId: Optional[str] = None
160
+
161
+
162
+ class StartTaggingRequest(AIRBaseModel):
163
+ """Start tagging process request model - matches API specification exactly."""
164
+
165
+ filter: StartTaggingFilter
166
+ schedulerConfig: StartTaggingSchedulerConfig
167
+
168
+
169
+ class TaggingResult(AIRBaseModel):
170
+ """Tagging process result model."""
171
+
172
+ taskId: str
173
+ message: str
174
+ processedTags: int
175
+ affectedAssets: int
176
+
177
+
178
+ class TaggingTask(AIRBaseModel):
179
+ """Individual tagging task result from start tagging API."""
180
+
181
+ task_id: str = Field(alias="_id")
182
+ name: str = Field(alias="name")
183
+
184
+
185
+ class TaggingResponse(AIRBaseModel):
186
+ """Response from start tagging API containing list of tasks."""
187
+
188
+ tasks: List[TaggingTask] = []
189
+
190
+ @classmethod
191
+ def from_api_result(cls, result_list: List[Dict[str, Any]]) -> 'TaggingResponse':
192
+ """Create TaggingResponse from API result list."""
193
+ if not isinstance(result_list, list):
194
+ raise ValueError("API result must be a list")
195
+
196
+ tasks = [TaggingTask(**task) for task in result_list]
197
+ return cls(tasks=tasks)
198
+
199
+ @property
200
+ def task_count(self) -> int:
201
+ """Get the number of tasks created."""
202
+ return len(self.tasks)
203
+
204
+ def get_task_ids(self) -> List[str]:
205
+ """Get list of all task IDs."""
206
+ return [task.task_id for task in self.tasks]
207
+
208
+
209
+ class AutoAssetTagFilter(Filter):
210
+ """Filter for auto asset tag queries."""
211
+
212
+ tag: Optional[str] = None
213
+ organization_ids: Optional[List[int]] = None
214
+ search_term: Optional[str] = None
215
+
216
+ def to_params(self) -> Dict[str, Any]:
217
+ """Convert filter to API parameters with proper field name mapping."""
218
+ params = super().to_params()
219
+
220
+ # Convert organization_ids to organizationIds for API compatibility
221
+ if "filter[organization_ids]" in params:
222
+ params["filter[organizationIds]"] = params.pop("filter[organization_ids]")
223
+
224
+ # Convert search_term to searchTerm for API compatibility
225
+ if "filter[search_term]" in params:
226
+ params["filter[searchTerm]"] = params.pop("filter[search_term]")
227
+
117
228
  return params
@@ -0,0 +1,138 @@
1
+ """
2
+ Backup 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 BackupStatus(str, Enum):
14
+ """Backup status enumeration."""
15
+ IN_PROGRESS = "in-progress"
16
+ SUCCEEDED = "succeeded"
17
+ UPLOADING = "uploading"
18
+ FAILED = "failed"
19
+ QUEUED = "queued"
20
+
21
+
22
+ class BackupSource(str, Enum):
23
+ """Backup source enumeration."""
24
+ USER = "user"
25
+ SCHEDULER = "scheduler"
26
+
27
+
28
+ class BackupLocation(str, Enum):
29
+ """Backup location enumeration."""
30
+ LOCAL = "local"
31
+ SFTP = "sftp"
32
+ S3 = "s3"
33
+
34
+
35
+ class Backup(AIRBaseModel):
36
+ """Backup model."""
37
+
38
+ id: str = Field(alias="_id")
39
+ location: BackupLocation
40
+ status: BackupStatus
41
+ size: Optional[int] = None
42
+ source: BackupSource
43
+ username: str
44
+ to: str # Backup file path/location
45
+ stats: Dict[str, Any] = {}
46
+ start_date: datetime = Field(alias="startDate")
47
+ end_date: Optional[datetime] = Field(default=None, alias="endDate")
48
+ created_at: datetime = Field(alias="createdAt")
49
+ updated_at: datetime = Field(alias="updatedAt")
50
+
51
+
52
+ class BackupFilter(AIRBaseModel):
53
+ """Filter parameters for backup history."""
54
+
55
+ page_size: Optional[int] = Field(default=10, alias="pageSize")
56
+ page_number: Optional[int] = Field(default=1, alias="pageNumber")
57
+ sort_type: Optional[str] = Field(default="DESC", alias="sortType") # ASC or DESC
58
+ sort_by: Optional[str] = Field(default="createdAt", alias="sortBy") # source, username, status, startDate, createdAt
59
+ search_term: Optional[str] = Field(default=None, alias="searchTerm")
60
+ username: Optional[str] = None
61
+ source: Optional[BackupSource] = None
62
+ status: Optional[BackupStatus] = None
63
+ start_date: Optional[datetime] = Field(default=None, alias="startDate")
64
+ end_date: Optional[datetime] = Field(default=None, alias="endDate")
65
+ location: Optional[BackupLocation] = None
66
+
67
+
68
+ class BackupHistoryResponse(AIRBaseModel):
69
+ """Paginated response for backup history."""
70
+
71
+ entities: List[Backup]
72
+ filters: List[Dict[str, Any]]
73
+ sortables: List[str]
74
+ total_entity_count: int = Field(alias="totalEntityCount")
75
+ current_page: int = Field(alias="currentPage")
76
+ page_size: int = Field(alias="pageSize")
77
+ previous_page: int = Field(alias="previousPage")
78
+ total_page_count: int = Field(alias="totalPageCount")
79
+ next_page: int = Field(alias="nextPage")
80
+
81
+
82
+ class BackupNowRequest(AIRBaseModel):
83
+ """Request model for creating an immediate backup."""
84
+
85
+ # The API appears to use filters for backup scope
86
+ # Based on the prerequest script, it uses includedEndpointIds
87
+ include_endpoint_ids: Optional[List[str]] = Field(default=None, alias="includedEndpointIds")
88
+ exclude_endpoint_ids: Optional[List[str]] = Field(default=None, alias="excludedEndpointIds")
89
+ organization_ids: Optional[List[int]] = Field(default=None, alias="organizationIds")
90
+ backup_location: Optional[BackupLocation] = BackupLocation.LOCAL
91
+
92
+
93
+ class BackupConfig(AIRBaseModel):
94
+ """Backup configuration model."""
95
+
96
+ enabled: bool = True
97
+ schedule: Optional[str] = None # Cron expression
98
+ location: BackupLocation = BackupLocation.LOCAL
99
+ retention_days: Optional[int] = Field(default=30, alias="retentionDays")
100
+ compression: bool = True
101
+ encryption: bool = False
102
+
103
+ # SFTP configuration
104
+ sftp_host: Optional[str] = Field(default=None, alias="sftpHost")
105
+ sftp_port: Optional[int] = Field(default=22, alias="sftpPort")
106
+ sftp_username: Optional[str] = Field(default=None, alias="sftpUsername")
107
+ sftp_password: Optional[str] = Field(default=None, alias="sftpPassword")
108
+ sftp_path: Optional[str] = Field(default=None, alias="sftpPath")
109
+
110
+ # S3 configuration
111
+ s3_bucket: Optional[str] = Field(default=None, alias="s3Bucket")
112
+ s3_region: Optional[str] = Field(default=None, alias="s3Region")
113
+ s3_access_key: Optional[str] = Field(default=None, alias="s3AccessKey")
114
+ s3_secret_key: Optional[str] = Field(default=None, alias="s3SecretKey")
115
+ s3_path: Optional[str] = Field(default=None, alias="s3Path")
116
+
117
+
118
+ class BackupStats(AIRBaseModel):
119
+ """Backup statistics model."""
120
+
121
+ total_backups: int = Field(default=0, alias="totalBackups")
122
+ successful_backups: int = Field(default=0, alias="successfulBackups")
123
+ failed_backups: int = Field(default=0, alias="failedBackups")
124
+ in_progress_backups: int = Field(default=0, alias="inProgressBackups")
125
+ total_size_bytes: int = Field(default=0, alias="totalSizeBytes")
126
+ average_backup_time_minutes: float = Field(default=0.0, alias="averageBackupTimeMinutes")
127
+ last_backup_date: Optional[datetime] = Field(default=None, alias="lastBackupDate")
128
+ next_scheduled_backup: Optional[datetime] = Field(default=None, alias="nextScheduledBackup")
129
+
130
+
131
+ class BackupDownloadInfo(AIRBaseModel):
132
+ """Backup download information model."""
133
+
134
+ backup_id: str = Field(alias="backupId")
135
+ filename: str
136
+ size_bytes: int = Field(alias="sizeBytes")
137
+ download_url: str = Field(alias="downloadUrl")
138
+ expires_at: Optional[datetime] = Field(default=None, alias="expiresAt")