Skip to content

Commit 93d61d0

Browse files
authored
nix: fix removing user Nix profiles from PATH (#220)
When launching a devbox shell, we filter out any Nix user profiles from the PATH (i.e., ~/.nix-profile). This fixes a couple of bugs with how we determine if a PATH directory matches a Nix profile: 1. The `strings.HasPrefix("/Users", profileDir)` call is backwards. 2. Checking for `/Users` is macOS-specific and won't work on Linux. Instead, check if the directory starts with `/nix` to determine if it's the default system profile.
1 parent 22411a6 commit 93d61d0

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

nix/shell.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ func splitNixList(s string) []string {
370370
//
371371
// 1. Applies filepath.Clean.
372372
// 2. Removes the path if it's relative (must begin with '/' and not be '.').
373-
// 3. Removes the path if it's a descendant of a Nix profile directory.
373+
// 3. Removes the path if it's a descendant of a user Nix profile directory
374+
// (the default Nix profile is kept).
374375
func cleanEnvPath(pathEnv string, nixProfileDirs []string) string {
375376
split := filepath.SplitList(pathEnv)
376377
if len(split) == 0 {
@@ -387,11 +388,14 @@ func cleanEnvPath(pathEnv string, nixProfileDirs []string) string {
387388

388389
keep := true
389390
for _, profileDir := range nixProfileDirs {
390-
// nixProfileDirs may be of the form: /nix/var/nix/profile/default or /Users/<username>/.nix-profile
391-
// We want to keep the former, so that nix tools are available inside the shell.
392-
// We want to filter out the latter, so that installed nix packages are not auto-included inside the shell.
393-
// This lets us maintain a veneer of pureness.
394-
if strings.HasPrefix(path, profileDir) && strings.HasPrefix("/Users", profileDir) {
391+
// nixProfileDirs may be of the form: /nix/var/nix/profile/default or
392+
// $HOME/.nix-profile. The former contains Nix itself (nix-store, nix-env,
393+
// etc.), which we want to keep so it's available in the shell. The latter
394+
// contains programs that the user installed with Nix, which we want to filter
395+
// out so that only devbox-managed Nix packages are available.
396+
isProfileDir := strings.HasPrefix(path, profileDir)
397+
isSystemProfile := strings.HasPrefix(profileDir, "/nix")
398+
if isProfileDir && !isSystemProfile {
395399
keep = false
396400
break
397401
}

nix/shell_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,45 @@ If the new shellrc is correct, you can update the golden file with:
8989
})
9090
}
9191
}
92+
93+
func TestCleanEnvPath(t *testing.T) {
94+
tests := []struct {
95+
name string
96+
nixProfiles []string
97+
inPath string
98+
outPath string
99+
}{
100+
{
101+
name: "RemoveUserNixProfileDarwin",
102+
nixProfiles: []string{"/nix/var/nix/profiles/default", "/Users/test/.nix-profile"},
103+
inPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/test/.nix-profile/bin:/nix/var/nix/profiles/default/bin",
104+
outPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/nix/var/nix/profiles/default/bin",
105+
},
106+
{
107+
name: "RemoveUserNixProfileLinux",
108+
nixProfiles: []string{"/nix/var/nix/profiles/default", "/home/test/.nix-profile"},
109+
inPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/test/.nix-profile/bin:/nix/var/nix/profiles/default/bin",
110+
outPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/nix/var/nix/profiles/default/bin",
111+
},
112+
{
113+
name: "NoNixProfiles",
114+
nixProfiles: []string{},
115+
inPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/test/.nix-profile/bin:/nix/var/nix/profiles/default/bin",
116+
outPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/test/.nix-profile/bin:/nix/var/nix/profiles/default/bin",
117+
},
118+
{
119+
name: "NoRelativePaths",
120+
nixProfiles: []string{},
121+
inPath: "/usr/local/bin:/usr/bin:../test:/bin:/usr/sbin:/sbin:.:..",
122+
outPath: "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
123+
},
124+
}
125+
for _, test := range tests {
126+
t.Run(test.name, func(t *testing.T) {
127+
got := cleanEnvPath(test.inPath, test.nixProfiles)
128+
if got != test.outPath {
129+
t.Errorf("Got incorrect cleaned PATH.\ngot: %s\nwant: %s", got, test.outPath)
130+
}
131+
})
132+
}
133+
}

0 commit comments

Comments
 (0)