Edit: I went ahead and opened an issue for this: Limited interface to system/nix-external dependencies? · Issue #8192 · NixOS/nix · GitHub
Packages that need run-time access to executables that aren’t/can’t be in the Nix store tend to be awkward if not broken. I have a vague proposal that might be an improvement; looking for people with ~ecosystem perspective to poke holes or help refine…
The main cases are setuid (like sudo
) and system/platform executables (like pbcopy
on macOS).
Background/problem
You can skip this section if you're familiar with the issues here.
I’ll focus on sudo
since it’s a good example of both cases, and it’s a common problem for Nix users on both NixOS and non-NixOS systems.
The store can’t contain setuid executables for security reasons. sudo
will refuse to run if it isn’t setuid 0, so pkgs.sudo
is a common a stumbling block. You can use it to embed a path to a sudo executable, but it’ll fail if it ever runs. Testing/review will catch this if you’re lucky, but if it’s a rare code path you’ll end up with a time-bomb. I see some in nixpkgs that probably don’t work as the packager intended. The sudo package is marked as platform linux, so another side effect of this is that Nix will refuse to install packages using pkgs.sudo
on non-Linux systems like macOS by default.
Aside:
pkgs.sudo
builds on macOS if you force the issue, but I don’t personally see much point in “fixing” the platform just to increase the number of people who get tricked into depending on it…
Some people try to work around this if they know/realize it, but we don’t have good tools so results are inevitably mixed:
- Since setuid executables on NixOS are implemented as wrappers located in /run/wrappers/, some packages hardcode this path (I currently see 73 instances of
/run/wrappers
in 53 files withinnixpkgs/pkgs/
). These won’t be working outside of NixOS. - Some packages patch sudo out of invocations. This is probably the right call if the sudo invocation is in a build/test/install script or is otherwise superfluous, but it wouldn’t shock me if this occasionally bites someone.
Other uses of sudo in packages probably go unnoticed, or get left alone by people who know pkgs.sudo
is a trap.
- If these are bare commands (I could find at least one of these in my own store), this will be fine if the package is run with a normal PATH–but it’s probably also causing some people grief if they use them in service definitions, test frameworks, or other contexts where a weird PATH is common.
- If these are abspaths like /usr/bin/sudo, they’re presumably failing on NixOS (not sure if any other Nix-supported systems have a sudo that isn’t @ /usr/bin/sudo?)
Proposal
This is ~sparse. I don’t grok all of the pressures/interests here and don’t want to fret details that may be moot if everyone hates this
-
Add an eval and/or build-time oracle to Nix that can, given an arbitrary executable name, hand out a stable path under Nix’s control. To ensure the contents of the path don’t affect the build, the path itself shouldn’t be accessible in the build sandbox.
(To avoid people hardcoding these paths, “stable” should probably not mean a priori “predictable”?)
-
Preserve these declared external dependencies (in the derivation? within nix-support?) for Nix to handle at realisation time.
-
At realisation time, attempt to resolve these external dependencies to paths present on the system. If they are found, symlink the stable path to the system executable. If they are not, error and ask the user to help disambiguate. (The user might be able to give Nix the correct path, obtain the dependency and retry, report a packaging problem, etc.)
I don’t have a strong opinion on how implicit vs. explicit resolution should be. AFAIK, ~system executables should usually be locatable with something equivalent to
PATH="$(getconf PATH)" type -p <executable>
, and I imagine that’ll almost always be the expected behavior. But some kind of config/lockfile mechanism for edge cases also feels inevitable, so it wouldn’t be the end of the world if an ~implicit mechanism just suggests additions and keeps the user in the loop?Aside: This naive getconf approach won’t actually work on NixOS atm, but I’m unsure if that’s a mistake or not. I noticed that
/run/wrappers/bin
is in my PATH on NixOS but is not in the PATH returned bygetconf PATH
(/run/current-system/sw/bin:/bin:/usr/bin
). Anyone have perspective on the pressures, here?There’s some context from 2013 in the PR that added /run/current-system/sw/bin. The last comment by @peti suggests maybe patching getconf to just return the existing PATH env (when it is set) might be better. That sounds like it would fix this issue on NixOS without adding additional PATH components for non-NixOS Linuxes, but I assume it would also meaningfully change the behavior of
getconf PATH
on those systems. IDK if the splash damage from that would be manageable or not. -
Add some mechanism(s) for ~managing the links (GC unused links? re-resolve broken ones? update links per user changes to config/locking mechanism? maybe list existing links?)
For thematic brevity, I nicknamed this affordance rime.