Skip to content

fix(codex): parse config.toml structurally for hook trust detection#1803

Open
saiprasannasastry wants to merge 1 commit into
entireio:mainfrom
saiprasannasastry:fix/codex-toml-trust-keys-1761
Open

fix(codex): parse config.toml structurally for hook trust detection#1803
saiprasannasastry wants to merge 1 commit into
entireio:mainfrom
saiprasannasastry:fix/codex-toml-trust-keys-1761

Conversation

@saiprasannasastry

Copy link
Copy Markdown

Fixes #1761

Problem

On Windows, entire doctor reported every approved Codex hook as REVIEW NEEDED, and the SessionStart banner nagged about approvals that already existed. The trust check scraped the user's config.toml with a regex that only matches double-quoted TOML state keys, while current Codex writes single-quoted literal keys — the natural serialization on Windows, where backslashes need no escaping:

[hooks.state.'C:\repo\.codex\hooks.json:session_start:0:0']
trusted_hash = "sha256:..."

As the issue notes, even accepting double quotes wouldn't be enough on Windows: a valid basic-string key carries escaped backslashes ("C:\\repo\\..."), and the regex captured them raw, so they could never compare equal to filepath.Join output.

Fix

As suggested in the issue: parse config.toml structurally and enumerate the keys under hooks.state, instead of regex-scraping table headers. Uses pelletier/go-toml/v2, which was already in the module graph (promoted indirect → direct, no new dependency). This handles literal keys, unescapes basic keys, and covers dotted-assignment form — the surrounding prefix-match logic is unchanged.

Failure semantics are now explicit rather than accidental:

  • HookTrustGaps returns ([]string, bool) — the bool is false when hooks.json or config.toml is missing or unparseable ("can't tell").
  • Doctor prints Codex hook trust: NOT VERIFIED instead of a false ✓ OK when the config can't be parsed. Previously (post-regex-era design carried over), a syntax error anywhere in config.toml would degrade to "zero trusted keys"; with a structural parse it would otherwise have silently swallowed genuine trust gaps behind an affirmative OK.
  • A parseable config with no hooks.state table still counts as "nothing approved yet" and the gap warning fires.
  • The SessionStart banner behavior is unchanged: it only speaks when gaps exist.

Regression coverage

Per the matrix suggested in the issue, plus the new failure semantics:

  • Single-quoted state keys, full flow: trusted → no gaps; one missing → flagged
  • Hardcoded Windows keys at the parser level (OS-independent): literal 'C:\repo\...' comes back verbatim; basic "C:\\repo\\..." unescapes to single-backslash form
  • Dotted-assignment form under [hooks.state]
  • Existing POSIX double-quoted cases (unchanged, still pass)
  • Unrelated config sections/entries ignored
  • Malformed TOML → check reports "can't tell"; doctor test pins NOT VERIFIED (duplicate-key config)
  • Config without hooks.state → genuine gap still fires

Verification

  • Full suite with -tags=integration -race: pass; Vogon E2E canary: pass; golangci-lint (pinned 2.11.3) on the full tree: 0 issues
  • End-to-end sandbox: reproduced the false positive with a pre-fix binary against a single-quoted config, then verified the fixed binary prints ✓ OK (all trusted), REVIEW NEEDED (one approval removed), and NOT VERIFIED (malformed config)
  • Cross-compiled windows/amd64 and windows/arm64

One residual risk worth noting: if Codex ever writes extended-length (\\?\C:\) paths or different drive-letter casing into state keys, the exact prefix match could still miss — out of scope for this issue, since the reported key format matches filepath.Join output.

🤖 Generated with Claude Code

The Codex hook-trust check scraped the user's config.toml with a regex
that only matched double-quoted TOML state keys
([hooks.state."..."]). Current Codex serializes state keys as
single-quoted literal strings — the natural form on Windows, where
backslashes need no escaping — so every approved hook was reported as
untrusted: doctor printed "REVIEW NEEDED" for all four hooks and the
SessionStart banner nagged about approvals that already existed.

Replace the regex with a structural parse via pelletier/go-toml/v2
(promoted from indirect to direct): enumerate the keys of the
hooks.state table, which handles literal keys, unescapes basic keys
(so "C:\\repo\\..." compares equal to filepath.Join output — the regex
could never match those either), and covers dotted-assignment form.

Failure semantics are now explicit: HookTrustGaps returns an ok bool,
false when hooks.json or config.toml is missing or unparseable. The
SessionStart banner still only warns on gaps; doctor prints
"Codex hook trust: NOT VERIFIED" instead of a false "✓ OK" when the
config can't be parsed — previously a syntax error anywhere in
config.toml silently swallowed genuine trust gaps.

Fixes entireio#1761

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXSV9C6QNJZ5GMCXRBYTW25E
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Windows: Codex hook trust detector ignores single-quoted TOML state keys

1 participant