Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions internal/devbox/shell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"flag"
"io/fs"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
Expand Down Expand Up @@ -487,3 +488,62 @@ func TestWriteDevboxShellrcWithZDOTDIR(t *testing.T) {
t.Error("Expected shellrc to source the custom .zshrc file")
}
}

// TestWriteDevboxShellrcZDOTDIRWithSpaces guards against a regression where the
// `[ -f <path> ]` guard around sourcing the user's shellrc was unquoted. When
// ZDOTDIR contains spaces (e.g. ".../Application Support/..."), the unquoted
// path expands to multiple words and `[` fails with "too many arguments", so
// the user's real shellrc never gets sourced.
func TestWriteDevboxShellrcZDOTDIRWithSpaces(t *testing.T) {
// A ZDOTDIR with a space, like the one some terminal integrations inject.
zdotdir := filepath.Join(t.TempDir(), "Application Support", "zsh")
if err := os.MkdirAll(zdotdir, 0o755); err != nil {
t.Fatal(err)
}
t.Setenv("ZDOTDIR", zdotdir)

zshrcPath := filepath.Join(zdotdir, ".zshrc")
if err := os.WriteFile(zshrcPath, []byte("# user zshrc"), 0o644); err != nil {
t.Fatalf("Failed to create test .zshrc: %v", err)
}

shell := initShellBinaryFields("/usr/bin/zsh")
shell.devbox = &Devbox{projectDir: "/test/project"}
shell.projectDir = "/test/project"

shellrcPath, err := shell.writeDevboxShellrc()
if err != nil {
t.Fatalf("Failed to write devbox shellrc: %v", err)
}
content, err := os.ReadFile(shellrcPath)
if err != nil {
t.Fatalf("Failed to read generated shellrc: %v", err)
}
contentStr := string(content)

// The guard must quote the path so the space doesn't split into words.
wantGuard := `if [ -f "` + zshrcPath + `" ]; then`
if !strings.Contains(contentStr, wantGuard) {
t.Errorf("expected quoted guard %q in generated shellrc:\n%s", wantGuard, contentStr)
}

// Run the actual generated guard line through /bin/sh to prove it doesn't
// error with "too many arguments" on a space-containing path.
var guardLine string
for _, line := range strings.Split(contentStr, "\n") {
if strings.HasPrefix(strings.TrimSpace(line), "if [ -f ") {
guardLine = strings.TrimSpace(line) + " echo sourced; fi"
break
}
}
if guardLine == "" {
t.Fatalf("could not find guard line in generated shellrc:\n%s", contentStr)
}
out, err := exec.Command("/bin/sh", "-c", guardLine).CombinedOutput()
if err != nil {
t.Fatalf("guard line failed to execute (%v): %s\nline: %s", err, out, guardLine)
}
if strings.TrimSpace(string(out)) != "sourced" {
t.Errorf("guard line did not take the true branch; output: %q\nline: %s", out, guardLine)
}
}
4 changes: 2 additions & 2 deletions internal/devbox/shellrc.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ content readable.

{{- if .OriginalInitPath -}}
{{- if eq .ShellName "zsh" -}}
if [ -f {{ .OriginalInitPath }} ]; then
if [ -f "{{ .OriginalInitPath }}" ]; then
local DEVBOX_ZDOTDIR="$ZDOTDIR"
export ZDOTDIR="{{dirPath .OriginalInitPath}}"
. "{{ .OriginalInitPath }}"
export ZDOTDIR="$DEVBOX_ZDOTDIR"
fi
{{ else -}}
if [ -f {{ .OriginalInitPath }} ]; then
if [ -f "{{ .OriginalInitPath }}" ]; then
. "{{ .OriginalInitPath }}"
fi
{{ end -}}
Expand Down
2 changes: 1 addition & 1 deletion internal/devbox/testdata/shellrc/basic/shellrc.golden
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if [ -f testdata/shellrc/basic/shellrc ]; then
if [ -f "testdata/shellrc/basic/shellrc" ]; then
. "testdata/shellrc/basic/shellrc"
fi
# Begin Devbox Post-init Hook
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if [ -f testdata/shellrc/zsh_zdotdir/shellrc ]; then
if [ -f "testdata/shellrc/zsh_zdotdir/shellrc" ]; then
local DEVBOX_ZDOTDIR="$ZDOTDIR"
export ZDOTDIR="testdata/shellrc/zsh_zdotdir"
. "testdata/shellrc/zsh_zdotdir/shellrc"
Expand Down
Loading