From 96d3b381e9890b466e52d20bec71001d045104e9 Mon Sep 17 00:00:00 2001 From: marcelsafin <179933638+marcelsafin@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:43:08 +0200 Subject: [PATCH] fix(workflows): reject explicit empty --from URL instead of catalog fallback 'workflow add foo --from ""' fell through 'from_url or ...' to a catalog install. Distinguish None from empty string so explicit values stay on the URL-validation path and fail closed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/specify_cli/workflows/_commands.py | 6 ++++-- tests/test_workflows.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/specify_cli/workflows/_commands.py b/src/specify_cli/workflows/_commands.py index 2ef514643..c517bc620 100644 --- a/src/specify_cli/workflows/_commands.py +++ b/src/specify_cli/workflows/_commands.py @@ -713,8 +713,10 @@ def workflow_add( # Try as URL (http/https) — either the positional source is a URL, or an # explicit --from URL names where to fetch it (mirrors `extension add --from`). - download_url = from_url or ( - source if source.startswith(("http://", "https://")) else None + download_url = ( + from_url + if from_url is not None + else (source if source.startswith(("http://", "https://")) else None) ) if download_url is not None: from ipaddress import ip_address diff --git a/tests/test_workflows.py b/tests/test_workflows.py index 2277db359..7554deb0d 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -7394,6 +7394,19 @@ steps: assert "does not match" in result.output assert not WorkflowRegistry(project_dir).is_installed("align-wf") + def test_add_from_empty_url_rejected_not_catalog_fallback(self, project_dir, monkeypatch): + """--from "" must fail URL validation, not silently install from the catalog.""" + from typer.testing import CliRunner + from specify_cli import app + from specify_cli.workflows.catalog import WorkflowRegistry + + monkeypatch.chdir(project_dir) + runner = CliRunner() + result = runner.invoke(app, ["workflow", "add", "align-wf", "--from", ""]) + assert result.exit_code != 0 + assert "HTTPS" in result.output + assert not WorkflowRegistry(project_dir).is_installed("align-wf") + def test_add_from_url_non_https_redirect_escapes_rich_markup(self, project_dir, monkeypatch): """A redirect to a non-HTTPS IPv6 literal (legally bracketed) must not be parsed as Rich markup.""" from unittest.mock import patch