mirror of
https://github.com/openai/codex.git
synced 2026-11-11 21:10:39 +00:00
Treat bundled cleanup hooks as built-ins (#42110)
## What changed - Centralize the allowlist for bundled MCP cleanup hooks and use it for both local and executor-discovered plugins, including `unified-computer-use` cleanup through `cua_repl`. - Mark matching cleanup hooks as trusted built-ins so they run without saved hook trust and remain active when regular hooks or their per-hook state are disabled. Plugin enablement and managed-only policy still apply. - Hide built-in cleanup hooks from hook listings and lifecycle notifications while retaining their metrics. Keep the built-in classification out of serialized protocol data. ## Testing - Cover allowlist boundaries, trust and enablement behavior, inline and file-based hook declarations, MCP success and error responses, hook listing, lifecycle notifications, metrics, and protocol serialization. GitOrigin-RevId: f93b7bc99f4ed9694f529def8ec383b45f31430e
This commit is contained in:
@@ -1663,6 +1663,11 @@ pub struct HookOutputEntry {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct HookRunSummary {
|
||||
/// Internal classification used to suppress lifecycle notifications without losing telemetry.
|
||||
#[serde(skip)]
|
||||
#[schemars(skip)]
|
||||
#[ts(skip)]
|
||||
pub builtin: bool,
|
||||
pub id: String,
|
||||
pub event_name: HookEventName,
|
||||
pub handler_type: HookHandlerType,
|
||||
@@ -4436,6 +4441,43 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hook_builtin_classification_stays_internal() -> Result<()> {
|
||||
let wire = json!({
|
||||
"id": "cleanup-hook",
|
||||
"event_name": "stop",
|
||||
"handler_type": "mcp_tool",
|
||||
"execution_mode": "sync",
|
||||
"scope": "turn",
|
||||
"source_path": test_path_buf("/tmp/hooks.json").abs(),
|
||||
"source": "plugin",
|
||||
"display_order": 0,
|
||||
"status": "completed",
|
||||
"status_message": null,
|
||||
"started_at": 10,
|
||||
"completed_at": 11,
|
||||
"duration_ms": 1000,
|
||||
"entries": [],
|
||||
});
|
||||
let mut run: HookRunSummary = serde_json::from_value(wire.clone())?;
|
||||
assert!(!run.builtin);
|
||||
run.builtin = true;
|
||||
assert_eq!(serde_json::to_value(run)?, wire);
|
||||
|
||||
let mut untrusted_wire = wire;
|
||||
untrusted_wire["builtin"] = json!(true);
|
||||
assert!(!serde_json::from_value::<HookRunSummary>(untrusted_wire)?.builtin);
|
||||
let schema = serde_json::to_value(schemars::schema_for!(HookRunSummary))?;
|
||||
assert!(
|
||||
!schema["properties"]
|
||||
.as_object()
|
||||
.expect("hook properties")
|
||||
.contains_key("builtin")
|
||||
);
|
||||
assert!(!HookRunSummary::decl().contains("builtin:"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn feature_thread_source_serializes_as_its_app_owned_label() -> Result<()> {
|
||||
let source = ThreadSource::Feature("automation".to_string());
|
||||
|
||||
Reference in New Issue
Block a user