From d260fbb30c47ad5d7bf0f5679b5e9b9c7a91c0de Mon Sep 17 00:00:00 2001 From: LeoBorcherding Date: Thu, 12 Mar 2026 22:55:06 -0500 Subject: [PATCH 1/4] fix: install data-designer plugin non-editable for Colab compatibility Editable installs (-e) work via a .pth file that is only processed at Python startup. In Colab the kernel is already running when setup.sh installs the plugin, so the .pth file never gets picked up and data_designer_unstructured_seed is not importable. Remove -e so pip copies the package files directly into site-packages, which the live kernel can find immediately. Local venv installs are unaffected since the venv is always created fresh before install. --- studio/install_python_stack.py | 1 - 1 file changed, 1 deletion(-) diff --git a/studio/install_python_stack.py b/studio/install_python_stack.py index 9ce16cd7bb..f7c62ade9b 100644 --- a/studio/install_python_stack.py +++ b/studio/install_python_stack.py @@ -270,7 +270,6 @@ def install_python_stack() -> int: "Installing local data-designer unstructured plugin", "--no-cache-dir", "--no-deps", - "-e", str(LOCAL_DD_UNSTRUCTURED_PLUGIN), constrain = False, ) From 24914d359bf8d8a47076aa1b573cc5533660f601 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Fri, 13 Mar 2026 01:45:24 -0700 Subject: [PATCH 2/4] fix: disable remote code loading for ai-assist model hint lookup --- studio/backend/utils/datasets/llm_assist.py | 7 ++++++- studio/backend/utils/models/model_config.py | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/studio/backend/utils/datasets/llm_assist.py b/studio/backend/utils/datasets/llm_assist.py index 398d73cdcc..c5892bfbc2 100644 --- a/studio/backend/utils/datasets/llm_assist.py +++ b/studio/backend/utils/datasets/llm_assist.py @@ -515,7 +515,12 @@ def _run_multi_pass_advisor( try: from utils.models.model_config import load_model_config - config = load_model_config(model_name, use_auth = True, token = hf_token) + config = load_model_config( + model_name, + use_auth = True, + token = hf_token, + trust_remote_code = False, + ) archs = getattr(config, "architectures", []) if archs and "Gemma3nForConditionalGeneration" in archs: is_gemma_3n = True diff --git a/studio/backend/utils/models/model_config.py b/studio/backend/utils/models/model_config.py index 960e263cb2..23ef9b2cbb 100644 --- a/studio/backend/utils/models/model_config.py +++ b/studio/backend/utils/models/model_config.py @@ -383,7 +383,10 @@ for canonical_file, model_names in MODEL_NAME_MAPPING.items(): def load_model_config( - model_name: str, use_auth: bool = False, token: Optional[str] = None + model_name: str, + use_auth: bool = False, + token: Optional[str] = None, + trust_remote_code: bool = True, ): """ Load model config with optional authentication control. @@ -392,18 +395,23 @@ def load_model_config( if token: # Explicit token provided - use it return AutoConfig.from_pretrained( - model_name, trust_remote_code = True, token = token + model_name, trust_remote_code = trust_remote_code, token = token ) if not use_auth: # Load without any authentication (for public model checks) with without_hf_auth(): return AutoConfig.from_pretrained( - model_name, trust_remote_code = True, token = None + model_name, + trust_remote_code = trust_remote_code, + token = None, ) # Use default authentication (cached tokens) - return AutoConfig.from_pretrained(model_name, trust_remote_code = True) + return AutoConfig.from_pretrained( + model_name, + trust_remote_code = trust_remote_code, + ) # VLM architecture suffixes and known VLM model_type values. From 9648c4306526c5895908a7f27d401cef79edaea0 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Fri, 13 Mar 2026 01:48:22 -0700 Subject: [PATCH 3/4] fix(seed): disable remote code execution for seed inspect loads --- studio/backend/routes/data_recipe/seed.py | 1 + studio/backend/tests/test_data_recipe_seed.py | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 studio/backend/tests/test_data_recipe_seed.py diff --git a/studio/backend/routes/data_recipe/seed.py b/studio/backend/routes/data_recipe/seed.py index 76e05be954..1765550adc 100644 --- a/studio/backend/routes/data_recipe/seed.py +++ b/studio/backend/routes/data_recipe/seed.py @@ -118,6 +118,7 @@ def _build_stream_load_kwargs( "path": dataset_name, "split": split, "streaming": True, + "trust_remote_code": False, } if data_file: kwargs["data_files"] = [data_file] diff --git a/studio/backend/tests/test_data_recipe_seed.py b/studio/backend/tests/test_data_recipe_seed.py new file mode 100644 index 0000000000..3311a49947 --- /dev/null +++ b/studio/backend/tests/test_data_recipe_seed.py @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 + +from pathlib import Path + + +def test_seed_inspect_load_kwargs_disables_remote_code_execution(): + seed_route = Path("studio/backend/routes/data_recipe/seed.py").read_text() + + assert '"trust_remote_code": False' in seed_route From c8c371610bee33404fb0fdc3ed52be47bba8585f Mon Sep 17 00:00:00 2001 From: Test Date: Fri, 13 Mar 2026 09:42:46 +0000 Subject: [PATCH 4/4] fix(test): use capsys instead of caplog for structlog output TestLogGpuMemory tests used pytest's caplog fixture to capture log output, but log_gpu_memory() uses structlog which writes to stdout, not Python's standard logging module. caplog only captures standard logging messages, so assertions always failed on empty text. Switch to capsys which captures stdout directly. --- studio/backend/tests/test_utils.py | 32 +++++++++++------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/studio/backend/tests/test_utils.py b/studio/backend/tests/test_utils.py index 3c33b33cb3..9ff457bb0b 100644 --- a/studio/backend/tests/test_utils.py +++ b/studio/backend/tests/test_utils.py @@ -285,7 +285,7 @@ class TestLogGpuMemory: def test_does_not_raise(self): log_gpu_memory("test") - def test_logs_gpu_info_when_available(self, caplog): + def test_logs_gpu_info_when_available(self, capsys): fake_info = { "available": True, "backend": "cuda", @@ -295,35 +295,27 @@ class TestLogGpuMemory: "utilization_pct": 12.5, "free_gb": 14.0, } - import structlog - from loggers import get_logger - with ( - patch( - "utils.hardware.hardware.get_gpu_memory_info", return_value = fake_info - ), - caplog.at_level(logging.INFO, logger = "utils.hardware.hardware"), + with patch( + "utils.hardware.hardware.get_gpu_memory_info", return_value = fake_info ): log_gpu_memory("unit-test") - assert "unit-test" in caplog.text - assert "CUDA" in caplog.text - assert "FakeGPU" in caplog.text + captured = capsys.readouterr().out + assert "unit-test" in captured + assert "CUDA" in captured + assert "FakeGPU" in captured - def test_logs_cpu_fallback_when_no_gpu(self, caplog): + def test_logs_cpu_fallback_when_no_gpu(self, capsys): fake_info = {"available": False, "backend": "cpu"} - import structlog - from loggers import get_logger - with ( - patch( - "utils.hardware.hardware.get_gpu_memory_info", return_value = fake_info - ), - caplog.at_level(logging.INFO, logger = "utils.hardware.hardware"), + with patch( + "utils.hardware.hardware.get_gpu_memory_info", return_value = fake_info ): log_gpu_memory("cpu-test") - assert "No GPU available" in caplog.text + captured = capsys.readouterr().out + assert "No GPU available" in captured # ========== format_error_message() ==========