Cache shell snapshots in the exec server (#39756)

## What changed

- Add the `shellSnapshotV2` executor capability and an optional shell snapshot request to `ExecParams`.
- Capture and restore Unix shell state and profile exports from an in-memory, attachment-scoped cache for `bash`, `zsh`, and `sh`.
- Apply environment policies, runtime `PATH` entries, sandbox context, and live managed-proxy settings when preparing restored commands.
- Bound snapshot size, capture time, scope length, and cache capacity, and fall back to the original command when capture fails.

## Testing

- Cover local, remote, TTY, sandboxed, and supported-shell execution, plus environment filtering, proxy handling, in-memory reuse, and capture failure fallback.

GitOrigin-RevId: 624f747972c249c88c6f10f42cf0af97b75b5541
This commit is contained in:
jif authored and copyberry committed 2026-08-20 17:39:06 +00:00
1 parent ce950dcf26
commit d0cc662b8c
20 files changed
+799 -1

No files matched your search

@@ -0,0 +1,87 @@
use std::collections::HashMap;
use codex_protocol::config_types::ShellEnvironmentPolicyInherit;
use pretty_assertions::assert_eq;
use super::parse_snapshot;
use crate::protocol::ExecEnvPolicy;
#[test]
fn snapshot_filters_profile_exports_after_capture() {
let policy = ExecEnvPolicy {
inherit: ShellEnvironmentPolicyInherit::All,
ignore_default_excludes: false,
exclude: vec!["PROFILE_DENIED".to_string()],
r#set: HashMap::from([("PROFILE_ALLOWED".to_string(), "override".to_string())]),
include_only: vec!["PROFILE_*".to_string()],
};
let snapshot = parse_snapshot(
b"profile noise\n# Snapshot file\nfunction profile_helper() { :; }\n\0PROFILE_ALLOWED=profile\0PROFILE_DENIED=denied\0PROFILE_SECRET=secret\0PWD=/tmp\0",
Some(&policy),
)
.expect("snapshot should parse");
assert_eq!(
snapshot.environment,
HashMap::from([("PROFILE_ALLOWED".to_string(), "override".to_string())])
);
assert_eq!(
snapshot.state,
"# Snapshot file\nfunction profile_helper() { :; }\n"
);
}
#[test]
fn snapshot_preserves_profile_exports_with_restrictive_inheritance() {
for inherit in [
ShellEnvironmentPolicyInherit::None,
ShellEnvironmentPolicyInherit::Core,
] {
let policy = ExecEnvPolicy {
inherit,
ignore_default_excludes: false,
exclude: vec!["PROFILE_DENIED".to_string()],
r#set: HashMap::new(),
include_only: Vec::new(),
};
let snapshot = parse_snapshot(
b"# Snapshot file\n\0PROFILE_ALLOWED=profile\0SDKROOT=/sdk\0PROFILE_SECRET=secret\0PROFILE_DENIED=denied\0",
Some(&policy),
)
.expect("snapshot should parse");
assert_eq!(
snapshot.environment,
HashMap::from([
("PROFILE_ALLOWED".to_string(), "profile".to_string()),
("SDKROOT".to_string(), "/sdk".to_string()),
])
);
}
}
#[test]
fn snapshot_caches_only_unmanaged_proxy_state() {
for (exports, expected) in [
(
"PROFILE_ALLOWED=profile\0HTTP_PROXY=http://127.0.0.1:4321\0CODEX_NETWORK_PROXY_ACTIVE=1\0CODEX_NETWORK_PROXY_CREDENTIAL_BROKER_ACTIVE=1\0",
HashMap::from([("PROFILE_ALLOWED".to_string(), "profile".to_string())]),
),
(
"PROFILE_ALLOWED=profile\0HTTP_PROXY=http://user-proxy.example\0",
HashMap::from([
("PROFILE_ALLOWED".to_string(), "profile".to_string()),
(
"HTTP_PROXY".to_string(),
"http://user-proxy.example".to_string(),
),
]),
),
] {
let output = format!("# Snapshot file\n\0{exports}");
let snapshot =
parse_snapshot(output.as_bytes(), /*env_policy*/ None).expect("snapshot should parse");
assert_eq!(snapshot.environment, expected);
}
}