Skip to content

Commit a7caeb6

Browse files
committed
Prefer /Users/t/bin:/Users/t/go/bin:/Users/t/.local/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/go/bin:/usr/pkg/bin:/usr/pkg/sbin:/opt/homebrew/bin:/opt/homebrew/sbin:/sbin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin for gh, hard-coded paths are only a fallback
1 parent 0b58e14 commit a7caeb6

File tree

1 file changed

+61
-47
lines changed

1 file changed

+61
-47
lines changed

cmd/goose/github.go

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -59,61 +59,75 @@ func (*App) token(ctx context.Context) (string, error) {
5959
log.Println("Using GitHub token from GITHUB_TOKEN environment variable")
6060
return token, nil
6161
}
62-
// Only check absolute paths for security - never use PATH
63-
var trustedPaths []string
64-
switch runtime.GOOS {
65-
case "windows":
66-
trustedPaths = []string{
67-
`C:\Program Files\GitHub CLI\gh.exe`,
68-
`C:\Program Files (x86)\GitHub CLI\gh.exe`,
69-
filepath.Join(os.Getenv("LOCALAPPDATA"), "Programs", "gh", "gh.exe"),
70-
filepath.Join(os.Getenv("LOCALAPPDATA"), "GitHub CLI", "gh.exe"),
62+
// Try to find gh in PATH first
63+
ghPath, err := exec.LookPath("gh")
64+
if err == nil {
65+
log.Printf("Found gh in PATH at: %s", ghPath)
66+
// Resolve any symlinks to get the real path
67+
if realPath, err := filepath.EvalSymlinks(ghPath); err == nil {
68+
ghPath = realPath
69+
log.Printf("Resolved to: %s", ghPath)
7170
}
72-
case "darwin":
73-
trustedPaths = []string{
74-
"/opt/homebrew/bin/gh", // Homebrew on Apple Silicon
75-
"/usr/local/bin/gh", // Homebrew on Intel / manual install
76-
"/usr/bin/gh", // System package managers
77-
}
78-
case "linux":
79-
trustedPaths = []string{
80-
"/usr/local/bin/gh", // Manual install
81-
"/usr/bin/gh", // System package managers
82-
"/home/linuxbrew/.linuxbrew/bin/gh", // Linuxbrew
83-
"/snap/bin/gh", // Snap package
84-
}
85-
default:
86-
// BSD and other Unix-like systems
87-
trustedPaths = []string{
88-
"/usr/local/bin/gh",
89-
"/usr/bin/gh",
71+
} else {
72+
// Fall back to checking common installation paths
73+
log.Print("gh not found in PATH, checking common locations...")
74+
var commonPaths []string
75+
switch runtime.GOOS {
76+
case "windows":
77+
commonPaths = []string{
78+
`C:\Program Files\GitHub CLI\gh.exe`,
79+
`C:\Program Files (x86)\GitHub CLI\gh.exe`,
80+
filepath.Join(os.Getenv("LOCALAPPDATA"), "Programs", "gh", "gh.exe"),
81+
filepath.Join(os.Getenv("LOCALAPPDATA"), "GitHub CLI", "gh.exe"),
82+
}
83+
case "darwin":
84+
commonPaths = []string{
85+
"/opt/homebrew/bin/gh", // Homebrew on Apple Silicon
86+
"/usr/local/bin/gh", // Homebrew on Intel / manual install
87+
"/usr/bin/gh", // System package managers
88+
"/opt/local/bin/gh", // MacPorts
89+
"/sw/bin/gh", // Fink
90+
"/nix/var/nix/profiles/default/bin/gh", // Nix
91+
}
92+
case "linux":
93+
homeDir := os.Getenv("HOME")
94+
commonPaths = []string{
95+
"/usr/local/bin/gh", // Manual install
96+
"/usr/bin/gh", // System package managers (apt, dnf, etc)
97+
"/home/linuxbrew/.linuxbrew/bin/gh", // Linuxbrew
98+
"/snap/bin/gh", // Snap package
99+
"/run/current-system/sw/bin/gh", // NixOS
100+
"/var/lib/flatpak/exports/bin/gh", // Flatpak system
101+
filepath.Join(homeDir, ".local", "share", "flatpak", "exports", "bin", "gh"), // Flatpak user
102+
"/usr/local/go/bin/gh", // Go install
103+
filepath.Join(homeDir, "go", "bin", "gh"), // Go install user
104+
filepath.Join(homeDir, ".local", "bin", "gh"), // pip/pipx install
105+
"/opt/gh/bin/gh", // Custom installs
106+
}
107+
default:
108+
// BSD and other Unix-like systems
109+
commonPaths = []string{
110+
"/usr/local/bin/gh",
111+
"/usr/bin/gh",
112+
"/usr/pkg/bin/gh", // NetBSD pkgsrc
113+
"/opt/local/bin/gh", // OpenBSD ports
114+
}
90115
}
91-
}
92116

93-
var ghPath string
94-
for _, path := range trustedPaths {
95-
// Verify the file exists and is executable
96-
if info, err := os.Stat(path); err == nil {
97-
// Check if it's a regular file and executable
98-
const executableMask = 0o111
99-
if info.Mode().IsRegular() && info.Mode()&executableMask != 0 {
100-
// Verify it's actually the gh binary by running version command
101-
// Use timeout to prevent hanging
102-
versionCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
103-
cmd := exec.CommandContext(versionCtx, path, "version")
104-
output, err := cmd.Output()
105-
cancel() // Call cancel immediately after command execution
106-
if err == nil && strings.Contains(string(output), "gh version") {
107-
log.Printf("Found and verified gh at: %s", path)
108-
ghPath = path
109-
break
110-
}
117+
for _, path := range commonPaths {
118+
if path == "" {
119+
continue // Skip empty paths from unset env vars
120+
}
121+
if _, err := os.Stat(path); err == nil {
122+
log.Printf("Found gh at common location: %s", path)
123+
ghPath = path
124+
break
111125
}
112126
}
113127
}
114128

115129
if ghPath == "" {
116-
return "", errors.New("gh cli not found in trusted locations and GITHUB_TOKEN not set")
130+
return "", errors.New("gh CLI not found in PATH or common locations, and GITHUB_TOKEN not set")
117131
}
118132

119133
log.Printf("Executing command: %s auth token", ghPath)

0 commit comments

Comments
 (0)