Skip to content

Commit 56faf42

Browse files
committed
Studio: match offline weight-index filenames case-insensitively
The index-name check compared the on-disk filename exactly, while the surrounding weight and safetensors matches use case-insensitive rules. On a case-insensitive volume (Windows or macOS) from_pretrained opens an oddly-cased cache file such as PYTORCH_MODEL.BIN.INDEX.JSON when it requests the canonical lowercase name, so the exact-case check skipped it and a nested pickle shard it referenced was allowed through. Lower-case the index name before matching, as the rest of the gate does, and add a regression test.
1 parent ef15858 commit 56faf42

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

studio/backend/tests/test_offline_embedding_minimal.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,27 @@ def test_gate_blocks_indexed_shard_with_no_pickle_extension(hf_cache):
460460
assert any(u["path"] == "shards/payload" for u in decision.unsafe_files)
461461

462462

463+
def test_gate_blocks_uppercase_index_filename(hf_cache):
464+
# On case-insensitive volumes (Windows/macOS) from_pretrained opens an oddly-cased index when it
465+
# requests the canonical lowercase name, so the index-name match must be case-insensitive too.
466+
_make_cache(
467+
hf_cache,
468+
"org/upper-index",
469+
{
470+
"PYTORCH_MODEL.BIN.INDEX.JSON": (
471+
'{"weight_map": {"w": "shards/pytorch_model-00001-of-00001.bin"}}'
472+
),
473+
"shards/pytorch_model-00001-of-00001.bin": "pickle",
474+
},
475+
)
476+
with _no_network():
477+
decision = _offline_decision("org/upper-index")
478+
assert decision.blocked is True
479+
assert any(
480+
u["path"] == "shards/pytorch_model-00001-of-00001.bin" for u in decision.unsafe_files
481+
)
482+
483+
463484
def test_gate_blocks_indexed_pickle_shard_in_module_subdir(hf_cache):
464485
# A weight index inside a sentence-transformers module load root points at a nested pickle shard.
465486
_make_cache(

studio/backend/utils/security/file_security.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,12 @@ def _add(path: Path):
390390
# torch.loads any not ending in .safetensors. A base safetensors makes it skip the pytorch
391391
# index; a safetensors index is itself chosen, so its non-safetensors targets always load.
392392
for index_path in entries:
393-
if index_path.name not in _TORCH_INDEX_FILES:
393+
# Case-insensitive like the weight/safetensors matches above: a case-insensitive volume
394+
# (Windows/macOS) opens an oddly-cased index when the loader asks for the canonical name.
395+
name = index_path.name.lower()
396+
if name not in _TORCH_INDEX_FILES:
394397
continue
395-
if index_path.name == "pytorch_model.bin.index.json" and has_base_safetensors:
398+
if name == "pytorch_model.bin.index.json" and has_base_safetensors:
396399
continue
397400
for shard_path in _indexed_pickle_shards(index_path, root, snapshot):
398401
_add(shard_path)

0 commit comments

Comments
 (0)