feat: add shell snapshot for shell command (#7786)

This commit is contained in:
jif-oai
2025-12-11 13:46:43 +00:00
committed by GitHub
parent b2280d6205
commit 29381ba5c2
14 changed files with 301 additions and 129 deletions

View File

@@ -7,6 +7,7 @@ small and focused and reuses the orchestrator for approvals + sandbox + retry.
use crate::exec::ExecExpiration;
use crate::sandboxing::CommandSpec;
use crate::sandboxing::SandboxPermissions;
use crate::shell::Shell;
use crate::tools::sandboxing::ToolError;
use std::collections::HashMap;
use std::path::Path;
@@ -38,3 +39,39 @@ pub(crate) fn build_command_spec(
justification,
})
}
/// POSIX-only helper: for commands produced by `Shell::derive_exec_args`
/// for Bash/Zsh/sh of the form `[shell_path, "-lc", "<script>"]`, and
/// when a snapshot is configured on the session shell, rewrite the argv
/// to a single non-login shell that sources the snapshot before running
/// the original script:
///
/// shell -lc "<script>"
/// => shell -c ". SNAPSHOT && <script>"
///
/// On non-POSIX shells or non-matching commands this is a no-op.
pub(crate) fn maybe_wrap_shell_lc_with_snapshot(
command: &[String],
session_shell: &Shell,
) -> Vec<String> {
let Some(snapshot) = &session_shell.shell_snapshot else {
return command.to_vec();
};
if command.len() < 3 {
return command.to_vec();
}
let flag = command[1].as_str();
if flag != "-lc" {
return command.to_vec();
}
let snapshot_path = snapshot.path.to_string_lossy();
let rewritten_script = format!(". \"{snapshot_path}\" && {}", command[2]);
let mut rewritten = command.to_vec();
rewritten[1] = "-c".to_string();
rewritten[2] = rewritten_script;
rewritten
}