Skip to content

Commit d0150b8

Browse files
committed
fix
1 parent ee242a0 commit d0150b8

File tree

3 files changed

+71
-30
lines changed

3 files changed

+71
-30
lines changed

modules/git/git.go

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,36 +39,37 @@ var (
3939
gitVersion *version.Version
4040
)
4141

42-
// loadGitVersion returns current Git version from shell. Internal usage only.
43-
func loadGitVersion() (*version.Version, error) {
42+
// loadGitVersion tries to get the current git version and stores it into a global variable
43+
func loadGitVersion() error {
4444
// doesn't need RWMutex because it's executed by Init()
4545
if gitVersion != nil {
46-
return gitVersion, nil
46+
return nil
4747
}
4848

4949
stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil)
5050
if runErr != nil {
51-
return nil, runErr
51+
return runErr
5252
}
5353

54-
fields := strings.Fields(stdout)
55-
if len(fields) < 3 {
56-
return nil, fmt.Errorf("invalid git version output: %s", stdout)
54+
ver, err := parseGitVersionLine(strings.TrimSpace(stdout))
55+
if err == nil {
56+
gitVersion = ver
5757
}
58+
return err
59+
}
5860

59-
var versionString string
60-
61-
// Handle special case on Windows.
62-
i := strings.Index(fields[2], "windows")
63-
if i >= 1 {
64-
versionString = fields[2][:i-1]
65-
} else {
66-
versionString = fields[2]
61+
func parseGitVersionLine(s string) (*version.Version, error) {
62+
fields := strings.Fields(s)
63+
if len(fields) < 3 {
64+
return nil, fmt.Errorf("invalid git version: %q", s)
6765
}
6866

69-
var err error
70-
gitVersion, err = version.NewVersion(versionString)
71-
return gitVersion, err
67+
// version string is like: "git version 2.29.3" or "git version 2.29.3.windows.1"
68+
versionString := fields[2]
69+
if pos := strings.Index(versionString, "windows"); pos >= 1 {
70+
versionString = versionString[:pos-1]
71+
}
72+
return version.NewVersion(versionString)
7273
}
7374

7475
// SetExecutablePath changes the path of git executable and checks the file permission and version.
@@ -83,8 +84,7 @@ func SetExecutablePath(path string) error {
8384
}
8485
GitExecutable = absPath
8586

86-
_, err = loadGitVersion()
87-
if err != nil {
87+
if err = loadGitVersion(); err != nil {
8888
return fmt.Errorf("unable to load git version: %w", err)
8989
}
9090

@@ -105,6 +105,9 @@ func SetExecutablePath(path string) error {
105105
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), RequiredVersion, moreHint)
106106
}
107107

108+
if err = checkGitVersionCompatibility(gitVersion); err != nil {
109+
return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please downgrade (or upgrade) your git", gitVersion.String(), err)
110+
}
108111
return nil
109112
}
110113

@@ -262,19 +265,18 @@ func syncGitConfig() (err error) {
262265
}
263266
}
264267

