Skip to content

Commit

Permalink
feat: enforce boundaries by simulating pure eval
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nrdxp committed Aug 4, 2024
1 parent 262ade1 commit da202e3
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 25 deletions.
48 changes: 36 additions & 12 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 1 addition & 4 deletions dev/mod.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
{
Pkgs = mod.pkgs;
Shell = mod.shell;
}
{ Shell = mod.shell; }
4 changes: 0 additions & 4 deletions dev/pkgs.nix

This file was deleted.

2 changes: 1 addition & 1 deletion dev/shell.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
pkgs ? mod.pkgs,
pkgs ? atom.pkgs,
}:
pkgs.mkShell {
packages = with pkgs; [
Expand Down
3 changes: 2 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
let
dev = import ./. {
extern = {
extern = rec {
pins = import ./npins;
pkgs = import pins.nixpkgs { };
};
} ./dev;
in
Expand Down
3 changes: 1 addition & 2 deletions test/bld.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion test/bld/mod.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit da202e3

Please sign in to comment.