feat: copy host OAuth tokens into sandbox at launch

Projects ~/.cache/coyote/oauth/ from the host into /home/agent/.cache/coyote/oauth/
inside the sandbox so agents can call OAuth-authenticated providers without
re-authenticating. Same trust model as the existing config-dir and vault-password
copies. One-way copy (not bind-mount) — matches Docker's universal support
surface. Refreshed tokens die with the sandbox instance; run coyote --authenticate
inside if a fresh token is needed (Device Flow works via the QR code render).
This commit is contained in:
2026-07-20 15:23:52 -06:00
parent 0fe430102a
commit f2a0e7453e
+20
View File
@@ -388,6 +388,26 @@ fn copy_host_files(name: &str) -> Result<()> {
); );
} }
let oauth_tokens_dir = paths::oauth_tokens_path();
if oauth_tokens_dir.exists() {
let sandbox_oauth_dir = "/home/agent/.cache/coyote/oauth";
ensure_sandbox_dir(name, sandbox_oauth_dir)?;
let dest = format!("{name}:{sandbox_oauth_dir}/");
for entry in fs::read_dir(&oauth_tokens_dir)
.with_context(|| format!("Failed to read {}", oauth_tokens_dir.display()))?
{
let entry = entry?;
let path = entry.path();
sbx_cp(&path.display().to_string(), &dest)?;
}
chown_agent_recursive(name, sandbox_oauth_dir)?;
} else {
debug!(
"Skipping OAuth token copy: {} does not exist",
oauth_tokens_dir.display()
);
}
match resolve_vault_password_file() { match resolve_vault_password_file() {
Some(password_file) if password_file.exists() => { Some(password_file) if password_file.exists() => {
let dest_path = host_to_sandbox_path(&password_file, &home_dir, cfg!(windows))?; let dest_path = host_to_sandbox_path(&password_file, &home_dir, cfg!(windows))?;