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,156 +1,156 @@
1
- """
2
- Acquisition-related queries for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import List, Optional
6
-
7
- from ..base import Query
8
- from ..models.acquisitions import (
9
- AcquisitionProfile, AcquisitionProfileDetails, AcquisitionFilter,
10
- AcquisitionProfilePlatformDetails, NetworkCaptureConfig, EDiscoveryPattern
11
- )
12
- from ..http_client import HTTPClient
13
-
14
-
15
- class ListAcquisitionProfilesQuery(Query[List[AcquisitionProfile]]):
16
- """Query to list acquisition profiles with optional filtering."""
17
-
18
- def __init__(
19
- self,
20
- http_client: HTTPClient,
21
- filter_params: Optional[AcquisitionFilter] = None,
22
- organization_ids: Optional[List[int]] = None,
23
- all_organizations: bool = False
24
- ):
25
- self.http_client = http_client
26
- # Initialize filter with default organization IDs if not provided
27
- if filter_params is None:
28
- filter_params = AcquisitionFilter()
29
-
30
- # Set organization parameters if not already set in filter
31
- if filter_params.organization_ids is None and organization_ids is not None:
32
- filter_params.organization_ids = organization_ids
33
- elif filter_params.organization_ids is None:
34
- filter_params.organization_ids = [0] # Default to organization 0
35
-
36
- # Set all_organizations parameter if not already set in filter
37
- if filter_params.all_organizations is None and all_organizations:
38
- filter_params.all_organizations = all_organizations
39
-
40
- self.filter_params = filter_params
41
-
42
- def execute(self) -> List[AcquisitionProfile]:
43
- """Execute the query to list acquisition profiles."""
44
- # Use filter's parameter generation
45
- params = self.filter_params.to_params()
46
-
47
- response = self.http_client.get("acquisitions/profiles", params=params)
48
-
49
- entities = response.get("result", {}).get("entities", [])
50
-
51
- # Convert to AcquisitionProfile objects
52
- profiles = []
53
- for entity_data in entities:
54
- mapped_data = {
55
- "id": entity_data.get("_id"),
56
- "name": entity_data.get("name"),
57
- "organization_ids": entity_data.get("organizationIds", []), # Keep as integers
58
- "created_at": entity_data.get("createdAt"),
59
- "updated_at": entity_data.get("updatedAt"),
60
- "created_by": entity_data.get("createdBy"),
61
- "deletable": entity_data.get("deletable", True),
62
- "average_time": entity_data.get("averageTime"),
63
- "last_used_at": entity_data.get("lastUsedAt"),
64
- "last_used_by": entity_data.get("lastUsedBy"),
65
- "has_event_log_records_evidence": entity_data.get("hasEventLogRecordsEvidence"),
66
- }
67
-
68
- # Remove None values
69
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
70
-
71
- profiles.append(AcquisitionProfile(**mapped_data))
72
-
73
- return profiles
74
-
75
-
76
- class GetAcquisitionProfileQuery(Query[AcquisitionProfileDetails]):
77
- """Query to get a specific acquisition profile by ID."""
78
-
79
- def __init__(self, http_client: HTTPClient, profile_id: str):
80
- self.http_client = http_client
81
- self.profile_id = profile_id
82
-
83
- def execute(self) -> AcquisitionProfileDetails:
84
- """Execute the query to get acquisition profile details."""
85
- response = self.http_client.get(f"acquisitions/profiles/{self.profile_id}")
86
-
87
- entity_data = response.get("result", {})
88
-
89
- # Parse platform configurations
90
- def parse_platform_config(platform_data: dict) -> AcquisitionProfilePlatformDetails:
91
- network_capture = None
92
- if "networkCapture" in platform_data:
93
- nc_data = platform_data["networkCapture"]
94
- network_capture = NetworkCaptureConfig(
95
- enabled=nc_data.get("enabled", False),
96
- duration=nc_data.get("duration", 60),
97
- pcap=nc_data.get("pcap", {"enabled": False}),
98
- network_flow=nc_data.get("networkFlow", {"enabled": False})
99
- )
100
-
101
- return AcquisitionProfilePlatformDetails(
102
- evidence_list=platform_data.get("evidenceList", []),
103
- artifact_list=platform_data.get("artifactList"),
104
- custom_content_profiles=platform_data.get("customContentProfiles", []),
105
- network_capture=network_capture
106
- )
107
-
108
- # Parse platform configurations
109
- windows_config = None
110
- linux_config = None
111
- macos_config = None
112
- aix_config = None
113
-
114
- if "windows" in entity_data:
115
- windows_config = parse_platform_config(entity_data["windows"])
116
-
117
- if "linux" in entity_data:
118
- linux_config = parse_platform_config(entity_data["linux"])
119
-
120
- if "macos" in entity_data:
121
- macos_config = parse_platform_config(entity_data["macos"])
122
-
123
- if "aix" in entity_data:
124
- aix_config = parse_platform_config(entity_data["aix"])
125
-
126
- # Parse eDiscovery patterns
127
- e_discovery = None
128
- if "eDiscovery" in entity_data and "patterns" in entity_data["eDiscovery"]:
129
- patterns = [
130
- EDiscoveryPattern(
131
- pattern=pattern.get("pattern", ""),
132
- category=pattern.get("category", "")
133
- )
134
- for pattern in entity_data["eDiscovery"]["patterns"]
135
- ]
136
- e_discovery = {"patterns": patterns}
137
-
138
- mapped_data = {
139
- "id": entity_data.get("_id"),
140
- "name": entity_data.get("name"),
141
- "organization_ids": [str(org_id) for org_id in entity_data.get("organizationIds", [])],
142
- "created_at": entity_data.get("createdAt"),
143
- "updated_at": entity_data.get("updatedAt"),
144
- "created_by": entity_data.get("createdBy"),
145
- "deletable": entity_data.get("deletable", True),
146
- "windows": windows_config,
147
- "linux": linux_config,
148
- "macos": macos_config,
149
- "aix": aix_config,
150
- "e_discovery": e_discovery,
151
- }
152
-
153
- # Remove None values
154
- mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
155
-
1
+ """
2
+ Acquisition-related queries for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Optional
6
+
7
+ from ..base import Query
8
+ from ..models.acquisitions import (
9
+ AcquisitionProfile, AcquisitionProfileDetails, AcquisitionFilter,
10
+ AcquisitionProfilePlatformDetails, NetworkCaptureConfig, EDiscoveryPattern
11
+ )
12
+ from ..http_client import HTTPClient
13
+
14
+
15
+ class ListAcquisitionProfilesQuery(Query[List[AcquisitionProfile]]):
16
+ """Query to list acquisition profiles with optional filtering."""
17
+
18
+ def __init__(
19
+ self,
20
+ http_client: HTTPClient,
21
+ filter_params: Optional[AcquisitionFilter] = None,
22
+ organization_ids: Optional[List[int]] = None,
23
+ all_organizations: bool = False
24
+ ):
25
+ self.http_client = http_client
26
+ # Initialize filter with default organization IDs if not provided
27
+ if filter_params is None:
28
+ filter_params = AcquisitionFilter()
29
+
30
+ # Set organization parameters if not already set in filter
31
+ if filter_params.organization_ids is None and organization_ids is not None:
32
+ filter_params.organization_ids = organization_ids
33
+ elif filter_params.organization_ids is None:
34
+ filter_params.organization_ids = [0] # Default to organization 0
35
+
36
+ # Set all_organizations parameter if not already set in filter
37
+ if filter_params.all_organizations is None and all_organizations:
38
+ filter_params.all_organizations = all_organizations
39
+
40
+ self.filter_params = filter_params
41
+
42
+ def execute(self) -> List[AcquisitionProfile]:
43
+ """Execute the query to list acquisition profiles."""
44
+ # Use filter's parameter generation
45
+ params = self.filter_params.to_params()
46
+
47
+ response = self.http_client.get("acquisitions/profiles", params=params)
48
+
49
+ entities = response.get("result", {}).get("entities", [])
50
+
51
+ # Convert to AcquisitionProfile objects
52
+ profiles = []
53
+ for entity_data in entities:
54
+ mapped_data = {
55
+ "id": entity_data.get("_id"),
56
+ "name": entity_data.get("name"),
57
+ "organization_ids": entity_data.get("organizationIds", []), # Keep as integers
58
+ "created_at": entity_data.get("createdAt"),
59
+ "updated_at": entity_data.get("updatedAt"),
60
+ "created_by": entity_data.get("createdBy"),
61
+ "deletable": entity_data.get("deletable", True),
62
+ "average_time": entity_data.get("averageTime"),
63
+ "last_used_at": entity_data.get("lastUsedAt"),
64
+ "last_used_by": entity_data.get("lastUsedBy"),
65
+ "has_event_log_records_evidence": entity_data.get("hasEventLogRecordsEvidence"),
66
+ }
67
+
68
+ # Remove None values
69
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
70
+
71
+ profiles.append(AcquisitionProfile(**mapped_data))
72
+
73
+ return profiles
74
+
75
+
76
+ class GetAcquisitionProfileQuery(Query[AcquisitionProfileDetails]):
77
+ """Query to get a specific acquisition profile by ID."""
78
+
79
+ def __init__(self, http_client: HTTPClient, profile_id: str):
80
+ self.http_client = http_client
81
+ self.profile_id = profile_id
82
+
83
+ def execute(self) -> AcquisitionProfileDetails:
84
+ """Execute the query to get acquisition profile details."""
85
+ response = self.http_client.get(f"acquisitions/profiles/{self.profile_id}")
86
+
87
+ entity_data = response.get("result", {})
88
+
89
+ # Parse platform configurations
90
+ def parse_platform_config(platform_data: dict) -> AcquisitionProfilePlatformDetails:
91
+ network_capture = None
92
+ if "networkCapture" in platform_data:
93
+ nc_data = platform_data["networkCapture"]
94
+ network_capture = NetworkCaptureConfig(
95
+ enabled=nc_data.get("enabled", False),
96
+ duration=nc_data.get("duration", 60),
97
+ pcap=nc_data.get("pcap", {"enabled": False}),
98
+ network_flow=nc_data.get("networkFlow", {"enabled": False})
99
+ )
100
+
101
+ return AcquisitionProfilePlatformDetails(
102
+ evidence_list=platform_data.get("evidenceList", []),
103
+ artifact_list=platform_data.get("artifactList"),
104
+ custom_content_profiles=platform_data.get("customContentProfiles", []),
105
+ network_capture=network_capture
106
+ )
107
+
108
+ # Parse platform configurations
109
+ windows_config = None
110
+ linux_config = None
111
+ macos_config = None
112
+ aix_config = None
113
+
114
+ if "windows" in entity_data:
115
+ windows_config = parse_platform_config(entity_data["windows"])
116
+
117
+ if "linux" in entity_data:
118
+ linux_config = parse_platform_config(entity_data["linux"])
119
+
120
+ if "macos" in entity_data:
121
+ macos_config = parse_platform_config(entity_data["macos"])
122
+
123
+ if "aix" in entity_data:
124
+ aix_config = parse_platform_config(entity_data["aix"])
125
+
126
+ # Parse eDiscovery patterns
127
+ e_discovery = None
128
+ if "eDiscovery" in entity_data and "patterns" in entity_data["eDiscovery"]:
129
+ patterns = [
130
+ EDiscoveryPattern(
131
+ pattern=pattern.get("pattern", ""),
132
+ category=pattern.get("category", "")
133
+ )
134
+ for pattern in entity_data["eDiscovery"]["patterns"]
135
+ ]
136
+ e_discovery = {"patterns": patterns}
137
+
138
+ mapped_data = {
139
+ "id": entity_data.get("_id"),
140
+ "name": entity_data.get("name"),
141
+ "organization_ids": [str(org_id) for org_id in entity_data.get("organizationIds", [])],
142
+ "created_at": entity_data.get("createdAt"),
143
+ "updated_at": entity_data.get("updatedAt"),
144
+ "created_by": entity_data.get("createdBy"),
145
+ "deletable": entity_data.get("deletable", True),
146
+ "windows": windows_config,
147
+ "linux": linux_config,
148
+ "macos": macos_config,
149
+ "aix": aix_config,
150
+ "e_discovery": e_discovery,
151
+ }
152
+
153
+ # Remove None values
154
+ mapped_data = {k: v for k, v in mapped_data.items() if v is not None}
155
+
156
156
  return AcquisitionProfileDetails(**mapped_data)
