Studio: keep the extras install working under a hardened uv.toml / pip.conf (#8579)

* Studio: keep the extras install working under a hardened uv.toml / pip.conf

A machine with security-hardened package-manager config could not install
Studio. With `no-build = true` in ~/.config/uv/uv.toml, the "unsloth extras"
step failed because extras.txt carries requirements that ship no wheel on PyPI
at any version, and uv correctly refused to build them:

    x No solution found when resolving dependencies:
    `-> Because openai-whisper==20250625 has no usable wheels [...]
        hint: building from source is disabled for all packages (--no-build)

The pip fallback then hit `require-hashes = true` in ~/.config/pip/pip.conf and
rejected every requirement, since the shipped requirements files are pinned but
unhashed.

The wheel-less requirements are already audited and allowlisted for source
builds in .github/scripts/clean-machine-assert.sh, so the installer now names
them explicitly with a package-scoped --no-binary. That overrides a global
no-build / only-binary policy for those four names only, and leaves the user's
binary-only policy in force for every other requirement. A blanket --no-build
or `--no-binary :none:` override would have discarded the policy entirely.

Hash-required mode has no command-line equivalent, so it is switched off in the
child environment of the installer's own pip commands. pip applies environment
variables after config files, so index-url, trusted-host, cert and proxy
settings from pip.conf all stay in force, and uv commands are untouched. The
override never reaches os.environ, so the user's own later pip commands keep
their policy.

Pinned-index installs additionally drop the restrictive UV_* / PIP_* variables.
That branch already neutralised the config files, but an environment variable
outranks a config file, so a hardened shell could still fail a torch repair the
pin was supposed to make deterministic.

Fixes #8530

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Carry the source-build exemptions into the later source-only installs

Two paths still aborted under a user-level `no-build = true` once the extras
step was fixed.

The pinned Diffusers revision is a source ARCHIVE, and uv refuses to build one
under no-build ("Building source distributions for `diffusers` is disabled"),
so a hardened host died at "diffusers pin" instead. That step runs on every
platform for python >= 3.10, which includes the macOS host in the report. The
exemption is guarded on the version marker because python < 3.10 resolves a
released wheel from diffusers-pin.txt that must not be forced through a source
build.

extras.txt pins MeCab==0.996.5 on macOS cp314 and up, the last release carrying
an sdist, so no-build refuses it there too. MeCab is a C extension, so the
exemption is conditional: every other host resolves 0.996.13 from a wheel and
must not be pushed into a compiler-dependent build.

Verified against uv 0.10 with a cold cache, which matters here: a warm cache
reuses the wheel it already built for the archive and hides the failure.

* Tighten the comments added by this PR

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Daniel Han 2026-08-12 09:46:34 -07:00 committed by GitHub
parent 51fac012be
commit 88262f5901
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 328 additions and 1 deletions

View file

@ -287,6 +287,232 @@ class TestPinnedIndexClearsUvEnv:
assert env is None
class TestSdistOnlyBuildArgs:
"""A hardened user config must not be able to fail the extras step.
#8530: `no-build = true` (uv.toml) or `only-binary = :all:` (pip.conf) makes every
wheel-less requirement in extras.txt unresolvable, so the install died at "unsloth
extras". A PACKAGE-SCOPED --no-binary overrides that for those names only -- verified
against uv 0.10 and pip 26: drop one name and that name is refused again.
"""
def test_emits_no_binary_for_every_sdist_only_package(self):
args = ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)
for name in ips.SDIST_ONLY_PACKAGES:
assert ["--no-binary", name] == args[
args.index(name) - 1 : args.index(name) + 1
], f"{name} must be passed as a package-scoped --no-binary, got: {args}"
assert len(args) == 2 * len(ips.SDIST_ONLY_PACKAGES)
def test_openai_whisper_is_covered(self):
"""The package named in the issue, and the transitive one behind omegaconf."""
assert "openai-whisper" in ips.SDIST_ONLY_PACKAGES
# omegaconf==2.3.1 pins antlr4-python3-runtime below the 4.13.2 wheel, so it
# arrives as a transitive sdist and fails no-build even though extras.txt
# never names it.
assert "antlr4-python3-runtime" in ips.SDIST_ONLY_PACKAGES
def test_flags_survive_translation_to_uv(self):
"""uv is the primary path, so the flags must reach _build_uv_cmd intact."""
cmd = ips._build_uv_cmd(tuple(ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)))
for name in ips.SDIST_ONLY_PACKAGES:
assert name in cmd
assert cmd.count("--no-binary") == len(ips.SDIST_ONLY_PACKAGES)
def test_flags_survive_translation_to_pip(self):
"""And the pip FALLBACK must carry them too, for the uv-less/uv-broken case."""
cmd = ips._build_pip_cmd(tuple(ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES)))
for name in ips.SDIST_ONLY_PACKAGES:
assert name in cmd
assert cmd.count("--no-binary") == len(ips.SDIST_ONLY_PACKAGES)
@pytest.mark.parametrize(
"is_macos, version, expected",
[
(True, (3, 14, 0), True),
(True, (3, 13, 12), False),
(False, (3, 14, 0), False),
(False, (3, 13, 12), False),
],
)
def test_mecab_is_exempted_only_where_it_has_no_wheel(self, is_macos, version, expected):
"""extras.txt pins MeCab==0.996.5 on macOS cp314+, which ships only an sdist.
MeCab is a C extension, so an unconditional exemption would force a
compiler-dependent build on every other host -- a worse bug than the one being
fixed. Verified against uv 0.10: 0.996.5 is refused under `no-build = true` for
macOS cp314 and resolves with --no-binary MeCab; 0.996.13 stays a wheel elsewhere.
"""
with (
mock.patch.object(ips, "IS_MACOS", is_macos),
mock.patch.object(sys, "version_info", version),
):
names = ips._extras_sdist_only_packages()
assert ("MeCab" in names) is expected
# The unconditional ones are always present.
assert set(ips.SDIST_ONLY_PACKAGES) <= set(names)
def test_the_diffusers_pin_is_exempted_on_the_archive_path(self):
"""The pin is a source ARCHIVE, and uv's no-build refuses to build one, so the
install still died here after extras.txt was fixed.
Guarded on python >= 3.10 because diffusers-pin.txt resolves a released wheel
below that, which must not be forced through a source build.
"""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
for node in ast.walk(tree):
if not (isinstance(node, ast.Call) and getattr(node.func, "id", None) == "pip_install"):
continue
req = next((k for k in node.keywords if k.arg == "req"), None)
if req is None or "diffusers-pin.txt" not in ast.unparse(req.value):
continue
splat = " ".join(ast.unparse(a.value) for a in node.args if isinstance(a, ast.Starred))
assert (
"_sdist_only_build_args('diffusers')" in splat
), f"the diffusers pin at line {node.lineno} must exempt the source archive"
assert "version_info >= (3, 10)" in splat, (
"the exemption must be guarded so the pre-3.10 wheel is not forced "
f"through a source build (line {node.lineno})"
)
return
pytest.fail("no pip_install(req=.../diffusers-pin.txt) call found")
def test_the_extras_step_actually_passes_them(self):
"""The helper existing is not the fix; the extras call site using it is.
extras.txt is the manifest that carries the wheel-less requirements, and its
pip_install() is fatal, so this is the call that #8530 died on.
"""
tree = ast.parse(Path(ips.__file__).read_text(encoding = "utf-8"))
for node in ast.walk(tree):
if not (isinstance(node, ast.Call) and getattr(node.func, "id", None) == "pip_install"):
continue
req = next((k for k in node.keywords if k.arg == "req"), None)
if req is None or "extras.txt" not in ast.unparse(req.value):
continue
starred = [ast.unparse(a.value) for a in node.args if isinstance(a, ast.Starred)]
assert any("_sdist_only_build_args(" in s for s in starred), (
f"the extras.txt install at line {node.lineno} must splat "
"_sdist_only_build_args() or a hardened uv.toml fails it again"
)
assert any("_extras_sdist_only_packages()" in s for s in starred), (
"the extras install must use the platform-aware list so the macOS "
"cp314 MeCab sdist is exempted too"
)
return
pytest.fail("no pip_install(req=.../extras.txt) call found")
def test_matches_the_ci_nobuild_allowlists(self):
"""CI already ratifies exactly these as audited pure-Python sdist builds.
If the two lists drift, either CI fails a legitimate build or we exempt a
package nobody audited, so pin them together.
"""
repo = Path(ips.__file__).resolve().parents[1]
shell = (repo / ".github/scripts/clean-machine-assert.sh").read_text(encoding = "utf-8")
allow = shell[shell.index('_allow="$(printf') :]
allow = allow[: allow.index("\n")]
ps1 = (repo / ".github/scripts/assert-nobuild.ps1").read_text(encoding = "utf-8")
for name in ips.SDIST_ONLY_PACKAGES:
assert name in allow, f"{name} missing from clean-machine-assert.sh nobuild allowlist"
assert f"'{name}'" in ps1, f"{name} missing from assert-nobuild.ps1 allowlist"
class TestHardenedPipConfigRelaxation:
"""`require-hashes = true` in pip.conf killed the pip FALLBACK in #8530.
Every requirements file we ship is pinned but unhashed, so hash-required mode can
never be satisfied. pip applies env vars AFTER config files, so PIP_REQUIRE_HASHES=0
in the child env overrides it while pip.conf's index-url, trusted-host, cert and
proxy stay in force. It has no command-line equivalent, hence the env var.
"""
HOSTILE = {
"PIP_REQUIRE_HASHES": "1",
"PIP_ONLY_BINARY": ":all:",
"UV_NO_BUILD": "1",
"UV_EXCLUDE_NEWER": "2024-01-01T00:00:00Z",
}
def test_uv_commands_are_left_alone(self):
"""uv reads none of the PIP_* vars, and its own no-build is handled by the
package-scoped --no-binary, so a uv command must still inherit the env
unchanged -- the mirror contract at test_non_pinned_install_keeps_user_mirror."""
with mock.patch.dict(os.environ, self.HOSTILE):
assert ips._install_env_for_cmd(["uv", "pip", "install", "-r", "extras.txt"]) is None
def test_non_pinned_pip_install_relaxes_hash_mode(self):
with mock.patch.dict(os.environ, self.HOSTILE):
env = ips._install_env_for_cmd(["python", "-m", "pip", "install", "-r", "extras.txt"])
assert env is not None, "the pip fallback must not inherit require-hashes"
assert env["PIP_REQUIRE_HASHES"] == "0"
def test_non_pinned_pip_keeps_the_user_mirror_and_binary_policy(self):
"""Only hash mode is relaxed. The mirror stays, and so does only-binary --
the wheel-less packages are exempted per-package on the command line instead."""
with mock.patch.dict(
os.environ,
dict(self.HOSTILE, PIP_INDEX_URL = "https://mirror.corp/simple"),
):
env = ips._install_env_for_cmd(["python", "-m", "pip", "install", "x"])
assert env["PIP_INDEX_URL"] == "https://mirror.corp/simple"
assert env["PIP_ONLY_BINARY"] == ":all:"
assert "PIP_CONFIG_FILE" not in env, "a non-pinned install must still read pip.conf"
assert "UV_NO_CONFIG" not in env, "a non-pinned install must still read uv.toml"
def test_non_install_commands_are_untouched(self):
"""run() routes EVERY command through this helper, not just installs."""
with mock.patch.dict(os.environ, self.HOSTILE):
assert ips._install_env_for_cmd(["python", "-m", "pip", "--version"]) is None
assert ips._install_env_for_cmd(["python", "-m", "ensurepip", "--upgrade"]) is None
def test_pinned_cmd_strips_restrictive_policy_env(self):
"""The pinned branch neutralises the config FILES, but an env var outranks a
config file, so a hardened shell could still fail a torch repair the pin was
supposed to make deterministic."""
with mock.patch.dict(os.environ, self.HOSTILE):
env = ips._install_env_for_cmd(
["uv", "pip", "install", "torch", "--index-url", "https://x/cu128"]
)
assert env is not None
for name in ("PIP_REQUIRE_HASHES", "PIP_ONLY_BINARY", "UV_NO_BUILD", "UV_EXCLUDE_NEWER"):
assert name not in env, f"{name} must be cleared for a pinned install"
# The pre-existing pinned contract is unchanged.
assert env["UV_NO_CONFIG"] == "1" and env["PIP_CONFIG_FILE"] == os.devnull
def test_the_parent_environment_is_never_mutated(self):
"""The relaxation is a child-env override. Leaking it into os.environ would
weaken the user's policy for their own later pip commands in this session."""
with mock.patch.dict(os.environ, self.HOSTILE):
ips._install_env_for_cmd(["python", "-m", "pip", "install", "x"])
ips._install_env_for_cmd(["uv", "pip", "install", "x", "--index-url", "https://y"])
assert os.environ["PIP_REQUIRE_HASHES"] == "1"
assert os.environ["UV_NO_BUILD"] == "1"
def test_the_pip_fallback_receives_the_relaxation(self):
"""End of the real path: uv fails, pip_install falls back through run(), and
that pip command is the one #8530 died on."""
seen: dict = {}
def _fake_run(label, cmd, *a, **kw):
seen["env"] = ips._install_env_for_cmd(cmd)
seen["cmd"] = cmd
with (
mock.patch.object(ips, "USE_UV", True),
mock.patch.object(ips, "subprocess") as sp,
mock.patch.object(ips, "run", _fake_run),
mock.patch.dict(os.environ, self.HOSTILE),
):
sp.run.return_value = mock.Mock(returncode = 1, stdout = "")
sp.PIPE, sp.STDOUT = -1, -2
ips.pip_install("deps", *ips._sdist_only_build_args(*ips.SDIST_ONLY_PACKAGES))
assert seen["env"]["PIP_REQUIRE_HASHES"] == "0"
for name in ips.SDIST_ONLY_PACKAGES:
assert name in seen["cmd"], "the fallback lost the source-build exemptions"
class TestProgressLineNotes:
"""_progress() leaves the cursor mid-line, so anything printed between two
progress steps must close that line first. Before centralising this, a real