[codex] Handle PowerShell UTF-8 setup failures (#24949)

Fixes #12496.

## Why

Windows sandboxed PowerShell commands can run under
`ConstrainedLanguage` on some machines, especially enterprise-managed
Windows environments. In that mode, our PowerShell command prelude could
fail before every command because it directly assigned
`[Console]::OutputEncoding` to UTF-8. The actual user command still ran,
but Codex surfaced noisy `Cannot set property. Property setting is
supported only on core types in this language mode.` output for every
shell call.

## What Changed

- Makes the PowerShell UTF-8 output encoding prelude best-effort by
wrapping the assignment in `try { ... } catch {}`.
- Keeps the existing UTF-8 behavior when PowerShell allows the
assignment.
- Adds focused tests for adding the prelude and avoiding duplicate
prelude insertion.

## Validation

- `cargo fmt -p codex-shell-command`
- `cargo check -p codex-shell-command`
- `git diff --check`
- Verified a local `ConstrainedLanguage` PowerShell probe prints only
the command output with no property-setting error.
- Verified `codex exec` from a temporary `chcp 437` context reports
`utf-8` / `65001` and preserves non-ASCII output (`café`, `漢字`).
This commit is contained in:
iceweasel-oai
2026-05-28 13:58:20 -07:00
committed by GitHub
Unverified
parent 2e0c4f4977
commit d9f53128b7
+36 -2
View File
@@ -8,8 +8,9 @@ use crate::shell_detect::detect_shell_type;
const POWERSHELL_FLAGS: &[&str] = &["-nologo", "-noprofile", "-command", "-c"];
/// Prefixed command for powershell shell calls to force UTF-8 console output.
pub const UTF8_OUTPUT_PREFIX: &str = "[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;\n";
/// Prefixed command for powershell shell calls to request UTF-8 console output.
pub const UTF8_OUTPUT_PREFIX: &str =
"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
pub fn prefix_powershell_script_with_utf8(command: &[String]) -> Vec<String> {
let Some((_, script)) = extract_powershell_command(command) else {
@@ -151,9 +152,11 @@ fn is_powershellish_executable_available(powershell_or_pwsh_exe: &std::path::Pat
#[cfg(test)]
mod tests {
use super::UTF8_OUTPUT_PREFIX;
use super::extract_powershell_command;
#[cfg(windows)]
use super::parse_powershell_command_into_plain_commands;
use super::prefix_powershell_script_with_utf8;
#[test]
fn extracts_basic_powershell_command() {
@@ -202,6 +205,37 @@ mod tests {
assert_eq!(script, "Get-ChildItem | Select-String foo");
}
#[test]
fn prefixes_powershell_command_with_best_effort_utf8() {
let cmd = vec![
"powershell".to_string(),
"-Command".to_string(),
"Write-Host hi".to_string(),
];
let prefixed = prefix_powershell_script_with_utf8(&cmd);
assert_eq!(
prefixed,
vec![
"powershell".to_string(),
"-Command".to_string(),
format!("{UTF8_OUTPUT_PREFIX}Write-Host hi"),
]
);
}
#[test]
fn does_not_duplicate_utf8_prefix() {
let cmd = vec![
"powershell".to_string(),
"-Command".to_string(),
format!("{UTF8_OUTPUT_PREFIX}Write-Host hi"),
];
assert_eq!(prefix_powershell_script_with_utf8(&cmd), cmd);
}
#[cfg(windows)]
#[test]
fn parses_plain_powershell_commands() {