Blacksands Bursar Python SDK
Python client for the Blacksands Bursar API -- zero-trust network security provisioning, certificate management, compliance, and posture verification.
Installation
pip install blacksands-shield
For development:
pip install -e ".[dev]"
Quickstart
from blacksands_shield import ShieldClient
client = ShieldClient(
client_cert="/path/to/client.crt",
client_key="/path/to/client.key",
ca_cert="/path/to/blacksands-ca.crt", # optional
)
# Create an organisation
org = client.orgs.create("Acme Corp", "admin@acme.com", tier="professional")
org_id = org["data"]["id"]
# Register an application
app = client.apps.register(org_id, "web-frontend", framework="react")
app_id = app["data"]["id"]
# Generate a certificate
cert = client.certs.generate(app_id)
# Provision an endpoint
ep = client.endpoints.provision(app_id, "ingress", "api.acme.com", 443)
# Run a verification scan and wait for results
scan = client.verify.scan(app_id)
result = client.operations.poll_until_complete(scan["data"]["operationId"])
Authentication
The Shield SDK uses mTLS client certificates exclusively. API-key authentication is not supported. An mTLS certificate bundle is issued by a Blacksands administrator through Overwatch or SysAdmin and delivered to the caller out-of-band.
client = ShieldClient(
client_cert="/path/to/client.crt",
client_key="/path/to/client.key",
)
The cert and key are attached to the underlying requests session via session.cert.
Configuration
client = ShieldClient(
client_cert="/path/to/client.crt",
client_key="/path/to/client.key",
ca_cert="/path/to/blacksands-ca.crt", # optional: pin the server cert
base_url="https://shield.blacksands.io/v1", # default
timeout=30, # seconds, default
max_retries=3, # retries on 5xx / connection errors, default
)
API Reference
Organisations -- client.orgs
| Method |
Description |
create(name, contact_email, tier="essentials") |
Create a new organisation |
get(org_id) |
Get organisation by ID |
list(limit=20, offset=0) |
List organisations |
update(org_id, **kwargs) |
Update organisation fields |
Applications -- client.apps
| Method |
Description |
register(org_id, name, version=None, framework=None, runtime=None) |
Register a new app |
get(app_id) |
Get application by ID |
list(org_id, limit=20, offset=0) |
List apps for an org |
decommission(app_id) |
Decommission an app |
Certificates -- client.certs
| Method |
Description |
generate(app_id, algorithm="RSA-2048") |
Generate a new certificate |
rotate(app_id, cert_id) |
Rotate a certificate |
revoke(app_id, cert_id) |
Revoke a certificate |
list(app_id, limit=20, offset=0) |
List certificates for an app |
Endpoints -- client.endpoints
| Method |
Description |
provision(app_id, type, hostname, port, protocol="https") |
Provision an endpoint |
list(app_id, limit=20, offset=0) |
List endpoints |
verify(app_id, endpoint_id) |
Verify an endpoint |
deprovision(app_id, endpoint_id) |
Deprovision an endpoint |
Policies -- client.policies
| Method |
Description |
create(app_id, type, name, rules, priority=1) |
Create a policy |
update(app_id, policy_id, **kwargs) |
Update a policy |
apply(app_id) |
Apply all policies for an app |
list(app_id, limit=20, offset=0) |
List policies |
DNS -- client.dns
| Method |
Description |
allow(app_id, domain, reason=None) |
Allow a domain |
block(app_id, domain, reason=None) |
Block a domain |
scan(app_id) |
Trigger a DNS scan |
report(app_id) |
Get DNS report |
Manifests -- client.manifests
| Method |
Description |
submit(org_id, manifest) |
Submit a deployment manifest |
get(manifest_id) |
Get manifest by ID |
provision(manifest_id) |
Provision from manifest |
diff(manifest_id, compare_version) |
Diff against a version |
Verify -- client.verify
| Method |
Description |
scan(app_id) |
Trigger a posture scan |
get_result(operation_id) |
Get scan result |
get_latest(app_id) |
Get latest posture |
Compliance -- client.compliance
| Method |
Description |
get_status(app_id) |
Get compliance status |
generate_report(app_id, framework="SOC2") |
Generate a report |
get_controls(framework) |
List controls for a framework |
get_history(app_id) |
Get compliance history |
Operations -- client.operations
| Method |
Description |
get_status(operation_id) |
Get operation status |
poll_until_complete(operation_id, timeout=120, interval=3) |
Block until done |
Sessions -- client.sessions
| Method |
Description |
list(app_id) |
List active sessions |
get(session_id) |
Get session details |
terminate(session_id) |
Terminate a session |
Error Handling
from blacksands_shield.exceptions import (
ShieldAPIError,
AuthenticationError,
RateLimitError,
NotFoundError,
ValidationError,
)
try:
client.orgs.get("nonexistent")
except NotFoundError as e:
print(f"Not found: {e} (HTTP {e.status_code})")
except AuthenticationError:
print("Check your API key")
except RateLimitError:
print("Slow down -- rate limit hit")
except ShieldAPIError as e:
print(f"API error: {e}")
All exceptions carry status_code and response attributes.
License
MIT