Skip to content

fix(presets): reject falsy non-mapping catalog config shapes - #4320

Open
Noor-ul-ain001 wants to merge 2 commits into
github:mainfrom
Noor-ul-ain001:fix/preset-catalog-config-falsy-shape
Open

fix(presets): reject falsy non-mapping catalog config shapes#4320
Noor-ul-ain001 wants to merge 2 commits into
github:mainfrom
Noor-ul-ain001:fix/preset-catalog-config-falsy-shape

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

PresetCatalog._load_catalog_config (src/specify_cli/presets/__init__.py) has two instances of the same "emptiness check runs before the shape check" bug, both of which mask a corrupted preset-catalogs.yml as an empty/no-op config instead of raising a clear error:

  1. Top level: data = yaml.safe_load(config_path.read_text(...)) or {} coerces a FALSY non-mapping document ([], false, 0, '') to {} before the isinstance(data, dict) guard runs — silently swallowed as "no config", while a TRUTHY non-mapping (a bare string) correctly raises "expected a mapping at root".
  2. One level down: catalogs_data = data.get("catalogs", []) followed by if not catalogs_data: return None checks emptiness before checking isinstance(catalogs_data, list). A FALSY non-list catalogs: value ({}, '', 0, false) is silently treated as "no catalogs", while a TRUTHY non-list (catalogs: "not-a-list") correctly raises "must be a list".

WorkflowCatalog._load_catalog_config and StepCatalog._load_catalog_config (src/specify_cli/workflows/catalog.py) already guard against exactly both cases, with explanatory comments (# Do NOT coerce with or {} here... / # Same asymmetry ... one nesting level down). This preset sibling wasn't updated to match. Fix reuses the same pattern and comments.

Test plan

  • Added test_load_catalog_config_rejects_falsy_non_mapping_root (parametrized over [], false, 0, '') and test_load_catalog_config_rejects_falsy_non_list_catalogs (parametrized over catalogs: {}, '', 0, false) to TestPresetCatalogMultiCatalog.
  • Verified all 8 new parametrized cases fail without the fix (stashed only the source change) and pass with it.
  • Ran TestPresetCatalogMultiCatalog in full — 33 passed, no regressions.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FW9fAYsCBCAgdKWovtSyqt

@Noor-ul-ain001
Noor-ul-ain001 requested a review from mnriem as a code owner August 25, 2026 14:53
`PresetCatalog._load_catalog_config` had two "shape check runs after
an emptiness check" bugs, both masking a corrupted preset-catalogs.yml
as an empty/no-op config instead of raising:

- Top level: `yaml.safe_load(...) or {}` coerced a FALSY non-mapping
  document (`[]`, `false`, `0`, `''`) to `{}` before the
  `isinstance(data, dict)` guard ran, so it was silently treated as
  "no config" — while a TRUTHY non-mapping (a bare string) already
  raised "expected a mapping at root".
- One level down: `catalogs_data = data.get("catalogs", [])` followed
  by `if not catalogs_data: return None` ran the emptiness check
  *before* the `isinstance(catalogs_data, list)` check, so a FALSY
  non-list `catalogs:` value (`{}`, `''`, `0`, `false`) was silently
  swallowed as "no catalogs" — while a TRUTHY non-list
  (`catalogs: "not-a-list"`) already raised "must be a list".

`WorkflowCatalog._load_catalog_config` and
`StepCatalog._load_catalog_config` (workflows/catalog.py) already
guard against both cases correctly, with the same explanatory
comments reused here. This preset sibling was missed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FW9fAYsCBCAgdKWovtSyqt

Copilot AI left a comment

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.

🟢 Approval recommended

The validation fix is consistent with sibling implementations and has focused regression coverage.

Pull request overview

Aligns preset catalog validation with workflow and step catalogs by rejecting falsy values with invalid YAML shapes.

Changes:

  • Validates root and catalogs types before emptiness checks.
  • Adds regression coverage for eight falsy invalid configurations.
File summaries
File Description
src/specify_cli/presets/__init__.py Corrects catalog configuration shape validation.
tests/test_presets.py Covers falsy non-mapping and non-list values.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…config-falsy-shape

# Conflicts:
#	src/specify_cli/presets/__init__.py
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.

3 participants