agentctl_auth/
test_credential.rs1use crate::credential::{Credential, TestResult};
4use crate::pool::AuthPool;
5use anyhow::Result;
6use std::time::Instant;
7
8pub async fn test_credential(name: &str, credential: &Credential) -> TestResult {
10 let start = Instant::now();
11
12 let result = match credential.provider.as_str() {
13 "anthropic" => test_anthropic(credential).await,
14 "openai" => test_openai(credential).await,
15 _ => Err(anyhow::anyhow!(
16 "Unknown provider: {}",
17 credential.provider
18 )),
19 };
20
21 let latency_ms = start.elapsed().as_millis() as u64;
22
23 match result {
24 Ok((success, status_code)) => TestResult {
25 credential_name: name.to_string(),
26 provider: credential.provider.clone(),
27 success,
28 status_code: Some(status_code),
29 error: if success {
30 None
31 } else {
32 Some(format!("HTTP {}", status_code))
33 },
34 latency_ms,
35 },
36 Err(e) => TestResult {
37 credential_name: name.to_string(),
38 provider: credential.provider.clone(),
39 success: false,
40 status_code: None,
41 error: Some(e.to_string()),
42 latency_ms,
43 },
44 }
45}
46
47pub async fn test_all(pool: &AuthPool) -> Vec<TestResult> {
49 let mut results = Vec::new();
50 for (name, cred) in pool.all_credentials() {
51 let result = test_credential(name, cred).await;
52 results.push(result);
53 }
54 results
55}
56
57async fn test_anthropic(credential: &Credential) -> Result<(bool, u16)> {
59 let token = credential
60 .resolved_token()
61 .ok_or_else(|| anyhow::anyhow!("Credential has no token"))?;
62
63 let client = reqwest::Client::new();
64 let response = client
65 .post("https://api.anthropic.com/v1/messages")
66 .header("x-api-key", token)
67 .header("anthropic-version", "2023-06-01")
68 .header("content-type", "application/json")
69 .body(r#"{"model":"claude-sonnet-4-20250514","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}"#)
70 .send()
71 .await?;
72
73 let status = response.status().as_u16();
74 let success = status == 200 || status == 429;
75 Ok((success, status))
76}
77
78async fn test_openai(credential: &Credential) -> Result<(bool, u16)> {
80 let token = credential
81 .resolved_token()
82 .ok_or_else(|| anyhow::anyhow!("Credential has no token"))?;
83
84 let client = reqwest::Client::new();
85 let response = client
86 .get("https://api.openai.com/v1/models")
87 .header("Authorization", format!("Bearer {}", token))
88 .send()
89 .await?;
90
91 let status = response.status().as_u16();
92 let success = status == 200;
93 Ok((success, status))
94}