From da202e37ba095fe6d27d916b03306656462aad9c Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Sun, 4 Aug 2024 13:40:26 -0600 Subject: [PATCH] feat: enforce boundaries by simulating pure eval With this, we have essentially achieved nixos/nix#6530 in pure nix. The only remaining "impurity" in this sense would be the path passed to the composer function, but this is actually a good thing, since it doesn't eagerly copy everything to the nix store like flakes, but instead only makes pure copies of files when they are actually accessed. If the path doesn't exist on the file-system we will immediately fail anyway, so it's "impurity" is irrelevant. There will be no way for the user to escape the module system with these new enforcements, so that means that we basically have a totally pure nix evaluation without the high cost of having to copy the entire repo into the /nix/store eagerly. --- default.nix | 48 ++++++++++++++++++++++++++++++++++++------------ dev/mod.nix | 5 +---- dev/pkgs.nix | 4 ---- dev/shell.nix | 2 +- shell.nix | 3 ++- test/bld.nix | 3 +-- test/bld/mod.nix | 2 +- 7 files changed, 42 insertions(+), 25 deletions(-) delete mode 100644 dev/pkgs.nix diff --git a/default.nix b/default.nix index 992cb0c..aa9bcc6 100644 --- a/default.nix +++ b/default.nix @@ -26,7 +26,17 @@ in }: dir: let - std = compose { } ./std // builtins; + std = + compose { } ./std + // filterMap ( + k: v: + if + builtins.match "^import|^scopedImport|^builtins|^fetch.*|^current.*|^nixPath|^storePath" k != null + then + null + else + { ${k} = v; } + ) builtins; atom' = builtins.removeAttrs (extern // atom // { inherit extern; }) [ "atom" (baseNameOf dir) @@ -54,17 +64,31 @@ let mod = if hasMod then scope "${dir + "/mod.nix"}" else { }; - scope = scopedImport ( - { - inherit std; - atom = atom'; - mod = lowerKeys (builtins.removeAttrs self [ "mod" ] // { outPath = filterMod dir; }); - } - // cond { - _if = pre != null; - inherit pre; - } - ); + scope = + let + importErr = "Importing arbitrary Nix files is forbidden. Declare your dependencies via the module system instead."; + in + scopedImport ( + { + inherit std; + atom = atom'; + mod = lowerKeys (builtins.removeAttrs self [ "mod" ] // { outPath = filterMod dir; }); + # override builtins, so they can only be accessed via `std` + builtins = abort "Please access builtins uniformly via the `std` scope."; + import = abort importErr; + scopedImport = abort importErr; + __fetchurl = abort "Ad hoc fetching is illegal. Declare dependencies statically in the manifest instead."; + __currentSystem = abort "Accessing the current system is impure. Declare supported systems in the manifest."; + __currentTime = abort "Accessing the current time is impure & illegal."; + __nixPath = abort "The NIX_PATH is an impure feature, and therefore illegal."; + __storePath = abort "Making explicit dependencies on store paths is illegal."; + + } + // cond { + _if = pre != null; + inherit pre; + } + ); g = name: type: diff --git a/dev/mod.nix b/dev/mod.nix index 9262f19..a540a34 100644 --- a/dev/mod.nix +++ b/dev/mod.nix @@ -1,4 +1 @@ -{ - Pkgs = mod.pkgs; - Shell = mod.shell; -} +{ Shell = mod.shell; } diff --git a/dev/pkgs.nix b/dev/pkgs.nix deleted file mode 100644 index 18f9084..0000000 --- a/dev/pkgs.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - inherit (atom.pins) nixpkgs; -in -import nixpkgs { } diff --git a/dev/shell.nix b/dev/shell.nix index 07c3995..691fa96 100644 --- a/dev/shell.nix +++ b/dev/shell.nix @@ -1,5 +1,5 @@ { - pkgs ? mod.pkgs, + pkgs ? atom.pkgs, }: pkgs.mkShell { packages = with pkgs; [ diff --git a/shell.nix b/shell.nix index 52e62ec..1b1e6d2 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,8 @@ let dev = import ./. { - extern = { + extern = rec { pins = import ./npins; + pkgs = import pins.nixpkgs { }; }; } ./dev; in diff --git a/test/bld.nix b/test/bld.nix index 33e435a..1dd86c6 100644 --- a/test/bld.nix +++ b/test/bld.nix @@ -2,8 +2,7 @@ let compose = import ../.; mod = compose { } ( # added to test implicit path conversion when path is a string - builtins.toPath - ./bld + builtins.toPath ./bld ); in builtins.deepSeq mod mod diff --git a/test/bld/mod.nix b/test/bld/mod.nix index 9451116..aaf307b 100644 --- a/test/bld/mod.nix +++ b/test/bld/mod.nix @@ -3,7 +3,7 @@ bar = atom.foo + 2; baz = mod.bar + 4; F = std.set.filterMap; - File = builtins.readFile "${mod}/bum"; + File = std.readFile "${mod}/bum"; Buzz = mod.buzz; Next = ./next; # should be a non-existant path: /nix/store/next Bar = mod.bar;