github_bot_sdk/lib.rs
1//! # GitHub Bot SDK
2//!
3//! A comprehensive Rust SDK for building GitHub Apps and bots with strong type safety,
4//! built-in security, and production-ready patterns.
5//!
6//! ## Features
7//!
8//! - **GitHub App Authentication** - RS256 JWT signing and automated installation token management
9//! - **🌐 API Client** - Type-safe GitHub REST API operations with automatic rate limiting
10//! - **Webhook Security** - HMAC-SHA256 signature validation with constant-time comparison
11//! - **Event Processing** - Structured webhook event parsing and routing
12//! - **Production Ready** - Exponential backoff, retry logic, and comprehensive error handling
13//! - **Rust First** - Zero-cost abstractions leveraging Rust's type system for correctness
14//!
15//! ## Quick Start
16//!
17//! Add to your `Cargo.toml`:
18//!
19//! ```toml
20//! [dependencies]
21//! github-bot-sdk = "0.1.0"
22//! tokio = { version = "1.0", features = ["full"] }
23//! ```
24//!
25//! ## Core Concepts
26//!
27//! ### Authentication
28//!
29//! GitHub Apps use a two-tier authentication model:
30//!
31//! 1. **App-level JWT** - Short-lived tokens (max 10 minutes) for app-level operations
32//! 2. **Installation Tokens** - Scoped tokens for operations on behalf of installations
33//!
34//! This SDK handles both automatically through the [`AuthenticationProvider`] trait.
35//!
36//! ### API Client
37//!
38//! The [`GitHubClient`] provides typed access to GitHub's REST API with:
39//!
40//! - Automatic token injection and refresh
41//! - Built-in rate limit detection and handling
42//! - Exponential backoff retry for transient failures
43//! - Pagination support for list operations
44//!
45//! ### Webhook Processing
46//!
47//! Validate and process GitHub webhooks securely:
48//!
49//! - HMAC-SHA256 signature verification via [`SignatureValidator`]
50//! - Structured event parsing with [`events`] module
51//! - Type-safe event routing and handling
52//!
53//! ## Usage Examples
54//!
55//! ### Basic GitHub Client Usage
56//!
57//! ```rust,no_run
58//! use github_bot_sdk::{
59//! auth::{GitHubAppId, InstallationId, AuthenticationProvider},
60//! client::{GitHubClient, ClientConfig},
61//! error::ApiError,
62//! };
63//!
64//! # async fn example(auth_provider: impl AuthenticationProvider + 'static) -> Result<(), ApiError> {
65//! // Build GitHub client with authentication
66//! let client = GitHubClient::builder(auth_provider)
67//! .config(ClientConfig::default()
68//! .with_user_agent("my-bot/1.0")
69//! .with_timeout(std::time::Duration::from_secs(30)))
70//! .build()?;
71//!
72//! // Get app information
73//! let app = client.get_app().await?;
74//! println!("Authenticated as: {}", app.name);
75//!
76//! // Get installation information
77//! let installation_id = InstallationId::new(12345);
78//! let installation = client.get_installation(installation_id).await?;
79//! println!("Installation ID: {}", installation.id.as_u64());
80//! # Ok(())
81//! # }
82//! ```
83//!
84//! ### Repository Operations
85//!
86//! ```rust,no_run
87//! # use github_bot_sdk::client::GitHubClient;
88//! # use github_bot_sdk::auth::InstallationId;
89//! # async fn example(client: &GitHubClient) -> Result<(), Box<dyn std::error::Error>> {
90//! let installation_id = InstallationId::new(12345);
91//! let installation = client.get_installation(installation_id).await?;
92//!
93//! // Get installation details
94//! println!("Installation ID: {}", installation.id.as_u64());
95//! println!("Account: {}", installation.account.login);
96//! # Ok(())
97//! # }
98//! ```
99//!
100//! ### Issue and Pull Request Operations
101//!
102//! ```rust,no_run
103//! # use github_bot_sdk::client::GitHubClient;
104//! # use github_bot_sdk::auth::InstallationId;
105//! # async fn example(client: &GitHubClient) -> Result<(), Box<dyn std::error::Error>> {
106//! let installation_id = InstallationId::new(12345);
107//!
108//! // Get installation to work with issues and pull requests
109//! let installation = client.get_installation(installation_id).await?;
110//! println!("Working with installation: {}", installation.id.as_u64());
111//!
112//! // See client module documentation for repository, issue, and PR operations
113//! # Ok(())
114//! # }
115//! ```
116//!
117//! ### Webhook Signature Validation
118//!
119//! ```rust,no_run
120//! use github_bot_sdk::{
121//! webhook::SignatureValidator,
122//! auth::SecretProvider,
123//! error::ValidationError,
124//! };
125//! use std::sync::Arc;
126//!
127//! # async fn example(secret_provider: Arc<dyn SecretProvider>) -> Result<(), ValidationError> {
128//! let validator = SignatureValidator::new(secret_provider);
129//!
130//! // Validate incoming webhook
131//! let payload = b"{\"action\":\"opened\",\"issue\":{...}}";
132//! let signature = "sha256=5c4a8d..."; // From X-Hub-Signature-256 header
133//!
134//! if validator.validate(payload, signature).await? {
135//! println!("✓ Valid webhook - processing event");
136//! // Parse and process the event
137//! } else {
138//! println!("✗ Invalid signature - rejecting webhook");
139//! }
140//! # Ok(())
141//! # }
142//! ```
143//!
144//! ### Working with Tokens
145//!
146//! ```rust
147//! use github_bot_sdk::auth::{JsonWebToken, GitHubAppId};
148//! use chrono::{Utc, Duration};
149//!
150//! let app_id = GitHubAppId::new(123456);
151//! let expires_at = Utc::now() + Duration::minutes(10);
152//! let jwt = JsonWebToken::new("eyJ0...".to_string(), app_id, expires_at);
153//!
154//! // Check expiration
155//! if jwt.is_expired() {
156//! println!("Token has expired");
157//! }
158//!
159//! // Check if token expires soon (within 5 minutes)
160//! if jwt.expires_soon(Duration::minutes(5)) {
161//! println!("Token expires soon - should refresh");
162//! }
163//! ```
164//!
165//! ## Module Organization
166//!
167//! - [`auth`] - Authentication types, traits, and token management
168//! - [`client`] - GitHub API client and operation implementations
169//! - [`error`] - Error types for all operations
170//! - [`events`] - Webhook event parsing and processing
171//! - [`webhook`] - Webhook signature validation and security
172//!
173//! ## Architecture
174//!
175//! This SDK follows hexagonal architecture principles:
176//!
177//! - **Core Domain** - Authentication, events, and API operations (in this crate)
178//! - **Abstraction Layer** - Traits for external dependencies ([`SecretProvider`], [`JwtSigner`], etc.)
179//! - **Infrastructure** - Your implementations for secret management, key storage, etc.
180//!
181//! This design ensures:
182//! - Testability through dependency injection
183//! - Flexibility to integrate with your infrastructure
184//! - Type safety at compile time
185//! - Clear separation of concerns
186//!
187//! ## Security
188//!
189//! Security is built into the SDK's design:
190//!
191//! - **No Token Logging** - Sensitive types implement custom `Debug` that redacts secrets
192//! - **Memory Safety** - Token types zero memory on drop
193//! - **Constant-Time Comparison** - Webhook signatures use timing-attack resistant comparison
194//! - **HTTPS Only** - All GitHub API communication uses TLS
195//! - **Type Safety** - Branded types prevent mixing up different ID types
196//!
197//! ## Error Handling
198//!
199//! All operations return `Result<T, E>` with rich error types:
200//!
201//! - [`ApiError`] - GitHub API errors, rate limits, network failures
202//! - [`AuthError`] - Authentication and token errors
203//! - [`ValidationError`] - Input validation and webhook signature errors
204//! - [`EventError`] - Event parsing and processing errors
205//!
206//! Errors include context for debugging and implement retry classification
207//! to distinguish transient failures from permanent errors.
208//!
209//! ## Rate Limiting
210//!
211//! The SDK automatically handles GitHub's rate limits:
212//!
213//! - Detects rate limit headers in responses
214//! - Automatically backs off when approaching limits
215//! - Respects `Retry-After` headers on 429 responses
216//! - Configurable safety margin to avoid hitting limits
217//!
218//! ## Testing
219//!
220//! The SDK is designed for testability:
221//!
222//! - Mock implementations for all traits
223//! - [`wiremock`](https://docs.rs/wiremock) integration for HTTP mocking
224//! - Comprehensive test coverage
225//! - Doc tests for all examples
226//!
227//! ## Specifications
228//!
229//! For detailed architectural specifications, see [`docs/specs/`](https://github.com/pvandervelde/github-bot-sdk/tree/master/docs/specs).
230//!
231//! ## Examples
232//!
233//! See the [repository examples](https://github.com/pvandervelde/github-bot-sdk/tree/master/examples)
234//! for complete, runnable examples demonstrating common use cases.
235
236// Public modules
237pub mod auth;
238pub mod client;
239pub mod error;
240pub mod events;
241pub mod webhook;
242
243// Re-export commonly used types at crate root for convenience
244pub use error::{
245 ApiError, AuthError, CacheError, EventError, SecretError, SigningError, ValidationError,
246};
247
248pub use auth::{
249 AuthenticationProvider, GitHubApiClient, GitHubAppId, Installation, InstallationId,
250 InstallationPermissions, InstallationToken, JsonWebToken, JwtClaims, JwtSigner, KeyAlgorithm,
251 Permission, PermissionLevel, PrivateKey, RateLimitInfo, Repository, RepositoryId,
252 RepositorySelection, SecretProvider, TokenCache, User, UserId, UserType,
253};
254
255pub use client::{ClientConfig, ClientConfigBuilder, GitHubClient, GitHubClientBuilder};
256
257pub use webhook::SignatureValidator;