codetether_agent/a2a/git_credentials/
request.rs1use anyhow::{Context, Result, anyhow};
13use reqwest::{Client, StatusCode};
14use serde::Serialize;
15
16use super::{GitCredentialMaterial, GitCredentialQuery};
17
18#[derive(Debug, Serialize)]
19struct GitCredentialRequestBody<'a> {
20 operation: &'a str,
21 protocol: Option<&'a str>,
22 host: Option<&'a str>,
23 path: Option<&'a str>,
24}
25
26pub async fn request_git_credentials(
36 server: &str,
37 token: &Option<String>,
38 worker_id: Option<&str>,
39 workspace_id: &str,
40 operation: &str,
41 query: &GitCredentialQuery,
42) -> Result<Option<GitCredentialMaterial>> {
43 let client = Client::builder()
44 .timeout(std::time::Duration::from_secs(30))
45 .build()
46 .unwrap_or_default();
47 let mut request = client.post(format!(
48 "{}/v1/agent/workspaces/{workspace_id}/git/credentials",
49 server.trim_end_matches('/')
50 ));
51 if let Some(token) = token {
52 request = request.bearer_auth(token);
53 }
54 if let Some(worker_id) = worker_id.filter(|value| !value.trim().is_empty()) {
55 request = request.header("X-Worker-ID", worker_id);
56 }
57 let response = request
58 .json(&GitCredentialRequestBody {
59 operation,
60 protocol: query.protocol.as_deref(),
61 host: query.host.as_deref(),
62 path: query.path.as_deref(),
63 })
64 .send()
65 .await
66 .context("Failed to request Git credentials from server")?;
67 match response.status() {
68 StatusCode::OK => Ok(Some(
69 response
70 .json::<GitCredentialMaterial>()
71 .await
72 .context("Failed to decode Git credential response")?,
73 )),
74 StatusCode::NOT_FOUND => Ok(None),
75 status => Err(anyhow!(
76 "Git credential request failed with {}: {}",
77 status,
78 response.text().await.unwrap_or_default()
79 )),
80 }
81}