/ CLAUDE.md
CLAUDE.md
1 # CLAUDE.md 2 3 This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 5 ## Project Overview 6 7 Auths is a decentralized identity system for developers. It enables cryptographic commit signing with Git-native storage using KERI-inspired identity principles. No central server or blockchain—just Git and cryptography. 8 9 ## Build & Test Commands 10 11 ```bash 12 # Build 13 cargo build # Debug build 14 cargo build --release # Release build 15 cargo build --package auths_cli # Build specific crate 16 17 # Test 18 cargo nextest run --workspace # Run all tests (except doc tests) 19 cargo test --all --doc # Run doc tests (nextest doesn't support these) 20 cargo nextest run -p auths_verifier # Test specific crate 21 cargo nextest run -E 'test(verify_chain)' # Run single test by name 22 23 # Lint & Format 24 cargo fmt --all # Format code 25 cargo fmt --check --all # Check formatting (CI uses this) 26 cargo clippy --all-targets --all-features -- -D warnings 27 28 # Security audit 29 cargo audit 30 31 # WASM verification (auths-verifier only) 32 # Must cd into the crate — resolver = "3" rejects --features from workspace root 33 cd crates/auths-verifier && cargo check --target wasm32-unknown-unknown --no-default-features --features wasm 34 ``` 35 36 ## Code Comments 37 38 You SHOULD NOT add code comments that explain processes - the code should be self-evident 39 40 Only leave comments where a particular decision was made - i.e. opinionated code 41 Or in places where 42 43 If you are leaving comments to explain processes, it is a sign to break the function into modular components and name them clearly. 44 45 ## Docstrings 46 47 Doc strings should look like this, including description, Args, and Usage code block 48 ``` 49 /// Verifies a GitHub Actions OIDC token and extracts its claims. 50 /// 51 /// Args: 52 /// * `token`: The raw JWT string provided by the GitHub Actions environment. 53 /// * `jwks_client`: The client used to fetch GitHub's public keys. 54 /// 55 /// Usage: 56 /// ```ignore (add ignore where necessary like doc tests) 57 /// let claims = verify_github_token(&raw_token, &jwks_client).await?; 58 /// ``` 59 ``` 60 All public functions, and public API functions should be documented 61 Private functions don't need to be documented - but you can if it seems like an important function 62 63 ## Crate Architecture 64 65 ``` 66 Layer 0: auths-crypto (cryptographic primitives, DID:key encoding) 67 Layer 1: auths-verifier (standalone verification, FFI/WASM) 68 Layer 2: auths-core (keychains, signing, policy, ports) 69 Layer 3: auths-id (identity, attestation, KERI, traits) 70 auths-policy (policy expression engine) 71 Layer 4: auths-storage (Git/SQL storage adapters) 72 auths-sdk (application services) 73 Layer 5: auths-infra-git (Git client adapter) 74 auths-infra-http (HTTP client adapter) 75 Layer 6: auths-cli (user commands) 76 ``` 77 78 **auths-crypto**: Layer 0 cryptographic primitives — Ed25519, KERI key parsing, DID:key encoding. 79 80 **auths-verifier**: Minimal-dependency verification library for FFI/WASM embedding. Depends only on auths-crypto. 81 82 **auths-core**: Foundation layer with platform keychains (macOS Security Framework, Linux Secret Service, Windows Credential Manager), signing, policy, and port abstractions. 83 84 **auths-id**: Identity and attestation domain logic. Defines key traits: `IdentityStorage`, `AttestationSource`, `AttestationSink`. KERI identity management. Refs stored under `refs/auths/` and `refs/keri/`. 85 86 **auths-storage**: Storage backend implementations — `GitAttestationStorage`, `GitIdentityStorage`, `GitRefSink`, `GitRegistryBackend`. 87 88 **auths-cli**: Command-line interface with three binaries: `auths`, `auths-sign`, `auths-verify`. Uses clap for argument parsing. 89 90 **auths-verifier**: Minimal-dependency verification library designed for embedding. Supports FFI (feature: `ffi`), WASM (feature: `wasm`). Does NOT depend on git2 or heavy deps. Core functions: `verify_chain()`, `verify_with_keys()`, `did_key_to_ed25519()`. 91 92 ## Key Patterns 93 94 **Git as Storage**: All identity data and attestations are stored as Git refs. The `~/.auths` directory is a Git repository. 95 96 **DID Types**: 97 - `did:keri:...` - Primary identity (derived from Ed25519 key) 98 - `did:key:z...` - Device identifiers (Ed25519 multicodec format) 99 100 **Attestation Structure**: JSON-serialized, canonicalized with `json-canon`, dual-signed (issuer + device). Fields include: version, rid, issuer, subject, device_public_key, identity_signature, device_signature, capabilities, expires_at. 101 102 **Trait Abstractions**: Platform-specific code uses traits (`Storage`, `DidResolver`) with conditional compilation for cross-platform support. 103 104 **Clock Injection**: `Utc::now()` is banned in `auths-core/src/` and `auths-id/src/` outside `#[cfg(test)]`. All time-sensitive functions accept `now: DateTime<Utc>` as their first parameter. The `auths-sdk` layer calls `clock.now()` and passes the value down. The CLI calls `Utc::now()` at the presentation boundary. Never add `Utc::now()` to domain or core logic — inject it instead. 105 106 ## Feature Flags 107 108 - `auths-core`: `keychain-file-fallback`, `keychain-windows`, `crypto-secp256k1`, `test-utils` 109 - `auths-id`: `auths-radicle`, `indexed-storage` 110 - `auths-verifier`: `ffi` (enables libc, FFI module), `wasm` (enables wasm-bindgen) 111 112 ## Writing Tests 113 114 Each crate uses a single integration-test binary: `tests/integration.rs` (entry point) with submodules under `tests/cases/`. Add new test cases as `tests/cases/<topic>.rs` and re-export from `tests/cases/mod.rs`. 115 116 Use `crates/auths-test-utils` for shared helpers — add `auths-test-utils.workspace = true` under `[dev-dependencies]`: 117 - `auths_test_utils::crypto::get_shared_keypair()` — shared Ed25519 key via `OnceLock` (fast, use by default) 118 - `auths_test_utils::crypto::create_test_keypair()` — fresh key per call (use only when uniqueness matters) 119 - `auths_test_utils::git::init_test_repo()` — new `TempDir` + initialised git repo 120 - `auths_test_utils::git::get_cloned_test_repo()` — cloned copy of a shared template repo (faster for read-only setup) 121 122 See `TESTING_STRATEGY.md` for full details. 123 124 ## CI Requirements 125 126 Tests require Git configuration, ask the user for this and help them find it: 127 ```bash 128 git config --global user.name "{user_current_name}" 129 git config --global user.email "{user_current_email}" 130 ``` 131 132 CI runs on: Ubuntu (x86_64), macOS (aarch64), Windows (x86_64). Rust 1.93 with clippy and rustfmt. 133 134 When the user is getting errors locally, don't forget to remind them to reinstall any local changes (e.g. `cargo install --path crates/auths-cli`) 135 136 1. **DRY & Separated**: Business workflows entirely separated from I/O. No monolithic functions. 137 2. **Documentation**: Rustdoc mandatory for all exported SDK/Core items. `/// Description`, `/// Args:`, `/// Usage:` blocks per CLAUDE.md conventions. 138 3. **Minimalism**: No inline comments explaining process. Use structural decomposition. Per CLAUDE.md: only comment opinionated decisions. 139 4. **Domain-Specific Errors**: `thiserror` enums only. No `anyhow::Error` or `Box<dyn Error>` in Core/SDK. Example: `DomainError::InvalidSignature`, `StorageError::ConcurrentModification`. 140 5. **`thiserror`/`anyhow` Translation Boundary**: The ban on `anyhow` in Core/SDK is strict, but the CLI and API servers (`auths-auth-server`, `auths-registry-server`) **must** define a clear translation boundary where domain errors are wrapped with operational context. The CLI and server crates continue using `anyhow::Context` to collect system-level information (paths, environment, subprocess output), but always wrap the domain `thiserror` errors cleanly — never discard the typed error: 141 ```rust 142 // auths-cli/src/commands/sign.rs (Presentation Layer) 143 // Converts the strict thiserror SigningError into a contextualized anyhow::Error 144 let signature = sign_artifact(&config, data) 145 .with_context(|| format!("Failed to sign artifact for namespace: {}", config.namespace))?; 146 ``` 147 The existing SDK error types (`SetupError`, `DeviceError`, `RegistrationError` in `crates/auths-sdk/src/error.rs`) currently wrap `anyhow::Error` in their `StorageError` and `NetworkError` variants (e.g., `StorageError(#[source] anyhow::Error)`). These must be migrated to domain-specific `thiserror` variants during Epic 1/2 execution — the `anyhow` wrapping is a transitional pattern, not a permanent design. The `map_storage_err()` and `map_device_storage_err()` helper functions should be replaced with direct `From` impls on the domain storage errors. 148 6. **No reverse dependencies**: Core and SDK must never reference presentation layer crates.