Metadata-Version: 2.4
Name: veltro-sdk
Version: 0.35.3
Summary: Python client for the Veltro security operations suite (VectorFlow, CHAD, Warden).
Project-URL: Repository, https://github.com/veltrosecurity/veltro
Project-URL: Documentation, https://veltrosecurity.github.io/veltro/operate/sdks/
Author: Veltro Security
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: sdk,security,siem,soar,veltro
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# veltro-sdk

Python client for the [Veltro](https://github.com/veltrosecurity/veltro) security
operations suite: **VectorFlow** (telemetry pipelines), **CHAD** (detection) and
**Warden** (SOAR / cases).

- No runtime dependencies — stdlib `urllib` only.
- Generated from the products' own OpenAPI documents, with a CI gate that fails
  when a product's API moves and the bindings do not
  (`scripts/generate_sdk.py check`).
- Apache-2.0, so it can be embedded in your own tooling regardless of the
  AGPL-3.0 servers it talks to.

Install:

```bash
pip install veltro-sdk
```

## Suite deployment

One origin, one identity session, three products. The gateway serves CHAD at
`/chad`, Warden at `/warden` and VectorFlow at `/vectorflow`, and exchanges the
identity session cookie for a short-lived request assertion toward each
product — so one login reaches all three.

```python
from veltro_sdk import VeltroClient

suite = VeltroClient.login(
    "https://soc.example.com",
    "analyst@example.com",
    password,
    vectorflow_key="vf_live_…",   # VectorFlow REST v1 takes a service-account key
)

for source in suite.chad.data_sources.list():
    print(source["name"])

cases = suite.warden.cases.list(params={"limit": 25, "status": "open"})
pipelines = suite.vectorflow.pipelines.list()
```

VectorFlow's REST v1 accepts **only** an environment-scoped service-account key
(`Authorization: Bearer vf_live_…`); a browser session authenticates the UI and
tRPC, not `/api/v1`. A client built without one refuses at the call site with
`MissingCredential` rather than sending a credential VectorFlow will reject.

## One product with a personal access token

Create a personal access token (`vmcp_…`) in the suite and send it as a bearer
to the product's gateway prefix. Identity turns it into the request assertion
the product checks, so the same token works for CHAD and Warden:

```python
from veltro_sdk import ChadClient, WardenClient, BearerToken

chad = ChadClient("https://soc.example.com/chad", auth=BearerToken(pat))
chad.rules.list()

warden = WardenClient("https://soc.example.com/warden", auth=BearerToken(pat))
warden.runbooks.list()
```

VectorFlow's `/api/v1` still wants its service-account key, so pass
`BearerToken("vf_live_…")` to `VectorFlowClient`.

## Example

[`examples/triage.py`](examples/triage.py) lists open Warden cases and new critical or high CHAD alerts
with a personal access token from `VELTRO_TOKEN`. It's read-only and isn't
part of the published package.

## Calling convention

Every operation is a method on a resource namespace. Path parameters are
positional and percent-encoded; everything else is a keyword option passed to
the transport:

```python
client.data_sources.get("ds-123")                       # path parameter
client.alerts.list(params={"status": "open", "limit": 50})
client.rules.create(json={"title": "…", "sigma_yaml": "…"})
client.export.download(raw=True)                        # bytes, not JSON
```

| Option | Meaning |
| --- | --- |
| `params` | query parameters (`None` values dropped, lists repeat the key) |
| `json` | JSON request body |
| `data` | raw request body |
| `headers` | extra headers, applied after the credential |
| `timeout` | per-request timeout override (seconds) |
| `raw` | return `bytes` instead of parsed JSON |

Responses are the products' JSON, decoded — the SDK does not reshape them. The
field-level reference is each product's OpenAPI document (`/openapi.json` on
CHAD and Warden, `/api/v1/openapi.json` on VectorFlow).

## Errors

| Exception | Raised when |
| --- | --- |
| `VeltroAPIError` | any non-2xx; carries `.status`, `.code` (the product's own refusal name), `.message`, `.body` |
| `VeltroTransportError` | the request never produced a response (DNS, TLS, connect, timeout) |
| `VeltroResponseTooLarge` | the response exceeded `max_response_bytes` (32 MiB default), enforced while streaming |
| `MissingCredential` | a product namespace was used without a credential it accepts |

`429`, `502`, `503` and `504` are retried twice with exponential backoff,
honouring `Retry-After`. Nothing else is retried: a `409` or `422` is the
product's answer, not a transient fault.

Credentials are never logged: every credential object masks its material in
`repr`, and the transport keeps request headers out of exception messages.

A suite session is scoped to the origin that minted it. Pointing a product
client at a different origin while passing `auth=session` sends no cookie
there rather than the suite session — the cookie runs through
`http.cookiejar`, so `Domain`, `Path` and `Secure` are all honoured.

## Coverage

| Product | Resources | Operations | Generated from |
| --- | --- | --- | --- |
| CHAD | 52 | 365 | CHAD 0.43.2 OpenAPI |
| Warden | 27 | 123 | Warden 0.11.7 OpenAPI |
| VectorFlow | 9 | 41 | VectorFlow REST API 2.0.0 |

Machine planes are deliberately not bound — product-peer and external
writeback seams (workload-exchange authorised), SCIM, ingest, agent enrollment,
inbound webhook receivers, the unauthenticated case portal, and VectorFlow's
tRPC transport. Each exclusion and its reason is recorded in
`sdk/specs/<product>-operations.json`.

`client.resource_names` lists the namespaces a client exposes.