265-
// Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user
266-
// however, some docker users and samba users find it difficult to configure their systems so that Gitea's git repositories are owned by the Gitea user. (Possibly Windows Service users - but ownership in this case should really be set correctly on the filesystem.)
267-
// see issue: https://github.com/go-gitea/gitea/issues/19455
268-
// Fundamentally the problem lies with the uid-gid-mapping mechanism for filesystems in docker on windows (and to a lesser extent samba).
269-
// Docker's configuration mechanism for local filesystems provides no way of setting this mapping and although there is a mechanism for setting this uid through using cifs mounting it is complicated and essentially undocumented
270-
// Thus the owner uid/gid for files on these filesystems will be marked as root.
268+
// Due to CVE-2022-24765, git now denies access to git directories which are not owned by current user.
269+
// However, some docker users and samba users find it difficult to configure their systems correctly,
270+
// so that Gitea's git repositories are owned by the Gitea user.
271+
// (Possibly Windows Service users - but ownership in this case should really be set correctly on the filesystem.)
272+
// See issue: https://github.com/go-gitea/gitea/issues/19455
271273
// As Gitea now always use its internal git config file, and access to the git repositories is managed through Gitea,
272274
// it is now safe to set "safe.directory=*" for internal usage only.
273-
// Please note: the wildcard "*" is only supported by Git 2.30.4/2.31.3/2.32.2/2.33.3/2.34.3/2.35.3/2.36 and later
274-
// Although only supported by Git 2.30.4/2.31.3/2.32.2/2.33.3/2.34.3/2.35.3/2.36 and later - this setting is tolerated by earlier versions
275+
// Although this setting is only supported by some new git versions, it is also tolerated by earlier versions
275276
if err := configAddNonExist("safe.directory", "*"); err != nil {
276277
return err
277278
}
279+
278280
if runtime.GOOS == "windows" {
279281
if err := configSet("core.longpaths", "true"); err != nil {
280282
return err
@@ -307,8 +309,8 @@ func syncGitConfig() (err error) {
307309

308310
// CheckGitVersionAtLeast check git version is at least the constraint version
309311
func CheckGitVersionAtLeast(atLeast string) error {
310-
if _, err := loadGitVersion(); err != nil {
311-
return err
312+
if gitVersion == nil {
313+
panic("git module is not initialized") // it shouldn't happen
312314
}
313315
atLeastVersion, err := version.NewVersion(atLeast)
314316
if err != nil {
@@ -320,6 +322,21 @@ func CheckGitVersionAtLeast(atLeast string) error {
320322
return nil
321323
}
322324

325+
func checkGitVersionCompatibility(gitVer *version.Version) error {
326+
badVersions := []struct {
327+
Version *version.Version
328+
Reason string
329+
}{
330+
{version.Must(version.NewVersion("2.43.1")), "regression bug of GIT_FLUSH"},
331+
}
332+
for _, bad := range badVersions {
333+
if gitVer.Equal(bad.Version) {
334+
return errors.New(bad.Reason)
335+
}
336+
}
337+
return nil
338+
}
339+
323340
func configSet(key, value string) error {
324341
stdout, _, err := NewCommand(DefaultContext, "config", "--global", "--get").AddDynamicArguments(key).RunStdString(nil)
325342
if err != nil && !err.IsExitCode(1) {

modules/git/git_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"code.gitea.io/gitea/modules/setting"
1414
"code.gitea.io/gitea/modules/util"
1515

16+
"github.com/hashicorp/go-version"
1617
"github.com/stretchr/testify/assert"
1718
)
1819

@@ -93,3 +94,25 @@ func TestSyncConfig(t *testing.T) {
9394
assert.True(t, gitConfigContains("[sync-test]"))
9495
assert.True(t, gitConfigContains("cfg-key-a = CfgValA"))
9596
}
97+
98+
func TestParseGitVersion(t *testing.T) {
99+
v, err := parseGitVersionLine("git version 2.29.3")
100+
assert.NoError(t, err)
101+
assert.Equal(t, "2.29.3", v.String())
102+
103+
v, err = parseGitVersionLine("git version 2.29.3.windows.1")
104+
assert.NoError(t, err)
105+
assert.Equal(t, "2.29.3", v.String())
106+
107+
_, err = parseGitVersionLine("git version")
108+
assert.Error(t, err)
109+
110+
_, err = parseGitVersionLine("git version windows")
111+
assert.Error(t, err)
112+
}
113+
114+
func TestCheckGitVersionCompatibility(t *testing.T) {
115+
assert.NoError(t, checkGitVersionCompatibility(version.Must(version.NewVersion("2.43.0"))))
116+
assert.ErrorContains(t, checkGitVersionCompatibility(version.Must(version.NewVersion("2.43.1"))), "regression bug of GIT_FLUSH")
117+
assert.NoError(t, checkGitVersionCompatibility(version.Must(version.NewVersion("2.43.2"))))
118+
}

modules/git/repo_attribute.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"io"
1111
"os"
12+
"time"
1213

1314
"code.gitea.io/gitea/modules/log"
1415
)

0 commit comments

Comments
 (0)