## Why
On Windows, Codex uses a PowerShell safe-command classifier to decide
whether a command is read-only enough to run without additional
approval. The classifier lowers `EndBlock.Statements` into argv-like
command words and checks those words against a safelist.
PowerShell can execute code stored elsewhere in the AST. Parameter
defaults, named blocks, `using` preambles, and top-level `trap` handlers
are not represented in the lowered statement list. Ignoring those
regions can make a side-effecting script look like a read-only command.
## What
Fail closed whenever a PowerShell script contains executable AST content
that the current lowering does not represent.
## How
- Return `unsupported` for parameter, dynamic-parameter, begin, process,
and clean blocks.
- Return `unsupported` for `using module` and `using assembly`
preambles.
- Return `unsupported` for non-empty `EndBlock.Traps` collections.
- Preserve compatibility with Windows PowerShell 5.1 by looking up
`CleanBlock` dynamically.
- Treat `unsupported` as a failure to prove that the command is safe,
routing it through the normal approval path.
- Add parser-level and end-to-end regressions for parameter blocks,
named blocks, using statements, and trap handlers.
This does not make these PowerShell forms invalid or prevent them from
running. It prevents automatic safe-command approval when the classifier
cannot account for all executable behavior.
## Testing
- `just test -p codex-shell-command`
- Windows CI exercises the parser and end-to-end safe-command
regressions against a real PowerShell installation.
---------
Co-authored-by: viyatb-oai <viyatb@openai.com>
## Summary
- Treat PowerShell stop-parsing token forms as unsupported in the
AST-backed command flattener.
- Add focused regressions at the parser layer and Windows command-safety
layer.
## Why
The command-safety parser lowers PowerShell AST elements into argv-like
words. Stop-parsing syntax preserves a native-command argument shape
that this lowering does not model, so these forms should stay on the
conservative unsupported path.
## Validation
- `cargo fmt --manifest-path codex-rs/Cargo.toml --all --check`
- `cargo test --manifest-path codex-rs/Cargo.toml -p
codex-shell-command`
## Why
`//codex-rs/shell-command:shell-command-unit-tests` became a real
bottleneck in the Windows Bazel lane because repeated calls to
`is_safe_command_windows()` were starting a fresh PowerShell parser
process for every `powershell.exe -Command ...` assertion.
PR #16056 was motivated by that same bottleneck, but its test-only
shortcut was the wrong layer to optimize because it weakened the
end-to-end guarantee that our runtime path really asks PowerShell to
parse the command the way we expect.
This PR attacks the actual cost center instead: it keeps the real
PowerShell parser in the loop, but turns that parser into a long-lived
helper process so both tests and the runtime safe-command path can reuse
it across many requests.
## What Changed
- add `shell-command/src/command_safety/powershell_parser.rs`, which
keeps one mutex-protected parser process per PowerShell executable path
and speaks a simple JSON-over-stdio request/response protocol
- turn `shell-command/src/command_safety/powershell_parser.ps1` into a
long-running parser server with comments explaining the protocol, the
AST-shape restrictions, and why unsupported constructs are rejected
conservatively
- keep request ids and a one-time respawn path so a dead or
desynchronized cached child fails closed instead of silently returning
mixed parser output
- preserve separate parser processes for `powershell.exe` and
`pwsh.exe`, since they do not accept the same language surface
- avoid a direct `PipelineChainAst` type reference in the PowerShell
script so the parser service still runs under Windows PowerShell 5.1 as
well as newer `pwsh`
- make `shell-command/src/command_safety/windows_safe_commands.rs`
delegate to the new parser utility instead of spawning a fresh
PowerShell process for every parse
- add a Windows-only unit test that exercises multiple sequential
requests against the same parser process
## Testing
- adds a Windows-only parser-reuse unit test in `powershell_parser.rs`
- the main end-to-end verification for this change is the Windows CI
lane, because the new service depends on real `powershell.exe` /
`pwsh.exe` behavior