From 9c9f962676509a8a7896b4ce38a4ba842fdaf3d9 Mon Sep 17 00:00:00 2001 From: Alpamys Date: Wed, 13 May 2026 19:45:21 +0500 Subject: [PATCH] =?UTF-8?q?fix(test):=20v0.53.7=20CI=20hardening=20?= =?UTF-8?q?=E2=80=94=20importorskip(fastapi)=20+=20Arrow=20target=20setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI run 25805598433 failed across all 9 OS×Python cells: - TestToolEndpointsLive / TestAnthropicMessagesStreaming / TestReviewFixesVllmAnthropicLive ModuleNotFoundError: fastapi (CI does not install [serve] extra) → autouse fixture pytest.importorskip() - test_load_pretokenized_dataset_rejects_symlink: load_pretokenized_dataset called datasets.load_from_disk on the symlink target before the lstat check ran → moved the lstat + S_ISLNK check to the entry of the helper so symlinks reject before any load attempt - test_redact_exc_message_handles_windows_paths: hardened _redact_exc_message to strip both POSIX absolute paths and Windows-style paths regardless of host platform Local pytest tests/test_v0537.py: 112 passed, 7 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) --- soup_cli/utils/data_pipeline.py | 4 +++- soup_cli/utils/recipe_run.py | 17 +++++++++++------ tests/test_v0537.py | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/soup_cli/utils/data_pipeline.py b/soup_cli/utils/data_pipeline.py index b320dfe..3847acd 100644 --- a/soup_cli/utils/data_pipeline.py +++ b/soup_cli/utils/data_pipeline.py @@ -488,8 +488,10 @@ def load_pretokenized_dataset( real = os.path.realpath(tokenized_path) if not is_under_cwd(real): raise ValueError("tokenized_path must stay under cwd") + # Lstat the ORIGINAL (unresolved) path to detect symlinks at the entry + # point — mirrors v0.33.0 #22 / v0.43.0 Part C TOCTOU policy. try: - lst = os.lstat(real) + lst = os.lstat(tokenized_path) except OSError as exc: raise ValueError(f"tokenized_path not found: {tokenized_path!r}") from exc if _stat.S_ISLNK(lst.st_mode): diff --git a/soup_cli/utils/recipe_run.py b/soup_cli/utils/recipe_run.py index 3cebb8c..aae7673 100644 --- a/soup_cli/utils/recipe_run.py +++ b/soup_cli/utils/recipe_run.py @@ -164,12 +164,17 @@ def _redact_exc_message(exc: BaseException, limit: int = 256) -> str: lambda m: os.path.basename(m.group(0)) or m.group(0), msg, ) - # Windows drive-letter paths (``C:\\foo\\bar``). - msg = re.sub( - r"[A-Za-z]:[\\/][^\s:'\"]+", - lambda m: os.path.basename(m.group(0)) or m.group(0), - msg, - ) + # Windows drive-letter paths (``C:\\foo\\bar`` or ``C:/foo/bar``). + # Use a cross-platform basename: split on both ``/`` and ``\\`` so this + # works on POSIX hosts too (``os.path.basename`` only splits on ``/`` + # on POSIX, leaving ``\\``-separated components intact). + def _win_basename(m: "re.Match[str]") -> str: + raw = m.group(0) + # Split on either separator; last non-empty component is the basename. + parts = [p for p in re.split(r"[/\\]", raw) if p] + return parts[-1] if parts else raw + + msg = re.sub(r"[A-Za-z]:[\\/][^\s:'\"]+", _win_basename, msg) return msg[:limit] diff --git a/tests/test_v0537.py b/tests/test_v0537.py index 08c1e30..f67903b 100644 --- a/tests/test_v0537.py +++ b/tests/test_v0537.py @@ -891,6 +891,11 @@ def _create_test_app(): class TestToolEndpointsLive: + @pytest.fixture(autouse=True) + def _require_fastapi(self): + pytest.importorskip("fastapi") + pytest.importorskip("httpx") + def test_python_tool_runs_simple_code(self): from fastapi.testclient import TestClient app = _create_test_app() @@ -1041,6 +1046,11 @@ class TestToolEndpointsLive: class TestAnthropicMessagesStreaming: + @pytest.fixture(autouse=True) + def _require_fastapi(self): + pytest.importorskip("fastapi") + pytest.importorskip("httpx") + def test_stream_true_returns_sse(self): from fastapi.testclient import TestClient @@ -1425,6 +1435,11 @@ class TestReviewFixesForge: class TestReviewFixesVllmAnthropicLive: """v0.53.7 H-I + M-Q: live route tests with mocked AsyncLLMEngine.""" + @pytest.fixture(autouse=True) + def _require_fastapi(self): + pytest.importorskip("fastapi") + pytest.importorskip("httpx") + def _build_vllm_app(self): try: import fastapi # noqa: F401