Skip to main content

codetether_agent/a2a/git_credentials/
helper.rs

1//! Git credential helper entrypoint logic.
2//!
3//! This module is the runtime bridge between Git's credential protocol and the
4//! control-plane credential broker.
5//!
6//! # Examples
7//!
8//! ```ignore
9//! run_git_credential_helper(&args).await?;
10//! ```
11
12use anyhow::{Result, anyhow};
13
14use super::gh_cli::{emit_credentials_via_gh_cli, should_delegate_to_gh_cli};
15use super::request_git_credentials;
16use super::stdin_query::read_git_credential_query_from_stdin;
17
18/// Runs the Git credential helper command for this worker binary.
19///
20/// `store` and `erase` are treated as no-ops because the worker only serves
21/// short-lived `get` requests.
22///
23/// # Examples
24///
25/// ```ignore
26/// run_git_credential_helper(&args).await?;
27/// ```
28pub async fn run_git_credential_helper(args: &crate::cli::GitCredentialHelperArgs) -> Result<()> {
29    let operation = args.operation.as_deref().unwrap_or("get").trim();
30    if matches!(operation, "store" | "erase") {
31        return Ok(());
32    }
33    let query = read_git_credential_query_from_stdin()?;
34    let server = args
35        .server
36        .clone()
37        .or_else(|| std::env::var("CODETETHER_SERVER").ok())
38        .ok_or_else(|| anyhow!("CODETETHER_SERVER is not set for Git credential helper"))?;
39    let token = args
40        .token
41        .clone()
42        .or_else(|| std::env::var("CODETETHER_TOKEN").ok());
43    let worker_id = args
44        .worker_id
45        .clone()
46        .or_else(|| std::env::var("CODETETHER_WORKER_ID").ok());
47    let creds = request_git_credentials(
48        &server,
49        &token,
50        worker_id.as_deref(),
51        &args.workspace_id,
52        operation,
53        &query,
54    )
55    .await?;
56    if let Some(creds) = creds {
57        if should_delegate_to_gh_cli(&query, &creds) {
58            match emit_credentials_via_gh_cli(&query, &creds) {
59                Ok(()) => return Ok(()),
60                Err(e) => {
61                    tracing::warn!(
62                        error = %e,
63                        "gh CLI delegation failed, falling back to direct credential output"
64                    );
65                }
66            }
67        }
68        println!("username={}", creds.username);
69        println!("password={}", creds.password);
70        println!();
71    }
72    Ok(())
73}