mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Attribute command executions to trusted plugin scripts (#35020)
## What changed - Resolve shell and unified-exec commands against the trusted plugin roots loaded for each turn. - Add optional `pluginId` and safe plugin-relative `scriptPath` fields to command execution items and legacy execution events, and propagate them through app-server notifications. - Include the attribution in command execution analytics while rejecting absolute, unsafe, and unattributed script paths. ## Testing - Cover attribution for cached curated and remote plugin scripts from command execution through core and app-server events. - Verify analytics serialization and unsafe-path filtering. GitOrigin-RevId: 02fac3a233284ccfc6642fa502a95f1881dba83d
This commit is contained in:
@@ -18,6 +18,7 @@ use crate::tools::events::ToolEventCtx;
|
||||
use crate::tools::events::ToolEventFailure;
|
||||
use crate::tools::events::ToolEventStage;
|
||||
use crate::unified_exec::head_tail_buffer::HeadTailBuffer;
|
||||
use codex_core_plugins::PluginCommandAttribution;
|
||||
use codex_protocol::exec_output::ExecToolCallOutput;
|
||||
use codex_protocol::exec_output::StreamOutput;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
@@ -162,6 +163,7 @@ pub(crate) fn spawn_exit_watcher(
|
||||
command: Vec<String>,
|
||||
cwd: PathUri,
|
||||
process_id: i32,
|
||||
plugin_attribution: Option<PluginCommandAttribution>,
|
||||
transcript: Arc<Mutex<HeadTailBuffer>>,
|
||||
started_at: Instant,
|
||||
network_denial_monitor: Option<tokio::task::JoinHandle<()>>,
|
||||
@@ -190,6 +192,7 @@ pub(crate) fn spawn_exit_watcher(
|
||||
command,
|
||||
cwd,
|
||||
Some(process_id.to_string()),
|
||||
plugin_attribution,
|
||||
transcript,
|
||||
String::new(),
|
||||
message,
|
||||
@@ -205,6 +208,7 @@ pub(crate) fn spawn_exit_watcher(
|
||||
command,
|
||||
cwd,
|
||||
Some(process_id.to_string()),
|
||||
plugin_attribution,
|
||||
transcript,
|
||||
String::new(),
|
||||
exit_code,
|
||||
@@ -258,6 +262,7 @@ pub(crate) async fn emit_exec_end_for_unified_exec(
|
||||
command: Vec<String>,
|
||||
cwd: PathUri,
|
||||
process_id: Option<String>,
|
||||
plugin_attribution: Option<PluginCommandAttribution>,
|
||||
transcript: Arc<Mutex<HeadTailBuffer>>,
|
||||
fallback_output: String,
|
||||
exit_code: i32,
|
||||
@@ -283,6 +288,7 @@ pub(crate) async fn emit_exec_end_for_unified_exec(
|
||||
cwd,
|
||||
ExecCommandSource::UnifiedExecStartup,
|
||||
process_id,
|
||||
plugin_attribution,
|
||||
);
|
||||
emitter
|
||||
.emit(
|
||||
@@ -303,6 +309,7 @@ pub(crate) async fn emit_failed_exec_end_for_unified_exec(
|
||||
command: Vec<String>,
|
||||
cwd: PathUri,
|
||||
process_id: Option<String>,
|
||||
plugin_attribution: Option<PluginCommandAttribution>,
|
||||
transcript: Arc<Mutex<HeadTailBuffer>>,
|
||||
fallback_output: String,
|
||||
message: String,
|
||||
@@ -337,6 +344,7 @@ pub(crate) async fn emit_failed_exec_end_for_unified_exec(
|
||||
cwd,
|
||||
ExecCommandSource::UnifiedExecStartup,
|
||||
process_id,
|
||||
plugin_attribution,
|
||||
);
|
||||
emitter
|
||||
.emit(
|
||||
|
||||
@@ -160,6 +160,7 @@ async fn exit_watcher_waits_for_late_network_denial_before_classifying_end() ->
|
||||
vec!["proof".to_string()],
|
||||
cwd,
|
||||
/*process_id*/ 123,
|
||||
/*plugin_attribution*/ None,
|
||||
transcript,
|
||||
Instant::now(),
|
||||
Some(network_denial_monitor),
|
||||
|
||||
@@ -58,6 +58,7 @@ use crate::unified_exec::process::OutputBuffer;
|
||||
use crate::unified_exec::process::OutputHandles;
|
||||
use crate::unified_exec::process::SpawnLifecycleHandle;
|
||||
use crate::unified_exec::process::UnifiedExecProcess;
|
||||
use codex_core_plugins::PluginCommandAttribution;
|
||||
use codex_network_proxy::NetworkProxy;
|
||||
use codex_protocol::config_types::ShellEnvironmentPolicy;
|
||||
use codex_protocol::error::CodexErr;
|
||||
@@ -326,6 +327,7 @@ async fn emit_failed_initial_exec_end_if_unstored(
|
||||
context: &UnifiedExecContext,
|
||||
request: &ExecCommandRequest,
|
||||
cwd: PathUri,
|
||||
plugin_attribution: Option<PluginCommandAttribution>,
|
||||
transcript: Arc<tokio::sync::Mutex<HeadTailBuffer>>,
|
||||
fallback_output: String,
|
||||
message: String,
|
||||
@@ -342,6 +344,7 @@ async fn emit_failed_initial_exec_end_if_unstored(
|
||||
request.command.clone(),
|
||||
cwd,
|
||||
Some(request.process_id.to_string()),
|
||||
plugin_attribution,
|
||||
transcript,
|
||||
fallback_output,
|
||||
message,
|
||||
@@ -445,11 +448,17 @@ impl UnifiedExecProcessManager {
|
||||
&context.call_id,
|
||||
/*turn_diff_tracker*/ None,
|
||||
);
|
||||
let plugin_attribution = cwd.to_abs_path().ok().and_then(|cwd| {
|
||||
context
|
||||
.turn
|
||||
.plugin_attribution_for_command(&request.command, &cwd)
|
||||
});
|
||||
let emitter = ToolEmitter::unified_exec(
|
||||
&request.command,
|
||||
cwd.clone(),
|
||||
ExecCommandSource::UnifiedExecStartup,
|
||||
Some(request.process_id.to_string()),
|
||||
plugin_attribution.clone(),
|
||||
);
|
||||
emitter.emit(event_ctx, ToolEventStage::Begin).await;
|
||||
|
||||
@@ -466,6 +475,7 @@ impl UnifiedExecProcessManager {
|
||||
&request.command,
|
||||
request.hook_command.clone(),
|
||||
cwd.clone(),
|
||||
plugin_attribution.clone(),
|
||||
start,
|
||||
request.process_id,
|
||||
request.tty,
|
||||
@@ -528,6 +538,7 @@ impl UnifiedExecProcessManager {
|
||||
context,
|
||||
&request,
|
||||
cwd.clone(),
|
||||
plugin_attribution.clone(),
|
||||
Arc::clone(&transcript),
|
||||
text.clone(),
|
||||
message.clone(),
|
||||
@@ -548,6 +559,7 @@ impl UnifiedExecProcessManager {
|
||||
context,
|
||||
&request,
|
||||
cwd.clone(),
|
||||
plugin_attribution.clone(),
|
||||
Arc::clone(&transcript),
|
||||
text.clone(),
|
||||
message.clone(),
|
||||
@@ -607,6 +619,7 @@ impl UnifiedExecProcessManager {
|
||||
context,
|
||||
&request,
|
||||
cwd.clone(),
|
||||
plugin_attribution.clone(),
|
||||
Arc::clone(&transcript),
|
||||
text.clone(),
|
||||
message.clone(),
|
||||
@@ -625,6 +638,7 @@ impl UnifiedExecProcessManager {
|
||||
request.command.clone(),
|
||||
cwd.clone(),
|
||||
Some(process_id.to_string()),
|
||||
plugin_attribution.clone(),
|
||||
Arc::clone(&transcript),
|
||||
text.clone(),
|
||||
exit,
|
||||
@@ -929,6 +943,7 @@ impl UnifiedExecProcessManager {
|
||||
command: &[String],
|
||||
hook_command: String,
|
||||
cwd: PathUri,
|
||||
plugin_attribution: Option<PluginCommandAttribution>,
|
||||
started_at: Instant,
|
||||
process_id: i32,
|
||||
tty: bool,
|
||||
@@ -970,6 +985,7 @@ impl UnifiedExecProcessManager {
|
||||
command.to_vec(),
|
||||
cwd,
|
||||
process_id,
|
||||
plugin_attribution,
|
||||
transcript,
|
||||
started_at,
|
||||
network_denial_monitor,
|
||||
|
||||
@@ -394,6 +394,7 @@ async fn failed_initial_end_for_unstored_process_uses_fallback_output() {
|
||||
&request,
|
||||
#[allow(deprecated)]
|
||||
turn.cwd.clone().into(),
|
||||
/*plugin_attribution*/ None,
|
||||
transcript,
|
||||
"PRE_DENIAL_MARKER".to_string(),
|
||||
"Network access denied".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user