Collect plugin metrics from remote executors (#38283)

## What changed

- Resolve manifest-declared metric operations against the executor filesystem for remote plugin commands.
- Create the measurement sidecar in an executor-native, owner-private temporary directory, stream its bounded output back for validation, and clean up the directory afterward.
- Extend the exec-server protocol with the executor temporary directory and atomic private-directory creation.

## Testing

- Cover remote unified-exec measurements for foreground and background commands.
- Verify private directories use owner-only permissions on Unix and fail closed on unsupported platforms.

GitOrigin-RevId: dbbd0a84717b91237fc5728e510e18994eb46dd4
This commit is contained in:
Kyle Brown
2026-08-13 00:27:55 +00:00
committed by copyberry
parent 1e71e35df6
commit 9579479d28
18 changed files with 416 additions and 82 deletions

View File

@@ -97,6 +97,9 @@ pub struct EnvironmentInfo {
/// On Windows, a command's `TEMP` or `TMP` overrides take precedence.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temporary_directories: Option<Vec<PathUri>>,
/// Executor-native temporary directory for private, child-visible sidecars.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temp_dir: Option<PathUri>,
/// Optional executor features that clients must gate before sending newer request fields.
#[serde(default)]
pub capabilities: EnvironmentCapabilities,
@@ -145,30 +148,33 @@ impl EnvironmentInfo {
} else {
&["TMPDIR"]
};
let normalize_temp_path = |path: std::ffi::OsString| {
PathUri::from_host_native_path(&path).ok().or_else(|| {
if cfg!(unix) {
PathUri::from_host_native_path(cwd.as_ref()?.join(path)).ok()
} else {
None
}
})
};
let mut temporary_directories = Vec::new();
for name in temporary_directory_env_vars {
if let Some(path) = std::env::var_os(name)
.filter(|path| !path.is_empty())
.filter(|path| cfg!(unix) || std::path::Path::new(path).is_absolute())
.and_then(|path| {
PathUri::from_host_native_path(&path).ok().or_else(|| {
if cfg!(unix) {
PathUri::from_host_native_path(cwd.as_ref()?.join(path)).ok()
} else {
None
}
})
})
.and_then(&normalize_temp_path)
&& !temporary_directories.contains(&path)
{
temporary_directories.push(path);
}
}
let temp_dir = normalize_temp_path(std::env::temp_dir().into_os_string());
Self {
shell: codex_shell_command::shell_detect::default_user_shell().into(),
cwd: cwd.and_then(|cwd| PathUri::from_host_native_path(cwd).ok()),
temporary_directories: Some(temporary_directories),
temp_dir,
capabilities: EnvironmentCapabilities {
network_proxy_launch: true,
capability_discovery_sandbox: true,
@@ -417,6 +423,9 @@ pub struct FsCreateDirectoryParams {
pub path: PathUri,
pub recursive: Option<bool>,
pub sandbox: Option<FileSystemSandboxContext>,
/// Atomically restrict a newly created, non-recursive directory to its owner.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub private: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -902,6 +911,7 @@ mod tests {
},
cwd: None,
temporary_directories: None,
temp_dir: None,
capabilities: EnvironmentCapabilities::default(),
}
);
@@ -1000,10 +1010,9 @@ mod tests {
.join("relative-temp"),
)
.expect("absolute temporary directory URI");
assert_eq!(
EnvironmentInfo::local().temporary_directories,
Some(vec![expected])
);
let info = EnvironmentInfo::local();
assert_eq!(info.temporary_directories, Some(vec![expected.clone()]));
assert_eq!(info.temp_dir, Some(expected));
}
#[test]