e93507a09c
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
151 lines
6.0 KiB
Python
151 lines
6.0 KiB
Python
"""Regression tests for the export-time remote-code trust decision.
|
|
|
|
FP8/FP4/INT quantization export re-reads the just-merged checkpoint. It used to enable
|
|
trust_remote_code whenever the checkpoint's config carried an ``auto_map`` entry, so a model
|
|
that loads fine with built-in classes (and therefore skips the load-time consent scan) could
|
|
smuggle unvetted remote code that then runs at export. The export paths now derive
|
|
trust_remote_code from ``_loaded_via_remote_code`` - the already approved load decision - instead.
|
|
|
|
These run on CPU with no torch / unsloth import: they AST-extract the real helper from
|
|
unsloth/save.py and exec it in isolation, plus assert the call sites dropped the auto_map trust.
|
|
"""
|
|
|
|
import ast
|
|
from pathlib import Path
|
|
|
|
_SAVE_PY = Path(__file__).resolve().parents[2] / "unsloth" / "save.py"
|
|
_SRC = _SAVE_PY.read_text(encoding = "utf-8")
|
|
|
|
|
|
def _load_helper():
|
|
"""Exec just `_loaded_via_remote_code` from save.py (no torch import) and return it."""
|
|
tree = ast.parse(_SRC)
|
|
fn = next(
|
|
n
|
|
for n in tree.body
|
|
if isinstance(n, ast.FunctionDef) and n.name == "_loaded_via_remote_code"
|
|
)
|
|
ns = {}
|
|
exec(compile(ast.Module(body = [fn], type_ignores = []), str(_SAVE_PY), "exec"), ns)
|
|
return ns["_loaded_via_remote_code"]
|
|
|
|
|
|
_loaded_via_remote_code = _load_helper()
|
|
|
|
|
|
def _obj(module_name, **attrs):
|
|
"""A throwaway instance whose class __module__ is `module_name`, plus given attributes."""
|
|
cls = type("Fake", (), {})
|
|
cls.__module__ = module_name
|
|
inst = cls()
|
|
for k, v in attrs.items():
|
|
setattr(inst, k, v)
|
|
return inst
|
|
|
|
|
|
def test_builtin_class_is_not_remote_code():
|
|
assert _loaded_via_remote_code(_obj("transformers.models.llama.modeling_llama")) is False
|
|
|
|
|
|
def test_transformers_modules_class_is_remote_code():
|
|
assert _loaded_via_remote_code(_obj("transformers_modules.acme.modeling_x")) is True
|
|
|
|
|
|
def test_none_is_not_remote_code():
|
|
assert _loaded_via_remote_code(None) is False
|
|
|
|
|
|
def test_none_module_is_not_remote_code():
|
|
# A class whose __module__ is None must not raise AttributeError.
|
|
assert _loaded_via_remote_code(_obj(None)) is False
|
|
|
|
|
|
def test_auto_map_in_config_alone_does_not_grant_trust():
|
|
# The core bypass: a built-in-loadable model whose config merely declares auto_map must NOT
|
|
# be treated as remote-code-loaded (that is exactly what enabled the consent-gate bypass).
|
|
cfg = type("Cfg", (), {"auto_map": {"AutoModelForCausalLM": "modeling_x.Model"}})()
|
|
assert (
|
|
_loaded_via_remote_code(_obj("transformers.models.llama.modeling_llama", config = cfg))
|
|
is False
|
|
)
|
|
|
|
|
|
def test_peft_base_model_is_unwrapped():
|
|
base = _obj("transformers_modules.acme.modeling_x")
|
|
peft = _obj("peft.peft_model", get_base_model = lambda: base)
|
|
assert _loaded_via_remote_code(peft) is True
|
|
|
|
|
|
def test_wrapper_model_attr_is_walked():
|
|
inner = _obj("transformers_modules.acme.modeling_x")
|
|
wrapper = _obj("peft.peft_model", model = inner)
|
|
assert _loaded_via_remote_code(wrapper) is True
|
|
|
|
|
|
def test_wrapper_over_builtin_stays_false():
|
|
inner = _obj("transformers.models.llama.modeling_llama")
|
|
wrapper = _obj("peft.peft_model", model = inner)
|
|
assert _loaded_via_remote_code(wrapper) is False
|
|
|
|
|
|
def test_processor_held_custom_tokenizer_is_detected():
|
|
# A built-in ProcessorMixin can hold an approved custom-code tokenizer; the walk must
|
|
# descend into processor components or the export reload loses that approved trust.
|
|
tok = _obj("transformers_modules.acme.tokenization_x")
|
|
proc = _obj("transformers.processing_utils", tokenizer = tok)
|
|
assert _loaded_via_remote_code(proc) is True
|
|
|
|
|
|
def test_processor_held_custom_image_processor_is_detected():
|
|
ip = _obj("transformers_modules.acme.image_processing_x")
|
|
proc = _obj("transformers.processing_utils", image_processor = ip)
|
|
assert _loaded_via_remote_code(proc) is True
|
|
|
|
|
|
def test_builtin_processor_with_builtin_components_stays_false():
|
|
proc = _obj(
|
|
"transformers.processing_utils",
|
|
tokenizer = _obj("transformers.tokenization_utils_fast"),
|
|
image_processor = _obj("transformers.image_processing_utils"),
|
|
)
|
|
assert _loaded_via_remote_code(proc) is False
|
|
|
|
|
|
def test_cyclic_wrappers_terminate():
|
|
a = _obj("peft.peft_model")
|
|
b = _obj("peft.peft_model", model = a)
|
|
a.model = b
|
|
assert _loaded_via_remote_code(a) is False
|
|
|
|
|
|
# -- call-site assertions: the auto_map-derived trust is gone from every export path -----------
|
|
|
|
|
|
def test_torchao_export_derives_trust_from_load_decision():
|
|
assert "model_trust = _loaded_via_remote_code(model)" in _SRC
|
|
assert "tok_trust = _loaded_via_remote_code(tokenizer)" in _SRC
|
|
assert "trust_remote_code = model_trust" in _SRC
|
|
assert "trust_remote_code = tok_trust" in _SRC
|
|
# The staged-config auto_map scan that granted trust is removed.
|
|
assert 'if "auto_map" in json.load' not in _SRC
|
|
|
|
|
|
def test_compressed_and_gguf_lora_paths_drop_auto_map_trust():
|
|
# No path derives a trust decision straight from config auto_map anymore, and no path
|
|
# collapses model and tokenizer trust into one flag.
|
|
assert 'bool(getattr(model.config, "auto_map", None))' not in _SRC
|
|
assert "_loaded_via_remote_code(model) or _loaded_via_remote_code(tokenizer)" not in _SRC
|
|
assert "if _loaded_via_remote_code(model):" in _SRC # GGUF-LoRA converter flag
|
|
|
|
|
|
def test_compressed_export_keeps_model_and_tokenizer_trust_separate():
|
|
# The subprocess gets one flag per component, so an approved custom tokenizer cannot
|
|
# enable an unapproved model's code during compressed quantization (or vice versa).
|
|
assert 'cmd.append("--trust-remote-code")' in _SRC
|
|
assert 'cmd.append("--trust-remote-code-tokenizer")' in _SRC
|
|
qsrc = (_SAVE_PY.parent / "_compressed_quantize.py").read_text(encoding = "utf-8")
|
|
assert 'ap.add_argument("--trust-remote-code-tokenizer", action = "store_true")' in qsrc
|
|
assert "trust_remote_code = args.trust_remote_code_tokenizer" in qsrc
|
|
# The model loads keep the model flag only.
|
|
assert "args.model, args.trust_remote_code)" in qsrc
|