Skip to content

fix(workflows): reject falsy non-mapping catalog config in add/remove - #4319

Closed
Noor-ul-ain001 wants to merge 4 commits into
github:mainfrom
Noor-ul-ain001:fix/catalog-remove-add-falsy-config
Closed

fix(workflows): reject falsy non-mapping catalog config in add/remove#4319
Noor-ul-ain001 wants to merge 4 commits into
github:mainfrom
Noor-ul-ain001:fix/catalog-remove-add-falsy-config

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

  • WorkflowCatalog.remove_catalog, StepCatalog.add_catalog, and StepCatalog.remove_catalog (all in src/specify_cli/workflows/catalog.py) read their config file with yaml.safe_load(config_path.read_text(...)) or {}.
  • That or {} coerces a falsy non-mapping top-level document ([], false, 0, '') to {} before the isinstance(data, dict) guard runs, so a corrupted config silently becomes "no catalogs" instead of raising "...corrupted (expected a mapping)". A truthy non-mapping (5, a bare list with items) already raised correctly — this was an inconsistency, and for remove_catalog it surfaces as a misleading "Catalog index N out of range" error instead.
  • WorkflowCatalog._load_catalog_config (the shared loader behind get_active_catalogs) and WorkflowCatalog.add_catalog already guard against exactly this, with an explanatory comment (# Do NOT coerce with or {} here: ...). The other three call sites in the same file reimplement the read inline and were missed.
  • Same bug shape as fix(presets): reject malformed catalog roots during mutation #4094 (preset catalog add/remove) and fix(integrations): report a falsy non-mapping integration descriptor as a shape error #4187 (integration descriptor loading) — falsy-or-coerce masking a shape error.

Test plan

  • Added test_remove_catalog_rejects_falsy_non_mapping_config to TestWorkflowCatalog and test_add_catalog_rejects_falsy_non_mapping_config / test_remove_catalog_rejects_falsy_non_mapping_config to TestStepCatalog, each parametrized over [], false, 0, ''.
  • Verified all 12 new parametrized cases fail without the fix (stashed only the source change) and pass with it.
  • Ran TestWorkflowCatalog + TestStepCatalog in full — 100 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:48
`WorkflowCatalog.remove_catalog`, `StepCatalog.add_catalog`, and
`StepCatalog.remove_catalog` all read their config file with
`yaml.safe_load(...) or {}`, which coerces a FALSY non-mapping
top-level document (`[]`, `false`, `0`, `''`) to `{}` before the
`isinstance(data, dict)` check ever runs — silently swallowing a
corrupted config instead of raising, while a truthy non-mapping
(`5`, a bare list with items) correctly raises.

`WorkflowCatalog._load_catalog_config` (used by `get_active_catalogs`)
and `WorkflowCatalog.add_catalog` already guard against this
correctly, with a comment explaining why `or {}` is wrong here; the
other three call sites in the same file reimplement the read inline
and missed the fix. Same shape as the falsy-or-coerce bug class fixed
in github#4094 (preset catalog add/remove) and github#4187 (integration
descriptor loading).

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 functional fix is correct and comprehensively tested; only a non-blocking docstring correction remains.

Pull request overview

Fixes catalog mutation paths so falsy non-mapping YAML roots raise validation errors instead of being treated as empty configurations.

Changes:

  • Corrects workflow and step catalog YAML shape validation.
  • Adds regression coverage for four falsy non-mapping values.
File summaries
File Description
src/specify_cli/workflows/catalog.py Preserves falsy values for type validation.
tests/test_workflows.py Adds parameterized regression tests.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

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

Comment thread tests/test_workflows.py Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

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.

🟡 Changes recommended

An unclosed test docstring causes a syntax error and prevents test collection.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tests/test_workflows.py Outdated
"""A FALSY non-mapping top-level config ([], false, 0, '') must raise
'corrupted (expected a mapping)', not be silently coerced to {} by
``or {}``; empty and explicit-null documents still parse as None and
retain their existing empty-config behavior.
test_add_catalog_rejects_falsy_non_mapping_config's docstring was
missing its closing triple-quote, merging the docstring with the
following import statement. This caused a SyntaxError on collection,
preventing the whole test_workflows.py module (963 tests) from being
collected.
…add-falsy-config

# Conflicts:
#	src/specify_cli/workflows/catalog.py
#	tests/test_workflows.py
@mnriem

mnriem commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Thanks — good fix, but it's already in main. The or {} → explicit-isinstance guard for falsy non-mapping catalog config landed via another change (see catalog.py:347, which now carries exactly this fix and comment). After your recent merge of main, this PR's net diff is empty, so I'm closing it as already-applied. Appreciate the contribution — the outcome you wanted is in place.

@mnriem mnriem added the triage-out-of-scope Verdict: won't land in core — invalid, duplicate, off-mission, or redirected to an extension label Sep 9, 2026
@mnriem mnriem closed this Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-out-of-scope Verdict: won't land in core — invalid, duplicate, off-mission, or redirected to an extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants