Skip to content

config: add strict config parsing#20559

Open
bolinfest wants to merge 1 commit intomainfrom
pr20559
Open

config: add strict config parsing#20559
bolinfest wants to merge 1 commit intomainfrom
pr20559

Conversation

@bolinfest
Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest commented May 1, 2026

Why

Codex intentionally ignores unknown config.toml fields by default so older and newer config files keep working across versions. That leniency also makes typo detection hard because misspelled or misplaced keys disappear silently. This adds an opt-in strict config mode so users and tooling can fail fast on unrecognized config fields without changing the default behavior.

This feature is possible because serde_ignored exposes the exact signal Codex needs: it can run ordinary Serde deserialization while recording fields Serde would otherwise ignore. That avoids requiring #[serde(deny_unknown_fields)] across every config type and lets strict config validation stay opt-in around the existing permissive model.

What Changed

User-facing strict mode

  • Added a global --strict-config flag.
  • Threaded strict config mode through the CLI, TUI, exec, MCP server, apply command, login, marketplace, and app-server config-loading paths.
  • Validated system, user, trusted project, legacy managed config file, macOS MDM managed config sources, and -c / --config CLI override layers when strict config mode is enabled.

Validation implementation

  • Added serde_ignored-based validation for ConfigToml in codex-rs/config/src/strict_config.rs.
  • Combined serde_ignored with serde_path_to_error so strict mode preserves typed config error paths while also collecting fields Serde would otherwise ignore.
  • Added strict-mode validation for unknown [features] keys, including keys that are normally captured by FeaturesToml's flattened boolean map.
  • Kept typed config errors ahead of ignored-field reporting, so malformed known fields are reported before unknown-field diagnostics.
  • Added source-range diagnostics for top-level and nested unknown config fields, including non-file managed preference source names.

Config loading shape

  • Added ConfigBuilder::strict_config(...) for top-level callers and ConfigLoadOptions plumbing for lower-level load sites.
  • Reworked file and managed-config loading so strict validation uses the already parsed TomlValue; for actual config sources, the loader reads the file/string once, parses it once, and validates that same parsed value.
  • Validated CLI override layers with the same base-directory context used for normal relative-path resolution, so unknown -c keys are still reported when another override contains a relative path.
  • Moved strict config validation into strict_config.rs, leaving diagnostics.rs focused on source/range mapping and formatting.

Coverage

  • Added tests for top-level and nested unknown config fields, unknown [features] keys, source-location reporting for unknown keys, non-file managed preference source names, and typed-error precedence over ignored-field reporting.
  • Added CLI coverage showing invalid --enable, invalid --disable, and unknown -c overrides still error when --strict-config is present, including compound-looking feature names such as multi_agent_v2.subagent_usage_hint_text.
  • Added loader coverage for --strict-config -c features.foo=true so unknown feature keys are rejected even though [features] uses a flattened map internally.
  • Added loader coverage for unknown -c keys combined with relative path overrides such as model_instructions_file=instructions.md.

Example Usage

Run Codex with strict config validation enabled:

codex --strict-config

Strict config mode can also be used with subcommands that load config.toml:

codex --strict-config exec "explain this repository"
codex mcp --strict-config list
codex login --strict-config status

For example, if ~/.codex/config.toml contains a typo in a key name:

model = "gpt-5"
approval_polic = "on-request"

then codex --strict-config reports the misspelled key instead of silently ignoring it. The path is shortened to ~ here for readability:

$ codex --strict-config
Error loading config.toml:
~/.codex/config.toml:2:1: unknown configuration field `approval_polic`
  |
2 | approval_polic = "on-request"
  | ^^^^^^^^^^^^^^

Without --strict-config, Codex keeps the existing permissive behavior and ignores the unknown key.

Strict config mode also validates ad-hoc -c / --config overrides:

$ codex --strict-config -c foo=bar features list
Error: unknown configuration field `foo` in -c/--config override

$ codex --strict-config -c features.foo=true features list
Error: unknown configuration field `features.foo` in -c/--config override

Strict config mode also composes with CLI feature toggles. Invalid feature names are rejected, including values that look like nested config paths:

$ codex --strict-config --enable does_not_exist
Error: Unknown feature flag: does_not_exist

$ codex --strict-config --disable does_not_exist
Error: Unknown feature flag: does_not_exist

$ codex --strict-config --enable multi_agent_v2.subagent_usage_hint_text
Error: Unknown feature flag: multi_agent_v2.subagent_usage_hint_text

Verification

  • cargo test -p codex-config
  • cargo test -p codex-config strict_config
  • cargo test -p codex-core config_loader_tests::strict_config
  • cargo test -p codex-cli strict_config
  • just fix -p codex-config -p codex-core
  • just fix -p codex-config -p codex-cli
  • just argument-comment-lint

The codex-cli strict_config tests cover invalid --enable, invalid --disable, the compound multi_agent_v2.subagent_usage_hint_text case, and the --strict-config -c foo=bar path. The codex-core config loader tests cover --strict-config -c features.foo=true and unknown -c keys combined with relative path overrides.

Documentation

The Codex CLI docs on developers.openai.com/codex should mention --strict-config as an opt-in validation mode for config.toml once this ships.

@bolinfest bolinfest requested a review from a team as a code owner May 1, 2026 04:28
@bolinfest bolinfest force-pushed the pr20559 branch 9 times, most recently from 9475d37 to d4d74a4 Compare May 1, 2026 18:31
@bolinfest bolinfest force-pushed the pr20559 branch 9 times, most recently from bbec96c to 999cbdb Compare May 1, 2026 23:19
@bolinfest bolinfest requested review from jif-oai and pakrym-oai May 1, 2026 23:21
@bolinfest
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 999cbdb177

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return Ok(());
}

if let Some(ignored_path) = ignored_toml_value_field::<ConfigToml>(cli_overrides_layer.clone())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate CLI overrides with a base path before strict checks

validate_cli_overrides_strictly_if_requested calls ignored_toml_value_field directly on the override layer, but that helper returns None whenever deserialization errors. Because no AbsolutePathBufGuard is set here, any valid relative-path override for an AbsolutePathBuf field (for example model_instructions_file=...) can cause deserialization to fail, which skips unknown-field detection entirely for the same -c payload. In --strict-config mode this lets unknown non-feature keys pass when combined with such a relative-path override, defeating the strict override validation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 246051aa7613. validate_cli_overrides_strictly_if_requested now receives the CLI override base directory and installs AbsolutePathBufGuard before running the strict serde/ignored-field check, so relative-path overrides no longer mask unknown -c keys. I also added strict_config_rejects_unknown_cli_override_key_with_relative_path_override to cover model_instructions_file = "instructions.md" combined with an unknown override.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant