(
server: &str,
name: &str,
command: &[String],
workdir: Option<&str>,
timeout_seconds: u32,
tty_override: Option<bool>,
environment: &HashMap<String, String>,
tls: &Tl
| 2727 | /// Returns the remote command's exit code. |
| 2728 | #[allow(clippy::too_many_arguments, clippy::implicit_hasher)] |
| 2729 | pub async fn sandbox_exec_grpc( |
| 2730 | server: &str, |
| 2731 | name: &str, |
| 2732 | command: &[String], |
| 2733 | workdir: Option<&str>, |
| 2734 | timeout_seconds: u32, |
| 2735 | tty_override: Option<bool>, |
| 2736 | environment: &HashMap<String, String>, |
| 2737 | tls: &TlsOptions, |
| 2738 | ) -> Result<i32> { |
| 2739 | let mut client = grpc_client(server, tls).await?; |
| 2740 | |
| 2741 | // Resolve sandbox name to id. |
| 2742 | let sandbox = client |
| 2743 | .get_sandbox(GetSandboxRequest { |
| 2744 | name: name.to_string(), |
| 2745 | }) |
| 2746 | .await |
| 2747 | .into_diagnostic()? |
| 2748 | .into_inner() |
| 2749 | .sandbox |
| 2750 | .ok_or_else(|| miette::miette!("sandbox not found"))?; |
| 2751 | |
| 2752 | // Verify the sandbox is ready before issuing the exec. |
| 2753 | if SandboxPhase::try_from(sandbox.phase()) != Ok(SandboxPhase::Ready) { |
| 2754 | return Err(miette::miette!( |
| 2755 | "sandbox '{}' is not ready (phase: {}); wait for it to reach Ready state", |
| 2756 | name, |
| 2757 | phase_name(sandbox.phase()) |
| 2758 | )); |
| 2759 | } |
| 2760 | |
| 2761 | // Read stdin if piped (not a TTY), using spawn_blocking to avoid blocking |
| 2762 | // the async runtime. Cap the read at MAX_STDIN_PAYLOAD + 1 so we never |
| 2763 | // buffer more than the limit into memory. |
| 2764 | let stdin_payload = if std::io::stdin().is_terminal() { |
| 2765 | Vec::new() |
| 2766 | } else { |
| 2767 | tokio::task::spawn_blocking(|| { |
| 2768 | let limit = (MAX_STDIN_PAYLOAD + 1) as u64; |
| 2769 | let mut buf = Vec::new(); |
| 2770 | std::io::stdin() |
| 2771 | .take(limit) |
| 2772 | .read_to_end(&mut buf) |
| 2773 | .into_diagnostic()?; |
| 2774 | if buf.len() > MAX_STDIN_PAYLOAD { |
| 2775 | return Err(miette::miette!( |
| 2776 | "stdin payload exceeds {} byte limit; pipe smaller inputs or use `sandbox upload`", |
| 2777 | MAX_STDIN_PAYLOAD |
| 2778 | )); |
| 2779 | } |
| 2780 | Ok(buf) |
| 2781 | }) |
| 2782 | .await |
| 2783 | .into_diagnostic()?? // first ? unwraps JoinError, second ? unwraps Result |
| 2784 | }; |
| 2785 | |
| 2786 | // Resolve TTY mode: explicit --tty / --no-tty wins, otherwise auto-detect. |
no test coverage detected