Warn when hooks.json has unsupported top-level fields (#26426)

Addresses #25875.

## Summary

`hooks.json` accepted unknown top-level fields. A file with
`SessionStart` at the root parsed as an empty hook configuration without
warning.

## Repro

```json
{ "SessionStart": [...] }
```

Previously: zero hooks, zero warnings.

Now:

```text
unknown field `SessionStart`, expected `hooks`
```

The supported shape remains:

```json
{ "hooks": { "SessionStart": [...] } }
```

## Fix

Reject unknown top-level fields and surface the parse warning in human
and JSONL `codex exec` output.
This commit is contained in:
Abhinav
2026-06-11 23:08:07 +00:00
committed by GitHub
parent e069153f2a
commit eddc5c75ed
3 changed files with 81 additions and 0 deletions
+1
View File
@@ -8,6 +8,7 @@ use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct HooksFile {
#[serde(default)]
pub hooks: HookEventsToml,
+24
View File
@@ -52,6 +52,30 @@ fn hooks_file_deserializes_existing_json_shape() {
);
}
#[test]
fn hooks_file_rejects_events_outside_hooks_object() {
let error = serde_json::from_str::<HooksFile>(
r#"{
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "python3 /tmp/session_start.py"
}
]
}
]
}"#,
)
.expect_err("root-level hook events should be rejected");
assert!(
error.to_string().contains("unknown field `SessionStart`"),
"unexpected parse error: {error}"
);
}
#[test]
fn hook_events_deserialize_from_toml_arrays_of_tables() {
let parsed: HookEventsToml = toml::from_str(