mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Add trusted plugin script attribution (#35016)
## What changed - Build a set of active, verified curated and remote plugin roots from loaded plugins. - Resolve direct and safely wrapped script commands to a plugin ID and normalized plugin-relative path. - Leave complex or ambiguous commands, local overrides, missing files, overlapping roots, and symlink escapes unattributed. - Add a shared validator for the safe cross-platform shape of serialized plugin-relative paths. ## Testing - Cover trusted-root selection, supported interpreters and shell wrappers, normalized paths, and fail-closed cases. GitOrigin-RevId: 6e4199a241fd6dfadfec3df0845e7cb615352a49
This commit is contained in:
@@ -180,6 +180,24 @@ impl From<ExecCommandStatus> for CommandExecutionStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether a path is safe to serialize as a trusted plugin-relative path.
|
||||
///
|
||||
/// This validates the cross-platform wire shape only. The trusted plugin resolver
|
||||
/// remains responsible for establishing that the path actually came from a plugin root.
|
||||
pub fn is_safe_plugin_relative_path(path: &str) -> bool {
|
||||
!path.is_empty()
|
||||
&& !path.starts_with('/')
|
||||
&& !path.contains('\\')
|
||||
&& path.split('/').all(|component| {
|
||||
!component.is_empty()
|
||||
&& !matches!(component, "." | "..")
|
||||
&& !matches!(
|
||||
component.as_bytes(),
|
||||
[drive, b':', ..] if drive.is_ascii_alphabetic()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq)]
|
||||
pub struct CommandExecutionItem {
|
||||
pub id: String,
|
||||
@@ -704,6 +722,28 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_relative_paths_use_safe_wire_shape() {
|
||||
assert!(is_safe_plugin_relative_path("scripts/run.py"));
|
||||
|
||||
for path in [
|
||||
"",
|
||||
"/home/user/.codex/plugins/cache/sample/scripts/run.py",
|
||||
"C:/Users/user/.codex/plugins/cache/sample/scripts/run.py",
|
||||
"scripts/C:/run.py",
|
||||
r"\\server\share\sample\scripts\run.py",
|
||||
r"scripts\run.py",
|
||||
"scripts//run.py",
|
||||
"scripts/./run.py",
|
||||
"scripts/../run.py",
|
||||
] {
|
||||
assert!(
|
||||
!is_safe_plugin_relative_path(path),
|
||||
"unsafe plugin-relative path should be rejected: {path:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hook_prompt_roundtrips_multiple_fragments() {
|
||||
let original = vec![
|
||||
|
||||
Reference in New Issue
Block a user