mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
## Why Line-based export parsing can truncate multiline values or mistake their contents for declarations. Snapshot replay also needs to restore Bash options before parsing functions that use extended glob syntax. ## What changed - Capture shell state, aliases, and complete export records with NUL-delimited boundaries, separating capture, credential preparation, and rendering. - Apply credential and environment policy to whole exports, preserving multiline values and making credential aliases follow allowed overrides. - Restore Bash `shopt` options before functions, including for Bash running as `sh`. - Support non-evaluating POSIX `ENV` path expansion and preserve native environment metadata and unset exports. - Move core and exec-server snapshot consumers to the shared capture parser. Allow capture overhead while enforcing the exec-server's 512 KiB state-and-environment limit before filtering. ## Testing Add regression coverage for complete capture records, multiline export filtering and replay, credential alias overrides, `ENV` expansion, and `PATH` export state. Extend exec-server tests to cover Bash-backed `sh`, `extglob`, `nocasematch`, `set -u`, and large environments. GitOrigin-RevId: 7589ab4d137529a395dcee10b5162718de24a621
82 lines
2.2 KiB
Rust
82 lines
2.2 KiB
Rust
//! Capture native export declarations and unset POSIX exports.
|
|
//! Set POSIX values are captured in bulk for quoting in Rust.
|
|
|
|
use crate::shell_detect::ShellType;
|
|
|
|
pub(super) fn script(shell_type: ShellType) -> String {
|
|
let script = match shell_type {
|
|
ShellType::Bash => {
|
|
r#"(
|
|
while IFS= read -r __codex_snapshot_export_name; do
|
|
case "$__codex_snapshot_export_name" in
|
|
""|[0-9]*|*[!A-Za-z0-9_]*|PWD|OLDPWD) continue ;;
|
|
esac
|
|
RECORD_START
|
|
declare -xp "$__codex_snapshot_export_name" 2>/dev/null || true
|
|
RECORD_END
|
|
done < <(compgen -e)
|
|
)
|
|
"#
|
|
}
|
|
ShellType::Zsh => {
|
|
r#"(
|
|
unsetopt rcquotes
|
|
# The bundled Zsh does not include the zsh/parameter module.
|
|
for __codex_snapshot_export_name in ${(f)"$(typeset +x)"}; do
|
|
case "$__codex_snapshot_export_name" in
|
|
""|[0-9]*|*[!A-Za-z0-9_]*|PWD|OLDPWD) continue ;;
|
|
esac
|
|
case "${(tP)__codex_snapshot_export_name}" in
|
|
*readonly*) continue ;;
|
|
*export*) ;;
|
|
*) continue ;;
|
|
esac
|
|
RECORD_START
|
|
typeset -xp "$__codex_snapshot_export_name"
|
|
RECORD_END
|
|
done
|
|
)
|
|
"#
|
|
}
|
|
ShellType::Sh => {
|
|
r#"if export -p >/dev/null 2>&1; then
|
|
export -p | __codex_snapshot_command awk '
|
|
/^(export|declare -x|typeset -x) [A-Za-z_][A-Za-z0-9_]*$/ {
|
|
name=$0
|
|
sub(/^(export|declare -x|typeset -x) /, "", name)
|
|
if (name ~ /^(PWD|OLDPWD)$/) {
|
|
next
|
|
}
|
|
if (!seen[name]++) {
|
|
print name
|
|
}
|
|
}' | while IFS= read -r __codex_snapshot_export_name; do
|
|
# Only the validated identifier enters eval. Set values come from the bulk environment.
|
|
if eval '[ "${'"$__codex_snapshot_export_name"'+x}" = x ]'; then
|
|
continue
|
|
fi
|
|
# Only preserve an unset export if the native shell confirms it already exists.
|
|
if (
|
|
set +a
|
|
set -- "$__codex_snapshot_export_name" "$(export -p)"
|
|
export "$1"
|
|
[ "$2" = "$(export -p)" ]
|
|
); then
|
|
RECORD_START
|
|
printf 'export %s\n' "$__codex_snapshot_export_name"
|
|
RECORD_END
|
|
fi
|
|
done
|
|
fi
|
|
"#
|
|
}
|
|
ShellType::PowerShell | ShellType::Cmd => return String::new(),
|
|
};
|
|
script
|
|
.replace(
|
|
"RECORD_START",
|
|
"printf '%s\\0' \"$__codex_snapshot_export_name\"",
|
|
)
|
|
.replace("RECORD_END", "printf '\\0'")
|
|
}
|