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
29 changes: 16 additions & 13 deletions tool/shelltool/localshell.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,37 +594,40 @@ func shellKindDescription(shell resolvedShell) string {
}

func (s resolvedShell) statelessArgvForCommand(command string) []string {
var suffix []string
switch s.kind {
case shellKindPowerShell:
suffix = []string{"-NoProfile", "-NoLogo", "-NonInteractive", "-Command", command}
return s.argvWithExtra([]string{"-NoProfile", "-NoLogo", "-NonInteractive", "-Command", command})
case shellKindCmd:
suffix = []string{"/d", "/c", command}
return s.argvWithExtra([]string{"/d", "/c", command})
case shellKindBash:
suffix = []string{"--noprofile", "--norc", "-c", command}
return s.argvWithExtra([]string{"--noprofile", "--norc", "-c", command})
default:
suffix = []string{"-c", command}
return s.argvWithExtra([]string{"-c", command})
}
return combineArgv(s.extraArgv, suffix)
}

func (s resolvedShell) persistentArgv() ([]string, error) {
var suffix []string
switch s.kind {
case shellKindPowerShell:
suffix = []string{"-NoProfile", "-NoLogo", "-NonInteractive", "-Command", "-"}
return s.launchArgv([]string{"-NoProfile", "-NoLogo", "-NonInteractive", "-Command", "-"}), nil
case shellKindCmd:
return nil, fmt.Errorf("persistent mode is not supported for cmd.exe; use pwsh, powershell, or a POSIX shell")
case shellKindBash:
suffix = []string{"--noprofile", "--norc"}
return s.launchArgv([]string{"--noprofile", "--norc"}), nil
default:
suffix = nil
return s.launchArgv(nil), nil
}
return append([]string{s.binary}, combineArgv(s.extraArgv, suffix)...), nil
}

func combineArgv(extra, suffix []string) []string {
return slices.Concat(extra, suffix)
func (s resolvedShell) launchArgv(suffix []string) []string {
return append([]string{s.binary}, s.argvWithExtra(suffix)...)
}

func (s resolvedShell) argvWithExtra(suffix []string) []string {
if len(s.extraArgv) == 0 {
return suffix
}
return append(slices.Clone(s.extraArgv), suffix...)
}

func classifyShellKind(shell string) shellKind {
Expand Down
26 changes: 25 additions & 1 deletion tool/shelltool/localshell_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

package shelltool

import "testing"
import (
"slices"
"testing"
)

func TestPreserveEnvironmentValuesKeepsOnlyAllowlist(t *testing.T) {
source := []string{
Expand All @@ -11,6 +14,7 @@ func TestPreserveEnvironmentValuesKeepsOnlyAllowlist(t *testing.T) {
"AF_SHELL_PARENT_VAR=should-not-leak",
"tmp=/tmp/test",
}

env := make(map[string]string)

preserveEnvironmentValues(env, source)
Expand All @@ -28,3 +32,23 @@ func TestPreserveEnvironmentValuesKeepsOnlyAllowlist(t *testing.T) {
t.Fatal("unexpected non-preserved variable copied")
}
}

func TestResolvedShellArgvIncludesExtraArgv(t *testing.T) {
shell := resolvedShell{
binary: "/custom/bash",
kind: shellKindBash,
extraArgv: []string{"--login"},
}

if got, want := shell.statelessArgvForCommand("echo hi"), []string{"--login", "--noprofile", "--norc", "-c", "echo hi"}; !slices.Equal(got, want) {
t.Fatalf("statelessArgvForCommand = %v, want %v", got, want)
}

got, err := shell.persistentArgv()
if err != nil {
t.Fatalf("persistentArgv: %v", err)
}
if want := []string{"/custom/bash", "--login", "--noprofile", "--norc"}; !slices.Equal(got, want) {
t.Fatalf("persistentArgv = %v, want %v", got, want)
}
}
Loading