Skip to content

Commit c87a0a6

Browse files
wxiaoguangdelvh
authored andcommitted
Refactor git version functions and check compatibility (go-gitea#29155)
Introduce a new function checkGitVersionCompatibility, when the git version can't be used by Gitea, tell the end users to downgrade or upgrade. The refactored functions are related to make the code easier to test. And simplify the comments for "safe.directory" --------- Co-authored-by: delvh <[email protected]>
1 parent 56759a9 commit c87a0a6

File tree

2 files changed

+70
-30
lines changed

2 files changed

+70
-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 upgrade (or downgrade) 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+
}

0 commit comments

Comments
 (0)