mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
codex: support hooks in config.toml and requirements.toml (#18893)
## Summary Support the existing hooks schema in inline TOML so hooks can be configured from both `config.toml` and enterprise-managed `requirements.toml` without requiring a separate `hooks.json` payload. This gives enterprise admins a way to ship managed hook policy through the existing requirements channel while still leaving script delivery to MDM or other device-management tooling, and it keeps `hooks.json` working unchanged for existing users. This also lays the groundwork for follow-on managed filtering work such as #15937, while continuing to respect project trust gating from #14718. It does **not** implement `allow_managed_hooks_only` itself. NOTE: yes, it's a bit unfortunate that the toml isn't formatted as closely as normal to our default styling. This is because we're trying to stay compatible with the spec for plugins/hooks that we'll need to support & the main usecase here is embedding into requirements.toml ## What changed - moved the shared hook serde model out of `codex-rs/hooks` into `codex-rs/config` so the same schema can power `hooks.json`, inline `config.toml` hooks, and managed `requirements.toml` hooks - added `hooks` support to both `ConfigToml` and `ConfigRequirementsToml`, including requirements-side `managed_dir` / `windows_managed_dir` - treated requirements-managed hooks as one constrained value via `Constrained`, so managed hook policy is merged atomically and cannot drift across requirement sources - updated hook discovery to load requirements-managed hooks first, then per-layer `hooks.json`, then per-layer inline TOML hooks, with a warning when a single layer defines both representations - threaded managed hook metadata through discovered handlers and exposed requirements hooks in app-server responses, generated schemas, and `/debug-config` - added hook/config coverage in `codex-rs/config`, `codex-rs/hooks`, `codex-rs/core/src/config_loader/tests.rs`, and `codex-rs/core/tests/suite/hooks.rs` ## Testing - `cargo test -p codex-config` - `cargo test -p codex-hooks` - `cargo test -p codex-app-server config_api` ## Documentation Companion updates are needed in the developers website repo for: - the hooks guide - the config reference, sample, basic, and advanced pages - the enterprise managed configuration guide --------- Co-authored-by: Michael Bolin <mbolin@openai.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
9955eacd22
commit
2b2de3f38b
@@ -941,11 +941,71 @@ pub struct ConfigRequirements {
|
||||
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
|
||||
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
|
||||
pub feature_requirements: Option<BTreeMap<String, bool>>,
|
||||
#[experimental("configRequirements/read.hooks")]
|
||||
pub hooks: Option<ManagedHooksRequirements>,
|
||||
pub enforce_residency: Option<ResidencyRequirement>,
|
||||
#[experimental("configRequirements/read.network")]
|
||||
pub network: Option<NetworkRequirements>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ManagedHooksRequirements {
|
||||
pub managed_dir: Option<PathBuf>,
|
||||
pub windows_managed_dir: Option<PathBuf>,
|
||||
#[serde(rename = "PreToolUse")]
|
||||
#[ts(rename = "PreToolUse")]
|
||||
pub pre_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PermissionRequest")]
|
||||
#[ts(rename = "PermissionRequest")]
|
||||
pub permission_request: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "PostToolUse")]
|
||||
#[ts(rename = "PostToolUse")]
|
||||
pub post_tool_use: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "SessionStart")]
|
||||
#[ts(rename = "SessionStart")]
|
||||
pub session_start: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "UserPromptSubmit")]
|
||||
#[ts(rename = "UserPromptSubmit")]
|
||||
pub user_prompt_submit: Vec<ConfiguredHookMatcherGroup>,
|
||||
#[serde(rename = "Stop")]
|
||||
#[ts(rename = "Stop")]
|
||||
pub stop: Vec<ConfiguredHookMatcherGroup>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ConfiguredHookMatcherGroup {
|
||||
pub matcher: Option<String>,
|
||||
pub hooks: Vec<ConfiguredHookHandler>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(tag = "type")]
|
||||
#[ts(tag = "type", export_to = "v2/")]
|
||||
pub enum ConfiguredHookHandler {
|
||||
#[serde(rename = "command")]
|
||||
#[ts(rename = "command")]
|
||||
Command {
|
||||
command: String,
|
||||
#[serde(rename = "timeoutSec")]
|
||||
#[ts(rename = "timeoutSec")]
|
||||
timeout_sec: Option<u64>,
|
||||
r#async: bool,
|
||||
#[serde(rename = "statusMessage")]
|
||||
#[ts(rename = "statusMessage")]
|
||||
status_message: Option<String>,
|
||||
},
|
||||
#[serde(rename = "prompt")]
|
||||
#[ts(rename = "prompt")]
|
||||
Prompt {},
|
||||
#[serde(rename = "agent")]
|
||||
#[ts(rename = "agent")]
|
||||
Agent {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -8837,6 +8897,7 @@ mod tests {
|
||||
allowed_sandbox_modes: None,
|
||||
allowed_web_search_modes: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
enforce_residency: None,
|
||||
network: None,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user