Metadata-Version: 2.5
Name: ratelkey-burrow-sdk
Version: 0.1.0
Summary: Read secrets from a self-hosted RatelKey Burrow with a machine identity.
Project-URL: Homepage, https://ratelkey.com
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: burrow,ratelkey,sdk,secrets
Requires-Python: >=3.9
Requires-Dist: cryptography>=41.0.0
Description-Content-Type: text/markdown

# Burrow SDK for Python

Read secrets from a self-hosted [RatelKey](https://ratelkey.com) Burrow with a machine identity.

- Single and structured secrets, and individual fields of a structured secret.
- The machine's own access map (`list_projects`, `list_secrets`).
- Certificate pinning, or standard CA trust (`TlsMode`).
- An OIDC token instead of a key (`Burrow.oidc`).

## Requirements

- Python 3.9+.
- One dependency: [`cryptography`](https://pypi.org/project/cryptography/) (Ed25519 signing and the certificate pin).

## Install

```
pip install ratelkey-burrow-sdk
```

## Bootstrap a machine

From the Burrow dashboard, **Machines → Add machine**, and run the install it gives you on the target host.
The identity lands at `~/.burrow/burrows/<slug>/identity.json`.

## Quick start

```python
from ratelkey_burrow import Burrow

# The single machine identity on this host (under ~/.burrow, or $BURROW_HOME).
burrow = Burrow()

# A single-value secret:
api_key = burrow.get_secret("payments/prod/API_KEY").value

# A structured secret — one read, projected locally (no re-fetch):
db = burrow.get_secret("payments/prod/DATABASE")
everything = db.to_dict()                                  # every field as name -> value
host = db.get_field("host")                                # one field
user, password = db.get_fields("username", "password")     # in order

# What this machine can read:
for p in burrow.list_projects():
    print(p.project, p.categories)
```

Point it at a specific identity by selector or path:

```python
Burrow("burrow-a1b2c3d4e5f60718")                            # slug / name / machine id / URL
Burrow("/home/you/.burrow/burrows/burrow-a1b2c3d4e5f60718")  # path (a burrow dir or identity.json)
```

## Without `~/.burrow`

For an app that manages its own key material:

```python
import os
from ratelkey_burrow import Burrow

burrow = Burrow.connect(
    burrow_url="https://burrow.internal:12010",
    machine_id="...",
    private_key_pem=os.environ["BURROW_MACHINE_KEY"],  # PKCS#8 PEM
)
```

## OIDC

```python
import os
from ratelkey_burrow import Burrow

burrow = Burrow.oidc(
    burrow_url="https://burrow.example.com",
    fingerprint=os.environ.get("BURROW_FINGERPRINT"),  # omit for a publicly-trusted certificate
)

api_key = burrow.get_secret("payments/prod/API_KEY").value
```

`audience` defaults to `burrow_url`. GitHub Actions currently requires `permissions: id-token: write`.

## Certificate trust

```python
from ratelkey_burrow import Burrow, TlsMode

burrow = Burrow(tls=TlsMode.SystemTrust)
```

- `TlsMode.Pinned` (default) — trust-on-first-use, stored at `~/.burrow/burrows/<slug>/known_cert`.
- `TlsMode.PinnedTo("aa:bb:...")` — a fixed fingerprint (from the Burrow's network settings).
- `TlsMode.SystemTrust` — CA + hostname verification, for a Burrow on a custom domain or Let's Encrypt.

## Errors

Every failure is a `BurrowError`: `BurrowAuthError` (401), `BurrowForbiddenError` (403, no grant),
`BurrowNotFoundError` (404), `BurrowServerError` (5xx), `BurrowCertificateError` (pin mismatch),
`BurrowTransportError` (unreachable / unparsable), `BurrowIdentityError` (no/ambiguous/invalid identity),
plus two projection errors on the result handle — `SecretShapeError` (e.g. `.value` on a structured secret)
and `FieldNotFoundError`. The message carries the Burrow's own reason.

## Build

```
python -m build
```
