Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

285 lines
7.9 KiB
Python

"""
Model File Verifier - Verify model file integrity using SHA256 checksums.
Example commands:
# Verify using HuggingFace model online metadata
python -m sglang.srt.utils.model_file_verifier verify --model-path /path/to/model --model-checksum Qwen/Qwen3-0.6B
# Verify using locally generated checksum
python -m sglang.srt.utils.model_file_verifier generate --model-path <hf-id-or-model-path> --model-checksum checksums.json
python -m sglang.srt.utils.model_file_verifier verify --model-path /path/to/model --model-checksum checksums.json
"""
import argparse
import fnmatch
import hashlib
import json
import warnings
from concurrent.futures import ThreadPoolExecutor
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Dict, List, Optional, Tuple
# ======== Data Format ========
@dataclass
class FileInfo:
sha256: str
size: int
@dataclass
class Manifest:
files: Dict[str, FileInfo]
@classmethod
def from_dict(cls, data: dict) -> "Manifest":
if "checksums" in data:
warnings.warn(
"The 'checksums' format is deprecated. "
"Please regenerate with the latest version to use the new 'files' format.",
DeprecationWarning,
stacklevel=3,
)
return cls(
files={
k: FileInfo(sha256=v, size=-1) for k, v in data["checksums"].items()
}
)
return cls(files={k: FileInfo(**v) for k, v in data["files"].items()})
def to_dict(self) -> dict:
return asdict(self)
# ======== Constants ========
IGNORE_PATTERNS = [
".DS_Store",
"*.lock",
".gitattributes",
"LICENSE",
"LICENSE.*",
"README.md",
"README.*",
"NOTICE",
]
# ======== Verify ========
def verify(*, model_path: str, checksums_source: str, max_workers: int = 4) -> None:
model_path = Path(model_path).resolve()
expected = _load_checksums(checksums_source)
actual = _compute_manifest_from_folder(
model_path=model_path,
filenames=list(expected.files.keys()),
max_workers=max_workers,
)
_compare_manifests(expected=expected, actual=actual)
print(f"[ModelFileVerifier] All {len(expected.files)} files verified successfully.")
def _compare_manifests(*, expected: Manifest, actual: Manifest) -> None:
errors = []
for filename, exp in expected.files.items():
if filename not in actual.files:
errors.append(f"{filename}: missing (expected size={exp.size})")
elif actual.files[filename].sha256 != exp.sha256:
act = actual.files[filename]
errors.append(
f"{filename}: mismatch (expected={exp.sha256[:16]}... size={exp.size}, actual={act.sha256[:16]}... size={act.size})"
)
if errors:
raise IntegrityError("Integrity check failed: " + "; ".join(errors))
# ======== Generate ========
def generate_checksums(
*, source: str, output_path: str, max_workers: int = 4
) -> Manifest:
if Path(source).is_dir():
model_path = Path(source).resolve()
files = _discover_files(model_path)
if not files:
raise IntegrityError(f"No model files found in {model_path}")
manifest = _compute_manifest_from_folder(
model_path=model_path, filenames=files, max_workers=max_workers
)
else:
manifest = Manifest(files=_load_file_infos_from_hf(repo_id=source))
Path(output_path).write_text(
json.dumps(manifest.to_dict(), indent=2, sort_keys=True)
)
print(
f"[ModelFileVerifier] Generated checksums for {len(manifest.files)} files -> {output_path}"
)
return manifest
def _discover_files(model_path: Path) -> List[str]:
return sorted(
e.name
for e in model_path.iterdir()
if e.is_file()
and not e.name.startswith(".")
and not any(fnmatch.fnmatch(e.name, p) for p in IGNORE_PATTERNS)
)
# ======== Load Checksums ========
def _load_checksums(source: str) -> Manifest:
if Path(source).is_file():
data = json.loads(Path(source).read_text())
return Manifest.from_dict(data)
return Manifest(files=_load_file_infos_from_hf(repo_id=source))
def _load_file_infos_from_hf(*, repo_id: str) -> Dict[str, FileInfo]:
from huggingface_hub import HfFileSystem
fs = HfFileSystem()
files = fs.ls(repo_id, detail=True)
file_infos = dict(
r for r in map(lambda f: _get_filename_and_info_from_hf_file(fs, f), files) if r
)
if not file_infos:
raise IntegrityError(f"No files found in HF repo {repo_id}.")
return file_infos
def _get_filename_and_info_from_hf_file(
fs, file_info
) -> Optional[Tuple[str, FileInfo]]:
if file_info.get("type") != "file":
return None
filename = Path(file_info.get("name", "")).name
if any(fnmatch.fnmatch(filename, pat) for pat in IGNORE_PATTERNS):
return None
size = file_info.get("size", -1)
lfs_info = file_info.get("lfs")
if lfs_info and "sha256" in lfs_info:
return filename, FileInfo(sha256=lfs_info["sha256"], size=size)
if "sha256" in file_info:
return filename, FileInfo(sha256=file_info["sha256"], size=size)
content = fs.read_bytes(file_info.get("name", ""))
return filename, FileInfo(
sha256=hashlib.sha256(content).hexdigest(), size=len(content)
)
# ======== Compute Checksums ========
def _compute_manifest_from_folder(
*, model_path: Path, filenames: List[str], max_workers: int
) -> Manifest:
from tqdm import tqdm
def compute_one(filename: str) -> Tuple[str, Optional[FileInfo]]:
full_path = model_path / filename
if not full_path.exists():
return filename, None
sha256 = compute_sha256(file_path=full_path)
size = full_path.stat().st_size
return filename, FileInfo(sha256=sha256, size=size)
with ThreadPoolExecutor(max_workers=max_workers) as executor:
results = list(
tqdm(
executor.map(compute_one, filenames),
total=len(filenames),
desc="Computing checksums",
)
)
return Manifest(files={k: v for k, v in results if v is not None})
def compute_sha256(*, file_path) -> str:
sha256 = hashlib.sha256()
with open(file_path, "rb") as f:
while chunk := f.read(64 * 1024):
sha256.update(chunk)
return sha256.hexdigest()
# ======== Exceptions ========
class IntegrityError(Exception):
pass
# ======== CLI ========
def _add_common_args(parser):
parser.add_argument(
"--model-path",
required=True,
help="Local model directory or HuggingFace repo ID",
)
parser.add_argument(
"--model-checksum",
required=True,
help="Checksums JSON file path",
)
parser.add_argument(
"--workers", type=int, default=4, help="Number of parallel workers"
)
def main():
parser = argparse.ArgumentParser(
description="Model File Verifier - Verify model file integrity using checksums"
)
subparsers = parser.add_subparsers(dest="command", required=True)
gen_parser = subparsers.add_parser(
"generate", help="Generate checksums.json for a model"
)
_add_common_args(gen_parser)
gen_parser.set_defaults(
func=lambda args: generate_checksums(
source=args.model_path,
output_path=args.model_checksum,
max_workers=args.workers,
)
)
verify_parser = subparsers.add_parser(
"verify", help="Verify model files against checksums"
)
_add_common_args(verify_parser)
verify_parser.set_defaults(
func=lambda args: verify(
model_path=args.model_path,
checksums_source=args.model_checksum,
max_workers=args.workers,
)
)
args = parser.parse_args()
args.func(args)
if __name__ == "__main__":
main()