fix(workflows): harden catalog.py against mis-shaped registry & non-string fields#3375
Open
jawwad-ali wants to merge 2 commits into
Open
fix(workflows): harden catalog.py against mis-shaped registry & non-string fields#3375jawwad-ali wants to merge 2 commits into
jawwad-ali wants to merge 2 commits into
Conversation
…tring fields Two robustness gaps where WorkflowRegistry/WorkflowCatalog diverged from their StepRegistry/StepCatalog siblings, which already guard both: - WorkflowRegistry._load returned json.load() verbatim, so a JSON-valid but mis-shaped registry (a list root, or a dict lacking a 'workflows' mapping) made is_installed/get/list/remove/add crash with TypeError/KeyError. Mirror StepRegistry._load: validate the shape and reset to default, and widen the except tuple to OSError/UnicodeError. - WorkflowCatalog.search joined name/description/id without coercion, so a null or non-string field raised TypeError. Coerce with str(... or '') exactly as StepCatalog.search does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Hardens specify_cli.workflows.catalog to better tolerate malformed on-disk registries and non-string catalog data, aligning Workflow* behavior with the existing Step* implementations.
Changes:
- Validate
workflow-registry.jsonshape inWorkflowRegistry._load()and fall back to a default structure for mis-shaped/corrupt content. - Coerce
WorkflowCatalog.search()searchable fields to strings to avoidTypeErroronnull/non-string values. - Add regression tests covering mis-shaped registry files and non-string workflow fields during search.
Show a summary per file
| File | Description |
|---|---|
tests/test_workflows.py |
Adds regression tests for mis-shaped workflow registry loading and non-string workflow catalog search fields. |
src/specify_cli/workflows/catalog.py |
Adds registry shape validation in _load() and coerces search fields to strings for robustness. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Low
Per review: WorkflowRegistry.list() always returns a dict, so assert
'== {}' directly (the previous '== {} or == []' called list() twice and
admitted a shape it never returns), and reference
WorkflowRegistry.SCHEMA_VERSION instead of hard-coding '1.0'.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two robustness gaps in
workflows/catalog.pywhere theWorkflow*classes diverge from theirStep*siblings, which already guard both cases:1.
WorkflowRegistry._loadreturnsjson.load()verbatim. A JSON-valid but mis-shaped registry file crashes every method that indexesdata["workflows"]:workflow-registry.json=[]→is_installed/get/list/remove/addraiseTypeError: list indices must be integers;{"schema_version": "1.0"}(noworkflowskey) →KeyError: 'workflows'.StepRegistry._loadalready validates the shape (dict root + dictsteps) and resets to default. Reproduced on main @92b7cf7.2.
WorkflowCatalog.searchjoinsname/description/idwithout coercion. A catalog entry with a null or non-string field raisesTypeError: sequence item 0: expected str instance, NoneType found.StepCatalog.searchalready coerces withstr(... or "")— and has a regression test for exactly this;WorkflowCatalog.searchwas the outlier.Fix
Mirror the siblings: validate the registry shape in
_load(+ widen the except tuple toOSError/UnicodeError), and coerce the search fields withstr(wf_data.get(...) or "").Testing
test_load_tolerates_misshaped_registry(parametrized[]/ no-workflows): registry recovers to the default shape and all methods run. Fails before (TypeError/KeyError).test_search_with_non_string_fields(WorkflowCatalog, mirrors the existing StepCatalog test): null/int fields no longer raise. Fails before (TypeError).TestWorkflowRegistry+ the new catalog test pass;uvx ruff checkclean.AI Disclosure
Found and fixed with Claude Code (Claude Fable 5) under my direction. AI diffed the Workflow* classes against their Step* siblings; I reproduced both crashes, verified fail-before/pass-after, and reviewed the diff.