chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user