Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package git-lfs for openSUSE:Factory checked in at 2022-04-26 20:15:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/git-lfs (Old) and /work/SRC/openSUSE:Factory/.git-lfs.new.1538 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "git-lfs" Tue Apr 26 20:15:50 2022 rev:10 rq:972854 version:3.1.4 Changes: -------- --- /work/SRC/openSUSE:Factory/git-lfs/git-lfs.changes 2022-02-17 23:41:38.215700363 +0100 +++ /work/SRC/openSUSE:Factory/.git-lfs.new.1538/git-lfs.changes 2022-04-26 20:17:46.736761439 +0200 @@ -1,0 +2,6 @@ +Thu Apr 21 13:23:07 UTC 2022 - [email protected] + +- Update to version 3.1.4: + https://github.com/git-lfs/git-lfs/releases/tag/v3.1.4 + +------------------------------------------------------------------- Old: ---- git-lfs-3.1.2.tar.gz New: ---- git-lfs-3.1.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ git-lfs.spec ++++++ --- /var/tmp/diff_new_pack.Kpd4of/_old 2022-04-26 20:17:47.144761932 +0200 +++ /var/tmp/diff_new_pack.Kpd4of/_new 2022-04-26 20:17:47.144761932 +0200 @@ -26,12 +26,12 @@ %endif Name: git-lfs -Version: 3.1.2 +Version: 3.1.4 Release: 0 Summary: Git extension for versioning large files License: MIT Group: Development/Tools/Version Control -URL: https://git-lfs.github.com/ +URL: https://github.com/git-lfs/git-lfs Source0: https://github.com/git-lfs/git-lfs/releases/download/v%{version}/git-lfs-v%{version}.tar.gz#/%{name}-%{version}.tar.gz BuildRequires: curl BuildRequires: fdupes ++++++ git-lfs-3.1.2.tar.gz -> git-lfs-3.1.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/.github/workflows/ci.yml new/git-lfs-3.1.4/.github/workflows/ci.yml --- old/git-lfs-3.1.2/.github/workflows/ci.yml 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/.github/workflows/ci.yml 2022-04-19 22:31:26.000000000 +0200 @@ -48,7 +48,7 @@ - run: script/cibuild build-windows: name: Build on Windows - runs-on: windows-latest + runs-on: windows-2019 steps: - uses: actions/checkout@v1 - uses: actions/setup-ruby@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/.github/workflows/release.yml new/git-lfs-3.1.4/.github/workflows/release.yml --- old/git-lfs-3.1.2/.github/workflows/release.yml 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/.github/workflows/release.yml 2022-04-19 22:31:26.000000000 +0200 @@ -6,7 +6,7 @@ jobs: build-windows: name: Build Windows Assets - runs-on: windows-latest + runs-on: windows-2019 strategy: matrix: go: ['1.17.x'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/CHANGELOG.md new/git-lfs-3.1.4/CHANGELOG.md --- old/git-lfs-3.1.2/CHANGELOG.md 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/CHANGELOG.md 2022-04-19 22:31:26.000000000 +0200 @@ -1,5 +1,49 @@ # Git LFS Changelog +## 3.1.4 (19 Apr 2022) + +This release is a bugfix release to fix some problems during the build of +v3.1.3. There are otherwise no substantial changes from v3.1.3. + +### Misc + +* Use only Windows Server 2019 runners for CI in GitHub Actions #4883 (@chrisd8088) +* remove unused `Pipe[Media]Command()` functions #4942 (@chrisd8088) + +## 3.1.3 (19 Apr 2022) + +This release introduces a security fix for Windows systems, which has been +assigned CVE-2022-24826. + +On Windows, if Git LFS operates on a malicious repository with a `..exe` file as +well as a file named `git.exe`, and `git.exe` is not found in PATH, the `..exe` +program will be executed, permitting the attacker to execute arbitrary code. +Similarly, if the malicious repository contains files named `..exe` and +`cygpath.exe`, and `cygpath.exe` is not found in PATH, the `..exe` program will +be executed when certain Git LFS commands are run. + +This security problem does not affect Unix systems. This is the same issue as +CVE-2020-27955 and CVE-2021-21237, but the fix for those issue was incomplete +and certain options can still cause the problem to occur. + +This occurs because on Windows, Go includes (and prefers) the current directory +when the name of a command run does not contain a directory separator, and it +continues to search for programs even when the specified program name is empty. +This has been solved by failing if the path is empty or not found. + +We would like to extend a special thanks to the following open-source +contributors: + +* @yuske for reporting this to us responsibly + +### Bugs + +* Report errors when finding executables and revise PATH search tests (@chrisd8088) + +### Misc + +* Update Windows signing certificate SHA hash in Makefile (@chrisd8088) + ## 3.1.2 (16 Feb 2022) This is a bugfix release which fixes a bug in `git lfs install` and some issues diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_clone.go new/git-lfs-3.1.4/commands/command_clone.go --- old/git-lfs-3.1.2/commands/command_clone.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/command_clone.go 2022-04-19 22:31:26.000000000 +0200 @@ -118,8 +118,11 @@ // Use `git submodule foreach --recursive` to cascade into nested submodules // Also good to call a new instance of git-lfs rather than do things // inside this instance, since that way we get a clean env in that subrepo - cmd := subprocess.ExecCommand("git", "submodule", "foreach", "--recursive", + cmd, err := subprocess.ExecCommand("git", "submodule", "foreach", "--recursive", "git lfs pull") + if err != nil { + return err + } cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_ls_files.go new/git-lfs-3.1.4/commands/command_ls_files.go --- old/git-lfs-3.1.2/commands/command_ls_files.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/command_ls_files.go 2022-04-19 22:31:26.000000000 +0200 @@ -4,6 +4,7 @@ "os" "strings" + "github.com/git-lfs/git-lfs/v3/errors" "github.com/git-lfs/git-lfs/v3/git" "github.com/git-lfs/git-lfs/v3/lfs" "github.com/git-lfs/git-lfs/v3/tools/humanize" @@ -50,7 +51,11 @@ } else { fullref, err := git.CurrentRef() if err != nil { - ref = git.EmptyTree() + ref, err = git.EmptyTree() + if err != nil { + ExitWithError(errors.Wrap( + err, tr.Tr.Get("Could not read empty Git tree object"))) + } } else { ref = fullref.Sha } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/command_status.go new/git-lfs-3.1.4/commands/command_status.go --- old/git-lfs-3.1.2/commands/command_status.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/command_status.go 2022-04-19 22:31:26.000000000 +0200 @@ -28,8 +28,12 @@ ref, _ := git.CurrentRef() scanIndexAt := "HEAD" + var err error if ref == nil { - scanIndexAt = git.EmptyTree() + scanIndexAt, err = git.EmptyTree() + if err != nil { + ExitWithError(err) + } } scanner, err := lfs.NewPointerScanner(cfg.GitEnv(), cfg.OSEnv()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/commands.go new/git-lfs-3.1.4/commands/commands.go --- old/git-lfs-3.1.2/commands/commands.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/commands.go 2022-04-19 22:31:26.000000000 +0200 @@ -281,18 +281,6 @@ } } -func PipeMediaCommand(name string, args ...string) error { - return PipeCommand("bin/"+name, args...) -} - -func PipeCommand(name string, args ...string) error { - cmd := subprocess.ExecCommand(name, args...) - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stdout - return cmd.Run() -} - func requireStdin(msg string) { var out string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/path_windows.go new/git-lfs-3.1.4/commands/path_windows.go --- old/git-lfs-3.1.2/commands/path_windows.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/path_windows.go 2022-04-19 22:31:26.000000000 +0200 @@ -48,7 +48,10 @@ if len(winBashPrefix) < 1 { // cmd.Path is something like C:\Program Files\Git\usr\bin\pwd.exe - cmd := subprocess.ExecCommand("pwd") + cmd, err := subprocess.ExecCommand("pwd") + if err != nil { + return pattern + } winBashPrefix = strings.Replace(filepath.Dir(filepath.Dir(filepath.Dir(cmd.Path))), `\`, "/", -1) + "/" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/commands/pull.go new/git-lfs-3.1.4/commands/pull.go --- old/git-lfs-3.1.2/commands/pull.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/commands/pull.go 2022-04-19 22:31:26.000000000 +0200 @@ -147,7 +147,10 @@ if i.cmd == nil { // Fire up the update-index command - cmd := git.UpdateIndexFromStdin() + cmd, err := git.UpdateIndexFromStdin() + if err != nil { + return err + } cmd.Stdout = &i.output cmd.Stderr = &i.output stdin, err := cmd.StdinPipe() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/config/version.go new/git-lfs-3.1.4/config/version.go --- old/git-lfs-3.1.2/config/version.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/config/version.go 2022-04-19 22:31:26.000000000 +0200 @@ -13,7 +13,7 @@ ) const ( - Version = "3.1.2" + Version = "3.1.4" ) func init() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/creds/creds.go new/git-lfs-3.1.4/creds/creds.go --- old/git-lfs-3.1.2/creds/creds.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/creds/creds.go 2022-04-19 22:31:26.000000000 +0200 @@ -241,7 +241,11 @@ // 'cmd' will run the GIT_ASKPASS (or core.askpass) command prompting // for the desired valueType (`Username` or `Password`) - cmd := subprocess.ExecCommand(a.Program, a.args(fmt.Sprintf("%s for %q", valueString, u))...) + cmd, errVal := subprocess.ExecCommand(a.Program, a.args(fmt.Sprintf("%s for %q", valueString, u))...) + if errVal != nil { + tracerx.Printf("creds: failed to find GIT_ASKPASS command: %s", a.Program) + return "", errVal + } cmd.Stderr = &err cmd.Stdout = &value @@ -301,7 +305,10 @@ func (h *commandCredentialHelper) exec(subcommand string, input Creds) (Creds, error) { output := new(bytes.Buffer) - cmd := subprocess.ExecCommand("git", "credential", subcommand) + cmd, err := subprocess.ExecCommand("git", "credential", subcommand) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git credential %s`: %v", subcommand, err)) + } cmd.Stdin = bufferCreds(input) cmd.Stdout = output /* @@ -316,7 +323,7 @@ */ cmd.Stderr = os.Stderr - err := cmd.Start() + err = cmd.Start() if err == nil { err = cmd.Wait() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/debian/changelog new/git-lfs-3.1.4/debian/changelog --- old/git-lfs-3.1.2/debian/changelog 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/debian/changelog 2022-04-19 22:31:26.000000000 +0200 @@ -1,3 +1,15 @@ +git-lfs (3.1.4) stable; urgency=low + + * New upstream version + + -- brian m. carlson <[email protected]> Tue, 19 Apr 2022 14:29:00 -0000 + +git-lfs (3.1.3) stable; urgency=low + + * New upstream version + + -- brian m. carlson <[email protected]> Tue, 19 Apr 2022 14:29:00 -0000 + git-lfs (3.1.2) stable; urgency=low * New upstream version diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/git/config.go new/git-lfs-3.1.4/git/config.go --- old/git-lfs-3.1.2/git/config.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/git/config.go 2022-04-19 22:31:26.000000000 +0200 @@ -199,7 +199,10 @@ func (c *Configuration) gitConfig(args ...string) (string, error) { args = append([]string{"config", "--includes"}, args...) - cmd := subprocess.ExecCommand("git", args...) + cmd, err := subprocess.ExecCommand("git", args...) + if err != nil { + return "", err + } if len(c.GitDir) > 0 { cmd.Dir = c.GitDir } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/git/git.go new/git-lfs-3.1.4/git/git.go --- old/git-lfs-3.1.2/git/git.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/git/git.go 2022-04-19 22:31:26.000000000 +0200 @@ -148,17 +148,20 @@ return false } -func EmptyTree() string { +func EmptyTree() (string, error) { emptyTreeMutex.Lock() defer emptyTreeMutex.Unlock() if len(emptyTree) == 0 { - cmd := gitNoLFS("hash-object", "-t", "tree", "/dev/null") + cmd, err := gitNoLFS("hash-object", "-t", "tree", "/dev/null") + if err != nil { + return "", errors.New(tr.Tr.Get("failed to find `git hash-object`: %v", err)) + } cmd.Stdin = nil out, _ := cmd.Output() emptyTree = strings.TrimSpace(string(out)) } - return emptyTree + return emptyTree, nil } // Some top level information about a commit (only first line of message) @@ -198,7 +201,7 @@ } // Invoke Git with disabled LFS filters -func gitNoLFS(args ...string) *subprocess.Cmd { +func gitNoLFS(args ...string) (*subprocess.Cmd, error) { return subprocess.ExecCommand("git", gitConfigNoLFS(args...)...) } @@ -211,7 +214,7 @@ } // Invoke Git with enabled LFS filters -func git(args ...string) *subprocess.Cmd { +func git(args ...string) (*subprocess.Cmd, error) { return subprocess.ExecCommand("git", args...) } @@ -253,7 +256,10 @@ } func HashObject(r io.Reader) (string, error) { - cmd := gitNoLFS("hash-object", "--stdin") + cmd, err := gitNoLFS("hash-object", "--stdin") + if err != nil { + return "", errors.New(tr.Tr.Get("failed to find `git hash-object`: %v", err)) + } cmd.Stdin = r out, err := cmd.Output() if err != nil { @@ -381,7 +387,10 @@ } func RemoteList() ([]string, error) { - cmd := gitNoLFS("remote") + cmd, err := gitNoLFS("remote") + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git remote`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -401,7 +410,10 @@ } func RemoteURLs(push bool) (map[string][]string, error) { - cmd := gitNoLFS("remote", "-v") + cmd, err := gitNoLFS("remote", "-v") + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git remote -v`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -451,7 +463,10 @@ // Refs returns all of the local and remote branches and tags for the current // repository. Other refs (HEAD, refs/stash, git notes) are ignored. func LocalRefs() ([]*Ref, error) { - cmd := gitNoLFS("show-ref") + cmd, err := gitNoLFS("show-ref") + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git show-ref`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -500,7 +515,10 @@ args = append(args, "-m", reason) } - cmd := gitNoLFS(args...) + cmd, err := gitNoLFS(args...) + if err != nil { + return errors.New(tr.Tr.Get("failed to find `git update-ref`: %v", err)) + } cmd.Dir = wd return cmd.Run() @@ -578,7 +596,7 @@ return fmt.Sprintf("file://%s%s", slash, filepath.ToSlash(path)) } -func UpdateIndexFromStdin() *subprocess.Cmd { +func UpdateIndexFromStdin() (*subprocess.Cmd, error) { return git("update-index", "-q", "--refresh", "--stdin") } @@ -588,10 +606,13 @@ // includeRemoteBranches: true to include refs on remote branches // onlyRemote: set to non-blank to only include remote branches on a single remote func RecentBranches(since time.Time, includeRemoteBranches bool, onlyRemote string) ([]*Ref, error) { - cmd := gitNoLFS("for-each-ref", + cmd, err := gitNoLFS("for-each-ref", `--sort=-committerdate`, `--format=%(refname) %(objectname) %(committerdate:iso)`, "refs") + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git for-each-ref`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { return nil, errors.New(tr.Tr.Get("failed to call `git for-each-ref`: %v", err)) @@ -687,8 +708,11 @@ // Get summary information about a commit func GetCommitSummary(commit string) (*CommitSummary, error) { - cmd := gitNoLFS("show", "-s", + cmd, err := gitNoLFS("show", "-s", `--format=%H|%h|%P|%ai|%ci|%ae|%an|%ce|%cn|%s`, commit) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git show`: %v", err)) + } out, err := cmd.CombinedOutput() if err != nil { @@ -722,7 +746,10 @@ } func GitAndRootDirs() (string, string, error) { - cmd := gitNoLFS("rev-parse", "--git-dir", "--show-toplevel") + cmd, err := gitNoLFS("rev-parse", "--git-dir", "--show-toplevel") + if err != nil { + return "", "", errors.New(tr.Tr.Get("failed to find `git rev-parse --git-dir --show-toplevel`: %v", err)) + } buf := &bytes.Buffer{} cmd.Stderr = buf @@ -760,7 +787,10 @@ } func RootDir() (string, error) { - cmd := gitNoLFS("rev-parse", "--show-toplevel") + cmd, err := gitNoLFS("rev-parse", "--show-toplevel") + if err != nil { + return "", errors.New(tr.Tr.Get("failed to find `git rev-parse --show-toplevel`: %v", err)) + } out, err := cmd.Output() if err != nil { return "", errors.New(tr.Tr.Get("failed to call `git rev-parse --show-toplevel`: %v %v", err, string(out))) @@ -775,7 +805,12 @@ } func GitDir() (string, error) { - cmd := gitNoLFS("rev-parse", "--git-dir") + cmd, err := gitNoLFS("rev-parse", "--git-dir") + if err != nil { + // The %w format specifier is unique to fmt.Errorf(), so we + // do not pass it to tr.Tr.Get(). + return "", fmt.Errorf("%s: %w", tr.Tr.Get("failed to find `git rev-parse --git-dir`"), err) + } buf := &bytes.Buffer{} cmd.Stderr = buf out, err := cmd.Output() @@ -797,7 +832,10 @@ return GitDir() } - cmd := gitNoLFS("rev-parse", "--git-common-dir") + cmd, err := gitNoLFS("rev-parse", "--git-common-dir") + if err != nil { + return "", errors.New(tr.Tr.Get("failed to find `git rev-parse --git-common-dir`: %v", err)) + } out, err := cmd.Output() buf := &bytes.Buffer{} cmd.Stderr = buf @@ -1055,14 +1093,17 @@ // Now args cmdargs = append(cmdargs, args...) - cmd := gitNoLFS(cmdargs...) + cmd, err := gitNoLFS(cmdargs...) + if err != nil { + return errors.New(tr.Tr.Get("failed to find `git clone`: %v", err)) + } // Assign all streams direct cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin - err := cmd.Start() + err = cmd.Start() if err != nil { return errors.New(tr.Tr.Get("failed to start `git clone`: %v", err)) } @@ -1102,7 +1143,10 @@ // currently cached locally. No remote request is made to verify them. func CachedRemoteRefs(remoteName string) ([]*Ref, error) { var ret []*Ref - cmd := gitNoLFS("show-ref") + cmd, err := gitNoLFS("show-ref") + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git show-ref`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -1157,7 +1201,10 @@ // accessing the remote via git ls-remote. func RemoteRefs(remoteName string) ([]*Ref, error) { var ret []*Ref - cmd := gitNoLFS("ls-remote", "--heads", "--tags", "-q", remoteName) + cmd, err := gitNoLFS("ls-remote", "--heads", "--tags", "-q", remoteName) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git ls-remote`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -1216,8 +1263,11 @@ // the given working directory "wd", or an error if those references could not // be loaded. func AllRefsIn(wd string) ([]*Ref, error) { - cmd := gitNoLFS( + cmd, err := gitNoLFS( "for-each-ref", "--format=%(objectname)%00%(refname)") + if err != nil { + return nil, lfserrors.Wrap(err, tr.Tr.Get("failed to find `git for-each-ref`: %v", err)) + } cmd.Dir = wd outp, err := cmd.StdoutPipe() @@ -1262,12 +1312,15 @@ rootWildcard := len(safePattern) < len(pattern) && strings.ContainsRune(safePattern, '*') var ret []string - cmd := gitNoLFS( + cmd, err := gitNoLFS( "-c", "core.quotepath=false", // handle special chars in filenames "ls-files", "--cached", // include things which are staged but not committed right now "--", // no ambiguous patterns safePattern) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git ls-files`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { @@ -1321,7 +1374,10 @@ } args = append(args, "--") // no ambiguous patterns - cmd := gitNoLFS(args...) + cmd, err := gitNoLFS(args...) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find `git diff-tree`: %v", err)) + } outp, err := cmd.StdoutPipe() if err != nil { return nil, errors.New(tr.Tr.Get("failed to call `git diff`: %v", err)) @@ -1352,7 +1408,10 @@ "--", // separator in case filename ambiguous filepath, } - cmd := git(args...) + cmd, err := git(args...) + if err != nil { + return false, lfserrors.Wrap(err, tr.Tr.Get("failed to find `git status`")) + } outp, err := cmd.StdoutPipe() if err != nil { return false, lfserrors.Wrap(err, tr.Tr.Get("Failed to call `git status`")) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/git/ls_files.go new/git-lfs-3.1.4/git/ls_files.go --- old/git-lfs-3.1.2/git/ls_files.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/git/ls_files.go 2022-04-19 22:31:26.000000000 +0200 @@ -35,7 +35,10 @@ if untracked { args = append(args, "--others") } - cmd := gitNoLFS(args...) + cmd, err := gitNoLFS(args...) + if err != nil { + return nil, err + } cmd.Dir = workingDir tracerx.Printf("NewLsFiles: running in %s git %s", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/git/rev_list_scanner.go new/git-lfs-3.1.4/git/rev_list_scanner.go --- old/git-lfs-3.1.2/git/rev_list_scanner.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/git/rev_list_scanner.go 2022-04-19 22:31:26.000000000 +0200 @@ -169,7 +169,10 @@ return nil, err } - cmd := gitNoLFS(args...).Cmd + cmd, err := gitNoLFS(args...) + if err != nil { + return nil, err + } if len(opt.WorkingDir) > 0 { cmd.Dir = opt.WorkingDir } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/lfs/extension.go new/git-lfs-3.1.4/lfs/extension.go --- old/git-lfs-3.1.2/lfs/extension.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/lfs/extension.go 2022-04-19 22:31:26.000000000 +0200 @@ -76,7 +76,11 @@ arg := strings.Replace(value, "%f", request.fileName, -1) args = append(args, arg) } - cmd := subprocess.ExecCommand(name, args...) + var cmd *subprocess.Cmd + cmd, err = subprocess.ExecCommand(name, args...) + if err != nil { + return + } ec := &extCommand{cmd: cmd, result: &pipeExtResult{name: e.Name}} extcmds = append(extcmds, ec) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/certs_darwin.go new/git-lfs-3.1.4/lfshttp/certs_darwin.go --- old/git-lfs-3.1.2/lfshttp/certs_darwin.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/lfshttp/certs_darwin.go 2022-04-19 22:31:26.000000000 +0200 @@ -19,7 +19,11 @@ // either, for consistency. // find system.keychain for user-added certs (don't assume location) - cmd := subprocess.ExecCommand("/usr/bin/security", "list-keychains") + cmd, err := subprocess.ExecCommand("/usr/bin/security", "list-keychains") + if err != nil { + tracerx.Printf("Error getting command to list keychains: %v", err) + return nil + } kcout, err := cmd.Output() if err != nil { tracerx.Printf("Error listing keychains: %v", err) @@ -54,7 +58,11 @@ } func appendRootCAsFromKeychain(pool *x509.CertPool, name, keychain string) *x509.CertPool { - cmd := subprocess.ExecCommand("/usr/bin/security", "find-certificate", "-a", "-p", "-c", name, keychain) + cmd, err := subprocess.ExecCommand("/usr/bin/security", "find-certificate", "-a", "-p", "-c", name, keychain) + if err != nil { + tracerx.Printf("Error getting command to read keychain %q: %v", keychain, err) + return pool + } data, err := cmd.Output() if err != nil { tracerx.Printf("Error reading keychain %q: %v", keychain, err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/ssh.go new/git-lfs-3.1.4/lfshttp/ssh.go --- old/git-lfs-3.1.2/lfshttp/ssh.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/lfshttp/ssh.go 2022-04-19 22:31:26.000000000 +0200 @@ -80,7 +80,10 @@ } exe, args := ssh.GetLFSExeAndArgs(c.os, c.git, &e.SSHMetadata, "git-lfs-authenticate", endpointOperation(e, method), false) - cmd := subprocess.ExecCommand(exe, args...) + cmd, err := subprocess.ExecCommand(exe, args...) + if err != nil { + return res, err + } // Save stdout and stderr in separate buffers var outbuf, errbuf bytes.Buffer @@ -90,7 +93,7 @@ now := time.Now() // Execute command - err := cmd.Start() + err = cmd.Start() if err == nil { err = cmd.Wait() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/lfshttp/standalone/standalone.go new/git-lfs-3.1.4/lfshttp/standalone/standalone.go --- old/git-lfs-3.1.2/lfshttp/standalone/standalone.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/lfshttp/standalone/standalone.go 2022-04-19 22:31:26.000000000 +0200 @@ -119,7 +119,10 @@ return "", err } - cmd := subprocess.ExecCommand("git", "rev-parse", "--git-dir") + cmd, err := subprocess.ExecCommand("git", "rev-parse", "--git-dir") + if err != nil { + return "", errors.Wrap(err, tr.Tr.Get("failed to find `git rev-parse --git-dir`")) + } cmd.Cmd.Env = env out, err := cmd.Output() if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/rpm/SPECS/git-lfs.spec new/git-lfs-3.1.4/rpm/SPECS/git-lfs.spec --- old/git-lfs-3.1.2/rpm/SPECS/git-lfs.spec 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/rpm/SPECS/git-lfs.spec 2022-04-19 22:31:26.000000000 +0200 @@ -1,5 +1,5 @@ Name: git-lfs -Version: 3.1.2 +Version: 3.1.4 Release: 1%{?dist} Summary: Git extension for versioning large files diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/ssh/connection.go new/git-lfs-3.1.4/ssh/connection.go --- old/git-lfs-3.1.2/ssh/connection.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/ssh/connection.go 2022-04-19 22:31:26.000000000 +0200 @@ -34,7 +34,10 @@ func startConnection(id int, osEnv config.Environment, gitEnv config.Environment, meta *SSHMetadata, operation string) (*PktlineConnection, error) { exe, args := GetLFSExeAndArgs(osEnv, gitEnv, meta, "git-lfs-transfer", operation, true) - cmd := subprocess.ExecCommand(exe, args...) + cmd, err := subprocess.ExecCommand(exe, args...) + if err != nil { + return nil, err + } r, err := cmd.StdoutPipe() if err != nil { return nil, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess.go new/git-lfs-3.1.4/subprocess/subprocess.go --- old/git-lfs-3.1.2/subprocess/subprocess.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/subprocess/subprocess.go 2022-04-19 22:31:26.000000000 +0200 @@ -20,7 +20,10 @@ // stdout & stderr pipes, wrapped in a BufferedCmd. The stdout buffer will be // of stdoutBufSize bytes. func BufferedExec(name string, args ...string) (*BufferedCmd, error) { - cmd := ExecCommand(name, args...) + cmd, err := ExecCommand(name, args...) + if err != nil { + return nil, err + } stdout, err := cmd.StdoutPipe() if err != nil { return nil, err @@ -49,7 +52,11 @@ // SimpleExec is a small wrapper around os/exec.Command. func SimpleExec(name string, args ...string) (string, error) { - return Output(ExecCommand(name, args...)) + cmd, err := ExecCommand(name, args...) + if err != nil { + return "", err + } + return Output(cmd) } func Output(cmd *Cmd) (string, error) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess_nix.go new/git-lfs-3.1.4/subprocess/subprocess_nix.go --- old/git-lfs-3.1.2/subprocess/subprocess_nix.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/subprocess/subprocess_nix.go 2022-04-19 22:31:26.000000000 +0200 @@ -8,9 +8,13 @@ ) // ExecCommand is a small platform specific wrapper around os/exec.Command -func ExecCommand(name string, arg ...string) *Cmd { +func ExecCommand(name string, arg ...string) (*Cmd, error) { cmd := exec.Command(name, arg...) - cmd.Path, _ = LookPath(name) + var err error + cmd.Path, err = LookPath(name) + if err != nil { + return nil, err + } cmd.Env = fetchEnvironment() - return newCmd(cmd) + return newCmd(cmd), nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/subprocess/subprocess_windows.go new/git-lfs-3.1.4/subprocess/subprocess_windows.go --- old/git-lfs-3.1.2/subprocess/subprocess_windows.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/subprocess/subprocess_windows.go 2022-04-19 22:31:26.000000000 +0200 @@ -9,10 +9,14 @@ ) // ExecCommand is a small platform specific wrapper around os/exec.Command -func ExecCommand(name string, arg ...string) *Cmd { +func ExecCommand(name string, arg ...string) (*Cmd, error) { cmd := exec.Command(name, arg...) - cmd.Path, _ = LookPath(name) + var err error + cmd.Path, err = LookPath(name) + if err != nil { + return nil, err + } cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} cmd.Env = fetchEnvironment() - return newCmd(cmd) + return newCmd(cmd), nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/t/Makefile new/git-lfs-3.1.4/t/Makefile --- old/git-lfs-3.1.2/t/Makefile 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/t/Makefile 2022-04-19 22:31:26.000000000 +0200 @@ -13,6 +13,7 @@ TEST_CMDS += ../bin/lfs-askpass$X TEST_CMDS += ../bin/lfs-ssh-echo$X TEST_CMDS += ../bin/lfs-ssh-proxy-test$X +TEST_CMDS += ../bin/lfstest-badpathcheck$X TEST_CMDS += ../bin/lfstest-count-tests$X TEST_CMDS += ../bin/lfstest-customadapter$X TEST_CMDS += ../bin/lfstest-gitserver$X diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/t/cmd/lfstest-badpathcheck.go new/git-lfs-3.1.4/t/cmd/lfstest-badpathcheck.go --- old/git-lfs-3.1.2/t/cmd/lfstest-badpathcheck.go 1970-01-01 01:00:00.000000000 +0100 +++ new/git-lfs-3.1.4/t/cmd/lfstest-badpathcheck.go 2022-04-19 22:31:26.000000000 +0200 @@ -0,0 +1,19 @@ +//go:build testtools +// +build testtools + +package main + +import ( + "fmt" + "os" +) + +func main() { + fmt.Println("exploit") + fmt.Fprintln(os.Stderr, "exploit") + + f, err := os.Create("exploit") + if err != nil { + f.Close() + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/t/t-credentials-no-prompt.sh new/git-lfs-3.1.4/t/t-credentials-no-prompt.sh --- old/git-lfs-3.1.2/t/t-credentials-no-prompt.sh 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/t/t-credentials-no-prompt.sh 2022-04-19 22:31:26.000000000 +0200 @@ -45,8 +45,7 @@ git config "credential.helper" "" GIT_TERMINAL_PROMPT=0 GIT_ASKPASS="lfs-askpass-2" SSH_ASKPASS="dont-call-me" GIT_TRACE=1 git push origin main 2>&1 | tee push.log - grep "filling with GIT_ASKPASS" push.log # attempt askpass - grep 'credential fill error: exec: "lfs-askpass-2"' push.log # askpass fails + grep "failed to find GIT_ASKPASS command" push.log # attempt askpass grep "creds: git credential fill" push.log # attempt git credential ) end_test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/t/t-path.sh new/git-lfs-3.1.4/t/t-path.sh --- old/git-lfs-3.1.2/t/t-path.sh 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/t/t-path.sh 2022-04-19 22:31:26.000000000 +0200 @@ -9,16 +9,18 @@ reponame="$(basename "$0" ".sh")" git init "$reponame" cd "$reponame" - export PATH="$(echo "$PATH" | sed -e "s/:.:/:/g" -e "s/::/:/g")" - printf "#!/bin/sh\necho exploit >&2\n" > git - chmod +x git || true - printf "echo exploit 1>&2\n" > git.bat - - # This needs to succeed. If it fails, that could be because our malicious - # "git" is broken but got invoked anyway. - git lfs env > output.log 2>&1 - ! grep -q 'exploit' output.log + cp "$BINPATH/lfstest-badpathcheck$X" "git$X" + + # This should always succeed, even if git-lfs is incorrectly searching for + # executables in the current directory first, because the "git-lfs env" + # command ignores all errors when it runs "git config". So we should always + # pass this step and then, if our malicious Git was executed, detect + # its output below. If this command does fail, something else is wrong. + PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1 + + grep "exploit" output.log && false + [ ! -f exploit ] ) end_test @@ -30,32 +32,156 @@ setup_remote_repo "$reponame" clone_repo "$reponame" credentials-1 - export PATH="$(echo "$PATH" | sed -e "s/:.:/:/g" -e "s/::/:/g")" - - printf "#!/bin/sh\necho exploit >&2\ntouch exploit\n" > git - chmod +x git || true - printf "echo exploit 1>&2\r\necho >exploit" > git.bat git lfs track "*.dat" printf abc > z.dat git add z.dat git add .gitattributes - git add git git.bat - git commit -m "Add files" + GITPATH="$(dirname "$(command -v git)")" + + # We add our malicious Git to the index and then remove it from the + # work tree so it is not found early, before we perform our key test. + # Specifically, our "git push" below will run git-lfs, which then runs + # "git credential", so if we are looking for Git in the current directory + # first when running a credential helper, we will fail at that point + # because our malicious Git will be found first. + # + # We prefer to check for this behavior during our "git-lfs pull" further + # below when we are populating LFS objects into a clone of this repo + # (which contains the malicious Git), so for now we remove the malicious + # Git as soon as possible. + cp "$BINPATH/lfstest-badpathcheck$X" "git$X" + PATH="$BINPATH:$GITPATH" "$GITPATH/git$X" add "git$X" + rm "git$X" + + git commit -m "Add files" git push origin HEAD cd .. unset GIT_ASKPASS SSH_ASKPASS - # This needs to succeed. If it fails, that could be because our malicious - # "git" is broken but got invoked anyway. - GIT_LFS_SKIP_SMUDGE=1 clone_repo "$reponame" credentials-2 + # When we call "git clone" below, it will run git-lfs as a smudge filter + # during the post-clone checkout phase, and specifically will run git-lfs + # in the newly cloned repository directory which contains a copy of our + # malicious Git. So, if we are looking for Git in the current directory + # first in most cases (and not just when running a credential helper), + # then when git-lfs runs "git config" we will fail at that point because + # our malicious Git will be found first. This occurs even if we specify + # GIT_LFS_SKIP_SMUDGE=1 because git-lfs will still run "git config". + # + # We could ignore errors from clone_repo() and then search for the output + # of our malicious Git in the t-path-credentials-2 directory; however, + # this may be somewhat fragile as clone_repo() performs other steps such + # as changing the current working directory to the new repo clone and + # attempting to run "git config" there. + # + # Instead, since our key check of "git-lfs pull" below will also detect + # the general failure case where we are looking for Git in the current + # directory first when running most commands, we temporarily uninstall + # Git LFS so no smudge filter will execute when "git clone" checks out the + # repository. + # + # We also remove any "exploit" file potentially created by our malicious + # Git in case it was run anywhere in clone_repo(), which may happen if + # PATH contains the "." directory already. Note that we reset PATH + # to contain only the necessary directories in our key "git-lfs pull" + # check below. + git lfs uninstall + clone_repo "$reponame" t-path-credentials-2 + rm -f exploit + pushd .. + git lfs install + popd + + # As noted, if we are looking for Git in the current directory first + # only when running a credential helper, then when this runs + # "git credential", it will find our malicious Git in the current directory + # and execute it. + # + # If we are looking for Git in the current directory first when running + # most commands (and not just when running a credential helper), then this + # will also find our malicious Git. However, in this case it will find it + # earlier when we try to run "git config" rather than later when we try + # to run "git credential". + # + # We use a pipeline with "tee" here so as to avoid an early failure in the + # case that our "git-lfs pull" command executes our malicious Git. + # Unlike "git-lfs env" in the other tests, "git-lfs pull" will halt when + # it does not receive the normal output from Git. This in turn halts + # our test due to our use of the "set -e" option, unless we terminate a + # pipeline with successful command like "tee". + PATH="$BINPATH:$GITPATH" PATHEXT="$X" "git-lfs$X" pull 2>&1 | tee output.log + + grep "exploit" output.log && false + [ ! -f exploit ] +) +end_test + +begin_test "does not look in current directory for wrong binary using PATHEXT" +( + set -e + + # Windows is the only platform where Go searches for executable files + # by appending file extensions from PATHEXT. + [ "$IS_WINDOWS" -eq 0 ] && exit 0 + + reponame="$(basename "$0" ".sh")-notfound" + git init "$reponame" + cd "$reponame" + + # Go on Windows always looks in the current directory first when creating + # a command handler, so we need a dummy git.exe for it to find there since + # we will restrict PATH to exclude the real Git when we run "git-lfs env" + # below. If our git-lfs incorrectly proceeds to run the command handler + # despite not finding Git in PATH either, Go may then search for a file + # named "." with any path extension from PATHEXT and execute that file + # instead, so we create a malicious file named "..exe" to check this case. + touch "git$X" + cp "$BINPATH/lfstest-badpathcheck$X" ".$X" + + # This should always succeed, even if git-lfs is incorrectly searching for + # executables in the current directory first, because the "git-lfs env" + # command ignores all errors when it runs "git config". So we should always + # pass this step and then, if our malicious program was executed, detect + # its output below. If this command does fail, something else is wrong. + PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1 + + grep "exploit" output.log && false + [ ! -f exploit ] +) +end_test + +begin_test "does not look in current directory for wrong binary using PATHEXT" +( + set -e + + # Windows is the only platform where Go searches for executable files + # by appending file extensions from PATHEXT. + [ "$IS_WINDOWS" -eq 0 ] && exit 0 + + reponame="$(basename "$0" ".sh")-notfound" + git init "$reponame" + cd "$reponame" - git lfs pull | tee output.log + # Go on Windows always looks in the current directory first when creating + # a command handler, so we need a dummy git.exe for it to find there since + # we will restrict PATH to exclude the real Git when we run "git-lfs env" + # below. If our git-lfs incorrectly proceeds to run the command handler + # despite not finding Git in PATH either, Go may then search for a file + # named "." with any path extension from PATHEXT and execute that file + # instead, so we create a malicious file named "..exe" to check this case. + touch "git$X" + cp "$BINPATH/lfstest-badpathcheck$X" ".$X" + + # This should always succeed, even if git-lfs is incorrectly searching for + # executables in the current directory first, because the "git-lfs env" + # command ignores all errors when it runs "git config". So we should always + # pass this step and then, if our malicious program was executed, detect + # its output below. If this command does fail, something else is wrong. + PATH="$BINPATH" PATHEXT="$X" "git-lfs$X" env >output.log 2>&1 - ! grep -q 'exploit' output.log - [ ! -f ../exploit ] + grep "exploit" output.log && false [ ! -f exploit ] ) end_test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/t/testenv.sh new/git-lfs-3.1.4/t/testenv.sh --- old/git-lfs-3.1.2/t/testenv.sh 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/t/testenv.sh 2022-04-19 22:31:26.000000000 +0200 @@ -6,12 +6,14 @@ UNAME=$(uname -s) IS_WINDOWS=0 IS_MAC=0 +X="" SHASUM="shasum -a 256" PATH_SEPARATOR="/" if [[ $UNAME == MINGW* || $UNAME == MSYS* || $UNAME == CYGWIN* ]] then IS_WINDOWS=1 + X=".exe" # Windows might be MSYS2 which does not have the shasum Perl wrapper # script by default, so use sha256sum directly. MacOS on the other hand diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/tools/cygwin_windows.go new/git-lfs-3.1.4/tools/cygwin_windows.go --- old/git-lfs-3.1.2/tools/cygwin_windows.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/tools/cygwin_windows.go 2022-04-19 22:31:26.000000000 +0200 @@ -38,7 +38,10 @@ return cygwinState.Enabled() } - cmd := subprocess.ExecCommand("uname") + cmd, err := subprocess.ExecCommand("uname") + if err != nil { + return false + } out, err := cmd.Output() if err != nil { return false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/tools/os_tools.go new/git-lfs-3.1.4/tools/os_tools.go --- old/git-lfs-3.1.2/tools/os_tools.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/tools/os_tools.go 2022-04-19 22:31:26.000000000 +0200 @@ -28,7 +28,12 @@ } func translateCygwinPath(path string) (string, error) { - cmd := subprocess.ExecCommand("cygpath", "-w", path) + cmd, err := subprocess.ExecCommand("cygpath", "-w", path) + if err != nil { + // If cygpath doesn't exist, that's okay: just return the paths + // as we got it. + return path, nil + } // cygpath uses ISO-8850-1 as the default encoding if the locale is not // set, resulting in breakage, since we want a UTF-8 path. env := make([]string, 0, len(cmd.Env)+1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/tq/custom.go new/git-lfs-3.1.4/tq/custom.go --- old/git-lfs-3.1.2/tq/custom.go 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/tq/custom.go 2022-04-19 22:31:26.000000000 +0200 @@ -125,7 +125,10 @@ // If concurrent = false we have already dialled back workers to 1 a.Trace("xfer: starting up custom transfer process %q for worker %d", a.name, workerNum) cmdName, cmdArgs := subprocess.FormatForShell(subprocess.ShellQuoteSingle(a.path), a.args) - cmd := subprocess.ExecCommand(cmdName, cmdArgs...) + cmd, err := subprocess.ExecCommand(cmdName, cmdArgs...) + if err != nil { + return nil, errors.New(tr.Tr.Get("failed to find custom transfer command %q remote: %v", a.path, err)) + } outp, err := cmd.StdoutPipe() if err != nil { return nil, errors.New(tr.Tr.Get("failed to get stdout for custom transfer command %q remote: %v", a.path, err)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/git-lfs-3.1.2/versioninfo.json new/git-lfs-3.1.4/versioninfo.json --- old/git-lfs-3.1.2/versioninfo.json 2022-02-16 18:49:01.000000000 +0100 +++ new/git-lfs-3.1.4/versioninfo.json 2022-04-19 22:31:26.000000000 +0200 @@ -4,7 +4,7 @@ "FileVersion": { "Major": 3, "Minor": 1, - "Patch": 2, + "Patch": 4, "Build": 0 } }, @@ -13,7 +13,7 @@ "FileDescription": "Git LFS", "LegalCopyright": "GitHub, Inc. and Git LFS contributors", "ProductName": "Git Large File Storage (LFS)", - "ProductVersion": "3.1.2" + "ProductVersion": "3.1.4" }, "IconPath": "script/windows-installer/git-lfs-logo.ico" }
