Fix root-as-dropped-euid exec env and restore Binary.load_or_install#32
Merged
Fix root-as-dropped-euid exec env and restore Binary.load_or_install#32
Conversation
- Binary.load_or_install: restore the "try load(), fall back to install()" helper that abx-plugins hooks rely on after it got inadvertently dropped. - BinProvider.exec: when running as root and dropping privileges to a non-root target UID, use sudo_env (target user's HOME/LOGNAME/USER) instead of fallback_env so the dropped subprocess finds its own cache/ config dirs (fixes brew "Permission denied ~/.cache/Homebrew" under root). - BrewProvider._refresh_bin_link: when running as root but about to drop to brew's owner UID, chmod the managed shim dir's ancestors to be traversable by that UID so version probes from the dropped-privilege subprocess can reach the symlink. - README: fix cargo_root alias typo in the CargoProvider section.
Devin Review caught that ``if loaded.is_valid and not no_cache:`` applied the caller's ``no_cache`` flag to the value we just got back from ``load()``. ``load()`` already honours the flag internally, so a valid result is fresh regardless — the ``and not no_cache`` guard was forcing a redundant ``install()`` whenever ``no_cache=True`` even though the binary already resolved. Drop the redundant condition.
The computed ``cache_dir = install_root/cache`` default works for the managed lib-dir layout but forced downstream plugins to treat ``PUPPETEER_CACHE_DIR`` as ``install_root.parent``, which broke callers that pin the cache at an arbitrary path (e.g. ``lib/puppeteer/chrome``). Add a writable ``browser_cache_dir`` field that wins over the computed default so hooks can pass the user-configured PUPPETEER_CACHE_DIR through to the provider verbatim while still using ``install_root`` / ``bin_dir`` for metadata and shim locations.
Per maintainer feedback: the removal was intentional — callsites should use ``install()`` directly (which is already a no-op short-circuit when ``is_valid`` and no ``no_cache`` is set). Reverting the restored helper and leaving it to the plugin hooks to adopt ``install()``.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes three paper cuts that show up when running abxpkg as root on Linux (the common CI/container case) plus one README typo:
Binary.load_or_installrestored. This convenience helper got dropped earlier but every downstream plugin hook inabx-pluginsstill calls it (npm/pip/puppeteer/brew/apt/bash/cargo/chromewebstore/…). Its absence made every hook crash with the opaque message"npm install failed: load_or_install". The restored method follows the documented semantics: tryload()first, fall back toinstall()when the binary isn't already valid.BinProvider.execenv when dropping from root. When the caller is root and the provider'sEUIDpoints at a non-root owner (e.g.brewowned bybrewuser/linuxbrew),preexec_fn=drop_privilegescorrectly switches the subprocess's UID but the environment was still being built fromfallback_env(root'sHOME/LOGNAME/USER). Brew then blew up withPermission denied @ dir_s_mkdir - /root/.cache/Homebrewbecause the dropped subprocess couldn't write into root's home. The fix pickssudo_env(target user's identity) when we're going to drop privileges.BrewProvider shim dir traversability. The
_refresh_bin_linkhelper creates<install_root>/bin/<name>in the parent Python process (running as root in the above flow). The laterself.execdrops to brew's owner UID for version probing, and that dropped subprocess couldn't traverse the root-owned ancestor directories. Now weos.chownthe shim dir and bump theother/groupexec bits on ancestors when we're about to drop privileges, so the version probe reaches the symlink.README typo. The CargoProvider section said
set \install_root=Path(...)` or `install_root=Path(...)`— the second reference is the alias, so it now readscargo_root=Path(...)`.Test plan
uv run prek run --all-files— cleanuv run pytest tests/test_brewprovider.py(as root on Linux,/home/linuxbrew/.linuxbrewowned by a non-root user) — all 7 tests pass with the exec env + shim chmod fixabx-pluginshooks that callbinary.load_or_install()now complete instead of failing fast with"load_or_install".Summary by cubic
Fixes root-to-user exec env and brew shim traversability when running as root to prevent Homebrew permission errors; adds a
PuppeteerProvidercache-dir override. Note:Binary.load_or_installremains removed — update hooks to callinstall().New Features
PuppeteerProvider: addbrowser_cache_dirto override computedcache_dirforPUPPETEER_CACHE_DIR.Bug Fixes
BinProvider.exec: when root drops to provider EUID, usesudo_env(target user's HOME/USER/LOGNAME).BrewProvider: chown shim dir to brew owner and add execute bits on ancestor dirs so dropped subprocess can reach the symlink.cargo_rootalias typo in theCargoProviderREADME.Written for commit 501cc33. Summary will update on new commits.