Skip to content

Commit 6fa85c5

Browse files
committed
fix(sandbox): resolve bundled boxlite via real executable path
- use the resolved executable path when locating the sibling bundled `boxlite` binary - add a regression test for the symlinked install layout
1 parent 0a3d702 commit 6fa85c5

2 files changed

Lines changed: 61 additions & 3 deletions

File tree

internal/sandbox/boxlitecli/resolve.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,33 @@ func bundledPath() string {
3232
if err != nil {
3333
return ""
3434
}
35-
candidate := filepath.Join(filepath.Dir(exe), defaultCLIPath)
35+
36+
for _, exePath := range executablePathCandidates(exe) {
37+
candidate := filepath.Join(filepath.Dir(exePath), defaultCLIPath)
38+
if isExecutableFile(candidate) {
39+
return candidate
40+
}
41+
}
42+
return ""
43+
}
44+
45+
func executablePathCandidates(exe string) []string {
46+
exe = strings.TrimSpace(exe)
47+
if exe == "" {
48+
return nil
49+
}
50+
51+
candidates := []string{exe}
52+
if resolved, err := filepath.EvalSymlinks(exe); err == nil && resolved != "" && resolved != exe {
53+
candidates = append(candidates, resolved)
54+
}
55+
return candidates
56+
}
57+
58+
func isExecutableFile(candidate string) bool {
3659
info, err := os.Stat(candidate)
3760
if err != nil || info.IsDir() {
38-
return ""
61+
return false
3962
}
40-
return candidate
63+
return info.Mode()&0o111 != 0
4164
}

internal/sandbox/boxlitecli/resolve_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,41 @@ func TestResolvePathUsesBundledBinaryWhenUnset(t *testing.T) {
5151
}
5252
}
5353

54+
func TestResolvePathUsesBundledBinaryBehindExecutableSymlink(t *testing.T) {
55+
dir := t.TempDir()
56+
installBinDir := filepath.Join(dir, "local", "bin")
57+
bundleBinDir := filepath.Join(dir, "local", "lib", "csgclaw", "v0.2.6", "csgclaw", "bin")
58+
if err := os.MkdirAll(installBinDir, 0o755); err != nil {
59+
t.Fatalf("MkdirAll(install) error = %v", err)
60+
}
61+
if err := os.MkdirAll(bundleBinDir, 0o755); err != nil {
62+
t.Fatalf("MkdirAll(bundle) error = %v", err)
63+
}
64+
65+
realExecutable := filepath.Join(bundleBinDir, "csgclaw")
66+
if err := os.WriteFile(realExecutable, []byte(""), 0o755); err != nil {
67+
t.Fatalf("WriteFile(csgclaw) error = %v", err)
68+
}
69+
bundled := filepath.Join(bundleBinDir, defaultCLIPath)
70+
if err := os.WriteFile(bundled, []byte(""), 0o755); err != nil {
71+
t.Fatalf("WriteFile(boxlite) error = %v", err)
72+
}
73+
executableSymlink := filepath.Join(installBinDir, "csgclaw")
74+
if err := os.Symlink(realExecutable, executableSymlink); err != nil {
75+
t.Fatalf("Symlink() error = %v", err)
76+
}
77+
restore := stubExecutablePath(t, executableSymlink)
78+
defer restore()
79+
80+
want, err := filepath.EvalSymlinks(bundled)
81+
if err != nil {
82+
t.Fatalf("EvalSymlinks(boxlite) error = %v", err)
83+
}
84+
if got := ResolvePath(""); got != want {
85+
t.Fatalf("ResolvePath(\"\") = %q, want %q", got, want)
86+
}
87+
}
88+
5489
func TestResolvePathFallsBackToPATHValue(t *testing.T) {
5590
restore := stubExecutablePath(t, filepath.Join(t.TempDir(), "bin", "csgclaw"))
5691
defer restore()

0 commit comments

Comments
 (0)