diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 8a362f033bb..ef56b7bc6b7 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -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: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cb7bb864c6..1edc2a7c53a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: diff --git a/.golangci.yml b/.golangci.yml index de90dc516c1..c458277eded 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -26,4 +26,4 @@ linters-settings: max-func-lines: 0 run: - go: 1.18 + go: 1.20 diff --git a/Dockerfile b/Dockerfile index 4271aca48ae..90a69b44509 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/go.mod b/go.mod index 0a9d911eaf0..13da2bd89c0 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index eea33970637..559d12fb416 100644 --- a/go.sum +++ b/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= diff --git a/pkg/app/daemon/daemon.go b/pkg/app/daemon/daemon.go index cf10e9a1822..95fa6bc9e39 100644 --- a/pkg/app/daemon/daemon.go +++ b/pkg/app/daemon/daemon.go @@ -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] } diff --git a/pkg/app/entry_point.go b/pkg/app/entry_point.go index 3f8de0ce3c4..fc2a4c7c4d0 100644 --- a/pkg/app/entry_point.go +++ b/pkg/app/entry_point.go @@ -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 diff --git a/pkg/commands/git_config/get_key.go b/pkg/commands/git_config/get_key.go index c3156a2db69..cd5a678ef4c 100644 --- a/pkg/commands/git_config/get_key.go +++ b/pkg/commands/git_config/get_key.go @@ -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...) } diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go index d1cc23c6734..06b07cd845c 100644 --- a/pkg/commands/oscommands/cmd_obj.go +++ b/pkg/commands/oscommands/cmd_obj.go @@ -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 { diff --git a/pkg/commands/oscommands/cmd_obj_builder.go b/pkg/commands/oscommands/cmd_obj_builder.go index 40aadaf1da8..77fb7e7c964 100644 --- a/pkg/commands/oscommands/cmd_obj_builder.go +++ b/pkg/commands/oscommands/cmd_obj_builder.go @@ -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, } diff --git a/pkg/commands/oscommands/cmd_obj_test.go b/pkg/commands/oscommands/cmd_obj_test.go index c9cb92eb505..b135f1b7433 100644 --- a/pkg/commands/oscommands/cmd_obj_test.go +++ b/pkg/commands/oscommands/cmd_obj_test.go @@ -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)) diff --git a/pkg/commands/oscommands/fake_cmd_obj_runner.go b/pkg/commands/oscommands/fake_cmd_obj_runner.go index dc75228a066..3e44bef3d01 100644 --- a/pkg/commands/oscommands/fake_cmd_obj_runner.go +++ b/pkg/commands/oscommands/fake_cmd_obj_runner.go @@ -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\\.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 diff --git a/pkg/commands/oscommands/os_windows_test.go b/pkg/commands/oscommands/os_windows_test.go index acb971b59bd..cf9c1e68a52 100644 --- a/pkg/commands/oscommands/os_windows_test.go +++ b/pkg/commands/oscommands/os_windows_test.go @@ -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) }, diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index 78180cae683..47f1a2dc290 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -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 } diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go index ce98e575a9f..51fa2310b5b 100644 --- a/pkg/integration/components/shell.go +++ b/pkg/integration/components/shell.go @@ -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 diff --git a/pkg/logs/tail/logs_default.go b/pkg/logs/tail/logs_default.go index 87965a1e7c4..1b866500f9b 100644 --- a/pkg/logs/tail/logs_default.go +++ b/pkg/logs/tail/logs_default.go @@ -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 { diff --git a/pkg/secureexec/secureexec_default.go b/pkg/secureexec/secureexec_default.go deleted file mode 100644 index f6b843d4556..00000000000 --- a/pkg/secureexec/secureexec_default.go +++ /dev/null @@ -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...) -} diff --git a/pkg/secureexec/secureexec_windows.go b/pkg/secureexec/secureexec_windows.go deleted file mode 100644 index ed4339cd3b6..00000000000 --- a/pkg/secureexec/secureexec_windows.go +++ /dev/null @@ -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 -} diff --git a/pkg/tasks/tasks_test.go b/pkg/tasks/tasks_test.go index 6f2edbbf4c9..89056807fd0 100644 --- a/pkg/tasks/tasks_test.go +++ b/pkg/tasks/tasks_test.go @@ -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 } diff --git a/vendor/github.com/cli/safeexec/LICENSE b/vendor/github.com/cli/safeexec/LICENSE deleted file mode 100644 index ca498575a70..00000000000 --- a/vendor/github.com/cli/safeexec/LICENSE +++ /dev/null @@ -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. diff --git a/vendor/github.com/cli/safeexec/README.md b/vendor/github.com/cli/safeexec/README.md deleted file mode 100644 index bd73e9ad6ef..00000000000 --- a/vendor/github.com/cli/safeexec/README.md +++ /dev/null @@ -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. diff --git a/vendor/github.com/cli/safeexec/lookpath.go b/vendor/github.com/cli/safeexec/lookpath.go deleted file mode 100644 index 41b77707845..00000000000 --- a/vendor/github.com/cli/safeexec/lookpath.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows - -package safeexec - -import "os/exec" - -func LookPath(file string) (string, error) { - return exec.LookPath(file) -} diff --git a/vendor/github.com/cli/safeexec/lookpath_windows.go b/vendor/github.com/cli/safeexec/lookpath_windows.go deleted file mode 100644 index 19b3e52f78a..00000000000 --- a/vendor/github.com/cli/safeexec/lookpath_windows.go +++ /dev/null @@ -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} -} diff --git a/vendor/modules.txt b/vendor/modules.txt index f42105cd37a..d019f976a95 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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