diff --git a/.buildkite/test_areas/misc.yaml b/.buildkite/test_areas/misc.yaml index 198def78e03c..5cbd074cba07 100644 --- a/.buildkite/test_areas/misc.yaml +++ b/.buildkite/test_areas/misc.yaml @@ -574,7 +574,9 @@ steps: - tools/pre_commit/test_tethering_allowlist.txt - tests/tools/test_check_test_tethering.py - tools/pre_commit/check_agent_files.py + - tools/pre_commit/check_forbidden_imports.py - tests/tools/test_check_agent_files.py + - tests/tools/test_check_forbidden_imports.py - tests/tool_parsers - tests/tokenizers_ - tests/parser @@ -626,6 +628,7 @@ steps: - pytest -v -s config - pytest -v -s tools/test_check_test_tethering.py - pytest -v -s tools/test_check_agent_files.py + - pytest -v -s tools/test_check_forbidden_imports.py - label: ":computer: (CPU) Reasoning + Renderers" key: cpu-reasoning-renderers diff --git a/tests/tools/test_check_forbidden_imports.py b/tests/tools/test_check_forbidden_imports.py new file mode 100644 index 000000000000..7ee8d795e744 --- /dev/null +++ b/tests/tools/test_check_forbidden_imports.py @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project +"""Portable proof imports stay local to exact files and import families.""" + +import subprocess +import sys +from pathlib import Path + +import pytest + +from tools.pre_commit.check_forbidden_imports import check_file + + +@pytest.mark.parametrize( + ("name", "source", "expected"), + [ + ("native_semantic_collector.py", "import base64\nimport re\n", 0), + ("native_tensor_artifact_transport.py", "import base64\nimport re\n", 0), + ("native_tensor_witness.py", "import base64\n", 0), + ("native_tensor_runtime_contract.py", "import re\n", 0), + ("neighbor.py", "import base64\n", 1), + ("neighbor.py", "import re\n", 1), + ("native_tensor_witness.py", "import re\n", 1), + ("native_tensor_runtime_contract.py", "import base64\n", 1), + ("native_semantic_collector.py", "import pickle\n", 1), + ], +) +def test_portable_exception_preserves_other_files_and_rules( + tmp_path, monkeypatch, name, source, expected +): + monkeypatch.chdir(tmp_path) + path = Path("vllm/plugins") / name + path.parent.mkdir(parents=True) + path.write_text(source) + assert check_file(str(path)) == expected + + +def test_canonical_protocol_modules_import_without_site_packages(): + root = Path(__file__).resolve().parents[2] + # Namespace shells load the actual protocol bytes without starting vLLM. + # The isolated interpreter cannot import C-extension fast-codec packages. + script = """ +import importlib, pathlib, sys, types +root = pathlib.Path(sys.argv[1]) +for name, path in [('vllm', root / 'vllm'), + ('vllm.plugins', root / 'vllm/plugins')]: + package = types.ModuleType(name) + package.__path__ = [str(path)] + sys.modules[name] = package +for name in ['native_semantic_collector', 'native_tensor_artifact_transport', + 'native_tensor_runtime_contract', 'native_tensor_witness', + 'native_attention_operator_observer', 'native_phase_drain']: + module = importlib.import_module('vllm.plugins.' + name) + assert pathlib.Path(module.__file__).parent == root / 'vllm/plugins' +assert not {'pybase64', 'regex', 'torch', 'torch_npu'} & sys.modules.keys() +""" + subprocess.run([sys.executable, "-I", "-S", "-c", script, str(root)], check=True) diff --git a/tools/pre_commit/check_forbidden_imports.py b/tools/pre_commit/check_forbidden_imports.py index d80a8e1fd26d..834941e5e9bb 100644 --- a/tools/pre_commit/check_forbidden_imports.py +++ b/tools/pre_commit/check_forbidden_imports.py @@ -87,6 +87,14 @@ class ForbiddenImport: "or 'import pybase64 as base64'." ), allowed_pattern=re.compile(r"^\s*import\s+pybase64(\s*|\s+as\s+base64\s*)$"), + # These bounded protocol modules must also run in an independent + # stdlib-only, cross-architecture evidence replayer. Other imports in + # these files remain checked; inference code retains the fast imports. + allowed_files={ + "vllm/plugins/native_semantic_collector.py", + "vllm/plugins/native_tensor_artifact_transport.py", + "vllm/plugins/native_tensor_witness.py", + }, ), "re": ForbiddenImport( # regex has no equivalent of the private sre modules @@ -96,7 +104,13 @@ class ForbiddenImport: ), tip="Replace 'import re' with 'import regex as re' or 'import regex'.", allowed_pattern=re.compile(r"^\s*import\s+regex(\s*|\s+as\s+re\s*)$"), - allowed_files={"setup.py"}, + # Exact portable protocol files only; do not exempt their directory. + allowed_files={ + "setup.py", + "vllm/plugins/native_semantic_collector.py", + "vllm/plugins/native_tensor_artifact_transport.py", + "vllm/plugins/native_tensor_runtime_contract.py", + }, ), "triton": ForbiddenImport( pattern=r"^(from|import)\s+triton(\s|\.|$)", diff --git a/vllm/plugins/native_semantic_collector.py b/vllm/plugins/native_semantic_collector.py index 0a2afd724df6..1cb2f0a3954d 100644 --- a/vllm/plugins/native_semantic_collector.py +++ b/vllm/plugins/native_semantic_collector.py @@ -11,9 +11,11 @@ from __future__ import annotations import argparse +import base64 import hashlib import json import os +import re import socket import socketserver import stat @@ -23,9 +25,6 @@ from pathlib import Path from typing import Any -import pybase64 as base64 -import regex as re - MAX_FRAME = 65536 MAPPING = "ecpa-native-request-id-mapping/v1" UPLOAD = "ecpa-native-block-table-upload/v1" diff --git a/vllm/plugins/native_tensor_artifact_transport.py b/vllm/plugins/native_tensor_artifact_transport.py index 09496012ab08..8f0f1e9531ba 100644 --- a/vllm/plugins/native_tensor_artifact_transport.py +++ b/vllm/plugins/native_tensor_artifact_transport.py @@ -6,16 +6,15 @@ from __future__ import annotations import argparse +import base64 import json import os +import re import stat import time from pathlib import Path from typing import TYPE_CHECKING, Any -import pybase64 as base64 -import regex as re - if TYPE_CHECKING or (__package__ and __package__.startswith("vllm.")): from . import native_semantic_collector as native from . import native_tensor_runtime_contract as runtime_contract diff --git a/vllm/plugins/native_tensor_runtime_contract.py b/vllm/plugins/native_tensor_runtime_contract.py index d6f094af0fb7..2d084a1f75c7 100644 --- a/vllm/plugins/native_tensor_runtime_contract.py +++ b/vllm/plugins/native_tensor_runtime_contract.py @@ -5,10 +5,9 @@ from __future__ import annotations +import re from typing import TYPE_CHECKING -import regex as re - if TYPE_CHECKING or (__package__ and __package__.startswith("vllm.")): from . import native_tensor_witness as witness else: diff --git a/vllm/plugins/native_tensor_witness.py b/vllm/plugins/native_tensor_witness.py index 4e8845c90dc2..69c748b89e90 100644 --- a/vllm/plugins/native_tensor_witness.py +++ b/vllm/plugins/native_tensor_witness.py @@ -5,12 +5,11 @@ from __future__ import annotations +import base64 import hashlib import time from typing import Any, cast -import pybase64 as base64 - SCHEMA = "ecpa-selected-KV-materialization-source-candidate/v1" _sink: Any = None