← Back to Docs

Rust Rust SDK

Zero-copy, memory-safe AVP implementation for high-performance applications

Zero-Copy

Efficient secret handling without unnecessary allocations

Memory Safe

Secrets are securely zeroed on drop with zeroize

Async/Await

Full async support with tokio runtime

Type Safe

Strong typing prevents credential misuse

Installation

# Cargo.toml
[dependencies]
avp = "0.1"

# With all backends
avp = { version = "0.1", features = ["file", "keychain"] }

# Async support
avp = { version = "0.1", features = ["async"] }

Quick Start

use avp::{Client, FileBackend, Result};

fn main() -> Result<()> {
    // Create client with file backend
    let backend = FileBackend::new("./vault.enc", "your-password")?;
    let client = Client::new(backend);

    // Authenticate to workspace
    let session = client.authenticate("my-agent", None)?;

    // Store a secret
    client.store(
        &session,
        "OPENAI_API_KEY",
        b"sk-...",
        Default::default()
    )?;

    // Retrieve a secret
    let secret = client.retrieve(&session, "OPENAI_API_KEY", None)?;
    println!("Key: {}", String::from_utf8_lossy(&secret.value));

    Ok(())
}

Async Usage

use avp::{AsyncClient, FileBackend, Result};

#[tokio::main]
async fn main() -> Result<()> {
    let backend = FileBackend::new("./vault.enc", "password")?;
    let client = AsyncClient::new(backend);

    let session = client.authenticate("workspace", None).await?;

    client.store(&session, "KEY", b"value", Default::default()).await?;

    let secret = client.retrieve(&session, "KEY", None).await?;

    Ok(())
}

Backends

MemoryBackend

In-memory storage for testing.

use avp::{Client, MemoryBackend};

let backend = MemoryBackend::new();
let client = Client::new(backend);

FileBackend

Encrypted file storage using AES-256-GCM with Argon2id key derivation.

use avp::FileBackend;

// Create with password
let backend = FileBackend::new("./vault.enc", "password")?;

// Create with custom options
let backend = FileBackend::builder()
    .path("./vault.enc")
    .password("password")
    .argon2_memory_cost(65536)
    .argon2_time_cost(3)
    .build()?;

KeychainBackend

OS-native credential storage (requires keychain feature).

use avp::KeychainBackend;

let backend = KeychainBackend::new("my-app-avp")?;

Operations

discover()

let info = client.discover()?;

println!("Version: {}", info.version);
println!("Backends: {:?}", info.backends);
println!("Operations: {:?}", info.operations);

authenticate()

use std::time::Duration;

// Default TTL (1 hour)
let session = client.authenticate("workspace", None)?;

// Custom TTL
let session = client.authenticate(
    "workspace",
    Some(Duration::from_secs(7200))
)?;

println!("Session ID: {}", session.id);
println!("Expires: {:?}", session.expires_at);

store()

use avp::StoreOptions;
use std::collections::HashMap;

// Simple store
client.store(&session, "API_KEY", b"sk-...", Default::default())?;

// With options
let mut labels = HashMap::new();
labels.insert("env".to_string(), "production".to_string());

let options = StoreOptions {
    labels: Some(labels),
    expires_at: None,
};

client.store(&session, "API_KEY", b"sk-...", options)?;

retrieve()

// Latest version
let secret = client.retrieve(&session, "API_KEY", None)?;

// Specific version
let secret = client.retrieve(&session, "API_KEY", Some(1))?;

println!("Value: {:?}", secret.value);
println!("Version: {}", secret.version);
println!("Labels: {:?}", secret.labels);

delete()

client.delete(&session, "OLD_KEY")?;

list()

use avp::ListOptions;

// List all
let secrets = client.list(&session, Default::default())?;

// With label filter
let mut filter = HashMap::new();
filter.insert("env".to_string(), "production".to_string());

let options = ListOptions {
    label_filter: Some(filter),
};

let secrets = client.list(&session, options)?;

for secret in secrets {
    println!("{}: v{}", secret.name, secret.version);
}

rotate()

let result = client.rotate(&session, "API_KEY", b"sk-new-...")?;

println!("Previous: v{}", result.previous_version);
println!("New: v{}", result.new_version);

Error Handling

use avp::{Error, ErrorKind};

match client.retrieve(&session, "UNKNOWN") {
    Ok(secret) => println!("Found: {:?}", secret),
    Err(Error { kind: ErrorKind::NotFound, .. }) => {
        println!("Secret not found");
    }
    Err(Error { kind: ErrorKind::SessionExpired, .. }) => {
        println!("Session expired, re-authenticate");
    }
    Err(e) => {
        println!("Error: {}", e);
    }
}

Memory Safety

Secure Memory: The Rust SDK uses the zeroize crate to securely clear secrets from memory when they go out of scope.
use avp::SecretValue;

{
    let secret = client.retrieve(&session, "KEY", None)?;
    // Use secret.value...
} // Secret is securely zeroed here

// For manual control:
use zeroize::Zeroize;

let mut sensitive_data = secret.value.clone();
// Use sensitive_data...
sensitive_data.zeroize(); // Explicitly zero

Custom Backend

use avp::{Backend, Session, Secret, StoreOptions, ListOptions, Result};

struct MyBackend {
    // Your storage implementation
}

impl Backend for MyBackend {
    fn discover(&self) -> Result {
        // Return capabilities
    }

    fn authenticate(&self, workspace: &str, ttl: Option) -> Result {
        // Create session
    }

    fn store(&self, session: &Session, name: &str, value: &[u8], options: StoreOptions) -> Result<()> {
        // Store secret
    }

    fn retrieve(&self, session: &Session, name: &str, version: Option) -> Result {
        // Retrieve secret
    }

    fn delete(&self, session: &Session, name: &str) -> Result<()> {
        // Delete secret
    }

    fn list(&self, session: &Session, options: ListOptions) -> Result> {
        // List secrets
    }

    fn rotate(&self, session: &Session, name: &str, new_value: &[u8]) -> Result {
        // Rotate secret
    }
}

Feature Flags

FeatureDescription
defaultMemory backend only
fileEncrypted file backend
keychainOS keychain backend
asyncAsync/await support with tokio
serdeSerde serialization support

Complete Example

use avp::{Client, FileBackend, StoreOptions, Result};
use std::collections::HashMap;

fn main() -> Result<()> {
    // Initialize
    let backend = FileBackend::new("./agent-vault.enc", "secure-password")?;
    let client = Client::new(backend);

    // Authenticate
    let session = client.authenticate("openai-agent", None)?;

    // Store with labels
    let mut labels = HashMap::new();
    labels.insert("provider".to_string(), "openai".to_string());
    labels.insert("env".to_string(), "production".to_string());

    client.store(
        &session,
        "OPENAI_API_KEY",
        b"sk-proj-...",
        StoreOptions { labels: Some(labels), expires_at: None }
    )?;

    // Retrieve and use
    let secret = client.retrieve(&session, "OPENAI_API_KEY", None)?;
    let api_key = String::from_utf8_lossy(&secret.value);

    // Use api_key with OpenAI client...
    println!("Using API key v{}", secret.version);

    // Rotate when needed
    let result = client.rotate(&session, "OPENAI_API_KEY", b"sk-new-...")?;
    println!("Rotated from v{} to v{}", result.previous_version, result.new_version);

    Ok(())
}