Skip to content

Commit d2588e7

Browse files
committed
fix: harden WorkflowRegistry against corrupted JSON
- Normalize 'workflows' field to dict in _load() (handles corrupted registry where 'workflows' is a list/string/null) - Validate top-level loaded data is a dict before using it - Guard enable/disable commands against non-dict metadata from get()
1 parent 71c5171 commit d2588e7

2 files changed

Lines changed: 16 additions & 4 deletions

File tree

src/specify_cli/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5478,6 +5478,9 @@ def workflow_enable(
54785478
raise typer.Exit(1)
54795479

54805480
metadata = registry.get(workflow_id)
5481+
if not isinstance(metadata, dict):
5482+
console.print(f"[red]Error:[/red] Workflow '{workflow_id}' has corrupted registry metadata")
5483+
raise typer.Exit(1)
54815484
if metadata.get("enabled", True):
54825485
console.print(f"[yellow]Workflow '{workflow_id}' is already enabled[/yellow]")
54835486
raise typer.Exit(0)
@@ -5506,6 +5509,9 @@ def workflow_disable(
55065509
raise typer.Exit(1)
55075510

55085511
metadata = registry.get(workflow_id)
5512+
if not isinstance(metadata, dict):
5513+
console.print(f"[red]Error:[/red] Workflow '{workflow_id}' has corrupted registry metadata")
5514+
raise typer.Exit(1)
55095515
if not metadata.get("enabled", True):
55105516
console.print(f"[yellow]Workflow '{workflow_id}' is already disabled[/yellow]")
55115517
raise typer.Exit(0)

src/specify_cli/workflows/catalog.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,20 @@ def __init__(self, project_root: Path) -> None:
7272

7373
def _load(self) -> dict[str, Any]:
7474
"""Load registry from disk or create default."""
75+
default = {"schema_version": self.SCHEMA_VERSION, "workflows": {}}
7576
if self.registry_path.exists():
7677
try:
7778
with open(self.registry_path, encoding="utf-8") as f:
78-
return json.load(f)
79+
data = json.load(f)
7980
except (json.JSONDecodeError, ValueError):
80-
# Corrupted registry file — reset to default
81-
return {"schema_version": self.SCHEMA_VERSION, "workflows": {}}
82-
return {"schema_version": self.SCHEMA_VERSION, "workflows": {}}
81+
return default
82+
if not isinstance(data, dict):
83+
return default
84+
# Normalize 'workflows' to a dict in case the file is corrupted
85+
if not isinstance(data.get("workflows"), dict):
86+
data["workflows"] = {}
87+
return data
88+
return default
8389

8490
def save(self) -> None:
8591
"""Persist registry to disk."""

0 commit comments

Comments
 (0)