blackshield-sdk 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/.gitignore +3 -1
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/PKG-INFO +8 -1
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/README.md +7 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_async_client.py +14 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_client.py +14 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_version.py +1 -1
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/__init__.py +6 -0
- blackshield_sdk-0.2.3/src/blackshield/resources/appliances.py +54 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/identity.py +44 -0
- blackshield_sdk-0.2.3/src/blackshield/resources/rules.py +220 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/security_agents.py +62 -6
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/siem.py +71 -3
- blackshield_sdk-0.2.3/src/blackshield/types/appliances.py +23 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/identity.py +37 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/ingestion.py +9 -1
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/security_agents.py +44 -2
- blackshield_sdk-0.2.3/src/blackshield/types/siem.py +98 -0
- blackshield_sdk-0.2.3/tests/test_alerts.py +171 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_api_keys.py +38 -4
- blackshield_sdk-0.2.3/tests/test_appliances_and_siem_sdk.py +271 -0
- blackshield_sdk-0.2.3/tests/test_audit.py +74 -0
- blackshield_sdk-0.2.3/tests/test_base_client_errors.py +89 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_client.py +1 -1
- blackshield_sdk-0.2.3/tests/test_compliance.py +246 -0
- blackshield_sdk-0.2.3/tests/test_evidence_siem_runbooks.py +506 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_findings.py +87 -6
- blackshield_sdk-0.2.3/tests/test_identity.py +159 -0
- blackshield_sdk-0.2.3/tests/test_ingestion.py +252 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_mcp.py +76 -5
- blackshield_sdk-0.2.3/tests/test_policies.py +273 -0
- blackshield_sdk-0.2.3/tests/test_remediation.py +177 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_reports.py +62 -4
- blackshield_sdk-0.2.3/tests/test_rules.py +292 -0
- blackshield_sdk-0.2.3/tests/test_security_agents.py +443 -0
- blackshield_sdk-0.2.3/tests/test_services_and_incidents.py +249 -0
- blackshield_sdk-0.2.2/src/blackshield/types/siem.py +0 -45
- blackshield_sdk-0.2.2/tests/test_alerts.py +0 -49
- blackshield_sdk-0.2.2/tests/test_audit.py +0 -48
- blackshield_sdk-0.2.2/tests/test_compliance.py +0 -116
- blackshield_sdk-0.2.2/tests/test_evidence_siem_runbooks.py +0 -252
- blackshield_sdk-0.2.2/tests/test_identity.py +0 -73
- blackshield_sdk-0.2.2/tests/test_ingestion.py +0 -195
- blackshield_sdk-0.2.2/tests/test_policies.py +0 -88
- blackshield_sdk-0.2.2/tests/test_remediation.py +0 -67
- blackshield_sdk-0.2.2/tests/test_security_agents.py +0 -97
- blackshield_sdk-0.2.2/tests/test_services_and_incidents.py +0 -108
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/pyproject.toml +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/__init__.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_base_client.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_exceptions.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/_types.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/mcp.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/ai_assets.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/ai_gateway.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/ai_integrations.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/alerts.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/api_keys.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/assertions.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/audit.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/compliance.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/connectors.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/customer_notifications.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/dashboard.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/dast.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/easm.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/evidence.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/findings.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/incidents.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/ingestion.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/oauth_apps.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/policies.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/remediation.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/reports.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/runbooks.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/security_reviews.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/services.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/threat_intel.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/threat_modeling.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/__init__.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/ai_assets.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/ai_gateway.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/ai_integrations.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/alerts.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/api_keys.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/assertions.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/audit.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/compliance.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/connectors.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/customer_notifications.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/dashboard.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/dast.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/easm.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/evidence.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/findings.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/incidents.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/oauth_apps.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/policies.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/remediation.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/reports.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/runbooks.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/security_reviews.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/services.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/threat_intel.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/types/threat_modeling.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/conftest.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_ai_gateway.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_ai_governance_sdk.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_assertions_dast_sdk.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_connectors.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_dashboard.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_easm.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_notifications_threat_modeling_sdk.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_request_models.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_security_reviews.py +0 -0
- {blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/tests/test_threat_intel.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blackshield-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Official Python SDK for the BlackShield Security Platform
|
|
5
5
|
Project-URL: Homepage, https://blackshield.chaplau.com
|
|
6
6
|
Project-URL: Documentation, https://blackshield.chaplau.com/en/docs
|
|
@@ -100,6 +100,13 @@ asyncio.run(main())
|
|
|
100
100
|
| `client.oauth_apps` | OAuth app and grant governance | `client.oauth_apps.grants(status="pending_review")` |
|
|
101
101
|
| `client.threat_modeling` | Hosted threat-model sessions & exports | `client.threat_modeling.create_session(title="Review")` |
|
|
102
102
|
|
|
103
|
+
The 0.2.3 release candidate adds appliance inventory and policy operations,
|
|
104
|
+
identity sessions, agent operations, SIEM entities and statistics, and ingestion
|
|
105
|
+
submission responses that accept either `id` or `job_id`. These operations have
|
|
106
|
+
matching synchronous and asynchronous clients. Publish and verify this candidate
|
|
107
|
+
before updating a lab's SDK lock; an existing 0.2.2 installation does not include
|
|
108
|
+
these additions.
|
|
109
|
+
|
|
103
110
|
Version 0.2.2 preserves the 0.2.0 surface and accepts both the legacy `job_id`
|
|
104
111
|
and current `id` ingestion job status fields. It also includes the 0.2.1 durable
|
|
105
112
|
EASM verification outcomes, explicit challenge rotation, and synchronous/asynchronous
|
|
@@ -70,6 +70,13 @@ asyncio.run(main())
|
|
|
70
70
|
| `client.oauth_apps` | OAuth app and grant governance | `client.oauth_apps.grants(status="pending_review")` |
|
|
71
71
|
| `client.threat_modeling` | Hosted threat-model sessions & exports | `client.threat_modeling.create_session(title="Review")` |
|
|
72
72
|
|
|
73
|
+
The 0.2.3 release candidate adds appliance inventory and policy operations,
|
|
74
|
+
identity sessions, agent operations, SIEM entities and statistics, and ingestion
|
|
75
|
+
submission responses that accept either `id` or `job_id`. These operations have
|
|
76
|
+
matching synchronous and asynchronous clients. Publish and verify this candidate
|
|
77
|
+
before updating a lab's SDK lock; an existing 0.2.2 installation does not include
|
|
78
|
+
these additions.
|
|
79
|
+
|
|
73
80
|
Version 0.2.2 preserves the 0.2.0 surface and accepts both the legacy `job_id`
|
|
74
81
|
and current `id` ingestion job status fields. It also includes the 0.2.1 durable
|
|
75
82
|
EASM verification outcomes, explicit challenge rotation, and synchronous/asynchronous
|
|
@@ -8,6 +8,7 @@ from blackshield.resources.ai_gateway import AsyncAiGatewayResource
|
|
|
8
8
|
from blackshield.resources.ai_integrations import AsyncAiIntegrationsResource
|
|
9
9
|
from blackshield.resources.alerts import AsyncAlertsResource
|
|
10
10
|
from blackshield.resources.api_keys import AsyncApiKeysResource
|
|
11
|
+
from blackshield.resources.appliances import AsyncAppliancesResource
|
|
11
12
|
from blackshield.resources.assertions import AsyncAssertionsResource
|
|
12
13
|
from blackshield.resources.audit import AsyncAuditResource
|
|
13
14
|
from blackshield.resources.compliance import AsyncComplianceResource
|
|
@@ -25,6 +26,7 @@ from blackshield.resources.oauth_apps import AsyncOAuthAppsResource
|
|
|
25
26
|
from blackshield.resources.policies import AsyncPoliciesResource
|
|
26
27
|
from blackshield.resources.remediation import AsyncRemediationResource
|
|
27
28
|
from blackshield.resources.reports import AsyncReportsResource
|
|
29
|
+
from blackshield.resources.rules import AsyncRulesResource
|
|
28
30
|
from blackshield.resources.runbooks import AsyncRunbooksResource
|
|
29
31
|
from blackshield.resources.security_agents import AsyncSecurityAgentsResource
|
|
30
32
|
from blackshield.resources.security_reviews import AsyncSecurityReviewsResource
|
|
@@ -82,6 +84,8 @@ class AsyncBlackShield:
|
|
|
82
84
|
self._oauth_apps = AsyncOAuthAppsResource(self._http)
|
|
83
85
|
self._customer_notifications = AsyncCustomerNotificationsResource(self._http)
|
|
84
86
|
self._threat_modeling = AsyncThreatModelingResource(self._http)
|
|
87
|
+
self._rules = AsyncRulesResource(self._http)
|
|
88
|
+
self._appliances = AsyncAppliancesResource(self._http)
|
|
85
89
|
|
|
86
90
|
@property
|
|
87
91
|
def findings(self) -> AsyncFindingsResource:
|
|
@@ -203,6 +207,16 @@ class AsyncBlackShield:
|
|
|
203
207
|
def threat_modeling(self) -> AsyncThreatModelingResource:
|
|
204
208
|
return self._threat_modeling
|
|
205
209
|
|
|
210
|
+
@property
|
|
211
|
+
def rules(self) -> AsyncRulesResource:
|
|
212
|
+
"""Detection ruleset operations."""
|
|
213
|
+
return self._rules
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def appliances(self) -> AsyncAppliancesResource:
|
|
217
|
+
"""Appliance configuration operations."""
|
|
218
|
+
return self._appliances
|
|
219
|
+
|
|
206
220
|
async def close(self) -> None:
|
|
207
221
|
"""Close the underlying async HTTP client."""
|
|
208
222
|
await self._http.close()
|
|
@@ -8,6 +8,7 @@ from blackshield.resources.ai_gateway import AiGatewayResource
|
|
|
8
8
|
from blackshield.resources.ai_integrations import AiIntegrationsResource
|
|
9
9
|
from blackshield.resources.alerts import AlertsResource
|
|
10
10
|
from blackshield.resources.api_keys import ApiKeysResource
|
|
11
|
+
from blackshield.resources.appliances import AppliancesResource
|
|
11
12
|
from blackshield.resources.assertions import AssertionsResource
|
|
12
13
|
from blackshield.resources.audit import AuditResource
|
|
13
14
|
from blackshield.resources.compliance import ComplianceResource
|
|
@@ -25,6 +26,7 @@ from blackshield.resources.oauth_apps import OAuthAppsResource
|
|
|
25
26
|
from blackshield.resources.policies import PoliciesResource
|
|
26
27
|
from blackshield.resources.remediation import RemediationResource
|
|
27
28
|
from blackshield.resources.reports import ReportsResource
|
|
29
|
+
from blackshield.resources.rules import RulesResource
|
|
28
30
|
from blackshield.resources.runbooks import RunbooksResource
|
|
29
31
|
from blackshield.resources.security_agents import SecurityAgentsResource
|
|
30
32
|
from blackshield.resources.security_reviews import SecurityReviewsResource
|
|
@@ -92,6 +94,8 @@ class BlackShield:
|
|
|
92
94
|
self._oauth_apps = OAuthAppsResource(self._http)
|
|
93
95
|
self._customer_notifications = CustomerNotificationsResource(self._http)
|
|
94
96
|
self._threat_modeling = ThreatModelingResource(self._http)
|
|
97
|
+
self._rules = RulesResource(self._http)
|
|
98
|
+
self._appliances = AppliancesResource(self._http)
|
|
95
99
|
|
|
96
100
|
@property
|
|
97
101
|
def findings(self) -> FindingsResource:
|
|
@@ -238,6 +242,16 @@ class BlackShield:
|
|
|
238
242
|
"""Hosted threat-modeling sessions and exports."""
|
|
239
243
|
return self._threat_modeling
|
|
240
244
|
|
|
245
|
+
@property
|
|
246
|
+
def rules(self) -> RulesResource:
|
|
247
|
+
"""Detection ruleset operations."""
|
|
248
|
+
return self._rules
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def appliances(self) -> AppliancesResource:
|
|
252
|
+
"""Appliance configuration operations."""
|
|
253
|
+
return self._appliances
|
|
254
|
+
|
|
241
255
|
def close(self) -> None:
|
|
242
256
|
"""Close the underlying HTTP client."""
|
|
243
257
|
self._http.close()
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from blackshield.resources.ai_assets import AiAssetsResource, AsyncAiAssetsResource
|
|
4
4
|
from blackshield.resources.ai_integrations import AiIntegrationsResource, AsyncAiIntegrationsResource
|
|
5
|
+
from blackshield.resources.appliances import AppliancesResource, AsyncAppliancesResource
|
|
5
6
|
from blackshield.resources.assertions import AssertionsResource, AsyncAssertionsResource
|
|
6
7
|
from blackshield.resources.customer_notifications import (
|
|
7
8
|
AsyncCustomerNotificationsResource,
|
|
@@ -10,6 +11,7 @@ from blackshield.resources.customer_notifications import (
|
|
|
10
11
|
from blackshield.resources.dast import AsyncDastResource, DastResource
|
|
11
12
|
from blackshield.resources.evidence import AsyncEvidenceResource, EvidenceResource
|
|
12
13
|
from blackshield.resources.oauth_apps import AsyncOAuthAppsResource, OAuthAppsResource
|
|
14
|
+
from blackshield.resources.rules import AsyncRulesResource, RulesResource
|
|
13
15
|
from blackshield.resources.runbooks import AsyncRunbooksResource, RunbooksResource
|
|
14
16
|
from blackshield.resources.security_agents import AsyncSecurityAgentsResource, SecurityAgentsResource
|
|
15
17
|
from blackshield.resources.siem import AsyncSiemResource, SiemResource
|
|
@@ -18,14 +20,17 @@ from blackshield.resources.threat_modeling import AsyncThreatModelingResource, T
|
|
|
18
20
|
__all__ = [
|
|
19
21
|
"AiAssetsResource",
|
|
20
22
|
"AiIntegrationsResource",
|
|
23
|
+
"AppliancesResource",
|
|
21
24
|
"AssertionsResource",
|
|
22
25
|
"AsyncAiAssetsResource",
|
|
23
26
|
"AsyncAiIntegrationsResource",
|
|
27
|
+
"AsyncAppliancesResource",
|
|
24
28
|
"AsyncAssertionsResource",
|
|
25
29
|
"AsyncCustomerNotificationsResource",
|
|
26
30
|
"AsyncDastResource",
|
|
27
31
|
"AsyncEvidenceResource",
|
|
28
32
|
"AsyncOAuthAppsResource",
|
|
33
|
+
"AsyncRulesResource",
|
|
29
34
|
"AsyncRunbooksResource",
|
|
30
35
|
"AsyncSecurityAgentsResource",
|
|
31
36
|
"AsyncSiemResource",
|
|
@@ -34,6 +39,7 @@ __all__ = [
|
|
|
34
39
|
"DastResource",
|
|
35
40
|
"EvidenceResource",
|
|
36
41
|
"OAuthAppsResource",
|
|
42
|
+
"RulesResource",
|
|
37
43
|
"RunbooksResource",
|
|
38
44
|
"SecurityAgentsResource",
|
|
39
45
|
"SiemResource",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Appliance configuration resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from blackshield.types.appliances import ApplianceConfig
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from blackshield._base_client import AsyncHTTPClient, SyncHTTPClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AppliancesResource:
|
|
14
|
+
"""Synchronous appliance configuration operations."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, client: SyncHTTPClient) -> None:
|
|
17
|
+
self._client = client
|
|
18
|
+
|
|
19
|
+
def get(self, kind: str) -> ApplianceConfig | None:
|
|
20
|
+
"""Fetch latest published configuration for an appliance kind, or None if not found."""
|
|
21
|
+
try:
|
|
22
|
+
response = self._client.get(f"/api/v1/appliance-config/{kind}")
|
|
23
|
+
return ApplianceConfig.model_validate(response.json())
|
|
24
|
+
except Exception as exc:
|
|
25
|
+
if getattr(exc, "status_code", None) == 404:
|
|
26
|
+
return None
|
|
27
|
+
raise
|
|
28
|
+
|
|
29
|
+
def publish(self, kind: str, *, config: dict[str, Any]) -> ApplianceConfig:
|
|
30
|
+
"""Publish a new appliance configuration."""
|
|
31
|
+
response = self._client.post(f"/api/v1/appliance-config/{kind}/publish", json={"config": config})
|
|
32
|
+
return ApplianceConfig.model_validate(response.json())
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AsyncAppliancesResource:
|
|
36
|
+
"""Asynchronous appliance configuration operations."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, client: AsyncHTTPClient) -> None:
|
|
39
|
+
self._client = client
|
|
40
|
+
|
|
41
|
+
async def get(self, kind: str) -> ApplianceConfig | None:
|
|
42
|
+
"""Fetch latest published configuration for an appliance kind, or None if not found."""
|
|
43
|
+
try:
|
|
44
|
+
response = await self._client.get(f"/api/v1/appliance-config/{kind}")
|
|
45
|
+
return ApplianceConfig.model_validate(response.json())
|
|
46
|
+
except Exception as exc:
|
|
47
|
+
if getattr(exc, "status_code", None) == 404:
|
|
48
|
+
return None
|
|
49
|
+
raise
|
|
50
|
+
|
|
51
|
+
async def publish(self, kind: str, *, config: dict[str, Any]) -> ApplianceConfig:
|
|
52
|
+
"""Publish a new appliance configuration."""
|
|
53
|
+
response = await self._client.post(f"/api/v1/appliance-config/{kind}/publish", json={"config": config})
|
|
54
|
+
return ApplianceConfig.model_validate(response.json())
|
|
@@ -11,6 +11,10 @@ from blackshield.types.identity import (
|
|
|
11
11
|
OIDCConfig,
|
|
12
12
|
SCIMConfig,
|
|
13
13
|
SCIMRotateResponse,
|
|
14
|
+
SpiffeBundle,
|
|
15
|
+
SshCaInfo,
|
|
16
|
+
SshCertificate,
|
|
17
|
+
WorkloadAttestation,
|
|
14
18
|
)
|
|
15
19
|
|
|
16
20
|
|
|
@@ -63,6 +67,26 @@ class IdentityResource:
|
|
|
63
67
|
resp = self._client.get("/api/v1/identity/audit")
|
|
64
68
|
return [IdentityAuditEvent.model_validate(e) for e in resp.json()]
|
|
65
69
|
|
|
70
|
+
def get_spiffe_bundle(self) -> SpiffeBundle:
|
|
71
|
+
"""Fetch SPIFFE trust bundle."""
|
|
72
|
+
resp = self._client.get("/api/v1/identity/spiffe-bundle")
|
|
73
|
+
return SpiffeBundle.model_validate(resp.json())
|
|
74
|
+
|
|
75
|
+
def attest_workload(self, **payload: Any) -> WorkloadAttestation:
|
|
76
|
+
"""Attest workload identity."""
|
|
77
|
+
resp = self._client.post("/api/v1/identity/workloads/attest", json=payload)
|
|
78
|
+
return WorkloadAttestation.model_validate(resp.json())
|
|
79
|
+
|
|
80
|
+
def get_ssh_ca_info(self) -> SshCaInfo:
|
|
81
|
+
"""Fetch SSH CA public key information."""
|
|
82
|
+
resp = self._client.get("/api/v1/identity/ssh-ca")
|
|
83
|
+
return SshCaInfo.model_validate(resp.json())
|
|
84
|
+
|
|
85
|
+
def request_ssh_certificate(self, **payload: Any) -> SshCertificate:
|
|
86
|
+
"""Request signed ephemeral SSH certificate."""
|
|
87
|
+
resp = self._client.post("/api/v1/identity/ssh-certificate", json=payload)
|
|
88
|
+
return SshCertificate.model_validate(resp.json())
|
|
89
|
+
|
|
66
90
|
|
|
67
91
|
class AsyncIdentityResource:
|
|
68
92
|
"""Async identity operations."""
|
|
@@ -85,3 +109,23 @@ class AsyncIdentityResource:
|
|
|
85
109
|
async def list_audit_events(self) -> list[IdentityAuditEvent]:
|
|
86
110
|
resp = await self._client.get("/api/v1/identity/audit")
|
|
87
111
|
return [IdentityAuditEvent.model_validate(e) for e in resp.json()]
|
|
112
|
+
|
|
113
|
+
async def get_spiffe_bundle(self) -> SpiffeBundle:
|
|
114
|
+
"""Fetch SPIFFE trust bundle."""
|
|
115
|
+
resp = await self._client.get("/api/v1/identity/spiffe-bundle")
|
|
116
|
+
return SpiffeBundle.model_validate(resp.json())
|
|
117
|
+
|
|
118
|
+
async def attest_workload(self, **payload: Any) -> WorkloadAttestation:
|
|
119
|
+
"""Attest workload identity."""
|
|
120
|
+
resp = await self._client.post("/api/v1/identity/workloads/attest", json=payload)
|
|
121
|
+
return WorkloadAttestation.model_validate(resp.json())
|
|
122
|
+
|
|
123
|
+
async def get_ssh_ca_info(self) -> SshCaInfo:
|
|
124
|
+
"""Fetch SSH CA public key information."""
|
|
125
|
+
resp = await self._client.get("/api/v1/identity/ssh-ca")
|
|
126
|
+
return SshCaInfo.model_validate(resp.json())
|
|
127
|
+
|
|
128
|
+
async def request_ssh_certificate(self, **payload: Any) -> SshCertificate:
|
|
129
|
+
"""Request signed ephemeral SSH certificate."""
|
|
130
|
+
resp = await self._client.post("/api/v1/identity/ssh-certificate", json=payload)
|
|
131
|
+
return SshCertificate.model_validate(resp.json())
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""Detection ruleset operations resource for BlackShield SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from typing import Any, cast
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RulesResource:
|
|
10
|
+
"""Synchronous detection ruleset operations."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, client: Any) -> None:
|
|
13
|
+
self._client = client
|
|
14
|
+
|
|
15
|
+
def list(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
target_type: str | None = None,
|
|
19
|
+
category: str | None = None,
|
|
20
|
+
severity: str | None = None,
|
|
21
|
+
is_system: bool | None = None,
|
|
22
|
+
search: str | None = None,
|
|
23
|
+
parent_rule_id: str | None = None,
|
|
24
|
+
page: int = 1,
|
|
25
|
+
page_size: int = 50,
|
|
26
|
+
) -> dict[str, Any]:
|
|
27
|
+
"""List detection rules visible to the tenant."""
|
|
28
|
+
params: dict[str, Any] = {"page": page, "page_size": page_size}
|
|
29
|
+
if target_type:
|
|
30
|
+
params["target_type"] = target_type
|
|
31
|
+
if category:
|
|
32
|
+
params["category"] = category
|
|
33
|
+
if severity:
|
|
34
|
+
params["severity"] = severity
|
|
35
|
+
if is_system is not None:
|
|
36
|
+
params["is_system"] = is_system
|
|
37
|
+
if search:
|
|
38
|
+
params["search"] = search
|
|
39
|
+
if parent_rule_id:
|
|
40
|
+
params["parent_rule_id"] = parent_rule_id
|
|
41
|
+
|
|
42
|
+
resp = self._client.get("/api/v1/rules", params=params)
|
|
43
|
+
return cast(dict[str, Any], resp.json())
|
|
44
|
+
|
|
45
|
+
def get(self, rule_id: str) -> dict[str, Any]:
|
|
46
|
+
"""Retrieve a detection rule by ID."""
|
|
47
|
+
resp = self._client.get(f"/api/v1/rules/{rule_id}")
|
|
48
|
+
return cast(dict[str, Any], resp.json())
|
|
49
|
+
|
|
50
|
+
def stats(self) -> dict[str, Any]:
|
|
51
|
+
"""Retrieve ruleset catalog summary metrics."""
|
|
52
|
+
resp = self._client.get("/api/v1/rules/stats")
|
|
53
|
+
return cast(dict[str, Any], resp.json())
|
|
54
|
+
|
|
55
|
+
def create(
|
|
56
|
+
self,
|
|
57
|
+
*,
|
|
58
|
+
rule_id: str,
|
|
59
|
+
title: str,
|
|
60
|
+
description: str = "",
|
|
61
|
+
severity: str = "medium",
|
|
62
|
+
category: str = "general",
|
|
63
|
+
target_type: str = "log",
|
|
64
|
+
match_logic: dict[str, Any] | None = None,
|
|
65
|
+
mitre_attack: Sequence[str] | None = None,
|
|
66
|
+
compliance_frameworks: Sequence[str] | None = None,
|
|
67
|
+
parent_rule_id: str | None = None,
|
|
68
|
+
is_enabled: bool = True,
|
|
69
|
+
remediation_guidance: str | None = None,
|
|
70
|
+
) -> dict[str, Any]:
|
|
71
|
+
"""Create a tenant custom detection rule."""
|
|
72
|
+
payload: dict[str, Any] = {
|
|
73
|
+
"rule_id": rule_id,
|
|
74
|
+
"title": title,
|
|
75
|
+
"description": description,
|
|
76
|
+
"severity": severity,
|
|
77
|
+
"category": category,
|
|
78
|
+
"target_type": target_type,
|
|
79
|
+
"match_logic": match_logic or {},
|
|
80
|
+
"mitre_attack": list(mitre_attack or []),
|
|
81
|
+
"compliance_frameworks": list(compliance_frameworks or []),
|
|
82
|
+
"parent_rule_id": parent_rule_id,
|
|
83
|
+
"is_enabled": is_enabled,
|
|
84
|
+
"remediation_guidance": remediation_guidance,
|
|
85
|
+
}
|
|
86
|
+
resp = self._client.post("/api/v1/rules", json=payload)
|
|
87
|
+
return cast(dict[str, Any], resp.json())
|
|
88
|
+
|
|
89
|
+
def update(self, rule_id: str, **kwargs: Any) -> dict[str, Any]:
|
|
90
|
+
"""Update a tenant custom detection rule."""
|
|
91
|
+
resp = self._client.patch(f"/api/v1/rules/{rule_id}", json=kwargs)
|
|
92
|
+
return cast(dict[str, Any], resp.json())
|
|
93
|
+
|
|
94
|
+
def delete(self, rule_id: str) -> None:
|
|
95
|
+
"""Delete a tenant custom detection rule."""
|
|
96
|
+
self._client.delete(f"/api/v1/rules/{rule_id}")
|
|
97
|
+
|
|
98
|
+
def test(
|
|
99
|
+
self,
|
|
100
|
+
*,
|
|
101
|
+
payload: dict[str, Any],
|
|
102
|
+
target_type: str = "log",
|
|
103
|
+
rule_id: str | None = None,
|
|
104
|
+
rule: dict[str, Any] | None = None,
|
|
105
|
+
) -> dict[str, Any]:
|
|
106
|
+
"""Dry-run test a rule against a sample payload."""
|
|
107
|
+
req: dict[str, Any] = {"payload": payload, "target_type": target_type}
|
|
108
|
+
if rule_id:
|
|
109
|
+
req["rule_id"] = rule_id
|
|
110
|
+
if rule:
|
|
111
|
+
req["rule"] = rule
|
|
112
|
+
resp = self._client.post("/api/v1/rules/test", json=req)
|
|
113
|
+
return cast(dict[str, Any], resp.json())
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class AsyncRulesResource:
|
|
117
|
+
"""Asynchronous detection ruleset operations."""
|
|
118
|
+
|
|
119
|
+
def __init__(self, client: Any) -> None:
|
|
120
|
+
self._client = client
|
|
121
|
+
|
|
122
|
+
async def list(
|
|
123
|
+
self,
|
|
124
|
+
*,
|
|
125
|
+
target_type: str | None = None,
|
|
126
|
+
category: str | None = None,
|
|
127
|
+
severity: str | None = None,
|
|
128
|
+
is_system: bool | None = None,
|
|
129
|
+
search: str | None = None,
|
|
130
|
+
parent_rule_id: str | None = None,
|
|
131
|
+
page: int = 1,
|
|
132
|
+
page_size: int = 50,
|
|
133
|
+
) -> dict[str, Any]:
|
|
134
|
+
"""List detection rules visible to the tenant asynchronously."""
|
|
135
|
+
params: dict[str, Any] = {"page": page, "page_size": page_size}
|
|
136
|
+
if target_type:
|
|
137
|
+
params["target_type"] = target_type
|
|
138
|
+
if category:
|
|
139
|
+
params["category"] = category
|
|
140
|
+
if severity:
|
|
141
|
+
params["severity"] = severity
|
|
142
|
+
if is_system is not None:
|
|
143
|
+
params["is_system"] = is_system
|
|
144
|
+
if search:
|
|
145
|
+
params["search"] = search
|
|
146
|
+
if parent_rule_id:
|
|
147
|
+
params["parent_rule_id"] = parent_rule_id
|
|
148
|
+
|
|
149
|
+
resp = await self._client.get("/api/v1/rules", params=params)
|
|
150
|
+
return cast(dict[str, Any], resp.json())
|
|
151
|
+
|
|
152
|
+
async def get(self, rule_id: str) -> dict[str, Any]:
|
|
153
|
+
"""Retrieve a detection rule by ID asynchronously."""
|
|
154
|
+
resp = await self._client.get(f"/api/v1/rules/{rule_id}")
|
|
155
|
+
return cast(dict[str, Any], resp.json())
|
|
156
|
+
|
|
157
|
+
async def stats(self) -> dict[str, Any]:
|
|
158
|
+
"""Retrieve ruleset catalog summary metrics asynchronously."""
|
|
159
|
+
resp = await self._client.get("/api/v1/rules/stats")
|
|
160
|
+
return cast(dict[str, Any], resp.json())
|
|
161
|
+
|
|
162
|
+
async def create(
|
|
163
|
+
self,
|
|
164
|
+
*,
|
|
165
|
+
rule_id: str,
|
|
166
|
+
title: str,
|
|
167
|
+
description: str = "",
|
|
168
|
+
severity: str = "medium",
|
|
169
|
+
category: str = "general",
|
|
170
|
+
target_type: str = "log",
|
|
171
|
+
match_logic: dict[str, Any] | None = None,
|
|
172
|
+
mitre_attack: Sequence[str] | None = None,
|
|
173
|
+
compliance_frameworks: Sequence[str] | None = None,
|
|
174
|
+
parent_rule_id: str | None = None,
|
|
175
|
+
is_enabled: bool = True,
|
|
176
|
+
remediation_guidance: str | None = None,
|
|
177
|
+
) -> dict[str, Any]:
|
|
178
|
+
"""Create a tenant custom detection rule asynchronously."""
|
|
179
|
+
payload: dict[str, Any] = {
|
|
180
|
+
"rule_id": rule_id,
|
|
181
|
+
"title": title,
|
|
182
|
+
"description": description,
|
|
183
|
+
"severity": severity,
|
|
184
|
+
"category": category,
|
|
185
|
+
"target_type": target_type,
|
|
186
|
+
"match_logic": match_logic or {},
|
|
187
|
+
"mitre_attack": list(mitre_attack or []),
|
|
188
|
+
"compliance_frameworks": list(compliance_frameworks or []),
|
|
189
|
+
"parent_rule_id": parent_rule_id,
|
|
190
|
+
"is_enabled": is_enabled,
|
|
191
|
+
"remediation_guidance": remediation_guidance,
|
|
192
|
+
}
|
|
193
|
+
resp = await self._client.post("/api/v1/rules", json=payload)
|
|
194
|
+
return cast(dict[str, Any], resp.json())
|
|
195
|
+
|
|
196
|
+
async def update(self, rule_id: str, **kwargs: Any) -> dict[str, Any]:
|
|
197
|
+
"""Update a tenant custom detection rule asynchronously."""
|
|
198
|
+
resp = await self._client.patch(f"/api/v1/rules/{rule_id}", json=kwargs)
|
|
199
|
+
return cast(dict[str, Any], resp.json())
|
|
200
|
+
|
|
201
|
+
async def delete(self, rule_id: str) -> None:
|
|
202
|
+
"""Delete a tenant custom detection rule asynchronously."""
|
|
203
|
+
await self._client.delete(f"/api/v1/rules/{rule_id}")
|
|
204
|
+
|
|
205
|
+
async def test(
|
|
206
|
+
self,
|
|
207
|
+
*,
|
|
208
|
+
payload: dict[str, Any],
|
|
209
|
+
target_type: str = "log",
|
|
210
|
+
rule_id: str | None = None,
|
|
211
|
+
rule: dict[str, Any] | None = None,
|
|
212
|
+
) -> dict[str, Any]:
|
|
213
|
+
"""Dry-run test a rule against a sample payload asynchronously."""
|
|
214
|
+
req: dict[str, Any] = {"payload": payload, "target_type": target_type}
|
|
215
|
+
if rule_id:
|
|
216
|
+
req["rule_id"] = rule_id
|
|
217
|
+
if rule:
|
|
218
|
+
req["rule"] = rule
|
|
219
|
+
resp = await self._client.post("/api/v1/rules/test", json=req)
|
|
220
|
+
return cast(dict[str, Any], resp.json())
|
{blackshield_sdk-0.2.2 → blackshield_sdk-0.2.3}/src/blackshield/resources/security_agents.py
RENAMED
|
@@ -6,9 +6,12 @@ import uuid
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from blackshield.types.security_agents import (
|
|
9
|
+
AgentAssignment,
|
|
9
10
|
AgentCredential,
|
|
10
11
|
AgentInstallation,
|
|
11
12
|
AgentMission,
|
|
13
|
+
AgentRun,
|
|
14
|
+
AgentRunReport,
|
|
12
15
|
AgentWorkflow,
|
|
13
16
|
CapabilityOperation,
|
|
14
17
|
OperatorMessage,
|
|
@@ -37,6 +40,10 @@ class SecurityAgentsResource:
|
|
|
37
40
|
).json()
|
|
38
41
|
return [AgentInstallation.model_validate(item) for item in response["items"]]
|
|
39
42
|
|
|
43
|
+
def create_installation(self, **payload: Any) -> AgentInstallation:
|
|
44
|
+
response = self._client.post("/api/v1/security-agents/installations", json=payload).json()
|
|
45
|
+
return AgentInstallation.model_validate(response)
|
|
46
|
+
|
|
40
47
|
def archive_installation(self, installation_id: uuid.UUID | str) -> AgentInstallation:
|
|
41
48
|
response = self._client.post(f"/api/v1/security-agents/installations/{installation_id}/archive")
|
|
42
49
|
return AgentInstallation.model_validate(response.json())
|
|
@@ -44,6 +51,31 @@ class SecurityAgentsResource:
|
|
|
44
51
|
def delete_installation(self, installation_id: uuid.UUID | str) -> None:
|
|
45
52
|
self._client.delete(f"/api/v1/security-agents/installations/{installation_id}")
|
|
46
53
|
|
|
54
|
+
def assignments(self) -> list[AgentAssignment]:
|
|
55
|
+
response = self._client.get("/api/v1/security-agents/assignments").json()
|
|
56
|
+
return [AgentAssignment.model_validate(item) for item in response["items"]]
|
|
57
|
+
|
|
58
|
+
def create_assignment(self, **payload: Any) -> AgentAssignment:
|
|
59
|
+
response = self._client.post("/api/v1/security-agents/assignments", json=payload).json()
|
|
60
|
+
return AgentAssignment.model_validate(response)
|
|
61
|
+
|
|
62
|
+
def runs(self, *, limit: int = 100, offset: int = 0, include_archived: bool = False) -> list[AgentRun]:
|
|
63
|
+
params = {"limit": limit, "offset": offset, "include_archived": include_archived}
|
|
64
|
+
response = self._client.get("/api/v1/security-agents/runs", params=params).json()
|
|
65
|
+
return [AgentRun.model_validate(item) for item in response["items"]]
|
|
66
|
+
|
|
67
|
+
def run(self, run_id: uuid.UUID | str) -> AgentRun:
|
|
68
|
+
response = self._client.get(f"/api/v1/security-agents/runs/{run_id}").json()
|
|
69
|
+
return AgentRun.model_validate(response)
|
|
70
|
+
|
|
71
|
+
def run_report(self, run_id: uuid.UUID | str) -> AgentRunReport:
|
|
72
|
+
response = self._client.get(f"/api/v1/security-agents/runs/{run_id}/report").json()
|
|
73
|
+
return AgentRunReport.model_validate(response)
|
|
74
|
+
|
|
75
|
+
def archive_run(self, run_id: uuid.UUID | str) -> AgentRun:
|
|
76
|
+
response = self._client.post(f"/api/v1/security-agents/runs/{run_id}/archive").json()
|
|
77
|
+
return AgentRun.model_validate(response)
|
|
78
|
+
|
|
47
79
|
def credentials(self) -> list[AgentCredential]:
|
|
48
80
|
response = self._client.get("/api/v1/security-agents/credentials").json()
|
|
49
81
|
return [AgentCredential.model_validate(item) for item in response["items"]]
|
|
@@ -136,14 +168,14 @@ class AsyncSecurityAgentsResource:
|
|
|
136
168
|
return [CapabilityOperation.model_validate(item) for item in response["operations"]]
|
|
137
169
|
|
|
138
170
|
async def installations(self, *, include_archived: bool = False) -> list[AgentInstallation]:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
"/api/v1/security-agents/installations",
|
|
142
|
-
params={"include_archived": include_archived},
|
|
143
|
-
)
|
|
144
|
-
).json()
|
|
171
|
+
params = {"include_archived": include_archived}
|
|
172
|
+
response = (await self._client.get("/api/v1/security-agents/installations", params=params)).json()
|
|
145
173
|
return [AgentInstallation.model_validate(item) for item in response["items"]]
|
|
146
174
|
|
|
175
|
+
async def create_installation(self, **payload: Any) -> AgentInstallation:
|
|
176
|
+
response = (await self._client.post("/api/v1/security-agents/installations", json=payload)).json()
|
|
177
|
+
return AgentInstallation.model_validate(response)
|
|
178
|
+
|
|
147
179
|
async def archive_installation(self, installation_id: uuid.UUID | str) -> AgentInstallation:
|
|
148
180
|
response = await self._client.post(f"/api/v1/security-agents/installations/{installation_id}/archive")
|
|
149
181
|
return AgentInstallation.model_validate(response.json())
|
|
@@ -151,6 +183,30 @@ class AsyncSecurityAgentsResource:
|
|
|
151
183
|
async def delete_installation(self, installation_id: uuid.UUID | str) -> None:
|
|
152
184
|
await self._client.delete(f"/api/v1/security-agents/installations/{installation_id}")
|
|
153
185
|
|
|
186
|
+
async def assignments(self) -> list[AgentAssignment]:
|
|
187
|
+
response = (await self._client.get("/api/v1/security-agents/assignments")).json()
|
|
188
|
+
return [AgentAssignment.model_validate(item) for item in response["items"]]
|
|
189
|
+
|
|
190
|
+
async def create_assignment(self, **payload: Any) -> AgentAssignment:
|
|
191
|
+
response = (await self._client.post("/api/v1/security-agents/assignments", json=payload)).json()
|
|
192
|
+
return AgentAssignment.model_validate(response)
|
|
193
|
+
|
|
194
|
+
async def runs(self, *, limit: int = 100, offset: int = 0, include_archived: bool = False) -> list[AgentRun]:
|
|
195
|
+
params = {"limit": limit, "offset": offset, "include_archived": include_archived}
|
|
196
|
+
response = (await self._client.get("/api/v1/security-agents/runs", params=params)).json()
|
|
197
|
+
return [AgentRun.model_validate(item) for item in response["items"]]
|
|
198
|
+
|
|
199
|
+
async def run(self, run_id: uuid.UUID | str) -> AgentRun:
|
|
200
|
+
return AgentRun.model_validate((await self._client.get(f"/api/v1/security-agents/runs/{run_id}")).json())
|
|
201
|
+
|
|
202
|
+
async def run_report(self, run_id: uuid.UUID | str) -> AgentRunReport:
|
|
203
|
+
response = (await self._client.get(f"/api/v1/security-agents/runs/{run_id}/report")).json()
|
|
204
|
+
return AgentRunReport.model_validate(response)
|
|
205
|
+
|
|
206
|
+
async def archive_run(self, run_id: uuid.UUID | str) -> AgentRun:
|
|
207
|
+
res = await self._client.post(f"/api/v1/security-agents/runs/{run_id}/archive")
|
|
208
|
+
return AgentRun.model_validate(res.json())
|
|
209
|
+
|
|
154
210
|
async def credentials(self) -> list[AgentCredential]:
|
|
155
211
|
response = (await self._client.get("/api/v1/security-agents/credentials")).json()
|
|
156
212
|
return [AgentCredential.model_validate(item) for item in response["items"]]
|