mirror of
https://github.com/openai/codex.git
synced 2026-09-10 20:26:47 +00:00
Expose trusted PowerShell parser selection by flavor
This commit is contained in:
@@ -4,8 +4,10 @@ pub mod is_dangerous_command;
|
||||
pub mod is_safe_command;
|
||||
#[cfg(windows)]
|
||||
pub(crate) mod windows_safe_commands;
|
||||
pub(crate) use powershell_parser::TrustedPowerShellFlavor;
|
||||
#[cfg(all(test, windows))]
|
||||
pub(crate) use powershell_parser::trusted_standard_pwsh_invocation_path;
|
||||
#[cfg(all(test, windows))]
|
||||
pub(crate) use powershell_parser::trusted_windows_powershell_invocation_path;
|
||||
pub(crate) use powershell_parser::try_parse_powershell_ast_commands;
|
||||
pub(crate) use powershell_parser::try_parse_powershell_ast_commands_with_trusted_flavor;
|
||||
|
||||
@@ -55,6 +55,46 @@ pub(crate) fn try_parse_powershell_ast_commands(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum TrustedPowerShellFlavor {
|
||||
WindowsPowerShell,
|
||||
PowerShell7,
|
||||
}
|
||||
|
||||
/// Parses a script with the authoritative machine-wide parser for the requested flavor.
|
||||
///
|
||||
/// Unlike [`try_parse_powershell_ast_commands`], parser selection here is independent of a
|
||||
/// runtime command's executable spelling. This lets callers inspect an untrusted runtime wrapper
|
||||
/// without ever spawning that wrapper before approval.
|
||||
pub(crate) fn try_parse_powershell_ast_commands_with_trusted_flavor(
|
||||
flavor: TrustedPowerShellFlavor,
|
||||
script: &str,
|
||||
) -> Option<Vec<Vec<String>>> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let parser_executable = match flavor {
|
||||
TrustedPowerShellFlavor::WindowsPowerShell => trusted_powershell_invocation_path(
|
||||
TrustedPowerShellRoot::System,
|
||||
WINDOWS_POWERSHELL_SUFFIX,
|
||||
),
|
||||
TrustedPowerShellFlavor::PowerShell7 => trusted_powershell_invocation_path(
|
||||
TrustedPowerShellRoot::ProgramFiles,
|
||||
WINDOWS_PWSH_SUFFIX,
|
||||
),
|
||||
}?;
|
||||
match parse_with_powershell_ast(&parser_executable, script) {
|
||||
PowershellParseOutcome::Commands(commands) => Some(commands),
|
||||
PowershellParseOutcome::Unsupported | PowershellParseOutcome::Failed => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = (flavor, script);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Selects the host-side parser only when the command itself names that same trusted binary.
|
||||
///
|
||||
/// The parser runs before the command approval and sandbox boundaries. Bare executable names and
|
||||
@@ -94,7 +134,7 @@ pub(crate) fn trusted_standard_pwsh_invocation_path() -> Option<PathBuf> {
|
||||
trusted_powershell_invocation_path(TrustedPowerShellRoot::ProgramFiles, WINDOWS_PWSH_SUFFIX)
|
||||
}
|
||||
|
||||
#[cfg(all(test, windows))]
|
||||
#[cfg(windows)]
|
||||
fn trusted_powershell_invocation_path(
|
||||
root_kind: TrustedPowerShellRoot,
|
||||
suffix: &str,
|
||||
@@ -102,8 +142,7 @@ fn trusted_powershell_invocation_path(
|
||||
let root = trusted_windows_root(root_kind).ok()?;
|
||||
let invocation_path = join_windows_path(&root, suffix);
|
||||
let invocation_path_str = invocation_path.to_str()?;
|
||||
trusted_powershell_parser_executable(invocation_path_str)?;
|
||||
Some(invocation_path)
|
||||
trusted_powershell_parser_executable(invocation_path_str)
|
||||
}
|
||||
|
||||
#[cfg(any(test, windows))]
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::path::PathBuf;
|
||||
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
use crate::command_safety::TrustedPowerShellFlavor;
|
||||
use crate::command_safety::try_parse_powershell_ast_commands;
|
||||
use crate::command_safety::try_parse_powershell_ast_commands_with_trusted_flavor;
|
||||
use crate::shell_detect::ShellType;
|
||||
use crate::shell_detect::detect_shell_type;
|
||||
|
||||
@@ -82,6 +84,28 @@ pub fn parse_powershell_command_into_plain_commands(
|
||||
try_parse_powershell_ast_commands(executable, script)
|
||||
}
|
||||
|
||||
/// Selects which protected machine-wide PowerShell installation parses a script.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum PowerShellFlavor {
|
||||
WindowsPowerShell,
|
||||
PowerShell7,
|
||||
}
|
||||
|
||||
/// Parses a PowerShell script without using the runtime wrapper as the parser executable.
|
||||
///
|
||||
/// The selected parser comes from the authoritative Windows System or Program Files known folder.
|
||||
/// On unsupported hosts, or when the protected parser is unavailable, this fails closed.
|
||||
pub fn parse_powershell_script_with_trusted_parser(
|
||||
flavor: PowerShellFlavor,
|
||||
script: &str,
|
||||
) -> Option<Vec<Vec<String>>> {
|
||||
let trusted_flavor = match flavor {
|
||||
PowerShellFlavor::WindowsPowerShell => TrustedPowerShellFlavor::WindowsPowerShell,
|
||||
PowerShellFlavor::PowerShell7 => TrustedPowerShellFlavor::PowerShell7,
|
||||
};
|
||||
try_parse_powershell_ast_commands_with_trusted_flavor(trusted_flavor, script)
|
||||
}
|
||||
|
||||
/// This function attempts to find a powershell.exe executable on the system.
|
||||
pub fn try_find_powershell_executable_blocking() -> Option<AbsolutePathBuf> {
|
||||
try_find_powershellish_executable_in_path(&["powershell.exe"])
|
||||
@@ -152,10 +176,14 @@ fn is_powershellish_executable_available(powershell_or_pwsh_exe: &std::path::Pat
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(windows)]
|
||||
use super::PowerShellFlavor;
|
||||
use super::UTF8_OUTPUT_PREFIX;
|
||||
use super::extract_powershell_command;
|
||||
#[cfg(windows)]
|
||||
use super::parse_powershell_command_into_plain_commands;
|
||||
#[cfg(windows)]
|
||||
use super::parse_powershell_script_with_trusted_parser;
|
||||
use super::prefix_powershell_script_with_utf8;
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -277,4 +305,29 @@ mod tests {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn parses_with_authoritative_parser_selected_independently_of_runtime_wrapper() {
|
||||
assert_eq!(
|
||||
parse_powershell_script_with_trusted_parser(
|
||||
PowerShellFlavor::WindowsPowerShell,
|
||||
"Write-Output windows",
|
||||
),
|
||||
Some(vec![vec![
|
||||
"Write-Output".to_string(),
|
||||
"windows".to_string(),
|
||||
]]),
|
||||
);
|
||||
|
||||
if crate::command_safety::trusted_standard_pwsh_invocation_path().is_some() {
|
||||
assert_eq!(
|
||||
parse_powershell_script_with_trusted_parser(
|
||||
PowerShellFlavor::PowerShell7,
|
||||
"Write-Output core",
|
||||
),
|
||||
Some(vec![vec!["Write-Output".to_string(), "core".to_string(),]]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user