Follow-up to the cherry-picked #116014: - Pin per the dependency policy (pre-1.0: `<0.(minor+2)`): httptools `>=0.6.3,<0.9` (floor = uvicorn[standard]'s own floor), uvloop `>=0.15.1,<0.24`. `watchfiles>=0.20,<2` already complied. - Copy uvicorn's own uvloop marker (win32, cygwin, PyPy) plus `sys_platform != 'android'` so `pip install '.[all]'` on those hosts does not fail on the extra either. - `tools/lazy_deps.py` mirrors the `web` extra for the lazy dashboard install: it also requested `uvicorn[standard]`, so a Termux user opening the dashboard would have hit the same uvloop build at first use. The web_server install hint follows. - `uv lock` regenerated; the lock delta is exactly the pyproject delta. - Two invariant tests: no Termux-reachable extra (or core, or the lazy dashboard feature) requests uvloop; `[all]` still does, off Android. - Docs: troubleshooting entry in the Termux guide.
38 lines
1.7 KiB
Python
38 lines
1.7 KiB
Python
"""Independent core/optional dependency and reviewed CVE policies."""
|
|
import tomllib
|
|
from pathlib import Path
|
|
|
|
from packaging.requirements import Requirement
|
|
from packaging.version import Version
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def test_core_and_optional_speech_dependencies():
|
|
project = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))["project"]
|
|
core = {Requirement(dep).name for dep in project["dependencies"]}
|
|
assert "packaging" in core # Runtime code imports it directly, not transitively.
|
|
assert "faster-whisper" not in core
|
|
assert "faster-whisper" in {
|
|
Requirement(dep).name for dep in project["optional-dependencies"]["stt-whisper"]
|
|
}
|
|
|
|
|
|
def test_starlette_server_pins_and_lock_exclude_cve_2026_48710():
|
|
# BadHost's reviewed fixed boundary is independent of today's exact pin.
|
|
floor = Version("1.0.1")
|
|
metadata = tomllib.loads((REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8"))
|
|
lock = tomllib.loads((REPO_ROOT / "uv.lock").read_text(encoding="utf-8"))
|
|
found = set()
|
|
for extra, specs in metadata["project"]["optional-dependencies"].items():
|
|
for requirement in map(Requirement, specs):
|
|
if requirement.name != "starlette":
|
|
continue
|
|
pins = list(requirement.specifier)
|
|
assert len(pins) == 1 and pins[0].operator == "==", (extra, requirement)
|
|
assert Version(pins[0].version) >= floor, (extra, requirement)
|
|
found.add(extra)
|
|
assert {"web", "mcp", "computer-use", "dev"} <= found
|
|
versions = [Version(row["version"]) for row in lock["package"] if row["name"] == "starlette"]
|
|
assert versions and all(version >= floor for version in versions)
|