Skip to content

Commit f6733ba

Browse files
committed
Validate integration.json is a dict, fail fast on missing manifest in switch
- _read_integration_json() validates parsed JSON is a dict, not a list/string - Switch fails fast with recovery guidance when manifest is missing instead of silently skipping teardown and risking co-existing integration files
1 parent 947a8e5 commit f6733ba

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

src/specify_cli/__init__.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,7 @@ def _read_integration_json(project_root: Path) -> dict[str, Any]:
15051505
if not path.exists():
15061506
return {}
15071507
try:
1508-
return json.loads(path.read_text(encoding="utf-8"))
1508+
data = json.loads(path.read_text(encoding="utf-8"))
15091509
except json.JSONDecodeError as exc:
15101510
console.print(f"[red]Error:[/red] {path} contains invalid JSON.")
15111511
console.print(f"Please fix or delete {INTEGRATION_JSON} and retry.")
@@ -1516,6 +1516,11 @@ def _read_integration_json(project_root: Path) -> dict[str, Any]:
15161516
console.print(f"Please fix file permissions or delete {INTEGRATION_JSON} and retry.")
15171517
console.print(f"[dim]Details:[/dim] {exc}")
15181518
raise typer.Exit(1)
1519+
if not isinstance(data, dict):
1520+
console.print(f"[red]Error:[/red] {path} must contain a JSON object, got {type(data).__name__}.")
1521+
console.print(f"Please fix or delete {INTEGRATION_JSON} and retry.")
1522+
raise typer.Exit(1)
1523+
return data
15191524

15201525

15211526
def _write_integration_json(
@@ -1911,7 +1916,12 @@ def integration_switch(
19111916
except (ValueError, FileNotFoundError) as exc:
19121917
console.print(f"[yellow]Warning:[/yellow] Could not read manifest for '{installed_key}': {exc}")
19131918
else:
1914-
console.print(f"[dim]No manifest for '{installed_key}' — skipping uninstall phase[/dim]")
1919+
console.print(f"[red]Error:[/red] Integration '{installed_key}' is installed but has no manifest.")
1920+
console.print(
1921+
f"Run [cyan]specify integration uninstall {installed_key}[/cyan] to clear metadata, "
1922+
f"then retry [cyan]specify integration switch {target}[/cyan]."
1923+
)
1924+
raise typer.Exit(1)
19151925

19161926
# Clear metadata so a failed Phase 2 doesn't leave stale references
19171927
_remove_integration_json(project_root)

0 commit comments

Comments
 (0)