Nix copies symlinks directly into the store, e.g. ln -s /etc sym
then “${sym}” will make a symlink to /etc in the store. If you build with sandbox then it’ll be a broken link, but without sandbox it’ll just walk into /etc. Is this intentional? I can’t think of a good reason to do this, vs say refusing to store symlinks or resolving them to their destinations, but it’s clearly done that way on purpose. I looked about in the source but couldn’t find any comments about why. The closest I got was that copyPathToStore
calls fetchToStore
with path.resolveSymlinks()
which implies they are meant to be resolved, at least to either Ancestors
or Full
, but they’re not.
The risk of course is that people will feed srcs into a derivation with path references, as they are supposed to, but someone will get clever and use a symlink. If it’s a relative link, it’ll turn into a broken link and they’ll get a confusing “file not found”, and if it’s an absolute link, it will either do the file not found thing if in a sandbox, or worse, if not in a sandbox, work on the local filesystem but not actually be reproducible on another one.
For me the simplest would be to simply refuse to store symlinks. A fancier way would be to store them if say you store a directory, and the symlink is relative and doesn’t escape the directory, similar to rsync’s notion of “safe” links. They could also get automatically flattened, but that would be surprising in a world where the standard is to not do that unless you pass a --follow-links type flag.