#[cfg(any(test, target_os = "windows"))]
use super::super::contract::SecretBackend;
#[cfg(any(test, target_os = "windows"))]
use anyhow::Result;
#[cfg(any(test, target_os = "windows"))]
const TARGET_PREFIX: &str = "yana-ai:";
#[cfg(target_os = "windows")]
const COMMAND_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(4);
#[cfg(any(test, target_os = "windows"))]
pub struct Backend;
#[cfg(any(test, target_os = "windows"))]
fn target_name(key: &str) -> String {
format!("{TARGET_PREFIX}{key}")
}
#[cfg(target_os = "windows")]
impl SecretBackend for Backend {
fn has_entry(&self, key: &str) -> Result<bool> {
use std::process::{Command, Stdio};
use std::time::Instant;
let mut child = Command::new("cmdkey")
.arg(format!("/list:{}", target_name(key)))
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.map_err(|error| anyhow::anyhow!("starting cmdkey: {error}"))?;
let deadline = Instant::now() + COMMAND_TIMEOUT;
let status = loop {
if let Some(status) = child.try_wait()? {
break status;
}
if Instant::now() >= deadline {
let _ = child.kill();
let _ = child.wait();
anyhow::bail!(
"cmdkey /list timed out after {}s",
COMMAND_TIMEOUT.as_secs()
);
}
std::thread::sleep(std::time::Duration::from_millis(20));
};
Ok(status.success())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn target_name_namespaces_the_key_under_the_yana_prefix() {
assert_eq!(
target_name("ANTHROPIC_API_KEY"),
"yana-ai:ANTHROPIC_API_KEY"
);
}
}