(
program: &str,
args: &[String],
workdir: Option<&str>,
interactive: bool,
policy: &SandboxPolicy,
netns_fd: Option<RawFd>,
ca_paths: Option<&(
| 488 | #[cfg(target_os = "linux")] |
| 489 | #[allow(clippy::too_many_arguments)] |
| 490 | fn spawn_impl( |
| 491 | program: &str, |
| 492 | args: &[String], |
| 493 | workdir: Option<&str>, |
| 494 | interactive: bool, |
| 495 | policy: &SandboxPolicy, |
| 496 | netns_fd: Option<RawFd>, |
| 497 | ca_paths: Option<&(PathBuf, PathBuf)>, |
| 498 | provider_env: &HashMap<String, String>, |
| 499 | ) -> Result<Self> { |
| 500 | let mut cmd = Command::new(program); |
| 501 | cmd.args(args) |
| 502 | .stdin(Stdio::inherit()) |
| 503 | .stdout(Stdio::inherit()) |
| 504 | .stderr(Stdio::inherit()) |
| 505 | .kill_on_drop(true) |
| 506 | .env(openshell_core::sandbox_env::SANDBOX, "1"); |
| 507 | |
| 508 | // Strip supervisor-only identity material from the entrypoint's |
| 509 | // inherited environment. The entrypoint drops to the sandbox user |
| 510 | // before `exec`; without this strip, sandbox code could recover |
| 511 | // supervisor credentials from its inherited environment. |
| 512 | strip_supervisor_only_env(&mut cmd); |
| 513 | |
| 514 | inject_provider_env(&mut cmd, provider_env); |
| 515 | |
| 516 | if let Some(dir) = workdir { |
| 517 | cmd.current_dir(dir); |
| 518 | } |
| 519 | |
| 520 | if matches!(policy.network.mode, NetworkMode::Proxy) { |
| 521 | let proxy = policy.network.proxy.as_ref().ok_or_else(|| { |
| 522 | miette::miette!( |
| 523 | "Network mode is set to proxy but no proxy configuration was provided" |
| 524 | ) |
| 525 | })?; |
| 526 | // When using network namespace, set proxy URL to the veth host IP |
| 527 | if netns_fd.is_some() { |
| 528 | // The proxy is on 10.200.0.1:3128 (or configured port) |
| 529 | let port = proxy.http_addr.map_or(3128, |addr| addr.port()); |
| 530 | let proxy_url = format!("http://10.200.0.1:{port}"); |
| 531 | // Both uppercase and lowercase variants: curl/wget use uppercase, |
| 532 | // gRPC C-core (libgrpc) checks lowercase http_proxy/https_proxy. |
| 533 | for (key, value) in child_env::proxy_env_vars(&proxy_url) { |
| 534 | cmd.env(key, value); |
| 535 | } |
| 536 | } else if let Some(http_addr) = proxy.http_addr { |
| 537 | let proxy_url = format!("http://{http_addr}"); |
| 538 | for (key, value) in child_env::proxy_env_vars(&proxy_url) { |
| 539 | cmd.env(key, value); |
| 540 | } |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | // Set TLS trust store env vars so sandbox processes trust the ephemeral CA |
| 545 | if let Some((ca_cert_path, combined_bundle_path)) = ca_paths { |
| 546 | for (key, value) in child_env::tls_env_vars(ca_cert_path, combined_bundle_path) { |
| 547 | cmd.env(key, value); |
nothing calls this directly
no test coverage detected