Suppress Windows console windows for background subprocesses (#49164)

## Why

Background helpers launched from a detached Windows process can allocate console windows. Job Object launches and containment fallbacks need to preserve console suppression as well.

## What changed

- Add `codex_utils_process::background_command` to set `CREATE_NO_WINDOW` on Windows, and use it across background subprocess launches, including Git, plugins, authentication, diagnostics, and sandbox helpers.
- Centralize console suppression in Job Object launches. Keep `CREATE_NO_WINDOW` when retrying without containment, and clear `CREATE_SUSPENDED` so the fallback child can run.
- Preserve console inheritance for interactive shell launches and interactive AWS authentication refreshes.

## Testing

Add Windows regression tests covering console-free launches from detached parents through standard and Tokio commands, stdout/stderr capture, successful containment, Job Object creation and assignment failures, and sandbox setup refresh helpers.

GitOrigin-RevId: b2c238fa7d4f9fbd868e5adf7d4be9958ff01e6c
This commit is contained in:
Eric Traut
2026-09-29 04:38:37 +00:00
committed by copyberry
parent 3226512d47
commit fbc169827e
44 changed files with 380 additions and 71 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ impl PluginGitMode {
/// Creates a Git command with the repository-environment policy for this operation.
/// Automatic remote lookups and initial clones must also select a trusted repository.
pub(crate) fn command(self, git_binary: &Path) -> Command {
let mut command = Command::new(git_binary);
let mut command = codex_utils_process::background_command(git_binary);
command.args(["-c", codex_git_utils::SAFE_BARE_REPOSITORY_CONFIG]);
if matches!(self, Self::Automatic) {
command.env("GIT_OPTIONAL_LOCKS", "0");
@@ -2,7 +2,6 @@ use super::MarketplaceAddError;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
pub(super) fn clone_git_source(
url: &str,
@@ -111,7 +110,7 @@ pub(super) fn marketplace_staging_root(install_root: &Path) -> PathBuf {
}
fn run_git(args: &[&str], cwd: Option<&Path>) -> Result<(), MarketplaceAddError> {
let mut command = Command::new("git");
let mut command = codex_utils_process::background_command("git");
command
.args(["-c", codex_git_utils::SAFE_BARE_REPOSITORY_CONFIG])
.args(args);
+1 -2
View File
@@ -5,7 +5,6 @@ use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
const NPM_PLUGIN_SOURCE_STAGING_DIR: &str = "plugins/.marketplace-plugin-source-staging";
@@ -87,7 +86,7 @@ fn pack_npm_package(
|| package.to_string(),
|version| format!("{package}@{version}"),
);
let mut command = Command::new(npm_command);
let mut command = codex_utils_process::background_command(npm_command);
command
.current_dir(destination)
.arg("pack")