Forward provider API keys to sandbox, wire up Daytona env vars, improve CLI error logging

- Collect provider API key env vars and pass them to sandbox exec_command
  so CLI tools can authenticate in the sandbox environment
- Wire up previously-ignored env_vars parameter in DaytonaSandbox, explicitly
  set all ExecuteCommandOptions fields (catches new fields at compile time)
- Write stdout/stderr logs on CLI failure, fall back to stdout in error detail

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-06 17:01:09 -05:00
parent adc70b6cef
commit de2458c518
2 changed files with 22 additions and 6 deletions

View file

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;
@ -317,8 +318,15 @@ impl CodergenBackend for AgentCliBackend {
let _ = tokio::fs::write(stage_dir.join("provider_used.json"), json).await;
}
// Forward provider API keys so CLI tools can authenticate
let env_vars: HashMap<String, String> = provider
.api_key_env_vars()
.iter()
.filter_map(|name| std::env::var(name).ok().map(|val| (name.to_string(), val)))
.collect();
let result = sandbox
.exec_command(&command, 600_000, None, None, None)
.exec_command(&command, 600_000, None, Some(&env_vars), None)
.await
.map_err(|e| ArcError::handler(format!("CLI command failed: {e}")))?;
@ -332,11 +340,19 @@ impl CodergenBackend for AgentCliBackend {
}
if result.exit_code != 0 {
let _ = tokio::fs::write(stage_dir.join("cli_stdout.log"), &result.stdout).await;
let _ = tokio::fs::write(stage_dir.join("cli_stderr.log"), &result.stderr).await;
let stderr: String = result.stderr.chars().rev().take(500).collect::<Vec<_>>().into_iter().rev().collect();
let detail = if stderr.is_empty() {
format!("command: {command}")
} else {
let detail = if !stderr.is_empty() {
stderr
} else {
let stdout: String = result.stdout.chars().rev().take(500).collect::<Vec<_>>().into_iter().rev().collect();
if !stdout.is_empty() {
format!("stdout: {stdout}")
} else {
format!("command: {command}")
}
};
return Err(ArcError::handler(format!(
"CLI command exited with code {}: {detail}",

View file

@ -781,7 +781,7 @@ impl Sandbox for DaytonaSandbox {
command: &str,
timeout_ms: u64,
working_dir: Option<&str>,
_env_vars: Option<&HashMap<String, String>>,
env_vars: Option<&HashMap<String, String>>,
_cancel_token: Option<tokio_util::sync::CancellationToken>,
) -> Result<ExecResult, String> {
let sandbox = self.sandbox()?;
@ -798,8 +798,8 @@ impl Sandbox for DaytonaSandbox {
let options = daytona_sdk::ExecuteCommandOptions {
cwd: Some(cwd),
env: env_vars.cloned(),
timeout: Some(std::time::Duration::from_millis(timeout_ms)),
..Default::default()
};
// Wrap with `bash -c` so pipes, env vars, and shell features work.