akv-cli 0.9.1

The Azure Key Vault CLI (unofficial) can read secrets from Key Vault, securely pass secrets to other commands or inject them into configuration files, encrypt and decrypt secrets, and managed keys and secrets in Key Vault.
Documentation
# Azure Key Vault CLI Development Guide

This is an unofficial Azure Key Vault CLI built in Rust that provides secure secret management, encryption/decryption, and Key Vault resource operations.

## Building and Testing

### Build Commands

```bash
# Build the project
cargo build

# Build with all features (includes color support)
cargo build --all-features

# Release build (optimized for size)
cargo build --release --all-features
```

### Test Commands

```bash
# Run all unit tests
cargo test --all-features --workspace

# Run tests for a specific module
cargo test --all-features --workspace <module_name>

# Run a specific test
cargo test --all-features --workspace <test_name>

# Run tests with logging output
RUST_LOG=info,akv=debug cargo test --all-features --workspace
```

### Lint and Format

```bash
# Check code formatting
cargo fmt --all -- --check

# Format code
cargo fmt --all

# Run clippy lints (CI runs with -Dwarnings)
cargo clippy --all-features --all-targets --no-deps --workspace

# Build documentation
cargo doc --all-features --no-deps --workspace
```

**Always run linting after making changes:**

- Format code with `cargo fmt --all`
- Use the [spell-check skill]skills/spell-check/SKILL.md for spelling issues
- Use the [markdown-lint skill]skills/markdown-lint/SKILL.md for markdown formatting
- Fix any issues before committing

### Benchmarks

```bash
# Run benchmarks (uses criterion)
cargo bench
```

## Project Architecture

### Binary Structure

The main binary is `akv` (crate name is `akv-cli`). Structure:

- **src/bin/akv/main.rs** - Entry point, argument parsing with clap, tracing setup
- **src/bin/akv/commands/** - Subcommand implementations (certificate, decrypt, encrypt, inject, key, read, run, secret)
- **src/bin/akv/pty/** - PTY handling for the `run` command to mask secrets in stdout/stderr

### Library Structure

- **src/lib.rs** - Public API surface (minimal; primarily CLI-focused)
- **src/cache.rs** - `ClientCache<T>` for caching Key Vault clients by vault URL
- **src/jose/** - JSON Web Encryption (JWE) implementation for local encrypt/decrypt
- **src/error.rs** - Error types (`Error`, `ErrorKind`, `Result`)
- **src/parsing.rs** - Utility functions for parsing arguments
- **src/json.rs** - JSON utility functions
- **src/color.rs** - Color mode configuration (when `color` feature enabled)

### Key Architectural Patterns

#### Authentication

- Uses Azure identity crates (`azure_identity`) with automatic credential discovery
- If `.azure/dev/.env` exists (created by `azd up`), uses `AzureDeveloperCliCredential` exclusively for consistent auth
- Otherwise falls back to `DeveloperToolsCredential` (tries multiple auth methods)
- Credentials are stored in a static `OnceLock<Arc<dyn TokenCredential>>`

#### Client Caching

The `ClientCache<T>` type caches Azure SDK clients (SecretClient, KeyClient, CertificateClient) by vault URL to avoid recreating clients for the same vault.

#### Secret Masking

The `run` command uses a PTY wrapper to intercept stdout/stderr and mask secrets in real-time. Secrets are identified by:

- Environment variable values that are URLs to Key Vault secrets
- JWE compact tokens in environment variables

#### JWE Implementation

Custom JWE (JSON Web Encryption) implementation in `src/jose/`:

- Generates content encryption keys (CEK) locally
- Wraps CEK using Azure Key Vault keys (RSA-OAEP algorithms)
- Supports AES-GCM for content encryption (128, 192, 256-bit)
- Compact serialization format for easy storage

#### Environment Variable Loading

Uses `dotazure` and `dotenvy` crates to:

1. First try loading `.azure/dev/.env` (created by Azure Developer CLI)
2. Fall back to ancestor directory search for `.env` files
3. Debug builds auto-load these; release builds require explicit `--vault` parameter

## Code Conventions

### Error Handling

- Use `Result<T>` alias defined in `src/error.rs` (maps to `std::result::Result<T, Error>`)
- Use `ErrorKind` enum for error categorization
- Extend errors with context using `ResultExt::context()` trait
- Use `Error::with_message()` or `Error::with_message_fn()` for custom messages

### Tracing

- Use `tracing` crate, not `println!` or `eprintln!` for debug/info logs
- Target specific traces with `target: "akv::module"` for better filtering
- Control verbosity via `RUST_LOG` environment variable (e.g., `RUST_LOG=info,akv=debug`)
- Trace levels: `-v` = INFO, `-vv` = DEBUG, `-vvv` = TRACE

### Features

- Default feature: `["color"]` - enables colored output
- Color support via `clap/color`, `colored_json`, and `yansi` crates
- Guard color-related code with `#[cfg(feature = "color")]`

### Testing

- Unit tests use `#[cfg(test)]` modules
- Integration tests require provisioning a real Key Vault via `azd up`
- Manual testing documented in CONTRIBUTING.md with example scripts in `examples/`

### Documentation

- All public items require `#![deny(missing_docs)]`
- Module-level docs use `//!` at the top of files
- Use doc comments `///` for public APIs

### Toolchain

- Requires nightly Rust (specified in `rust-toolchain.toml`)
- MSRV: 1.85 (specified in Cargo.toml)
- Uses unstable features: `windows_process_extensions_raw_attribute`, `once_cell_try`

## Development Workflow

### Local Development Setup

```bash
# Install Azure Developer CLI (optional but recommended)
brew install azd  # or see https://aka.ms/azure-dev

# Provision a test Key Vault (creates .azure/dev/.env)
azd up

# Run the CLI in development mode (auto-loads .env)
cargo run -- secret list
cargo run -- read --name secret-1

# Set up example environment variables
source ./examples/setup.sh  # bash/zsh
# or
. ./examples/setup.ps1      # PowerShell
```

### Troubleshooting

```bash
# Enable detailed tracing
RUST_LOG=info,akv=debug cargo run -- <command>

# Trace Azure SDK calls
RUST_LOG=azure_core=debug,akv=debug cargo run -- <command>
```

### CI Environment

- Runs on macOS, Ubuntu, and Windows
- Sets `RUSTFLAGS: -Dwarnings` (treat warnings as errors)
- Sets `CARGO_INCREMENTAL: 0` for clean builds
- Windows builds require OpenSSL configuration