Skip to content

fix(venv_shebang_rewriter): avoid depending on host coreutils - #4125

Open
nicdumz wants to merge 2 commits into
bazel-contrib:mainfrom
nicdumz:nixos-coreutils-fix
Open

fix(venv_shebang_rewriter): avoid depending on host coreutils#4125
nicdumz wants to merge 2 commits into
bazel-contrib:mainfrom
nicdumz:nixos-coreutils-fix

Conversation

@nicdumz

@nicdumz nicdumz commented Aug 29, 2026

Copy link
Copy Markdown

Two scripts used as build actions in the pip integration ran directly (ctx.actions.run, no shell) with no declared PATH. On sandboxed environments without an FHS-style /bin:/usr/bin (e.g. NixOS), these fail with <tool>: command not found, even though the action's own executable resolves fine.

  • venv_shebang_rewriter.sh resolved head/tail/chmod from PATH.
  • wheel_record_rewriter.sh resolved awk from PATH.

Fix

Both are ported to plain Python scripts exposed as py_binary targets, per this project's own documented guidance (PyExecToolsInfo's exec_interpreter docs recommend a py_binary + cfg=exec over manual interpreter wiring). This sidesteps host PATH concerns entirely.

@nicdumz
nicdumz force-pushed the nixos-coreutils-fix branch from a31d314 to bc2e057 Compare August 29, 2026 14:24
@nicdumz
nicdumz marked this pull request as ready for review August 29, 2026 14:25
@nicdumz
nicdumz marked this pull request as draft August 29, 2026 14:27
@nicdumz
nicdumz force-pushed the nixos-coreutils-fix branch 2 times, most recently from 52a7184 to e0e8047 Compare August 29, 2026 14:38
…ils script

venv_shebang_rewriter.sh ran directly (ctx.actions.run) with no
declared PATH, and used head/tail/chmod resolved from PATH. On
systems without an FHS-style /bin:/usr/bin (e.g. NixOS), this failed
with 'head: command not found'.

Port it to a plain Python script and expose it as a py_binary,
matching this project's own documented guidance (PyExecToolsInfo's
exec_interpreter docs: 'prefer to define a py_binary instead ... this
makes it much easier to setup the runtime environment'). This needs
no new external dependency: the interpreter comes from this project's
own Python toolchain, already used everywhere else in this repo.
wheel_record_rewriter.sh ran directly (ctx.actions.run) with no
declared PATH, and used awk resolved from PATH. On systems without an
FHS-style /bin:/usr/bin (e.g. NixOS), this failed with 'awk: command
not found'.

Rather than translate the awk program into POSIX sh, port it to a
plain Python script and expose it as a py_binary, same rationale and
approach as venv_shebang_rewriter.py.
@rickeylev

Copy link
Copy Markdown
Collaborator

I'm a bit confused how this is working -- I would expect there to be a bootstrapping issue (a py_binary is being required to build a py_binary)

If Nix doesn't have /usr:/usr/bin on path, what does it have? How is one supposed to invoke coreutils if not by relying on path?

@nicdumz

nicdumz commented Aug 29, 2026

Copy link
Copy Markdown
Author

Hey Richard,

  • On circularity: the rewriters are used as part of whl_library / dependency fetching and AFAICT a py_binary using only stdlib doesn't use a wheel directly, so we seem OK here unless I missed something.
  • In NixOS there's not much in /usr/ and /usr/bin, most stuff is in /run/current-system/sw/bin which is a changing symlink (in fact Bazel users on nix need --shell_executable=/run/current-system/sw/bin/bash in their .blazerc otherwise even bash actions themselves fail). Overall I think we can think of this as "OK we can we have truly hermetic builds" and not rely on the expectation that there are coreutils binaries in PATH=/usr/:/usr/bin/ (it's true most of the time, false some of the times). Several approaches:
    • Only code in bash without any of the coreutils (works for simple patterns but is not always readable e.g. > foo instead of touch foo or similar bash tricks).
    • Ship a built coreutils toolchains and call coreutils head, coreutils sort etc. This approach is used by some bazel modules, in particular those happy to depend on aspecs_bazel_lib which already exposes such a toolchain
    • Or rewrite scripts / logic differently so there's no coreutils, e.g. a simple Python script in this case felt simple.

Note that awk in particular is found on most distros and it's natural to expect it in most distros, but it's also not coreutils, so using this binary, in fact encodes another hidden expectation for users of this library: your system must ship awk as well

A upside of this PR: perhaps as a follow-up both rewriters can move to Python only instead of having to fork between windows vs other execution platforms?


Notes:

  • I'm not approaching this from a "all rules should be hermetic or work on non-Linux UNIX" philosophical approach. AFAUI there's no real way in Bazel at the moment to modify PATH for basic .sh executions and this means that the only way to really use these rules in NixOS is to also make them hermetic
  • [LLMD] builds fail on NixOS due to FHS path assumptions zml/zml#747 has broader context and a higher level e2e test

HTH

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants