blackshield-sdk 0.1.0__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.
Potentially problematic release.
This version of blackshield-sdk might be problematic. Click here for more details.
- blackshield_sdk-0.1.0/.gitignore +52 -0
- blackshield_sdk-0.1.0/PKG-INFO +153 -0
- blackshield_sdk-0.1.0/README.md +122 -0
- blackshield_sdk-0.1.0/pyproject.toml +66 -0
- blackshield_sdk-0.1.0/src/blackshield/__init__.py +47 -0
- blackshield_sdk-0.1.0/src/blackshield/_async_client.py +130 -0
- blackshield_sdk-0.1.0/src/blackshield/_base_client.py +420 -0
- blackshield_sdk-0.1.0/src/blackshield/_client.py +156 -0
- blackshield_sdk-0.1.0/src/blackshield/_exceptions.py +74 -0
- blackshield_sdk-0.1.0/src/blackshield/_types.py +14 -0
- blackshield_sdk-0.1.0/src/blackshield/_version.py +3 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/__init__.py +1 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/ai_gateway.py +64 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/alerts.py +127 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/api_keys.py +61 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/audit.py +95 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/compliance.py +112 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/connectors.py +40 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/dashboard.py +76 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/easm.py +108 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/findings.py +221 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/identity.py +87 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/ingestion.py +178 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/policies.py +242 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/remediation.py +175 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/reports.py +109 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/security_reviews.py +158 -0
- blackshield_sdk-0.1.0/src/blackshield/resources/threat_intel.py +97 -0
- blackshield_sdk-0.1.0/src/blackshield/types/__init__.py +86 -0
- blackshield_sdk-0.1.0/src/blackshield/types/ai_gateway.py +47 -0
- blackshield_sdk-0.1.0/src/blackshield/types/alerts.py +73 -0
- blackshield_sdk-0.1.0/src/blackshield/types/api_keys.py +30 -0
- blackshield_sdk-0.1.0/src/blackshield/types/audit.py +24 -0
- blackshield_sdk-0.1.0/src/blackshield/types/compliance.py +50 -0
- blackshield_sdk-0.1.0/src/blackshield/types/connectors.py +60 -0
- blackshield_sdk-0.1.0/src/blackshield/types/dashboard.py +77 -0
- blackshield_sdk-0.1.0/src/blackshield/types/easm.py +64 -0
- blackshield_sdk-0.1.0/src/blackshield/types/findings.py +113 -0
- blackshield_sdk-0.1.0/src/blackshield/types/identity.py +76 -0
- blackshield_sdk-0.1.0/src/blackshield/types/ingestion.py +134 -0
- blackshield_sdk-0.1.0/src/blackshield/types/policies.py +78 -0
- blackshield_sdk-0.1.0/src/blackshield/types/remediation.py +87 -0
- blackshield_sdk-0.1.0/src/blackshield/types/reports.py +42 -0
- blackshield_sdk-0.1.0/src/blackshield/types/security_reviews.py +47 -0
- blackshield_sdk-0.1.0/src/blackshield/types/threat_intel.py +62 -0
- blackshield_sdk-0.1.0/tests/conftest.py +32 -0
- blackshield_sdk-0.1.0/tests/test_ai_gateway.py +38 -0
- blackshield_sdk-0.1.0/tests/test_alerts.py +49 -0
- blackshield_sdk-0.1.0/tests/test_api_keys.py +60 -0
- blackshield_sdk-0.1.0/tests/test_audit.py +48 -0
- blackshield_sdk-0.1.0/tests/test_client.py +149 -0
- blackshield_sdk-0.1.0/tests/test_compliance.py +46 -0
- blackshield_sdk-0.1.0/tests/test_connectors.py +52 -0
- blackshield_sdk-0.1.0/tests/test_dashboard.py +70 -0
- blackshield_sdk-0.1.0/tests/test_easm.py +59 -0
- blackshield_sdk-0.1.0/tests/test_findings.py +91 -0
- blackshield_sdk-0.1.0/tests/test_identity.py +73 -0
- blackshield_sdk-0.1.0/tests/test_ingestion.py +90 -0
- blackshield_sdk-0.1.0/tests/test_policies.py +88 -0
- blackshield_sdk-0.1.0/tests/test_remediation.py +67 -0
- blackshield_sdk-0.1.0/tests/test_reports.py +54 -0
- blackshield_sdk-0.1.0/tests/test_security_reviews.py +77 -0
- blackshield_sdk-0.1.0/tests/test_threat_intel.py +57 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
|
|
9
|
+
# Node
|
|
10
|
+
node_modules/
|
|
11
|
+
frontend/dist/
|
|
12
|
+
frontend/.next/
|
|
13
|
+
frontend/.serverless-frontend/
|
|
14
|
+
frontend/.amplify-hosting/
|
|
15
|
+
frontend/tsconfig.tsbuildinfo
|
|
16
|
+
|
|
17
|
+
# Environment
|
|
18
|
+
.env
|
|
19
|
+
.env.local
|
|
20
|
+
*.env
|
|
21
|
+
|
|
22
|
+
# IDE
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
*.swp
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
|
|
31
|
+
# Docker
|
|
32
|
+
docker-compose.override.yml
|
|
33
|
+
|
|
34
|
+
# CDK
|
|
35
|
+
iac/cdk.out/
|
|
36
|
+
|
|
37
|
+
# Coverage
|
|
38
|
+
htmlcov/
|
|
39
|
+
.coverage
|
|
40
|
+
coverage.xml
|
|
41
|
+
|
|
42
|
+
# Terraform (legacy)
|
|
43
|
+
.terraform/
|
|
44
|
+
*.tfstate*
|
|
45
|
+
|
|
46
|
+
.tools
|
|
47
|
+
.next
|
|
48
|
+
|
|
49
|
+
.mipy
|
|
50
|
+
|
|
51
|
+
# Local agent worktrees
|
|
52
|
+
.claude/worktrees/
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blackshield-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the BlackShield Security Platform
|
|
5
|
+
Project-URL: Homepage, https://blackshield.security
|
|
6
|
+
Project-URL: Documentation, https://docs.blackshield.security/sdk/python
|
|
7
|
+
Project-URL: Repository, https://github.com/blackshield-security/blackshield-python
|
|
8
|
+
Author-email: BlackShield Security <contact@chaplau.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx<1,>=0.27
|
|
22
|
+
Requires-Dist: pydantic<3,>=2.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: respx>=0.22; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# BlackShield Python SDK
|
|
33
|
+
|
|
34
|
+
Official Python SDK for the [BlackShield Security Platform](https://blackshield.security).
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install blackshield-sdk
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import blackshield
|
|
46
|
+
|
|
47
|
+
client = blackshield.BlackShield(api_key="bsk_live_...")
|
|
48
|
+
|
|
49
|
+
# List critical findings
|
|
50
|
+
page = client.findings.list(severity=["critical", "high"], page_size=10)
|
|
51
|
+
for f in page.items:
|
|
52
|
+
print(f"{f.severity.value} | {f.title}")
|
|
53
|
+
|
|
54
|
+
# Get a specific finding
|
|
55
|
+
finding = client.findings.get("550e8400-e29b-41d4-a716-446655440000")
|
|
56
|
+
|
|
57
|
+
# Update finding status
|
|
58
|
+
client.findings.update_status(finding.id, status="in_progress", reason="Investigating")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Async Usage
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
from blackshield import AsyncBlackShield
|
|
66
|
+
|
|
67
|
+
async def main():
|
|
68
|
+
async with AsyncBlackShield(api_key="bsk_live_...") as client:
|
|
69
|
+
page = await client.findings.list(severity=["critical"])
|
|
70
|
+
for f in page.items:
|
|
71
|
+
print(f.title)
|
|
72
|
+
|
|
73
|
+
asyncio.run(main())
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Available Resources
|
|
77
|
+
|
|
78
|
+
| Resource | Description | Example |
|
|
79
|
+
|----------|-------------|---------|
|
|
80
|
+
| `client.findings` | List, get, update findings | `client.findings.list(severity=["critical"])` |
|
|
81
|
+
| `client.ingestion` | Ingest findings & assets | `client.ingestion.ingest_findings([...])` |
|
|
82
|
+
| `client.dashboard` | Stats, trends, usage | `client.dashboard.stats()` |
|
|
83
|
+
| `client.compliance` | Compliance overview & controls | `client.compliance.overview(framework="SOC2")` |
|
|
84
|
+
| `client.reports` | Summaries & CSV/PDF exports | `client.reports.export_findings_csv()` |
|
|
85
|
+
| `client.easm` | External attack surface | `client.easm.overview()` |
|
|
86
|
+
| `client.threat_intel` | Blocklist & indicator lookup | `client.threat_intel.lookup(indicator="1.2.3.4")` |
|
|
87
|
+
| `client.connectors` | Connector health monitoring | `client.connectors.freshness()` |
|
|
88
|
+
| `client.api_keys` | API key management | `client.api_keys.create(label="CI")` |
|
|
89
|
+
|
|
90
|
+
## Ingestion
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from blackshield.types.ingestion import UnifiedFinding, AffectedResource, SourceMeta
|
|
94
|
+
|
|
95
|
+
finding = UnifiedFinding(
|
|
96
|
+
finding_type="vulnerability",
|
|
97
|
+
title="CVE-2024-1234 in openssl 3.0.8",
|
|
98
|
+
severity="critical",
|
|
99
|
+
cve_id="CVE-2024-1234",
|
|
100
|
+
affected_resource=AffectedResource(
|
|
101
|
+
resource_type="container_image",
|
|
102
|
+
resource_id="sha256:abc123",
|
|
103
|
+
resource_name="myapp:latest",
|
|
104
|
+
),
|
|
105
|
+
source=SourceMeta(scanner="trivy", scanner_version="0.50.0"),
|
|
106
|
+
dedup_key="vuln:CVE-2024-1234:sha256:abc123",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
result = client.ingestion.ingest_findings([finding])
|
|
110
|
+
print(f"Job ID: {result.job_id}, Status: {result.status}")
|
|
111
|
+
|
|
112
|
+
# Poll for completion
|
|
113
|
+
job = client.ingestion.get_job(result.job_id)
|
|
114
|
+
print(f"Created: {job.created}, Updated: {job.updated}")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Error Handling
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import blackshield
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
finding = client.findings.get("nonexistent-id")
|
|
124
|
+
except blackshield.NotFoundError:
|
|
125
|
+
print("Finding not found")
|
|
126
|
+
except blackshield.RateLimitError as e:
|
|
127
|
+
print(f"Rate limited, retry after {e.retry_after}s")
|
|
128
|
+
except blackshield.AuthenticationError:
|
|
129
|
+
print("Invalid API key")
|
|
130
|
+
except blackshield.BlackShieldError as e:
|
|
131
|
+
print(f"API error: {e}")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
client = blackshield.BlackShield(
|
|
138
|
+
api_key="bsk_live_...",
|
|
139
|
+
base_url="https://api.blackshield.security", # or self-hosted URL
|
|
140
|
+
timeout=60.0, # request timeout in seconds
|
|
141
|
+
max_retries=3, # automatic retries on 429/5xx
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Development
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
cd sdk
|
|
149
|
+
pip install -e ".[dev]"
|
|
150
|
+
pytest -v --cov=blackshield
|
|
151
|
+
ruff check .
|
|
152
|
+
mypy .
|
|
153
|
+
```
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# BlackShield Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [BlackShield Security Platform](https://blackshield.security).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install blackshield-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import blackshield
|
|
15
|
+
|
|
16
|
+
client = blackshield.BlackShield(api_key="bsk_live_...")
|
|
17
|
+
|
|
18
|
+
# List critical findings
|
|
19
|
+
page = client.findings.list(severity=["critical", "high"], page_size=10)
|
|
20
|
+
for f in page.items:
|
|
21
|
+
print(f"{f.severity.value} | {f.title}")
|
|
22
|
+
|
|
23
|
+
# Get a specific finding
|
|
24
|
+
finding = client.findings.get("550e8400-e29b-41d4-a716-446655440000")
|
|
25
|
+
|
|
26
|
+
# Update finding status
|
|
27
|
+
client.findings.update_status(finding.id, status="in_progress", reason="Investigating")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Async Usage
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
from blackshield import AsyncBlackShield
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
async with AsyncBlackShield(api_key="bsk_live_...") as client:
|
|
38
|
+
page = await client.findings.list(severity=["critical"])
|
|
39
|
+
for f in page.items:
|
|
40
|
+
print(f.title)
|
|
41
|
+
|
|
42
|
+
asyncio.run(main())
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Available Resources
|
|
46
|
+
|
|
47
|
+
| Resource | Description | Example |
|
|
48
|
+
|----------|-------------|---------|
|
|
49
|
+
| `client.findings` | List, get, update findings | `client.findings.list(severity=["critical"])` |
|
|
50
|
+
| `client.ingestion` | Ingest findings & assets | `client.ingestion.ingest_findings([...])` |
|
|
51
|
+
| `client.dashboard` | Stats, trends, usage | `client.dashboard.stats()` |
|
|
52
|
+
| `client.compliance` | Compliance overview & controls | `client.compliance.overview(framework="SOC2")` |
|
|
53
|
+
| `client.reports` | Summaries & CSV/PDF exports | `client.reports.export_findings_csv()` |
|
|
54
|
+
| `client.easm` | External attack surface | `client.easm.overview()` |
|
|
55
|
+
| `client.threat_intel` | Blocklist & indicator lookup | `client.threat_intel.lookup(indicator="1.2.3.4")` |
|
|
56
|
+
| `client.connectors` | Connector health monitoring | `client.connectors.freshness()` |
|
|
57
|
+
| `client.api_keys` | API key management | `client.api_keys.create(label="CI")` |
|
|
58
|
+
|
|
59
|
+
## Ingestion
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from blackshield.types.ingestion import UnifiedFinding, AffectedResource, SourceMeta
|
|
63
|
+
|
|
64
|
+
finding = UnifiedFinding(
|
|
65
|
+
finding_type="vulnerability",
|
|
66
|
+
title="CVE-2024-1234 in openssl 3.0.8",
|
|
67
|
+
severity="critical",
|
|
68
|
+
cve_id="CVE-2024-1234",
|
|
69
|
+
affected_resource=AffectedResource(
|
|
70
|
+
resource_type="container_image",
|
|
71
|
+
resource_id="sha256:abc123",
|
|
72
|
+
resource_name="myapp:latest",
|
|
73
|
+
),
|
|
74
|
+
source=SourceMeta(scanner="trivy", scanner_version="0.50.0"),
|
|
75
|
+
dedup_key="vuln:CVE-2024-1234:sha256:abc123",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
result = client.ingestion.ingest_findings([finding])
|
|
79
|
+
print(f"Job ID: {result.job_id}, Status: {result.status}")
|
|
80
|
+
|
|
81
|
+
# Poll for completion
|
|
82
|
+
job = client.ingestion.get_job(result.job_id)
|
|
83
|
+
print(f"Created: {job.created}, Updated: {job.updated}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Error Handling
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import blackshield
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
finding = client.findings.get("nonexistent-id")
|
|
93
|
+
except blackshield.NotFoundError:
|
|
94
|
+
print("Finding not found")
|
|
95
|
+
except blackshield.RateLimitError as e:
|
|
96
|
+
print(f"Rate limited, retry after {e.retry_after}s")
|
|
97
|
+
except blackshield.AuthenticationError:
|
|
98
|
+
print("Invalid API key")
|
|
99
|
+
except blackshield.BlackShieldError as e:
|
|
100
|
+
print(f"API error: {e}")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
client = blackshield.BlackShield(
|
|
107
|
+
api_key="bsk_live_...",
|
|
108
|
+
base_url="https://api.blackshield.security", # or self-hosted URL
|
|
109
|
+
timeout=60.0, # request timeout in seconds
|
|
110
|
+
max_retries=3, # automatic retries on 429/5xx
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
cd sdk
|
|
118
|
+
pip install -e ".[dev]"
|
|
119
|
+
pytest -v --cov=blackshield
|
|
120
|
+
ruff check .
|
|
121
|
+
mypy .
|
|
122
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "blackshield-sdk"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Official Python SDK for the BlackShield Security Platform"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "Apache-2.0"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "BlackShield Security", email = "contact@chaplau.com" }]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Security",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"httpx>=0.27,<1",
|
|
27
|
+
"pydantic>=2.0,<3",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://blackshield.security"
|
|
32
|
+
Documentation = "https://docs.blackshield.security/sdk/python"
|
|
33
|
+
Repository = "https://github.com/blackshield-security/blackshield-python"
|
|
34
|
+
|
|
35
|
+
[tool.hatch.version]
|
|
36
|
+
path = "src/blackshield/_version.py"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/blackshield"]
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"pytest>=8.0",
|
|
44
|
+
"pytest-asyncio>=0.24",
|
|
45
|
+
"respx>=0.22",
|
|
46
|
+
"ruff>=0.8",
|
|
47
|
+
"mypy>=1.13",
|
|
48
|
+
"pytest-cov>=6.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
target-version = "py310"
|
|
53
|
+
line-length = 120
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
select = ["E", "F", "I", "N", "W", "UP", "B", "SIM", "RUF"]
|
|
57
|
+
|
|
58
|
+
[tool.mypy]
|
|
59
|
+
python_version = "3.10"
|
|
60
|
+
strict = true
|
|
61
|
+
warn_return_any = true
|
|
62
|
+
warn_unused_configs = true
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
66
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""BlackShield Python SDK — Official client for the BlackShield Security Platform.
|
|
2
|
+
|
|
3
|
+
Quick start::
|
|
4
|
+
|
|
5
|
+
import blackshield
|
|
6
|
+
|
|
7
|
+
client = blackshield.BlackShield(api_key="bsk_live_...")
|
|
8
|
+
page = client.findings.list(severity=["critical", "high"])
|
|
9
|
+
for finding in page.items:
|
|
10
|
+
print(f"{finding.severity.value} | {finding.title}")
|
|
11
|
+
|
|
12
|
+
For async usage::
|
|
13
|
+
|
|
14
|
+
from blackshield import AsyncBlackShield
|
|
15
|
+
|
|
16
|
+
async with AsyncBlackShield(api_key="bsk_live_...") as client:
|
|
17
|
+
page = await client.findings.list()
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from blackshield._async_client import AsyncBlackShield
|
|
21
|
+
from blackshield._client import BlackShield
|
|
22
|
+
from blackshield._exceptions import (
|
|
23
|
+
APIError,
|
|
24
|
+
AuthenticationError,
|
|
25
|
+
BlackShieldError,
|
|
26
|
+
ConflictError,
|
|
27
|
+
NotFoundError,
|
|
28
|
+
PermissionDeniedError,
|
|
29
|
+
RateLimitError,
|
|
30
|
+
ValidationError,
|
|
31
|
+
)
|
|
32
|
+
from blackshield._version import __version__
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"APIError",
|
|
36
|
+
"AsyncBlackShield",
|
|
37
|
+
"AuthenticationError",
|
|
38
|
+
"BlackShield",
|
|
39
|
+
# Exceptions
|
|
40
|
+
"BlackShieldError",
|
|
41
|
+
"ConflictError",
|
|
42
|
+
"NotFoundError",
|
|
43
|
+
"PermissionDeniedError",
|
|
44
|
+
"RateLimitError",
|
|
45
|
+
"ValidationError",
|
|
46
|
+
"__version__",
|
|
47
|
+
]
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Asynchronous BlackShield client — async/await variant."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from blackshield._base_client import AsyncHTTPClient
|
|
6
|
+
from blackshield.resources.ai_gateway import AsyncAiGatewayResource
|
|
7
|
+
from blackshield.resources.alerts import AsyncAlertsResource
|
|
8
|
+
from blackshield.resources.api_keys import AsyncApiKeysResource
|
|
9
|
+
from blackshield.resources.audit import AsyncAuditResource
|
|
10
|
+
from blackshield.resources.compliance import AsyncComplianceResource
|
|
11
|
+
from blackshield.resources.connectors import AsyncConnectorsResource
|
|
12
|
+
from blackshield.resources.dashboard import AsyncDashboardResource
|
|
13
|
+
from blackshield.resources.easm import AsyncEasmResource
|
|
14
|
+
from blackshield.resources.findings import AsyncFindingsResource
|
|
15
|
+
from blackshield.resources.identity import AsyncIdentityResource
|
|
16
|
+
from blackshield.resources.ingestion import AsyncIngestionResource
|
|
17
|
+
from blackshield.resources.policies import AsyncPoliciesResource
|
|
18
|
+
from blackshield.resources.remediation import AsyncRemediationResource
|
|
19
|
+
from blackshield.resources.reports import AsyncReportsResource
|
|
20
|
+
from blackshield.resources.security_reviews import AsyncSecurityReviewsResource
|
|
21
|
+
from blackshield.resources.threat_intel import AsyncThreatIntelResource
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AsyncBlackShield:
|
|
25
|
+
"""Asynchronous client for the BlackShield Security Platform API."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
api_key: str,
|
|
30
|
+
*,
|
|
31
|
+
base_url: str = "https://api.blackshield.security",
|
|
32
|
+
timeout: float = 60.0,
|
|
33
|
+
max_retries: int = 3,
|
|
34
|
+
) -> None:
|
|
35
|
+
self._http = AsyncHTTPClient(
|
|
36
|
+
base_url=base_url,
|
|
37
|
+
api_key=api_key,
|
|
38
|
+
timeout=timeout,
|
|
39
|
+
max_retries=max_retries,
|
|
40
|
+
)
|
|
41
|
+
self._findings = AsyncFindingsResource(self._http)
|
|
42
|
+
self._ingestion = AsyncIngestionResource(self._http)
|
|
43
|
+
self._dashboard = AsyncDashboardResource(self._http)
|
|
44
|
+
self._compliance = AsyncComplianceResource(self._http)
|
|
45
|
+
self._reports = AsyncReportsResource(self._http)
|
|
46
|
+
self._easm = AsyncEasmResource(self._http)
|
|
47
|
+
self._threat_intel = AsyncThreatIntelResource(self._http)
|
|
48
|
+
self._connectors = AsyncConnectorsResource(self._http)
|
|
49
|
+
self._api_keys = AsyncApiKeysResource(self._http)
|
|
50
|
+
self._policies = AsyncPoliciesResource(self._http)
|
|
51
|
+
self._security_reviews = AsyncSecurityReviewsResource(self._http)
|
|
52
|
+
self._audit = AsyncAuditResource(self._http)
|
|
53
|
+
self._alerts = AsyncAlertsResource(self._http)
|
|
54
|
+
self._identity = AsyncIdentityResource(self._http)
|
|
55
|
+
self._remediation = AsyncRemediationResource(self._http)
|
|
56
|
+
self._ai_gateway = AsyncAiGatewayResource(self._http)
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def findings(self) -> AsyncFindingsResource:
|
|
60
|
+
return self._findings
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def ingestion(self) -> AsyncIngestionResource:
|
|
64
|
+
return self._ingestion
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def dashboard(self) -> AsyncDashboardResource:
|
|
68
|
+
return self._dashboard
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def compliance(self) -> AsyncComplianceResource:
|
|
72
|
+
return self._compliance
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def reports(self) -> AsyncReportsResource:
|
|
76
|
+
return self._reports
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def easm(self) -> AsyncEasmResource:
|
|
80
|
+
return self._easm
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def threat_intel(self) -> AsyncThreatIntelResource:
|
|
84
|
+
return self._threat_intel
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def connectors(self) -> AsyncConnectorsResource:
|
|
88
|
+
return self._connectors
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def api_keys(self) -> AsyncApiKeysResource:
|
|
92
|
+
return self._api_keys
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def policies(self) -> AsyncPoliciesResource:
|
|
96
|
+
return self._policies
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def security_reviews(self) -> AsyncSecurityReviewsResource:
|
|
100
|
+
return self._security_reviews
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def audit(self) -> AsyncAuditResource:
|
|
104
|
+
return self._audit
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def alerts(self) -> AsyncAlertsResource:
|
|
108
|
+
return self._alerts
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def identity(self) -> AsyncIdentityResource:
|
|
112
|
+
return self._identity
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def remediation(self) -> AsyncRemediationResource:
|
|
116
|
+
return self._remediation
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def ai_gateway(self) -> AsyncAiGatewayResource:
|
|
120
|
+
return self._ai_gateway
|
|
121
|
+
|
|
122
|
+
async def close(self) -> None:
|
|
123
|
+
"""Close the underlying async HTTP client."""
|
|
124
|
+
await self._http.close()
|
|
125
|
+
|
|
126
|
+
async def __aenter__(self) -> AsyncBlackShield:
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
async def __aexit__(self, *_args: object) -> None:
|
|
130
|
+
await self.close()
|