mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Remove secureexec package
From the go 1.19 release notes:
Command and LookPath no longer allow results from a PATH search to be found relative to the current directory. This removes a common source of security problems but may also break existing programs that depend on using, say, exec.Command("prog") to run a binary named prog (or, on Windows, prog.exe) in the current directory. See the os/exec package documentation for information about how best to update such programs.
			
			
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							| @@ -16,7 +16,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Run goreleaser | ||||
|         uses: goreleaser/goreleaser-action@v1 | ||||
|         with: | ||||
|   | ||||
							
								
								
									
										12
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| name: Continuous Integration | ||||
|  | ||||
| env: | ||||
|   GO_VERSION: 1.18 | ||||
|   GO_VERSION: 1.20 | ||||
|  | ||||
| on: | ||||
|   push: | ||||
| @@ -32,7 +32,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Cache build | ||||
|         uses: actions/cache@v3 | ||||
|         with: | ||||
| @@ -91,7 +91,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Cache build | ||||
|         uses: actions/cache@v1 | ||||
|         with: | ||||
| @@ -117,7 +117,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Cache build | ||||
|         uses: actions/cache@v1 | ||||
|         with: | ||||
| @@ -153,7 +153,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Cache build | ||||
|         uses: actions/cache@v1 | ||||
|         with: | ||||
| @@ -187,7 +187,7 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v1 | ||||
|         with: | ||||
|           go-version: 1.18.x | ||||
|           go-version: 1.20.x | ||||
|       - name: Cache build | ||||
|         uses: actions/cache@v1 | ||||
|         with: | ||||
|   | ||||
| @@ -26,4 +26,4 @@ linters-settings: | ||||
|     max-func-lines: 0 | ||||
|  | ||||
| run: | ||||
|   go: 1.18 | ||||
|   go: 1.20 | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| # docker build -t lazygit . | ||||
| # docker run -it lazygit:latest /bin/sh | ||||
|  | ||||
| FROM golang:1.18 as build  | ||||
| FROM golang:1.20 as build | ||||
| WORKDIR /go/src/github.com/jesseduffield/lazygit/ | ||||
| COPY go.mod go.sum ./ | ||||
| RUN go mod download | ||||
|   | ||||
							
								
								
									
										3
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,12 +1,11 @@ | ||||
| module github.com/jesseduffield/lazygit | ||||
|  | ||||
| go 1.18 | ||||
| go 1.20 | ||||
|  | ||||
| require ( | ||||
| 	github.com/OpenPeeDeeP/xdg v1.0.0 | ||||
| 	github.com/atotto/clipboard v0.1.4 | ||||
| 	github.com/aybabtme/humanlog v0.4.1 | ||||
| 	github.com/cli/safeexec v1.0.0 | ||||
| 	github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 | ||||
| 	github.com/creack/pty v1.1.11 | ||||
| 	github.com/fsmiamoto/git-todo-parser v0.0.5 | ||||
|   | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -55,8 +55,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA | ||||
| github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= | ||||
| github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | ||||
| github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | ||||
| github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI= | ||||
| github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= | ||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||
| github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do= | ||||
| github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc= | ||||
|   | ||||
| @@ -5,12 +5,12 @@ import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/fsmiamoto/git-todo-parser/todo" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/commands/models" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/common" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
| 	"github.com/samber/lo" | ||||
| ) | ||||
| @@ -92,7 +92,7 @@ func getDaemonKind() DaemonKind { | ||||
| } | ||||
|  | ||||
| func getCommentChar() byte { | ||||
| 	cmd := secureexec.Command("git", "config", "--get", "--null", "core.commentChar") | ||||
| 	cmd := exec.Command("git", "config", "--get", "--null", "core.commentChar") | ||||
| 	if output, err := cmd.Output(); err == nil && len(output) == 2 { | ||||
| 		return output[0] | ||||
| 	} | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"runtime/debug" | ||||
| @@ -17,7 +18,6 @@ import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/env" | ||||
| 	integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/logs/tail" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
| 	"github.com/samber/lo" | ||||
| 	"gopkg.in/yaml.v3" | ||||
| @@ -280,7 +280,7 @@ func mergeBuildInfo(buildInfo *BuildInfo) { | ||||
| } | ||||
|  | ||||
| func getGitVersionInfo() string { | ||||
| 	cmd := secureexec.Command("git", "--version") | ||||
| 	cmd := exec.Command("git", "--version") | ||||
| 	stdout, _ := cmd.Output() | ||||
| 	gitVersion := strings.Trim(strings.TrimPrefix(string(stdout), "git version "), " \r\n") | ||||
| 	return gitVersion | ||||
|   | ||||
| @@ -7,8 +7,6 @@ import ( | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| ) | ||||
|  | ||||
| // including license from https://github.com/tcnksm/go-gitconfig because this file is an adaptation of that repo's code | ||||
| @@ -55,10 +53,10 @@ func runGitConfigCmd(cmd *exec.Cmd) (string, error) { | ||||
|  | ||||
| func getGitConfigCmd(key string) *exec.Cmd { | ||||
| 	gitArgs := []string{"config", "--get", "--null", key} | ||||
| 	return secureexec.Command("git", gitArgs...) | ||||
| 	return exec.Command("git", gitArgs...) | ||||
| } | ||||
|  | ||||
| func getGitConfigGeneralCmd(args string) *exec.Cmd { | ||||
| 	gitArgs := append([]string{"config"}, strings.Split(args, " ")...) | ||||
| 	return secureexec.Command("git", gitArgs...) | ||||
| 	return exec.Command("git", gitArgs...) | ||||
| } | ||||
|   | ||||
| @@ -73,10 +73,6 @@ type ICmdObj interface { | ||||
| } | ||||
|  | ||||
| type CmdObj struct { | ||||
| 	// the secureexec package will swap out the first arg with the full path to the binary, | ||||
| 	// so we store these args separately so that ToString() will output the original | ||||
| 	args []string | ||||
|  | ||||
| 	cmd *exec.Cmd | ||||
|  | ||||
| 	runner ICmdObjRunner | ||||
| @@ -121,7 +117,7 @@ func (self *CmdObj) GetCmd() *exec.Cmd { | ||||
|  | ||||
| func (self *CmdObj) ToString() string { | ||||
| 	// if a given arg contains a space, we need to wrap it in quotes | ||||
| 	quotedArgs := lo.Map(self.args, func(arg string, _ int) string { | ||||
| 	quotedArgs := lo.Map(self.cmd.Args, func(arg string, _ int) string { | ||||
| 		if strings.Contains(arg, " ") { | ||||
| 			return `"` + arg + `"` | ||||
| 		} | ||||
| @@ -132,7 +128,7 @@ func (self *CmdObj) ToString() string { | ||||
| } | ||||
|  | ||||
| func (self *CmdObj) Args() []string { | ||||
| 	return self.args | ||||
| 	return self.cmd.Args | ||||
| } | ||||
|  | ||||
| func (self *CmdObj) AddEnvVars(vars ...string) ICmdObj { | ||||
|   | ||||
| @@ -3,9 +3,9 @@ package oscommands | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| 	"github.com/mgutz/str" | ||||
| ) | ||||
|  | ||||
| @@ -27,11 +27,10 @@ type CmdObjBuilder struct { | ||||
| var _ ICmdObjBuilder = &CmdObjBuilder{} | ||||
|  | ||||
| func (self *CmdObjBuilder) New(args []string) ICmdObj { | ||||
| 	cmd := secureexec.Command(args[0], args[1:]...) | ||||
| 	cmd := exec.Command(args[0], args[1:]...) | ||||
| 	cmd.Env = os.Environ() | ||||
|  | ||||
| 	return &CmdObj{ | ||||
| 		args:   args, | ||||
| 		cmd:    cmd, | ||||
| 		runner: self.runner, | ||||
| 	} | ||||
|   | ||||
| @@ -27,7 +27,8 @@ func TestCmdObjToString(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	for _, scenario := range scenarios { | ||||
| 		cmdObj := &CmdObj{args: scenario.cmdArgs} | ||||
| 		cmd := exec.Command(scenario.cmdArgs[0], scenario.cmdArgs[1:]...) | ||||
| 		cmdObj := &CmdObj{cmd: cmd} | ||||
| 		actual := cmdObj.ToString() | ||||
| 		if actual != scenario.expected { | ||||
| 			t.Errorf("Expected %s, got %s", quote(scenario.expected), quote(actual)) | ||||
|   | ||||
| @@ -3,8 +3,6 @@ package oscommands | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| @@ -124,27 +122,7 @@ func (self *FakeCmdObjRunner) ExpectFunc(description string, fn func(cmdObj ICmd | ||||
| func (self *FakeCmdObjRunner) ExpectArgs(expectedArgs []string, output string, err error) *FakeCmdObjRunner { | ||||
| 	description := fmt.Sprintf("matches args %s", strings.Join(expectedArgs, " ")) | ||||
| 	self.ExpectFunc(description, func(cmdObj ICmdObj) bool { | ||||
| 		args := cmdObj.GetCmd().Args | ||||
|  | ||||
| 		if runtime.GOOS == "windows" { | ||||
| 			// thanks to the secureexec package, the first arg is something like | ||||
| 			// '"C:\\Program Files\\Git\\mingw64\\bin\\<command>.exe" | ||||
| 			// on windows so we'll just ensure it contains our program | ||||
| 			if !strings.Contains(args[0], expectedArgs[0]) { | ||||
| 				return false | ||||
| 			} | ||||
| 		} else { | ||||
| 			// first arg is the program name | ||||
| 			if expectedArgs[0] != args[0] { | ||||
| 				return false | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if !slices.Equal(expectedArgs[1:], args[1:]) { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 		return slices.Equal(expectedArgs, cmdObj.GetCmd().Args) | ||||
| 	}, output, err) | ||||
|  | ||||
| 	return self | ||||
| @@ -153,18 +131,7 @@ func (self *FakeCmdObjRunner) ExpectArgs(expectedArgs []string, output string, e | ||||
| func (self *FakeCmdObjRunner) ExpectGitArgs(expectedArgs []string, output string, err error) *FakeCmdObjRunner { | ||||
| 	description := fmt.Sprintf("matches git args %s", strings.Join(expectedArgs, " ")) | ||||
| 	self.ExpectFunc(description, func(cmdObj ICmdObj) bool { | ||||
| 		// first arg is 'git' on unix and something like '"C:\\Program Files\\Git\\mingw64\\bin\\git.exe" on windows so we'll just ensure it ends in either 'git' or 'git.exe' | ||||
| 		re := regexp.MustCompile(`git(\.exe)?$`) | ||||
| 		args := cmdObj.GetCmd().Args | ||||
| 		if !re.MatchString(args[0]) { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		if !slices.Equal(expectedArgs, args[1:]) { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 		return slices.Equal(expectedArgs, cmdObj.GetCmd().Args[1:]) | ||||
| 	}, output, err) | ||||
|  | ||||
| 	return self | ||||
|   | ||||
| @@ -6,7 +6,6 @@ package oscommands | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/cli/safeexec" | ||||
| 	"github.com/go-errors/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| @@ -20,13 +19,11 @@ func TestOSCommandOpenFileWindows(t *testing.T) { | ||||
| 		test     func(error) | ||||
| 	} | ||||
|  | ||||
| 	fullCmdPath, _ := safeexec.LookPath("cmd") | ||||
|  | ||||
| 	scenarios := []scenario{ | ||||
| 		{ | ||||
| 			filename: "test", | ||||
| 			runner: NewFakeRunner(t). | ||||
| 				ExpectArgs([]string{fullCmdPath, "/c", "start", "", "test"}, "", errors.New("error")), | ||||
| 				ExpectArgs([]string{"cmd", "/c", "start", "", "test"}, "", errors.New("error")), | ||||
| 			test: func(err error) { | ||||
| 				assert.Error(t, err) | ||||
| 			}, | ||||
| @@ -34,7 +31,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { | ||||
| 		{ | ||||
| 			filename: "test", | ||||
| 			runner: NewFakeRunner(t). | ||||
| 				ExpectArgs([]string{fullCmdPath, "/c", "start", "", "test"}, "", nil), | ||||
| 				ExpectArgs([]string{"cmd", "/c", "start", "", "test"}, "", nil), | ||||
| 			test: func(err error) { | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| @@ -42,7 +39,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { | ||||
| 		{ | ||||
| 			filename: "filename with spaces", | ||||
| 			runner: NewFakeRunner(t). | ||||
| 				ExpectArgs([]string{fullCmdPath, "/c", "start", "", "filename with spaces"}, "", nil), | ||||
| 				ExpectArgs([]string{"cmd", "/c", "start", "", "filename with spaces"}, "", nil), | ||||
| 			test: func(err error) { | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| @@ -50,7 +47,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { | ||||
| 		{ | ||||
| 			filename: "let's_test_with_single_quote", | ||||
| 			runner: NewFakeRunner(t). | ||||
| 				ExpectArgs([]string{fullCmdPath, "/c", "start", "", "let's_test_with_single_quote"}, "", nil), | ||||
| 				ExpectArgs([]string{"cmd", "/c", "start", "", "let's_test_with_single_quote"}, "", nil), | ||||
| 			test: func(err error) { | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
| @@ -58,7 +55,7 @@ func TestOSCommandOpenFileWindows(t *testing.T) { | ||||
| 		{ | ||||
| 			filename: "$USER.txt", | ||||
| 			runner: NewFakeRunner(t). | ||||
| 				ExpectArgs([]string{fullCmdPath, "/c", "start", "", "$USER.txt"}, "", nil), | ||||
| 				ExpectArgs([]string{"cmd", "/c", "start", "", "$USER.txt"}, "", nil), | ||||
| 			test: func(err error) { | ||||
| 				assert.NoError(t, err) | ||||
| 			}, | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| @@ -13,7 +14,6 @@ import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/style" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/components" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| 	"github.com/samber/lo" | ||||
| ) | ||||
|  | ||||
| @@ -124,7 +124,7 @@ func RunTUI() { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code -r pkg/integration/tests/%s.go", currentTest.Name())) | ||||
| 		cmd := exec.Command("sh", "-c", fmt.Sprintf("code -r pkg/integration/tests/%s.go", currentTest.Name())) | ||||
| 		if err := cmd.Run(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| @@ -140,7 +140,7 @@ func RunTUI() { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code test/results/%s", currentTest.Name())) | ||||
| 		cmd := exec.Command("sh", "-c", fmt.Sprintf("code test/results/%s", currentTest.Name())) | ||||
| 		if err := cmd.Run(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -4,10 +4,9 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
|  | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| ) | ||||
|  | ||||
| // this is for running shell commands, mostly for the sake of setting up the repo | ||||
| @@ -44,7 +43,7 @@ func (self *Shell) RunCommandExpectError(args []string) *Shell { | ||||
| } | ||||
|  | ||||
| func (self *Shell) runCommandWithOutput(args []string) (string, error) { | ||||
| 	cmd := secureexec.Command(args[0], args[1:]...) | ||||
| 	cmd := exec.Command(args[0], args[1:]...) | ||||
| 	cmd.Env = os.Environ() | ||||
| 	cmd.Dir = self.dir | ||||
|  | ||||
| @@ -61,7 +60,7 @@ func (self *Shell) RunShellCommand(cmdStr string) *Shell { | ||||
| 		shellArg = "/C" | ||||
| 	} | ||||
|  | ||||
| 	cmd := secureexec.Command(shell, shellArg, cmdStr) | ||||
| 	cmd := exec.Command(shell, shellArg, cmdStr) | ||||
| 	cmd.Env = os.Environ() | ||||
| 	cmd.Dir = self.dir | ||||
|  | ||||
|   | ||||
| @@ -6,13 +6,13 @@ package tail | ||||
| import ( | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
|  | ||||
| 	"github.com/aybabtme/humanlog" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| ) | ||||
|  | ||||
| func tailLogsForPlatform(logFilePath string, opts *humanlog.HandlerOptions) { | ||||
| 	cmd := secureexec.Command("tail", "-f", logFilePath) | ||||
| 	cmd := exec.Command("tail", "-f", logFilePath) | ||||
|  | ||||
| 	stdout, _ := cmd.StdoutPipe() | ||||
| 	if err := cmd.Start(); err != nil { | ||||
|   | ||||
| @@ -1,12 +0,0 @@ | ||||
| //go:build !windows | ||||
| // +build !windows | ||||
|  | ||||
| package secureexec | ||||
|  | ||||
| import ( | ||||
| 	"os/exec" | ||||
| ) | ||||
|  | ||||
| func Command(name string, args ...string) *exec.Cmd { | ||||
| 	return exec.Command(name, args...) | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| //go:build windows | ||||
| // +build windows | ||||
|  | ||||
| package secureexec | ||||
|  | ||||
| import ( | ||||
| 	"os/exec" | ||||
|  | ||||
| 	"github.com/cli/safeexec" | ||||
| ) | ||||
|  | ||||
| // calling exec.Command directly on a windows machine poses a security risk due to | ||||
| // the current directory being searched first before any directories in the PATH | ||||
| // variable, meaning you might clone a repo that contains a program called 'git' | ||||
| // which does something malicious when executed. | ||||
|  | ||||
| // see https://github.com/golang/go/issues/38736 for more context. We'll likely | ||||
| // be able to just throw out this code and switch to the official solution when it exists. | ||||
|  | ||||
| // I consider this a minor security concern because you're just as vulnerable if | ||||
| // you call `git status` from the command line directly but no harm in playing it | ||||
| // safe. | ||||
|  | ||||
| var pathCache = map[string]string{} | ||||
|  | ||||
| func Command(name string, args ...string) *exec.Cmd { | ||||
| 	path := getPath(name) | ||||
|  | ||||
| 	return exec.Command(path, args...) | ||||
| } | ||||
|  | ||||
| func getPath(name string) string { | ||||
| 	if path, ok := pathCache[name]; ok { | ||||
| 		return path | ||||
| 	} | ||||
|  | ||||
| 	path, err := safeexec.LookPath(name) | ||||
| 	if err != nil { | ||||
| 		pathCache[name] = name | ||||
| 		return name | ||||
| 	} | ||||
|  | ||||
| 	pathCache[name] = path | ||||
| 	return path | ||||
| } | ||||
| @@ -11,7 +11,6 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/jesseduffield/gocui" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/secureexec" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
| ) | ||||
|  | ||||
| @@ -46,7 +45,7 @@ func TestNewCmdTaskInstantStop(t *testing.T) { | ||||
| 	reader := bytes.NewBufferString("test") | ||||
| 	start := func() (*exec.Cmd, io.Reader) { | ||||
| 		// not actually starting this because it's not necessary | ||||
| 		cmd := secureexec.Command("blah blah") | ||||
| 		cmd := exec.Command("blah") | ||||
|  | ||||
| 		close(stop) | ||||
|  | ||||
| @@ -111,7 +110,7 @@ func TestNewCmdTask(t *testing.T) { | ||||
| 	reader := bytes.NewBufferString("test") | ||||
| 	start := func() (*exec.Cmd, io.Reader) { | ||||
| 		// not actually starting this because it's not necessary | ||||
| 		cmd := secureexec.Command("blah blah") | ||||
| 		cmd := exec.Command("blah") | ||||
|  | ||||
| 		return cmd, reader | ||||
| 	} | ||||
| @@ -246,7 +245,7 @@ func TestNewCmdTaskRefresh(t *testing.T) { | ||||
| 		reader := BlankLineReader{totalLinesToYield: s.totalTaskLines} | ||||
| 		start := func() (*exec.Cmd, io.Reader) { | ||||
| 			// not actually starting this because it's not necessary | ||||
| 			cmd := secureexec.Command("blah blah") | ||||
| 			cmd := exec.Command("blah") | ||||
|  | ||||
| 			return cmd, &reader | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/github.com/cli/safeexec/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/cli/safeexec/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| BSD 2-Clause License | ||||
|  | ||||
| Copyright (c) 2020, GitHub Inc. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										40
									
								
								vendor/github.com/cli/safeexec/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/cli/safeexec/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,40 +0,0 @@ | ||||
| # safeexec | ||||
|  | ||||
| A Go module that provides a safer alternative to `exec.LookPath()` on Windows. | ||||
|  | ||||
| The following, relatively common approach to running external commands has a subtle vulnerability on Windows: | ||||
| ```go | ||||
| import "os/exec" | ||||
|  | ||||
| func gitStatus() error { | ||||
|     // On Windows, this will result in `.\git.exe` or `.\git.bat` being executed | ||||
|     // if either were found in the current working directory. | ||||
|     cmd := exec.Command("git", "status") | ||||
|     return cmd.Run() | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Searching the current directory (surprising behavior) before searching folders listed in the PATH environment variable (expected behavior) seems to be intended in Go and unlikely to be changed: https://github.com/golang/go/issues/38736 | ||||
|  | ||||
| Since Go does not provide a version of [`exec.LookPath()`](https://golang.org/pkg/os/exec/#LookPath) that only searches PATH and does not search the current working directory, this module provides a `LookPath` function that works consistently across platforms. | ||||
|  | ||||
| Example use: | ||||
| ```go | ||||
| import ( | ||||
|     "os/exec" | ||||
|     "github.com/cli/safeexec" | ||||
| ) | ||||
|  | ||||
| func gitStatus() error { | ||||
|     gitBin, err := safeexec.LookPath("git") | ||||
|     if err != nil { | ||||
|         return err | ||||
|     } | ||||
|     cmd := exec.Command(gitBin, "status") | ||||
|     return cmd.Run() | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## TODO | ||||
|  | ||||
| Ideally, this module would also provide `exec.Command()` and `exec.CommandContext()` equivalents that delegate to the patched version of `LookPath`. However, this doesn't seem possible since `LookPath` may return an error, while `exec.Command/CommandContext()` themselves do not return an error. In the standard library, the resulting `exec.Cmd` struct stores the LookPath error in a private field, but that functionality isn't available to us. | ||||
							
								
								
									
										9
									
								
								vendor/github.com/cli/safeexec/lookpath.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/cli/safeexec/lookpath.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +0,0 @@ | ||||
| // +build !windows | ||||
|  | ||||
| package safeexec | ||||
|  | ||||
| import "os/exec" | ||||
|  | ||||
| func LookPath(file string) (string, error) { | ||||
| 	return exec.LookPath(file) | ||||
| } | ||||
							
								
								
									
										120
									
								
								vendor/github.com/cli/safeexec/lookpath_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/cli/safeexec/lookpath_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,120 +0,0 @@ | ||||
| // Copyright (c) 2009 The Go Authors. All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| // modification, are permitted provided that the following conditions are | ||||
| // met: | ||||
| // | ||||
| //    * Redistributions of source code must retain the above copyright | ||||
| // notice, this list of conditions and the following disclaimer. | ||||
| //    * Redistributions in binary form must reproduce the above | ||||
| // copyright notice, this list of conditions and the following disclaimer | ||||
| // in the documentation and/or other materials provided with the | ||||
| // distribution. | ||||
| //    * Neither the name of Google Inc. nor the names of its | ||||
| // contributors may be used to endorse or promote products derived from | ||||
| // this software without specific prior written permission. | ||||
| // | ||||
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
| // Package safeexec provides alternatives for exec package functions to avoid | ||||
| // accidentally executing binaries found in the current working directory on | ||||
| // Windows. | ||||
| package safeexec | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| func chkStat(file string) error { | ||||
| 	d, err := os.Stat(file) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if d.IsDir() { | ||||
| 		return os.ErrPermission | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func hasExt(file string) bool { | ||||
| 	i := strings.LastIndex(file, ".") | ||||
| 	if i < 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	return strings.LastIndexAny(file, `:\/`) < i | ||||
| } | ||||
|  | ||||
| func findExecutable(file string, exts []string) (string, error) { | ||||
| 	if len(exts) == 0 { | ||||
| 		return file, chkStat(file) | ||||
| 	} | ||||
| 	if hasExt(file) { | ||||
| 		if chkStat(file) == nil { | ||||
| 			return file, nil | ||||
| 		} | ||||
| 	} | ||||
| 	for _, e := range exts { | ||||
| 		if f := file + e; chkStat(f) == nil { | ||||
| 			return f, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return "", os.ErrNotExist | ||||
| } | ||||
|  | ||||
| // LookPath searches for an executable named file in the | ||||
| // directories named by the PATH environment variable. | ||||
| // If file contains a slash, it is tried directly and the PATH is not consulted. | ||||
| // LookPath also uses PATHEXT environment variable to match | ||||
| // a suitable candidate. | ||||
| // The result may be an absolute path or a path relative to the current directory. | ||||
| func LookPath(file string) (string, error) { | ||||
| 	var exts []string | ||||
| 	x := os.Getenv(`PATHEXT`) | ||||
| 	if x != "" { | ||||
| 		for _, e := range strings.Split(strings.ToLower(x), `;`) { | ||||
| 			if e == "" { | ||||
| 				continue | ||||
| 			} | ||||
| 			if e[0] != '.' { | ||||
| 				e = "." + e | ||||
| 			} | ||||
| 			exts = append(exts, e) | ||||
| 		} | ||||
| 	} else { | ||||
| 		exts = []string{".com", ".exe", ".bat", ".cmd"} | ||||
| 	} | ||||
|  | ||||
| 	if strings.ContainsAny(file, `:\/`) { | ||||
| 		if f, err := findExecutable(file, exts); err == nil { | ||||
| 			return f, nil | ||||
| 		} else { | ||||
| 			return "", &exec.Error{file, err} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// https://github.com/golang/go/issues/38736 | ||||
| 	// if f, err := findExecutable(filepath.Join(".", file), exts); err == nil { | ||||
| 	// 	return f, nil | ||||
| 	// } | ||||
|  | ||||
| 	path := os.Getenv("path") | ||||
| 	for _, dir := range filepath.SplitList(path) { | ||||
| 		if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil { | ||||
| 			return f, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return "", &exec.Error{file, exec.ErrNotFound} | ||||
| } | ||||
							
								
								
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @@ -7,9 +7,6 @@ github.com/atotto/clipboard | ||||
| # github.com/aybabtme/humanlog v0.4.1 | ||||
| ## explicit; go 1.13 | ||||
| github.com/aybabtme/humanlog | ||||
| # github.com/cli/safeexec v1.0.0 | ||||
| ## explicit; go 1.15 | ||||
| github.com/cli/safeexec | ||||
| # github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 | ||||
| ## explicit | ||||
| github.com/cloudfoundry/jibber_jabber | ||||
|   | ||||
		Reference in New Issue
	
	Block a user