Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13
3.14
199 changes: 160 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
# Directory Python SDK

[![Release](https://img.shields.io/github/v/release/agntcy/dir-sdk-python)](CHANGELOG.md)
## Overview

## About The Project

The Directory Python SDK provides a simple way to interact with the Directory API.
Dir Python SDK provides a simple way to interact with the Directory API.
It allows developers to integrate and use Directory functionality from their Python applications with ease.

## Getting Started
## Features

To get a local copy up and running follow these simple steps.
The Directory Python SDK provides comprehensive access to all Directory APIs with a simple, intuitive interface:

### Prerequisites
### **Store API**
- **Record Management**: Push records to the store and pull them by reference
- **Metadata Operations**: Look up record metadata without downloading full content
- **Data Lifecycle**: Delete records permanently from the store
- **Referrer Support**: Push and pull artifacts for existing records
- **Sync Management**: Manage storage synchronization policies between Directory servers

- Python 3.10 or higher
- Directory server instance
- [dirctl](https://github.com/agntcy/dir/releases) - Directory CLI binary
### **Search API**
- **Flexible Search**: Search stored records using text, semantic, and structured queries
- **Advanced Filtering**: Filter results by metadata, content type, and other criteria

### Installation
### **Routing API**
- **Network Publishing**: Publish records to make them discoverable across the network
- **Content Discovery**: List and query published records across the network
- **Network Management**: Unpublish records to remove them from network discovery

```sh
uv add agntcy-dir --index https://buf.build/gen/python
### **Signing and Verification**
- **Local Signing**: Sign records locally using private keys or OIDC-based authentication.
Requires [dirctl](https://github.com/agntcy/dir/releases) binary to perform signing.
- **Remote Verification**: Verify record signatures using the Directory gRPC API

### **Developer Experience**
- **Type Safety**: Full type hints for better IDE support and fewer runtime errors
- **Async Support**: Non-blocking operations with streaming responses for large datasets
- **Error Handling**: Comprehensive gRPC error handling with detailed error messages
- **Configuration**: Flexible configuration via environment variables or direct instantiation

## Installation

Install the SDK using [uv](https://github.com/astral-sh/uv)

1. Initialize the project:
```bash
uv init
```

## Usage
2. Add the SDK to your project:
```bash
uv add agntcy-dir --index https://buf.build/gen/python
```

### Configuration
## Configuration

The SDK can be configured either via environment variables:
The SDK can be configured via environment variables or direct instantiation:

```sh
```python
# Environment variables (insecure mode, default)
export DIRECTORY_CLIENT_SERVER_ADDRESS="localhost:8888"
export DIRCTL_PATH="/path/to/dirctl"
Expand All @@ -44,11 +69,8 @@ export DIRECTORY_CLIENT_SERVER_ADDRESS="localhost:8888"
export DIRECTORY_CLIENT_AUTH_MODE="jwt"
export DIRECTORY_CLIENT_SPIFFE_SOCKET_PATH="/tmp/agent.sock"
export DIRECTORY_CLIENT_JWT_AUDIENCE="spiffe://example.org/dir-server"
```

Or via a `Config` object:

```python
# Or configure directly
from agntcy.dir_sdk.client import Config, Client

# Insecure mode (default, for development only)
Expand Down Expand Up @@ -78,13 +100,92 @@ jwt_config = Config(
jwt_client = Client(jwt_config)
```

### Error Handling
### OAuth 2.0 for Directory Bearer Auth

The Python SDK currently supports these OIDC/OAuth flows for Directory bearer auth:

- Interactive login via Authorization Code + PKCE with a loopback callback
- Pre-issued access token via `DIRECTORY_CLIENT_AUTH_TOKEN`

Interactive PKCE sessions are cached in the same location as the Go client:
`$XDG_CONFIG_HOME/dirctl/auth-token.json` or `~/.config/dirctl/auth-token.json`.
Explicit pre-issued tokens are used directly and are not cached.

Use this mode when your deployment expects a **Bearer access token** on gRPC (for example via a gateway that validates OIDC tokens). Register your IdP application with a **redirect URI** that matches `oidc_redirect_uri` exactly (for example `http://localhost:8484/callback`). The SDK starts a short-lived HTTP server on loopback to receive the authorization redirect.

Some IdPs use **public clients** with PKCE; Authlib may still expect a `client_secret` value in configuration. In that case, use a **random placeholder** from environment variables, not a real secret in source code.

**Important:** The default in-repo Envoy authz stack validates **GitHub** tokens. OIDC access tokens from your IdP provider only work if your environment’s gateway or auth service is configured to accept them.

```bash
export DIRECTORY_CLIENT_AUTH_MODE="oidc"
export DIRECTORY_CLIENT_SERVER_ADDRESS="directory.example.com:443"
export DIRECTORY_CLIENT_OIDC_ISSUER="https://your-idp-provider.example.com"
export DIRECTORY_CLIENT_OIDC_CLIENT_ID="your-app-client-id"
# Optional placeholder for public clients:
export DIRECTORY_CLIENT_OIDC_CLIENT_SECRET="random-non-secret-string"
export DIRECTORY_CLIENT_OIDC_REDIRECT_URI="http://localhost:8484/callback"
# Optional: comma-separated scopes
export DIRECTORY_CLIENT_OIDC_SCOPES="openid,profile,email"
# Optional: override gRPC TLS server name / authority
export DIRECTORY_CLIENT_TLS_SERVER_NAME="directory.example.com"
# Optional: non-interactive use (CI) after obtaining a token elsewhere
export DIRECTORY_CLIENT_AUTH_TOKEN="your-access-token"
# Optional: skip TLS certificate verification for IdP HTTPS only (development; avoid in production)
export DIRECTORY_CLIENT_TLS_SKIP_VERIFY="false"
```

```python
from agntcy.dir_sdk.client import Client, Config, OAuthPkceError

config = Config(
server_address="directory.example.com:443",
auth_mode="oidc",
oidc_issuer="https://your-idp-provider.example.com",
oidc_client_id="your-app-client-id",
oidc_client_secret="random-placeholder-if-required",
oidc_redirect_uri="http://localhost:8484/callback",
oidc_callback_port=8484,
oidc_auth_timeout=300.0,
)
client = Client(config)
# Client construction does not start browser login automatically.
# Opens the system browser and completes PKCE on loopback:
try:
client.authenticate_oauth_pkce()
except OAuthPkceError as e:
print(f"Login failed: {e}")
```

gRPC transport to the Directory still uses **TLS with system trust anchors** (or `tls_ca_file` if set). `TLS_SKIP_VERIFY` applies to **HTTPS calls to the OIDC issuer** (discovery and token endpoint), not to relaxing gRPC TLS to the Directory.

If you need to force the TLS server name / authority used by gRPC, set
`DIRECTORY_CLIENT_TLS_SERVER_NAME`.

For non-interactive callers that already have an access token, skip PKCE entirely:

```python
from agntcy.dir_sdk.client import Client, Config

config = Config(
server_address="directory.example.com:443",
auth_mode="oidc",
auth_token="your-access-token",
)
client = Client(config)
```

If no explicit `auth_token` is provided, the SDK will also try to reuse a valid
cached interactive token from the shared `dirctl` cache path before you need to
run `client.authenticate_oauth_pkce()`.

## Error Handling

The SDK primarily raises `grpc.RpcError` exceptions for gRPC communication issues and `RuntimeError` for configuration problems:

```python
import grpc
from agntcy.dir_sdk.client import Client
from agntcy.dir_sdk.client import Client, OAuthPkceError

try:
client = Client()
Expand All @@ -100,6 +201,9 @@ except grpc.RpcError as e:
except RuntimeError as e:
# Handle configuration or subprocess errors
print(f"Runtime error: {e}")
except OAuthPkceError as e:
# Browser / loopback OAuth PKCE flow failed
print(f"OAuth error: {e}")
```

Common gRPC status codes:
Expand All @@ -109,27 +213,44 @@ Common gRPC status codes:
- `PERMISSION_DENIED`: Authentication/authorization failure
- `INVALID_ARGUMENT`: Invalid request parameters

_For more examples, please refer to the [Documentation](https://docs.agntcy.org/dir/directory-sdk/#python-sdk) or
the [Wiki](https://github.com/agntcy/dir-sdk-python/wiki)_

## Roadmap
## Getting Started

### Prerequisites

- Python 3.10 or higher
- [uv](https://github.com/astral-sh/uv) - Package manager
- [dirctl](https://github.com/agntcy/dir/releases) - Directory CLI binary
- Directory server instance (see setup below)

### 1. Server Setup

See the [open issues](https://github.com/agntcy/dir-sdk-python/issues) for a list
of proposed features (and known issues).
**Option A: Local Development Server**

## Contributing
```bash
# Clone the repository and start the server using Taskfile
task server:start
```

Contributions are what make the open source community such an amazing place to
learn, inspire, and create. Any contributions you make are **greatly
appreciated**. For detailed contributing guidelines, please see
[CONTRIBUTING.md](CONTRIBUTING.md)
**Option B: Custom Server**

## License
```bash
# Set your Directory server address
export DIRECTORY_CLIENT_SERVER_ADDRESS="your-server:8888"
```

Distributed under the Apache 2.0 License. See [LICENSE](LICENSE) for more
information.
### 2. SDK Installation

## Contact
```bash
# Add the Directory SDK
uv add agntcy-dir --index https://buf.build/gen/python
```

Project Link:
[https://github.com/agntcy/dir-sdk-python](https://github.com/agntcy/dir-sdk-python)
### Usage Examples

See the [Example Python Project](../examples/example-py/) for a complete working example that demonstrates all SDK features.

```bash
uv sync
uv run example.py
```
6 changes: 1 addition & 5 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ tasks:

sdk:build:python:
desc: Build python client SDK package
dir: ./dir-sdk-python
deps:
- task: sdk:deps:python
cmds:
Expand All @@ -60,7 +59,6 @@ tasks:

sdk:test:python:
desc: Test python client SDK package
dir: ./dir-sdk-python
deps:
- task: sdk:deps:python
cmds:
Expand All @@ -80,7 +78,6 @@ tasks:

sdk:deps:python:
desc: Install deps for python SDK package
dir: ./dir-sdk-python
deps:
- task: deps:uv
- task: deps:cosign
Expand All @@ -91,7 +88,7 @@ tasks:
sdk:deps:python:example:
desc: Install deps for Python SDK example package
internal: true
dir: ./sdk/examples/example-py
dir: ./examples
deps:
- task: deps:uv
cmds:
Expand All @@ -105,7 +102,6 @@ tasks:

sdk:release:python:
desc: Release python client SDK package
dir: ./dir-sdk-python
env:
UV_PUBLISH_TOKEN: "{{ .UV_PUBLISH_TOKEN }}"
deps:
Expand Down
5 changes: 3 additions & 2 deletions dir-sdk-python/agntcy/dir_sdk/client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0

from .client import Client
from .config import Config
from agntcy.dir_sdk.client.client import Client
from agntcy.dir_sdk.client.config import Config
from agntcy.dir_sdk.client.oauth_pkce import OAuthPkceError as OAuthPkceError
Loading
Loading