Skip to content

fix: validate nested configuration value graphs - #365

Open
codeforester wants to merge 2 commits into
mainfrom
bug/359-20260918-validate-config-graph
Open

codeforester wants to merge 2 commits into
mainfrom
bug/359-20260918-validate-config-graph

Conversation

@codeforester

Copy link
Copy Markdown
Contributor

Summary

  • Validate string keys throughout nested mapping/list values before merge or provenance traversal.
  • Reject cycles and excessive depth/traversal with source-aware ConfigurationError messages while permitting shared aliases.
  • Cover first insertion, overlays, native/attached human/JSON boundaries, cycles, and depth.

Closes #359

Validation

  • uv run --extra dev --extra typer --extra quality python -m pytest tests/test_batteries_included_config.py tests/test_explicit_config_validation.py -q
  • uv run --extra dev --extra typer --extra quality python -m mypy --strict lib/python/base_cli/config.py
  • Ruff check/format and git diff --check

if exiting:
active.remove(identity)
continue
if not isinstance(current, (Mapping, list, tuple)):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correctness (reproduced): _CONFIG_MAX_NODES in _validate_config_graph only increments visited_nodes for Mapping/list/tuple nodes, so a flat structure made almost entirely of scalar leaves never trips the 100,000-node limit. Reproduced: a single top-level mapping with 5,000,000 scalar leaf keys validated in ~1.8s with zero errors, even though the PR's stated goal is to reject excessive size/traversal cost. This defeats the guard for the most common shape of a bloated config.

return {}
if not isinstance(data, dict):
raise ConfigurationError(f"Config file '{path}' must contain a YAML mapping.")
_validate_config_graph(data, source=f"Config file '{path}'")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bug (message quality): load_yaml_file builds source=f"Config file '{path}'" and _validate_config_graph wraps that again as f"Configuration source '{source}' ...", producing a doubled-quote error like Configuration source 'Config file '/tmp/x.yaml'' has a non-string key... — reads like a bug in the CLI's own output rather than deliberate nested attribution.

raise ConfigurationError(f"Unable to read config file '{path}': {exc}") from exc
try:
data = yaml.safe_load(contents)
except RecursionError as exc:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Test gap: the new except RecursionError handler in load_yaml_file isn't exercised by any test — the PR's deepest test config (65 levels) is caught earlier by _validate_config_graph's own _CONFIG_MAX_DEPTH check, never reaching PyYAML's parser far enough to raise RecursionError. A future change to the depth limit or parser could silently regress this path with nothing to catch it.

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.

bug: validate nested configuration shape before merge and provenance traversal

1 participant