NixOS / nix

Nix, the purely functional package manager
https://nixos.org/
GNU Lesser General Public License v2.1
12.73k stars 1.52k forks source link

Passing store paths into functions from other flakes causes errors in pure evaluation mode #11030

Open endgame opened 4 months ago

endgame commented 4 months ago

Affected releases (non-exhaustive): Nix 2.20.6, Nix 2.21.2, Nix 2.22.1 Last unaffected release: Nix 2.19.4

It appears that recent versions of Nix have tightened pure evaluation mode. In the flake below, I pass a store path to a function from another flake, which used to work in older versions of Nix.

To reproduce, run nix build on the following flake:

{
  description = "Pass a store path to a flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
    nix-freeze-tree.url = "git+https://git.sr.ht/~jack/nix-freeze-tree?rev=60e09710d6062d54d063c8488337c14d9d302d58";
  };

  outputs = inputs: {
    packages.x86_64-linux.default =
      let
        pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;

        step1 = pkgs.runCommand "step1" {} ''
          mkdir -p $out
          echo '19 + 23' > $out/theanswer
        '';

        step2 = inputs.nix-freeze-tree.lib.x86_64-linux.freeze step1;
      in
      step2;
  };
}

You should see error: access to absolute path '/nix/store/bhgy1rz0hi7b9anbnyr6zjgp0jh5dwrg-step1' is forbidden in pure evaluation mode (use '--impure' to override).

nixos-discourse commented 3 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2024-07-03-nix-team-meeting-minutes-158/49097/1

roberth commented 3 months ago

Triaged 2024-07-03:

This may be an IFD-related problem, considering this import in nix-freeze-tree

Could also be caused by recent-ish changes in EvalState to use Source- / InputAccessor for allow-listing the accessible paths.

Maybe it's only allowing the direct references to the imported outputs; should be allowing whole closures.

Or maybe we should require

Two flakes is not necessary. One flake is enough to reproduce.

Call chain is realisePath -> realiseContext -> addPath -> addPathPrefix; no computeFSClosure or similar. It should compute the closure.

This was not previously discovered because a lot of IFD only looks at the output, ignoring references.

endgame commented 1 month ago

git bisect says that ea95327e72f5781295417b0eae46a5e351bebebd is the breaking commit. I tested on a cloud VM by building nix from git, then using it to build the dodgy flake in the OP of this issue: cd ~/dodgy-flake && nix shell ${HOME}/nix#nix -c nix build --no-link and doing a full GC between checks.