Metadata-Version: 2.4
Name: carryall-baton-backend
Version: 0.1.0
Summary: ConductorOne Baton adapter for Authority Runtime — plug a baton-github .c1z file into Carryall as an identity-graph backend
Author: Tronmongoose LLC
License: MIT
Project-URL: Homepage, https://github.com/tronmongoose/carryall-baton-backend
Project-URL: Repository, https://github.com/tronmongoose/carryall-baton-backend
Project-URL: Authority Runtime, https://github.com/tronmongoose/agent.carryall
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: authority-runtime>=0.4.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Dynamic: license-file

# carryall-baton-backend

**A Carryall backend that reads ConductorOne Baton `.c1z` files.**

Plugs a [Baton](https://github.com/ConductorOne/baton) sync (produced by any `baton-*` connector — `baton-github`, `baton-okta`, `baton-snowflake`, …) into [Authority Runtime](https://github.com/tronmongoose/agent.carryall) as an identity-graph source of truth for Carryall's runtime authorization layer.

| Layer | Who owns it | What it does |
|---|---|---|
| Entitlement graph | ConductorOne Baton | `baton-github` → `sync.c1z` (a gzipped SQLite) |
| **Adapter (this package)** | **you** | Projects the `.c1z` into Carryall's `Backend` Protocol |
| Runtime authorization | Authority Runtime / Carryall | Intent → compiled scopes → signed envelope → enforced action |

---

## Install

```bash
pip install carryall-baton-backend
```

Requires `authority-runtime>=0.4.0` (the release that introduced the
`Backend` Protocol and entry-point-driven backend loading).

## Quick start

```python
from carryall_baton import BatonBackend

backend = BatonBackend(
    c1z_path="./sync.c1z",
    agent_to_principal={"release-agent": "alice"},  # Carryall agent_id → GitHub username
)
```

Or load it the Carryall-idiomatic way via `CARRYALL_SLOS_CONFIG`:

```json
{
  "backend": "baton",
  "init": {
    "c1z_path": "./sync.c1z",
    "agent_to_principal": { "release-agent": "alice" }
  }
}
```

```bash
export CARRYALL_SLOS_CONFIG=./backend.json
carryall shell                     # or any other CLI subcommand
```

Under the hood, Authority Runtime's `load_backend()` resolves the `"baton"` name via the `authority_runtime.backends` entry-point group that this package registers.

## Producing a `.c1z`

You need a baton sync to point this backend at. Example for GitHub:

```bash
# https://github.com/ConductorOne/baton-github
BATON_TOKEN=<github-pat> baton-github
# produces sync.c1z in the current directory
```

The adapter works against any `.c1z` that follows the baton-sdk v1 schema (`v1_resources`, `v1_entitlements`, `v1_grants`).

## Access decision model

`BatonBackend.check_access(envelope, action, uri)` tries three things, in order:

1. **Envelope scope match.** If the envelope's `authority.scopes` already contains `vault:{vault}:{action}` or `vault:{vault}:*`, allow. This is the same short-circuit `MemoryBackend` uses.
2. **Baton grant match.** If `agent_to_principal` maps `envelope.agent_id` to a baton principal that has a grant matching `action` on the target resource, allow. `admin` and `maintain` entitlements grant any action; `write` grants imply `read`.
3. **Default deny.** With a clear `reason` + `metadata` on the returned `PolicyResult`.

## URI shape

```
slos://vaults/{org}/{repo}
```

The `slos://` scheme is reused from Authority Runtime's existing convention so the same Carryall tools/tests can target either a SLOS, Memory, or Baton backend without re-plumbing. The `{vault}` and `{resource}` are derived from Baton's `external_id` by splitting on the first `/` (the baton-github convention).

Override by subclassing `BatonBackend` and replacing any of the helpers in `carryall_baton.mapping`.

## What v0.1 does not do

- **No protobuf decoding.** The `.c1z`'s `data` blobs (containing display names, descriptions, and connector-specific metadata) are untouched; everything the adapter surfaces comes from indexed columns. That means display names fall back to `external_id`. A future version may add `protobuf` as an optional dependency.
- **No write path.** `write_document` raises `NotImplementedError`. Baton syncs are produced by connectors — not written to by agents.
- **Single-org scope.** Grants across multiple orgs work fine, but the convention of "vault = org" assumes one primary org per sync. For multi-org syncs, subclass and override `split_external_id`.

## Testing & development

The test suite uses a programmatically-generated synthetic `.c1z` (see `tests/conftest.py`) — no external dependencies, no live baton sync required. The fixture models a small GitHub-ish organization (3 users, 2 teams, 3 repos, 9 grants) and exercises both the envelope-scope and baton-grant decision paths.

```bash
pip install -e ".[dev]"
pytest
```

## License

MIT. See [LICENSE](LICENSE).

The upstream `authority-runtime` library is under BSL 1.1; this adapter is intentionally MIT so that integration work done here is maximally reusable.
