Skip to content

fix(workflows): StepRegistry.add tolerates a corrupted non-dict existing entry#3630

Merged
mnriem merged 1 commit into
github:mainfrom
jawwad-ali:fix/step-registry-add-nondict-guard
Jul 22, 2026
Merged

fix(workflows): StepRegistry.add tolerates a corrupted non-dict existing entry#3630
mnriem merged 1 commit into
github:mainfrom
jawwad-ali:fix/step-registry-add-nondict-guard

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

StepRegistry.add reads the existing entry then calls .get() on it:

existing = self.data["steps"].get(step_id, {})
metadata_to_store["installed_at"] = existing.get("installed_at", ...)   # AttributeError if existing is a str/list/int

A corrupted-but-parseable registry — e.g. {"steps": {"foo": "corrupted"}}, which _load() accepts because it validates only the top-level dict and that steps is a dict — makes add() raise AttributeError: 'str' object has no attribute 'get'.

Its sibling WorkflowRegistry.add was hardened for exactly this in #3419 (existing = raw_existing if isinstance(raw_existing, dict) else {}); StepRegistry.add was left unguarded — a same-file parity gap.

Fix

Mirror the WorkflowRegistry guard so a non-dict existing entry is treated as absent.

Test

test_step_registry_add_survives_non_dict_existing_entry (a 1:1 copy of the WorkflowRegistry sibling test): a "corrupted" string entry no longer crashes add() — fails before (AttributeError), passes after.


🤖 Written with the assistance of Claude Code (AI). Bug self-found; fix/tests verified locally (fail-before / pass-after), ruff clean.

…ing entry

StepRegistry.add read existing = self.data['steps'].get(step_id, {}) then called
existing.get('installed_at', ...). A corrupted-but-parseable registry holding a
non-dict entry (e.g. {'steps': {'foo': 'corrupted'}}) — which _load() accepts,
since it validates only the top-level dict and that 'steps' is a dict — made
add() raise AttributeError. WorkflowRegistry.add was hardened for exactly this
(github#3419); mirror its isinstance guard so a non-dict existing entry is treated as
absent.

Test copies the WorkflowRegistry sibling test for StepRegistry (fails before:
AttributeError on existing.get()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.

Pull request overview

Hardens StepRegistry.add against corrupted non-dict entries, matching WorkflowRegistry behavior.

Changes:

  • Treats non-dict existing step metadata as absent.
  • Adds regression coverage for the corrupted-entry case.
Show a summary per file
File Description
src/specify_cli/workflows/catalog.py Adds the defensive type guard.
tests/test_workflows.py Adds regression coverage.

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: 0
  • Review effort level: Medium

@mnriem
mnriem merged commit 03f9013 into github:main Jul 22, 2026
12 checks passed
@mnriem

mnriem commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

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