diff --git a/src/specify_cli/workflows/catalog.py b/src/specify_cli/workflows/catalog.py index 203fb6753..0ab5d81c5 100644 --- a/src/specify_cli/workflows/catalog.py +++ b/src/specify_cli/workflows/catalog.py @@ -92,8 +92,10 @@ class WorkflowRegistry: """Add or update an installed workflow entry.""" from datetime import datetime, timezone - existing = self.data["workflows"].get(workflow_id, {}) + raw_existing = self.data["workflows"].get(workflow_id) had_entry = workflow_id in self.data["workflows"] + # Corrupted-but-parseable registries may hold non-dict entries. + existing = raw_existing if isinstance(raw_existing, dict) else {} metadata["installed_at"] = existing.get( "installed_at", datetime.now(timezone.utc).isoformat() ) @@ -105,7 +107,7 @@ class WorkflowRegistry: # Roll back the in-memory mutation so a later successful save # cannot persist metadata for a write that failed. if had_entry: - self.data["workflows"][workflow_id] = existing + self.data["workflows"][workflow_id] = raw_existing else: del self.data["workflows"][workflow_id] raise diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 8514017c6..e773f3b60 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -7555,8 +7555,16 @@ steps: registry.add("other-wf", {"version": "1.0.0", "source": "catalog"}) assert registry.get("other-wf") is None + def test_registry_add_survives_non_dict_existing_entry(self, project_dir): + from specify_cli.workflows.catalog import WorkflowRegistry + + registry = WorkflowRegistry(project_dir) + registry.data["workflows"]["align-wf"] = "corrupted" + registry.add("align-wf", {"version": "1.0.0", "source": "catalog"}) + assert registry.get("align-wf")["version"] == "1.0.0" + def test_run_refuses_falsy_non_bool_enabled(self, project_dir, monkeypatch): - """"enabled": 0 shows as disabled in list — run must agree.""" + """A falsy non-bool "enabled" (0) shows as disabled in list — run must agree.""" import json as json_mod from typer.testing import CliRunner @@ -8127,7 +8135,7 @@ steps: assert result.exit_code == 0, result.output def test_disable_blocks_run_via_path_equivalent_id(self, project_dir, monkeypatch): - """"align-wf/" must not run a disabled workflow by dodging the registry lookup.""" + """Path spelling "align-wf/" must not run a disabled workflow by dodging the registry lookup.""" from typer.testing import CliRunner from specify_cli import app