diff --git a/codex-rs/config/src/tui_keymap.rs b/codex-rs/config/src/tui_keymap.rs index 6e1e05dcc9..169bf3f1c1 100644 --- a/codex-rs/config/src/tui_keymap.rs +++ b/codex-rs/config/src/tui_keymap.rs @@ -264,6 +264,7 @@ pub struct TuiOnboardingKeymap { /// runtime preset defaults, and selected chat/composer actions can fall back /// through `global` during runtime resolution. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)] +#[serde(deny_unknown_fields)] #[schemars(deny_unknown_fields)] pub struct TuiKeymap { #[serde(default)] @@ -424,3 +425,33 @@ or one of: enter, tab, backspace, esc, delete, arrows, home/end, page-up/page-do Keymap template: https://github.com/openai/codex/blob/main/docs/default-keymap.toml" )) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn misplaced_action_at_keymap_root_is_rejected() { + // Actions placed directly under [tui.keymap] instead of a context + // sub-table (e.g. [tui.keymap.global]) must produce a parse error, + // not be silently ignored. + let toml_input = r#" + open_transcript = "ctrl-s" + "#; + let result = toml::from_str::(toml_input); + assert!( + result.is_err(), + "expected error for action at keymap root, got: {result:?}" + ); + } + + #[test] + fn action_under_global_context_is_accepted() { + let toml_input = r#" + [global] + open_transcript = "ctrl-s" + "#; + let keymap: TuiKeymap = toml::from_str(toml_input).expect("valid config"); + assert!(keymap.global.open_transcript.is_some()); + } +}