Files
codex/codex-rs/rollout-trace/src/protocol_event_tests.rs
T
Kyle Brown 9fc4e5a7aa Preserve plugin attribution across command approvals (#35029)
## What changed

- Add optional `plugin_id` and `script_path` fields to execution approval and guardian assessment events.
- Propagate validated plugin attribution through delegated approvals, guardian-reviewed command items, app-server notifications, thread history, and rollout traces.
- Preserve attribution on both started and completed command items, including declined commands.

## Testing

- Extend core, app-server, thread-history, and rollout-trace tests to cover plugin attribution propagation and serialization.

GitOrigin-RevId: 723684d010cab04142918d7a95e06ed95d008da1
2026-07-23 23:13:59 +00:00

138 lines
4.7 KiB
Rust

use codex_protocol::AgentPath;
use codex_protocol::ThreadId;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::ExecCommandBeginEvent;
use codex_protocol::protocol::ExecCommandEndEvent;
use codex_protocol::protocol::ExecCommandSource;
use codex_protocol::protocol::ExecCommandStatus;
use codex_protocol::protocol::SubAgentActivityEvent;
use codex_protocol::protocol::SubAgentActivityKind;
use pretty_assertions::assert_eq;
use serde_json::json;
use std::time::Duration;
use super::ToolRuntimeTraceEvent;
use super::tool_runtime_trace_event;
use crate::ExecutionStatus;
#[test]
fn sub_agent_activity_is_a_terminal_tool_runtime_event() -> anyhow::Result<()> {
let agent_thread_id = ThreadId::new();
let event = EventMsg::SubAgentActivity(SubAgentActivityEvent {
event_id: "call-spawn".to_string(),
occurred_at_ms: 1234,
agent_thread_id,
agent_path: AgentPath::try_from("/root/reviewer").map_err(anyhow::Error::msg)?,
kind: SubAgentActivityKind::Started,
});
let Some(ToolRuntimeTraceEvent::Ended {
tool_call_id,
status,
payload,
}) = tool_runtime_trace_event(&event)
else {
panic!("expected terminal tool runtime event");
};
assert_eq!(tool_call_id, "call-spawn");
assert_eq!(status, ExecutionStatus::Completed);
assert_eq!(
serde_json::to_value(payload)?,
json!({
"event_id": "call-spawn",
"occurred_at_ms": 1234,
"agent_thread_id": agent_thread_id,
"agent_path": "/root/reviewer",
"kind": "started"
})
);
Ok(())
}
#[test]
fn exec_command_trace_payloads_use_inferred_native_cwd() -> anyhow::Result<()> {
// Convention inference depends on the URI spelling, not the test host, so exercise both
// Windows and POSIX paths on every platform.
let begin = EventMsg::ExecCommandBegin(ExecCommandBeginEvent {
call_id: "call-begin".to_string(),
plugin_id: Some("sample@openai-curated".to_string()),
script_path: Some("scripts/run.py".to_string()),
process_id: Some("process-1".to_string()),
turn_id: "turn-1".to_string(),
started_at_ms: 1234,
command: vec!["pwd".to_string()],
cwd: "file:///C:/windows".parse()?,
parsed_cmd: Vec::new(),
source: ExecCommandSource::Agent,
interaction_input: None,
});
let end = EventMsg::ExecCommandEnd(ExecCommandEndEvent {
call_id: "call-end".to_string(),
plugin_id: Some("sample@openai-curated".to_string()),
script_path: Some("scripts/run.py".to_string()),
process_id: None,
turn_id: "turn-1".to_string(),
completed_at_ms: 2345,
command: vec!["pwd".to_string()],
cwd: "file:///workspace/project".parse()?,
parsed_cmd: Vec::new(),
source: ExecCommandSource::UnifiedExecInteraction,
interaction_input: Some("input".to_string()),
stdout: "output".to_string(),
stderr: String::new(),
aggregated_output: "output".to_string(),
exit_code: 0,
duration: Duration::from_millis(250),
formatted_output: "output".to_string(),
status: ExecCommandStatus::Completed,
});
let Some(ToolRuntimeTraceEvent::Started { payload, .. }) = tool_runtime_trace_event(&begin)
else {
panic!("expected started tool runtime event");
};
assert_eq!(
serde_json::to_value(payload)?,
json!({
"call_id": "call-begin",
"plugin_id": "sample@openai-curated",
"script_path": "scripts/run.py",
"process_id": "process-1",
"turn_id": "turn-1",
"started_at_ms": 1234,
"command": ["pwd"],
"cwd": r"C:\windows",
"parsed_cmd": [],
"source": "agent"
})
);
let Some(ToolRuntimeTraceEvent::Ended { payload, .. }) = tool_runtime_trace_event(&end) else {
panic!("expected ended tool runtime event");
};
assert_eq!(
serde_json::to_value(payload)?,
json!({
"call_id": "call-end",
"plugin_id": "sample@openai-curated",
"script_path": "scripts/run.py",
"turn_id": "turn-1",
"completed_at_ms": 2345,
"command": ["pwd"],
"cwd": "/workspace/project",
"parsed_cmd": [],
"source": "unified_exec_interaction",
"interaction_input": "input",
"stdout": "output",
"stderr": "",
"aggregated_output": "output",
"exit_code": 0,
"duration": {"secs": 0, "nanos": 250000000},
"formatted_output": "output",
"status": "completed"
})
);
Ok(())
}