Python SDK
The Python client provides typed clients for APIGuard, NIS2 Compass, and CITADEL, plus dataclasses for all opensecstack SDK & Contracts integration contracts. It requires Python 3.11+. Both synchronous and async clients are available.
Installation
Install the package from PyPI:
pip install opensecstack
Import the clients you need:
from opensecstack import APIGuardClient, NIS2CompassClient from opensecstack.citadel import CITADELClient, Kerkese, Action, Principal, Evidence
Client construction
Clients accept a base_url and an api_key. An optional timeout (in seconds) can be passed; the default is 30 s. Clients support use as context managers to ensure the underlying session is closed.
from opensecstack import APIGuardClient "cm"># Standard usage client = APIGuardClient( base_url="https://apiguard.internal", api_key="ag_key_...", timeout=30, ) "cm"># Context manager — session closed automatically on exit with APIGuardClient(base_url="https://apiguard.internal", api_key="ag_key_...") as client: result = client.get_scan(scan_id)
Running a scan
Start an APIGuard scan and use the blocking wait_for_scan helper to poll until the scan completes, then iterate over the findings.
from opensecstack import APIGuardClient client = APIGuardClient(base_url="https://apiguard.internal", api_key="ag_key_...") "cm"># Start scan with selected OWASP modules scan = client.start_scan( target="https://api.example.com", spec_url="https://api.example.com/openapi.json", modules=["bola", "broken_auth", "injection"], metadata={"project": "my-project-001"}, ) print(f"Scan ID: {scan.id}") "cm"># Block until complete (polls every 5 s, times out after 600 s) result = client.wait_for_scan( scan_id=scan.id, poll_interval=5, timeout=600, ) for finding in result.findings: print(f"[{finding.severity}] {finding.owasp} — {finding.title}")
An async client is also available for non-blocking workflows:
from opensecstack import AsyncAPIGuardClient
async with AsyncAPIGuardClient(
base_url="https://apiguard.internal",
client_id="...",
client_secret="...",
) as client:
scan = await client.create_scan(spec_url="https://api.example.com/openapi.json")
result = await client.get_scan(scan["id"])NIS2 Compass client
Create an assessment, list its controls, and mark a NIS2 Article 21 measure as compliant after uploading evidence from an APIGuard scan.
from opensecstack import NIS2CompassClient nis2 = NIS2CompassClient(base_url="https://nis2compass.internal", api_key="nc_key_...") "cm"># Create organisation org = nis2.create_organisation( name="Acme Corp", industry="finance", country="AL", size="large", entity_type="essential", ) "cm"># Create assessment assessment = nis2.create_assessment( org_id=org.id, title="Q1 2026 NIS2 Assessment", framework_version="NIS2-2022/0383", ) "cm"># List controls and print current status assessment = nis2.get_assessment(org.id, assessment.id) for control in assessment.controls: print(f"{control.measure_ref}: {control.status}") "cm"># Mark control art21_e as compliant updated = nis2.patch_control( org_id=org.id, assessment_id=assessment.id, measure_ref="art21_e", status="compliant", notes="APIGuard scan completed — zero critical findings", evidence_refs=["sha256:abc123..."], )
CITADEL client
Submit a governance Kerkese request to the MARSHAL 5-gate engine and check the outcome before proceeding with a privileged action.
from opensecstack.citadel import CITADELClient, Kerkese, Action, Principal, Evidence
client = CITADELClient(
base_url="https://citadel.internal",
key_id=KEY_ID,
secret=SECRET,
)
"cm"># Check for active advisories before acting
advisory = client.get_advisory("my-project-001", "deploy_change")
if advisory.has_critical():
print(f"CITADEL advisory: {advisory.advisories}")
"cm"># Submit a governance request and evaluate
result = client.evaluate(Kerkese(
project_id="my-project-001",
action=Action(type="deploy_change", description="Deploy v2.1.0"),
actor=Principal(user_id="alice@example.com", role="group_sig_operator"),
verifier=Principal(user_id="bob@example.com", role="group_sig_verifier"),
evidence=Evidence(change_id="CHG-001"),
))
if result["outcome"] != "EXECUTE":
raise RuntimeError(f"Governance denied: {result['reasons']}")Error handling
Import exception types from opensecstack.exceptions to handle specific failure modes. RateLimitError carries a retry_after attribute (seconds) to guide back-off logic.
from opensecstack.exceptions import RateLimitError, AuthError, NotFoundError
import time
try:
result = client.start_scan(
target="https://api.example.com",
spec_url="https://api.example.com/openapi.json",
)
except RateLimitError as e:
time.sleep(e.retry_after)
result = client.start_scan(...) "cm"># retry
except AuthError:
raise "cm"># re-raise — fix the API key
except NotFoundError:
raise| Exception | HTTP status | Meaning |
|---|---|---|
AuthError | 401 | Invalid API key |
NotFoundError | 404 | Resource not found |
RateLimitError | 429 | Rate limited; has retry_after attribute |
ServerError | 5xx | Server-side error |
Full documentation
Other SDK language clients: Go SDK, TypeScript SDK, Rust SDK.
The complete Python client reference — including all method signatures, dataclass definitions, and type hints — is available in the SDK repository: