Create a container configuration for both interactive and non-interactive modes. # Arguments `image` - The Docker image to use `task` - The task containing all necessary configuration `agent` - The agent to get volumes and environment variables from `network_name` - The Docker network name for the container to join `proxy_config` - The proxy configuration for env var setup
(
&self,
image: &str,
task: &crate::task::Task,
agent: &dyn Agent,
network_name: Option<&str>,
proxy_config: Option<&crate::context::ResolvedProxyConfig
| 382 | /// * `network_name` - The Docker network name for the container to join |
| 383 | /// * `proxy_config` - The proxy configuration for env var setup |
| 384 | fn create_container_config( |
| 385 | &self, |
| 386 | image: &str, |
| 387 | task: &crate::task::Task, |
| 388 | agent: &dyn Agent, |
| 389 | network_name: Option<&str>, |
| 390 | proxy_config: Option<&crate::context::ResolvedProxyConfig>, |
| 391 | proxy_container_ip: Option<&str>, |
| 392 | ) -> (ContainerCreateBody, DindStorage) { |
| 393 | let resolved = resolve_config_from_task(task, &self.ctx, &self.event_sender); |
| 394 | let mut binds = self.build_bind_volumes(task, agent, &resolved); |
| 395 | let instructions_file_path = PathBuf::from(&task.instructions_file); |
| 396 | let working_dir = container_working_dir(&task.project); |
| 397 | |
| 398 | let mut env_vars = if let Some(pc) = proxy_config { |
| 399 | self.build_proxy_env_vars(&resolved, pc) |
| 400 | } else if self.is_nested() { |
| 401 | // Nested mode: use a default proxy config to forward env vars |
| 402 | let default_pc = crate::context::ResolvedProxyConfig::default(); |
| 403 | self.build_proxy_env_vars(&resolved, &default_pc) |
| 404 | } else { |
| 405 | Vec::new() |
| 406 | }; |
| 407 | |
| 408 | // Add TSK environment variables for container detection |
| 409 | env_vars.push("TSK_CONTAINER=1".to_string()); |
| 410 | env_vars.push(format!("TSK_TASK_ID={}", task.id)); |
| 411 | |
| 412 | // Add agent-specific environment variables |
| 413 | for (key, value) in agent.environment() { |
| 414 | env_vars.push(format!("{key}={value}")); |
| 415 | } |
| 416 | |
| 417 | // Add environment variables from resolved config (already merged from defaults + project) |
| 418 | for env_var in &resolved.env { |
| 419 | env_vars.push(format!("{}={}", env_var.name, env_var.value)); |
| 420 | } |
| 421 | |
| 422 | // Use chroot isolation for Podman/Buildah builds inside DIND containers. |
| 423 | // Full OCI isolation fails in nested user namespaces because the kernel |
| 424 | // denies devpts mounts (Permission denied). Chroot isolation avoids |
| 425 | // creating new namespaces or mounting devpts/proc/sysfs during RUN steps, |
| 426 | // which is safe since we're already inside a container. |
| 427 | if task.dind { |
| 428 | env_vars.push("BUILDAH_ISOLATION=chroot".to_string()); |
| 429 | } |
| 430 | |
| 431 | // Set PYTHONPATH for Python stacks so imports work from the project directory |
| 432 | if task.stack == "python" { |
| 433 | env_vars.push(format!("PYTHONPATH={working_dir}")); |
| 434 | } |
| 435 | |
| 436 | let agent_command = agent.build_command( |
| 437 | instructions_file_path.to_str().unwrap_or("instructions.md"), |
| 438 | task.is_interactive, |
| 439 | ); |
| 440 | |
| 441 | let command = if agent_command.is_empty() { |
no test coverage detected