Skip to content

Commit 56de262

Browse files
feat: enhance user shell resolution for macOS in RunAsUser function
1 parent 5079586 commit 56de262

1 file changed

Lines changed: 35 additions & 1 deletion

File tree

internal/executor/executor_unix.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,52 @@ package executor
55
import (
66
"context"
77
"os"
8+
"runtime"
89
"strings"
910
)
1011

1112
func (r *Real) IsRoot() bool {
1213
return os.Getuid() == 0
1314
}
1415

16+
// resolveUserShell returns the given user's configured login shell on macOS by
17+
// consulting Directory Services (dscl). Returns "" on non-darwin platforms, if
18+
// the lookup fails, or if the resolved path isn't an executable file — in which
19+
// case callers should fall back to /bin/bash.
20+
//
21+
// Mirrors stepsecurity-dev-machine-guard.sh:run_as_logged_in_user. Matters when
22+
// the user's PATH (including npm/pnpm/yarn via nvm/fnm/homebrew) is configured
23+
// only in zsh profile files (.zprofile/.zshrc) — bash -l on such a user sources
24+
// nothing and runs with a stripped PATH, producing empty package scans.
25+
func (r *Real) resolveUserShell(ctx context.Context, username string) string {
26+
if runtime.GOOS != "darwin" || username == "" {
27+
return ""
28+
}
29+
stdout, _, _, err := r.Run(ctx, "dscl", ".", "-read", "/Users/"+username, "UserShell")
30+
if err != nil {
31+
return ""
32+
}
33+
fields := strings.Fields(strings.TrimSpace(stdout))
34+
if len(fields) < 2 {
35+
return ""
36+
}
37+
shell := fields[1]
38+
info, err := os.Stat(shell)
39+
if err != nil || info.IsDir() || info.Mode()&0o111 == 0 {
40+
return ""
41+
}
42+
return shell
43+
}
44+
1545
func (r *Real) RunAsUser(ctx context.Context, username, command string) (string, error) {
1646
if !r.IsRoot() {
1747
stdout, _, _, err := r.Run(ctx, "bash", "-c", command)
1848
return strings.TrimSpace(stdout), err
1949
}
20-
stdout, _, _, err := r.Run(ctx, "sudo", "-H", "-u", username, "bash", "-l", "-c", command)
50+
shell := r.resolveUserShell(ctx, username)
51+
if shell == "" {
52+
shell = "/bin/bash"
53+
}
54+
stdout, _, _, err := r.Run(ctx, "sudo", "-H", "-u", username, shell, "-l", "-c", command)
2155
return strings.TrimSpace(stdout), err
2256
}

0 commit comments

Comments
 (0)