aptu_core/
auth.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Token provider abstraction for multi-platform credential resolution.
4//!
5//! This module defines the `TokenProvider` trait, which abstracts credential
6//! resolution across different platforms (CLI, iOS, etc.). Each platform
7//! implements this trait to provide GitHub and `OpenRouter` tokens from their
8//! respective credential sources.
9
10use secrecy::SecretString;
11
12/// Provides GitHub and `OpenRouter` credentials for API calls.
13///
14/// This trait abstracts credential resolution across platforms:
15/// - **CLI:** Resolves from environment variables, GitHub CLI, or system keyring
16/// - **iOS:** Resolves from iOS keychain via FFI
17///
18/// Implementations should handle credential lookup and return `None` if
19/// credentials are not available.
20pub trait TokenProvider: Send + Sync {
21    /// Retrieves the GitHub API token.
22    ///
23    /// Returns `None` if no token is available from any source.
24    fn github_token(&self) -> Option<SecretString>;
25
26    /// Retrieves the `OpenRouter` API key.
27    ///
28    /// Returns `None` if no API key is available from any source.
29    fn openrouter_key(&self) -> Option<SecretString>;
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    /// Mock implementation for testing.
37    struct MockTokenProvider {
38        github_token: Option<SecretString>,
39        openrouter_key: Option<SecretString>,
40    }
41
42    impl TokenProvider for MockTokenProvider {
43        fn github_token(&self) -> Option<SecretString> {
44            self.github_token.clone()
45        }
46
47        fn openrouter_key(&self) -> Option<SecretString> {
48            self.openrouter_key.clone()
49        }
50    }
51
52    #[test]
53    fn test_mock_provider_with_tokens() {
54        let provider = MockTokenProvider {
55            github_token: Some(SecretString::new("gh_token".to_string().into())),
56            openrouter_key: Some(SecretString::new("or_key".to_string().into())),
57        };
58
59        assert!(provider.github_token().is_some());
60        assert!(provider.openrouter_key().is_some());
61    }
62
63    #[test]
64    fn test_mock_provider_without_tokens() {
65        let provider = MockTokenProvider {
66            github_token: None,
67            openrouter_key: None,
68        };
69
70        assert!(provider.github_token().is_none());
71        assert!(provider.openrouter_key().is_none());
72    }
73}