@@ -0,0 +1,46 @@
1
+ """
2
+ API Tokens queries for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import Optional, Dict, Any
6
+
7
+ from ..base import Query
8
+ from ..models.api_tokens import APIToken, APITokensPaginatedResponse, APITokenFilter
9
+ from ..http_client import HTTPClient
10
+
11
+
12
+ class ListAPITokensQuery(Query[APITokensPaginatedResponse]):
13
+ """Query to list API tokens with optional filtering."""
14
+
15
+ def __init__(self, http_client: HTTPClient, filter_params: Optional[APITokenFilter] = None):
16
+ self.http_client = http_client
17
+ self.filter_params = filter_params or APITokenFilter()
18
+
19
+ def execute(self) -> APITokensPaginatedResponse:
20
+ """Execute the query."""
21
+ params = {}
22
+
23
+ if self.filter_params.page_size is not None:
24
+ params["pageSize"] = self.filter_params.page_size
25
+ if self.filter_params.page_number is not None:
26
+ params["pageNumber"] = self.filter_params.page_number
27
+ if self.filter_params.sort_type is not None:
28
+ params["sortType"] = self.filter_params.sort_type
29
+ if self.filter_params.sort_by is not None:
30
+ params["sortBy"] = self.filter_params.sort_by
31
+
32
+ response = self.http_client.get("api-tokens", params=params)
33
+ return APITokensPaginatedResponse(**response["result"])
34
+
35
+
36
+ class GetAPITokenQuery(Query[APIToken]):
37
+ """Query to get a specific API token by ID."""
38
+
39
+ def __init__(self, http_client: HTTPClient, token_id: str):
40
+ self.http_client = http_client
41
+ self.token_id = token_id
42
+
43
+ def execute(self) -> APIToken:
44
+ """Execute the query."""
45
+ response = self.http_client.get(f"api-tokens/{self.token_id}")
46
+ return APIToken(**response["result"])
@@ -1,105 +1,186 @@
1
- """
2
- Asset-related queries for the Binalyze AIR SDK.
3
- """
4
-
5
- from typing import List, Dict, Any, Optional
6
-
7
- from ..base import Query, PaginatedResponse, APIResponse, PaginatedList
8
- from ..models.assets import Asset, AssetDetail, AssetTask, AssetFilter, AssetTaskFilter
9
- from ..http_client import HTTPClient
10
-
11
-
12
- class ListAssetsQuery(Query[List[Asset]]):
13
- """Query to list assets with optional filtering."""
14
-
15
- def __init__(self, http_client: HTTPClient, filter_params: Optional[AssetFilter] = None):
16
- self.http_client = http_client
17
- self.filter_params = filter_params or AssetFilter()
18
-
19
- def execute(self) -> List[Asset]:
20
- """Execute the query to list assets."""
21
- params = self.filter_params.to_params()
22
-
23
- # Set default organization_ids if not provided
24
- if not self.filter_params.organization_ids:
25
- params["filter[organizationIds]"] = "0"
26
-
27
- # Ensure consistent sorting to match API defaults
28
- if "sortBy" not in params:
29
- params["sortBy"] = "createdAt"
30
- if "sortType" not in params:
31
- params["sortType"] = "ASC"
32
-
33
- response = self.http_client.get("assets", params=params)
34
-
35
- # Parse the paginated response
36
- entities = response.get("result", {}).get("entities", [])
37
-
38
- # Convert to Asset objects using Pydantic parsing with aliases
39
- assets = []
40
- for entity_data in entities:
41
- # Let Pydantic handle the field mapping via aliases
42
- asset = Asset.model_validate(entity_data)
43
- assets.append(asset)
44
-
45
- return assets
46
-
47
-
48
- class GetAssetQuery(Query[AssetDetail]):
49
- """Query to get a specific asset by ID."""
50
-
51
- def __init__(self, http_client: HTTPClient, asset_id: str):
52
- self.http_client = http_client
53
- self.asset_id = asset_id
54
-
55
- def execute(self) -> AssetDetail:
56
- """Execute the query to get asset details."""
57
- response = self.http_client.get(f"assets/{self.asset_id}")
58
-
59
- entity_data = response.get("result", {})
60
-
61
- # Let Pydantic handle the field mapping via aliases
62
- return AssetDetail.model_validate(entity_data)
63
-
64
-
65
- class GetAssetTasksQuery(Query[List[AssetTask]]):
66
- """Query to get tasks for a specific asset with optional filtering."""
67
-
68
- def __init__(self, http_client: HTTPClient, asset_id: str, filter_params: Optional[AssetTaskFilter] = None):
69
- self.http_client = http_client
70
- self.asset_id = asset_id
71
- self.filter_params = filter_params or AssetTaskFilter()
72
-
73
- def execute(self) -> List[AssetTask]:
74
- """Execute the query to get asset tasks."""
75
- # Get filter parameters
76
- params = self.filter_params.to_params()
77
-
78
- # Provide sensible defaults that mirror the HTTP test defaults if not supplied
79
- # Default pagination
80
- if "pageNumber" not in params:
81
- params["pageNumber"] = 1
82
- if "pageSize" not in params:
83
- params["pageSize"] = 10
84
- # Default sorting
85
- if "sortBy" not in params:
86
- params["sortBy"] = "createdAt"
87
- if "sortType" not in params:
88
- params["sortType"] = "ASC"
89
-
90
- # Make request with parameters
91
- response = self.http_client.get(f"assets/{self.asset_id}/tasks", params=params)
92
-
93
- result_meta = response.get("result", {})
94
- entities_data = result_meta.get("entities", [])
95
-
96
- # Convert to AssetTask objects using Pydantic parsing with aliases
97
- paginated_tasks = PaginatedList(
98
- [AssetTask.model_validate(entity) for entity in entities_data],
99
- total_entity_count=result_meta.get("totalEntityCount"),
100
- current_page=result_meta.get("currentPage", params.get("pageNumber", 1)),
101
- page_size=result_meta.get("pageSize", params.get("pageSize", len(entities_data))),
102
- total_page_count=result_meta.get("totalPageCount"),
103
- )
104
-
105
- return paginated_tasks
1
+ """
2
+ Asset-related queries for the Binalyze AIR SDK.
3
+ """
4
+
5
+ from typing import List, Dict, Any, Optional
6
+
7
+ from ..base import Query, PaginatedResponse, APIResponse, PaginatedList
8
+ from ..models.assets import Asset, AssetDetail, AssetTask, AssetFilter, AssetTaskFilter
9
+ from ..http_client import HTTPClient
10
+
11
+
12
+ class ListAssetsQuery(Query[List[Asset]]):
13
+ """Query to list assets with optional filtering."""
14
+
15
+ def __init__(self, http_client: HTTPClient, filter_params: Optional[AssetFilter] = None):
16
+ self.http_client = http_client
17
+ self.filter_params = filter_params or AssetFilter()
18
+
19
+ def execute(self) -> List[Asset]:
20
+ """Execute the query to list assets."""
21
+ params = self.filter_params.to_params()
22
+
23
+ # Set default organization_ids if not provided
24
+ if not self.filter_params.organization_ids:
25
+ params["filter[organizationIds]"] = "0"
26
+
27
+ # Ensure consistent sorting to match API defaults
28
+ if "sortBy" not in params:
29
+ params["sortBy"] = "createdAt"
30
+ if "sortType" not in params:
31
+ params["sortType"] = "ASC"
32
+
33
+ response = self.http_client.get("assets", params=params)
34
+
35
+ # Parse the paginated response
36
+ entities = response.get("result", {}).get("entities", [])
37
+
38
+ # Convert to Asset objects using Pydantic parsing with aliases
39
+ assets = []
40
+ for entity_data in entities:
41
+ # Let Pydantic handle the field mapping via aliases
42
+ asset = Asset.model_validate(entity_data)
43
+ assets.append(asset)
44
+
45
+ return assets
46
+
47
+
48
+ class GetAssetQuery(Query[AssetDetail]):
49
+ """Query to get a specific asset by ID."""
50
+
51
+ def __init__(self, http_client: HTTPClient, asset_id: str):
52
+ self.http_client = http_client
53
+ self.asset_id = asset_id
54
+
55
+ def execute(self) -> AssetDetail:
56
+ """Execute the query to get asset details."""
57
+ response = self.http_client.get(f"assets/{self.asset_id}")
58
+
59
+ entity_data = response.get("result", {})
60
+
61
+ # Let Pydantic handle the field mapping via aliases
62
+ return AssetDetail.model_validate(entity_data)
63
+
64
+
65
+ class GetAssetTasksQuery(Query[List[AssetTask]]):
66
+ """Query to get tasks for a specific asset with optional filtering."""
67
+
68
+ def __init__(self, http_client: HTTPClient, asset_id: str, filter_params: Optional[AssetTaskFilter] = None):
69
+ self.http_client = http_client
70
+ self.asset_id = asset_id
71
+ self.filter_params = filter_params or AssetTaskFilter()
72
+
73
+ def execute(self) -> List[AssetTask]:
74
+ """Execute the query to get asset tasks."""
75
+ # Get filter parameters
76
+ params = self.filter_params.to_params()
77
+
78
+ # Provide sensible defaults that mirror the HTTP test defaults if not supplied
79
+ # Default pagination
80
+ if "pageNumber" not in params:
81
+ params["pageNumber"] = 1
82
+ if "pageSize" not in params:
83
+ params["pageSize"] = 10
84
+ # Default sorting
85
+ if "sortBy" not in params:
86
+ params["sortBy"] = "createdAt"
87
+ if "sortType" not in params:
88
+ params["sortType"] = "ASC"
89
+
90
+ # Make request with parameters
91
+ response = self.http_client.get(f"assets/{self.asset_id}/tasks", params=params)
92
+
93
+ result_meta = response.get("result", {})
94
+ entities_data = result_meta.get("entities", [])
95
+
96
+ # Convert to AssetTask objects using Pydantic parsing with aliases
97
+ paginated_tasks = PaginatedList(
98
+ [AssetTask.model_validate(entity) for entity in entities_data],
99
+ total_entity_count=result_meta.get("totalEntityCount"),
100
+ current_page=result_meta.get("currentPage", params.get("pageNumber", 1)),
101
+ page_size=result_meta.get("pageSize", params.get("pageSize", len(entities_data))),
102
+ total_page_count=result_meta.get("totalPageCount"),
103
+ )
104
+
105
+ return paginated_tasks
106
+
107
+
108
+ class GetAssetGroupsByOrganizationIdQuery(Query[List[Dict[str, Any]]]):
109
+ """Query to get root asset groups by organization ID."""
110
+
111
+ def __init__(self, http_client: HTTPClient, organization_id: int):
112
+ self.http_client = http_client
113
+ self.organization_id = organization_id
114
+
115
+ def execute(self) -> List[Dict[str, Any]]:
116
+ """Execute the query to get asset groups by organization ID."""
117
+ response = self.http_client.get(f"asset-groups/root/{self.organization_id}")
118
+ return response.get("result", [])
119
+
120
+
121
+ class GetAssetGroupsByParentIdQuery(Query[List[Dict[str, Any]]]):
122
+ """Query to get asset groups by parent ID."""
123
+
124
+ def __init__(self, http_client: HTTPClient, group_id: str):
125
+ self.http_client = http_client
126
+ self.group_id = group_id
127
+
128
+ def execute(self) -> List[Dict[str, Any]]:
129
+ """Execute the query to get asset groups by parent ID."""
130
+ response = self.http_client.get(f"asset-groups/{self.group_id}")
131
+ return response.get("result", [])
132
+
133
+
134
+ class GetAssetTagsQuery(Query[Dict[str, Any]]):
135
+ """Query to get asset tags with filtering."""
136
+
137
+ def __init__(self, http_client: HTTPClient, organization_ids: List[int],
138
+ page_number: int = 1, page_size: int = 10, sort_by: str = "createdAt",
139
+ search_term: Optional[str] = None):
140
+ self.http_client = http_client
141
+ self.organization_ids = organization_ids
142
+ self.page_number = page_number
143
+ self.page_size = page_size
144
+ self.sort_by = sort_by
145
+ self.search_term = search_term
146
+
147
+ def execute(self) -> Dict[str, Any]:
148
+ """Execute the query to get asset tags."""
149
+ params = {
150
+ "filter[organizationIds]": ",".join(map(str, self.organization_ids)),
151
+ "pageNumber": self.page_number,
152
+ "pageSize": self.page_size,
153
+ "sortBy": self.sort_by
154
+ }
155
+
156
+ if self.search_term:
157
+ params["filter[searchTerm]"] = self.search_term
158
+
159
+ response = self.http_client.get("asset-tags", params=params)
160
+ return response.get("result", {})
161
+
162
+
163
+ class GetProcessorsByAssetTypeIdQuery(Query[List[Dict[str, Any]]]):
164
+ """Query to get processors by asset type ID."""
165
+
166
+ def __init__(self, http_client: HTTPClient, asset_type_id: int):
167
+ self.http_client = http_client
168
+ self.asset_type_id = asset_type_id
169
+
170
+ def execute(self) -> List[Dict[str, Any]]:
171
+ """Execute the query to get processors by asset type ID."""
172
+ response = self.http_client.get(f"processors/asset-type/{self.asset_type_id}")
173
+ return response.get("result", [])
174
+
175
+
176
+ class GetProcessorTypesByAssetTypeQuery(Query[Dict[str, Any]]):
177
+ """Query to get processor types by asset type ID."""
178
+
179
+ def __init__(self, http_client: HTTPClient, asset_type_id: int):
180
+ self.http_client = http_client
181
+ self.asset_type_id = asset_type_id
182
+
183
+ def execute(self) -> Dict[str, Any]:
184
+ """Execute the query to get processor types by asset type ID."""
185
+ response = self.http_client.get(f"processors/type/{self.asset_type_id}")
186
+ return response.get("result", {})