From c8660364d98536fa4c0db45b743331541dc8ee2a Mon Sep 17 00:00:00 2001 From: Artem Lytkin <146867384+4RH1T3CT0R7@users.noreply.github.com> Date: Tue, 25 Aug 2026 15:02:31 +0300 Subject: [PATCH] fix(asymkey): do not verify OpenPGP signatures with an SSH instance key, require git 2.18 (#39073) With SIGNING_FORMAT = ssh the OpenPGP verification path builds its GPGSettings from the instance signing key but leaves the format empty, so it runs `gpg -a --export` on an SSH public key path. Depending on the local gpg setup that either exports nothing, so an OpenPGP signed commit reports gpg.error.generate_hash instead of a missing key, or it fails outright and logs an export error for every such commit. Both guards are needed. The first covers SIGNING_KEY set to a path with SIGNING_FORMAT=ssh; the second covers the shipped default SIGNING_KEY=default, where the format comes from git's own gpg.format and never gets reconciled with the hardcoded "openpgp". Drop either one and a working config goes back to broken. Also raise minimum git version to 2.18 which was already required before this change. Fixes: https://github.com/go-gitea/gitea/issues/37452 Co-authored-by: wxiaoguang Co-authored-by: silverwind --- modules/git/config.go | 20 +++--- modules/git/git.go | 2 +- modules/git/gpg.go | 114 +++++++++++++------------------- modules/git/gpg_test.go | 33 +++++++++ modules/git/key.go | 22 ++---- modules/git/repo_commitgraph.go | 7 +- modules/git/utils.go | 28 -------- services/asymkey/commit.go | 105 +++++++++++++++-------------- services/asymkey/commit_test.go | 34 ++++++++++ 9 files changed, 184 insertions(+), 181 deletions(-) create mode 100644 modules/git/gpg_test.go diff --git a/modules/git/config.go b/modules/git/config.go index 6e07aea0c07..648c708baab 100644 --- a/modules/git/config.go +++ b/modules/git/config.go @@ -42,16 +42,16 @@ func syncGitConfig(ctx context.Context) (err error) { return err } - if DefaultFeatures().CheckVersionAtLeast("2.18") { - if err := configSet(ctx, "core.commitGraph", "true"); err != nil { - return err - } - if err := configSet(ctx, "gc.writeCommitGraph", "true"); err != nil { - return err - } - if err := configSet(ctx, "fetch.writeCommitGraph", "true"); err != nil { - return err - } + if err := configSet(ctx, "core.commitGraph", "true"); err != nil { + return err + } + + if err := configSet(ctx, "gc.writeCommitGraph", "true"); err != nil { + return err + } + + if err := configSet(ctx, "fetch.writeCommitGraph", "true"); err != nil { + return err } if DefaultFeatures().SupportProcReceive { diff --git a/modules/git/git.go b/modules/git/git.go index ec25c8c504d..193e3837897 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -24,7 +24,7 @@ import ( "github.com/hashicorp/go-version" ) -const RequiredVersion = "2.13.0" // the minimum Git version required +const RequiredVersion = "2.18.0" // the minimum Git version required type Features struct { gitVersion *version.Version diff --git a/modules/git/gpg.go b/modules/git/gpg.go index 68974b93674..480c1db430a 100644 --- a/modules/git/gpg.go +++ b/modules/git/gpg.go @@ -9,94 +9,70 @@ import ( "fmt" "os" "strings" - "sync" + "sync/atomic" "gitea.dev/modules/git/gitcmd" "gitea.dev/modules/process" + "gitea.dev/modules/util" ) -// GPGSettings represents the default GPG settings for this repository -type GPGSettings struct { - Sign bool - KeyID string - Email string - Name string - PublicKeyContent string - Format string +type CommitSignSettings struct { + Sign bool + Email string + Name string + + Format string // default to GPG + KeyID string // GPG key id or SSH key file + + cachedPublicKeyContent atomic.Pointer[string] } -// LoadPublicKeyContent will load the key from gpg -func (gpgSettings *GPGSettings) LoadPublicKeyContent() error { - if gpgSettings.PublicKeyContent != "" { - return nil +func (css *CommitSignSettings) PublicKeyContent() (string, error) { + cached := css.cachedPublicKeyContent.Load() + if cached != nil { + return *cached, nil } - if gpgSettings.Format == SigningKeyFormatSSH { - content, err := os.ReadFile(gpgSettings.KeyID) + if css.Format == SigningKeyFormatSSH { + content, err := os.ReadFile(css.KeyID) if err != nil { - return fmt.Errorf("unable to read SSH public key file: %s, %w", gpgSettings.KeyID, err) + return "", fmt.Errorf("unable to read SSH public key file: %s, %w", css.KeyID, err) } - gpgSettings.PublicKeyContent = string(content) - return nil + s := string(content) + css.cachedPublicKeyContent.Store(&s) + return s, nil } - content, stderr, err := process.GetManager().Exec( - "gpg -a --export", - "gpg", "-a", "--export", gpgSettings.KeyID) + + content, stderr, err := process.GetManager().Exec("gpg -a --export", "gpg", "-a", "--export", css.KeyID) if err != nil { - return fmt.Errorf("unable to get default signing key: %s, %s, %w", gpgSettings.KeyID, stderr, err) + return "", fmt.Errorf("unable to get default signing key: %s, %s, %w", css.KeyID, stderr, err) } - gpgSettings.PublicKeyContent = content - return nil + css.cachedPublicKeyContent.Store(&content) + return content, nil } -var ( - loadPublicGPGKeyMutex sync.RWMutex - globalGPGSettings *GPGSettings -) +var GlobalCommitSignSettings = util.OnceValue[*CommitSignSettings]{ + Func: func() *CommitSignSettings { + ctx := context.Background() + css := &CommitSignSettings{} -// GetDefaultPublicGPGKey will return and cache the default public GPG settings -func GetDefaultPublicGPGKey(ctx context.Context, forceUpdate bool) (*GPGSettings, error) { - if !forceUpdate { - loadPublicGPGKeyMutex.RLock() - if globalGPGSettings != nil { - defer loadPublicGPGKeyMutex.RUnlock() - return globalGPGSettings, nil - } - loadPublicGPGKeyMutex.RUnlock() - } + // all errors are ignored because the keys might not exist + // "--type=bool" resolves a valueless "commit.gpgsign" to true + value, _, _ := gitcmd.NewCommand("config", "--global", "--default", "false", "--type=bool", "--get", "commit.gpgsign").RunStdString(ctx) + css.Sign = strings.TrimSpace(value) == "true" - loadPublicGPGKeyMutex.Lock() - defer loadPublicGPGKeyMutex.Unlock() + signingKey, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.signingkey").RunStdString(ctx) + css.KeyID = strings.TrimSpace(signingKey) + css.Sign = css.Sign && css.KeyID != "" - if globalGPGSettings != nil && !forceUpdate { - return globalGPGSettings, nil - } + format, _, _ := gitcmd.NewCommand("config", "--global", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(ctx) + css.Format = strings.TrimSpace(format) - globalGPGSettings = &GPGSettings{ - Sign: true, - } + defaultEmail, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.email").RunStdString(ctx) + css.Email = strings.TrimSpace(defaultEmail) - value, _, _ := gitcmd.NewCommand("config", "--global", "--get", "commit.gpgsign").RunStdString(ctx) - sign, valid := ParseBool(strings.TrimSpace(value)) - if !sign || !valid { - globalGPGSettings.Sign = false - return globalGPGSettings, nil - } - - signingKey, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.signingkey").RunStdString(ctx) - globalGPGSettings.KeyID = strings.TrimSpace(signingKey) - - format, _, _ := gitcmd.NewCommand("config", "--global", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(ctx) - globalGPGSettings.Format = strings.TrimSpace(format) - - defaultEmail, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.email").RunStdString(ctx) - globalGPGSettings.Email = strings.TrimSpace(defaultEmail) - - defaultName, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.name").RunStdString(ctx) - globalGPGSettings.Name = strings.TrimSpace(defaultName) - - if err := globalGPGSettings.LoadPublicKeyContent(); err != nil { - return nil, err - } - return globalGPGSettings, nil + defaultName, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.name").RunStdString(ctx) + css.Name = strings.TrimSpace(defaultName) + return css + }, } diff --git a/modules/git/gpg_test.go b/modules/git/gpg_test.go new file mode 100644 index 00000000000..eca9df8a6f2 --- /dev/null +++ b/modules/git/gpg_test.go @@ -0,0 +1,33 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "os" + "path/filepath" + "testing" + + "gitea.dev/modules/setting" + "gitea.dev/modules/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGlobalCommitSignSettings(t *testing.T) { + defer test.MockVariableValue(&setting.Git.HomePath)() + defer GlobalCommitSignSettings.Reset() + + signWithGitConfig := func(gitConfig string) bool { + setting.Git.HomePath = t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(setting.Git.HomePath, ".gitconfig"), []byte(gitConfig), 0o600)) + GlobalCommitSignSettings.Reset() + return GlobalCommitSignSettings.Value().Sign + } + + assert.False(t, signWithGitConfig("[user]\n\tsigningkey = KEY\n"), "must not sign when commit.gpgsign is unset") + assert.True(t, signWithGitConfig("[user]\n\tsigningkey = KEY\n[commit]\n\tgpgsign = true\n")) + assert.True(t, signWithGitConfig("[user]\n\tsigningkey = KEY\n[commit]\n\tgpgsign\n"), "git reads a valueless commit.gpgsign as true") + assert.False(t, signWithGitConfig("[user]\n\tsigningkey = KEY\n[commit]\n\tgpgsign = nonsense\n"), "must not sign when git cannot parse commit.gpgsign") +} diff --git a/modules/git/key.go b/modules/git/key.go index d18254f3110..b8cf33cd4df 100644 --- a/modules/git/key.go +++ b/modules/git/key.go @@ -5,9 +5,7 @@ package git import ( "context" - "strings" - "gitea.dev/modules/git/gitcmd" "gitea.dev/modules/setting" ) @@ -38,24 +36,12 @@ func GetSigningKey(ctx context.Context) (*SigningKey, *Signature) { } if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" { - // Can ignore the error here as it means that commit.gpgsign is not set - value, _, _ := gitcmd.NewCommand("config", "--global", "--get", "commit.gpgsign").RunStdString(ctx) - sign, valid := ParseBool(strings.TrimSpace(value)) - if !sign || !valid { + commitSignSettings := GlobalCommitSignSettings.Value() + if !commitSignSettings.Sign { return nil, nil } - - format, _, _ := gitcmd.NewCommand("config", "--global", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(ctx) - signingKey, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.signingkey").RunStdString(ctx) - signingName, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.name").RunStdString(ctx) - signingEmail, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.email").RunStdString(ctx) - - if strings.TrimSpace(signingKey) == "" { - return nil, nil - } - - sigKey := &SigningKey{KeyID: strings.TrimSpace(signingKey), Format: strings.TrimSpace(format)} - sig := &Signature{Name: strings.TrimSpace(signingName), Email: strings.TrimSpace(signingEmail)} + sigKey := &SigningKey{KeyID: commitSignSettings.KeyID, Format: commitSignSettings.Format} + sig := &Signature{Name: commitSignSettings.Name, Email: commitSignSettings.Email} return sigKey, sig } diff --git a/modules/git/repo_commitgraph.go b/modules/git/repo_commitgraph.go index e03cc60213a..fc7b8e53b60 100644 --- a/modules/git/repo_commitgraph.go +++ b/modules/git/repo_commitgraph.go @@ -11,12 +11,9 @@ import ( ) // WriteCommitGraph write commit graph to speed up repo access -// this requires git v2.18 to be installed func WriteCommitGraph(ctx context.Context, repo RepositoryFacade) error { - if DefaultFeatures().CheckVersionAtLeast("2.18") { - if _, _, err := gitcmd.NewCommand("commit-graph", "write").WithRepo(repo).RunStdString(ctx); err != nil { - return fmt.Errorf("unable to write commit-graph for '%s' : %w", repo.GitRepoLocation(), err) - } + if _, _, err := gitcmd.NewCommand("commit-graph", "write").WithRepo(repo).RunStdString(ctx); err != nil { + return fmt.Errorf("unable to write commit-graph for '%s' : %w", repo.GitRepoLocation(), err) } return nil } diff --git a/modules/git/utils.go b/modules/git/utils.go index 848af0b9e70..34b3d1f1787 100644 --- a/modules/git/utils.go +++ b/modules/git/utils.go @@ -6,7 +6,6 @@ package git import ( "crypto/sha1" "encoding/hex" - "strconv" "strings" "sync" @@ -40,33 +39,6 @@ func (oc *ObjectCache[T]) Get(id string) (T, bool) { return obj, has } -// ParseBool returns the boolean value represented by the string as per git's git_config_bool -// true will be returned for the result if the string is empty, but valid will be false. -// "true", "yes", "on" are all true, true -// "false", "no", "off" are all false, true -// 0 is false, true -// Any other integer is true, true -// Anything else will return false, false -func ParseBool(value string) (result, valid bool) { - // Empty strings are true but invalid - if len(value) == 0 { - return true, false - } - // These are the git expected true and false values - if strings.EqualFold(value, "true") || strings.EqualFold(value, "yes") || strings.EqualFold(value, "on") { - return true, true - } - if strings.EqualFold(value, "false") || strings.EqualFold(value, "no") || strings.EqualFold(value, "off") { - return false, true - } - // Try a number - intValue, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return false, false - } - return intValue != 0, true -} - func HashFilePathForWebUI(s string) string { h := sha1.New() _, _ = h.Write([]byte(s)) diff --git a/services/asymkey/commit.go b/services/asymkey/commit.go index c10fe9d6983..ef1a910155f 100644 --- a/services/asymkey/commit.go +++ b/services/asymkey/commit.go @@ -17,6 +17,7 @@ import ( "gitea.dev/modules/git" "gitea.dev/modules/log" "gitea.dev/modules/setting" + "gitea.dev/modules/util" "github.com/42wim/sshsig" "github.com/ProtonMail/go-crypto/openpgp/packet" @@ -61,6 +62,31 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi return parseCommitWithGPGSignature(ctx, c, committer) } +func getInstanceCommitSignSettings(fmt string) *git.CommitSignSettings { + settingFmt := util.IfZero(setting.Repository.Signing.SigningFormat, git.SigningKeyFormatOpenPGP) + if settingFmt != fmt { + return nil + } + if slices.Contains([]string{"", "default", "none"}, setting.Repository.Signing.SigningKey) { + return nil + } + return &git.CommitSignSettings{ + Sign: true, + Name: setting.Repository.Signing.SigningName, + Email: setting.Repository.Signing.SigningEmail, + Format: fmt, + KeyID: setting.Repository.Signing.SigningKey, + } +} + +func getGitGlobalCommitSignSettings(fmt string) *git.CommitSignSettings { + css := git.GlobalCommitSignSettings.Value() + if css.Format != fmt || !css.Sign { + return nil + } + return css +} + func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification { // Parsing signature sig, err := asymkey_model.ExtractSignature(c.Signature.Signature) @@ -143,37 +169,20 @@ func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer * } } - if setting.Repository.Signing.SigningKey != "" && setting.Repository.Signing.SigningKey != "default" && setting.Repository.Signing.SigningKey != "none" { - // OK we should try the default key - gpgSettings := git.GPGSettings{ - Sign: true, - KeyID: setting.Repository.Signing.SigningKey, - Name: setting.Repository.Signing.SigningName, - Email: setting.Repository.Signing.SigningEmail, - } - if err := gpgSettings.LoadPublicKeyContent(); err != nil { - log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err) - } else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { - if commitVerification.Reason == asymkey_model.BadSignature { - defaultReason = asymkey_model.BadSignature - } else { + if instanceSettings := getInstanceCommitSignSettings(git.SigningKeyFormatOpenPGP); instanceSettings != nil { + if commitVerification := verifyCommitSignByGPGSettings(ctx, instanceSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + if commitVerification.Reason != asymkey_model.BadSignature { return commitVerification } + defaultReason = commitVerification.Reason } } - - defaultGPGSettings, err := git.GetDefaultPublicGPGKey(ctx, false) - if err != nil { - log.Error("Error getting default public gpg key: %v", err) - } else if defaultGPGSettings == nil { - log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String()) - } else if defaultGPGSettings.Sign { - if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { - if commitVerification.Reason == asymkey_model.BadSignature { - defaultReason = asymkey_model.BadSignature - } else { + if globalSettings := getGitGlobalCommitSignSettings(git.SigningKeyFormatOpenPGP); globalSettings != nil { + if commitVerification := verifyCommitSignByGPGSettings(ctx, globalSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + if commitVerification.Reason != asymkey_model.BadSignature { return commitVerification } + defaultReason = commitVerification.Reason } } @@ -182,9 +191,7 @@ func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer * Verified: false, Warning: defaultReason != asymkey_model.NoKeyFound, Reason: defaultReason, - SigningKey: &asymkey_model.GPGKey{ - KeyID: keyID, - }, + SigningKey: &asymkey_model.GPGKey{KeyID: keyID}, } } @@ -280,17 +287,23 @@ func HashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s Verified: false, Warning: true, Reason: asymkey_model.BadSignature, + SigningKey: &asymkey_model.GPGKey{KeyID: keyID}, } } -func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *asymkey_model.CommitVerification { +func verifyCommitSignByGPGSettings(ctx context.Context, gpgSettings *git.CommitSignSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *asymkey_model.CommitVerification { // First try to find the key in the db if commitVerification := HashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil { return commitVerification } // Otherwise we have to parse the key - ekeys, err := asymkey_model.CheckArmoredGPGKeyString(gpgSettings.PublicKeyContent) + pubKeyContent, err := gpgSettings.PublicKeyContent() + if err != nil { + log.Error("gpgSettings.PublicKeyContent: %v", err) + return nil + } + ekeys, err := asymkey_model.CheckArmoredGPGKeyString(pubKeyContent) if err != nil { log.Error("Unable to get default signing key: %v", err) return &asymkey_model.CommitVerification{ @@ -342,13 +355,14 @@ func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, si Verified: false, Warning: true, Reason: asymkey_model.BadSignature, + SigningKey: &asymkey_model.GPGKey{KeyID: keyID}, } } } return nil } -func verifySSHCommitVerificationByInstanceKey(c *git.Commit, committerUser, signerUser *user_model.User, committerGitEmail, publicKeyContent string) *asymkey_model.CommitVerification { +func verifyCommitSignBySSHSettings(c *git.Commit, committerUser, signerUser *user_model.User, committerGitEmail, publicKeyContent string) *asymkey_model.CommitVerification { fingerprint, err := asymkey_model.CalcFingerprint(publicKeyContent) if err != nil { log.Error("Error calculating the fingerprint public key %q, err: %v", publicKeyContent, err) @@ -360,7 +374,7 @@ func verifySSHCommitVerificationByInstanceKey(c *git.Commit, committerUser, sign Fingerprint: fingerprint, HasUsed: true, } - return verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, sshPubKey, committerUser, signerUser, committerGitEmail) + return verifyCommitSignBySSHPublicKey(c.Signature.Signature, c.Signature.Payload, sshPubKey, committerUser, signerUser, committerGitEmail) } // parseCommitWithSSHSignature check if signature is good against keystore. @@ -382,7 +396,7 @@ func parseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUs for _, k := range keys { if k.Verified { - commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committerUser, committerUser, c.Committer.Email) + commitVerification := verifyCommitSignBySSHPublicKey(c.Signature.Signature, c.Signature.Payload, k, committerUser, committerUser, c.Committer.Email) if commitVerification != nil { return commitVerification } @@ -398,29 +412,20 @@ func parseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUs Name: setting.Repository.Signing.SigningName, Email: setting.Repository.Signing.SigningEmail, } - commitVerification := verifySSHCommitVerificationByInstanceKey(c, committerUser, signerUser, c.Committer.Email, k) + commitVerification := verifyCommitSignBySSHSettings(c, committerUser, signerUser, c.Committer.Email, k) if commitVerification != nil && commitVerification.Verified { return commitVerification } } // Try the configured instance-wide SSH public key - if setting.Repository.Signing.SigningFormat == git.SigningKeyFormatSSH && !slices.Contains([]string{"", "default", "none"}, setting.Repository.Signing.SigningKey) { - gpgSettings := git.GPGSettings{ - Sign: true, - KeyID: setting.Repository.Signing.SigningKey, - Name: setting.Repository.Signing.SigningName, - Email: setting.Repository.Signing.SigningEmail, - Format: setting.Repository.Signing.SigningFormat, - } - signerUser := &user_model.User{ - Name: gpgSettings.Name, - Email: gpgSettings.Email, - } - if err := gpgSettings.LoadPublicKeyContent(); err != nil { - log.Error("Error getting instance-wide SSH signing key %q, err: %v", gpgSettings.KeyID, err) + if instanceSettings := getInstanceCommitSignSettings(git.SigningKeyFormatSSH); instanceSettings != nil { + pubKeyContent, err := instanceSettings.PublicKeyContent() + if err != nil { + log.Error("commitSignSettings.PublicKeyContent: %v", err) } else { - commitVerification := verifySSHCommitVerificationByInstanceKey(c, committerUser, signerUser, gpgSettings.Email, gpgSettings.PublicKeyContent) + signerUser := &user_model.User{Name: instanceSettings.Name, Email: instanceSettings.Email} + commitVerification := verifyCommitSignBySSHSettings(c, committerUser, signerUser, instanceSettings.Email, pubKeyContent) if commitVerification != nil && commitVerification.Verified { return commitVerification } @@ -434,7 +439,7 @@ func parseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committerUs } } -func verifySSHCommitVerification(sig, payload string, k *asymkey_model.PublicKey, committer, signer *user_model.User, email string) *asymkey_model.CommitVerification { +func verifyCommitSignBySSHPublicKey(sig, payload string, k *asymkey_model.PublicKey, committer, signer *user_model.User, email string) *asymkey_model.CommitVerification { if err := sshsig.Verify(strings.NewReader(payload), []byte(sig), []byte(k.Content), "git"); err != nil { return nil } diff --git a/services/asymkey/commit_test.go b/services/asymkey/commit_test.go index 03eac38aa76..46e499a30ef 100644 --- a/services/asymkey/commit_test.go +++ b/services/asymkey/commit_test.go @@ -19,6 +19,40 @@ import ( "github.com/stretchr/testify/require" ) +func TestCommitSignSettings(t *testing.T) { + defer test.MockVariableValue(&setting.Repository.Signing.SigningFormat)() + defer test.MockVariableValue(&setting.Repository.Signing.SigningKey, "any-content")() + + t.Run("InstanceSettings", func(t *testing.T) { + setting.Repository.Signing.SigningFormat = "" + css := getInstanceCommitSignSettings(git.SigningKeyFormatOpenPGP) + assert.NotNil(t, css) + assert.Equal(t, git.SigningKeyFormatOpenPGP, css.Format) + css = getInstanceCommitSignSettings(git.SigningKeyFormatSSH) + assert.Nil(t, css) + + setting.Repository.Signing.SigningFormat = git.SigningKeyFormatOpenPGP + css = getInstanceCommitSignSettings(git.SigningKeyFormatOpenPGP) + assert.NotNil(t, css) + assert.Equal(t, git.SigningKeyFormatOpenPGP, css.Format) + + setting.Repository.Signing.SigningFormat = git.SigningKeyFormatSSH + css = getInstanceCommitSignSettings(git.SigningKeyFormatSSH) + assert.NotNil(t, css) + assert.Equal(t, git.SigningKeyFormatSSH, css.Format) + css = getInstanceCommitSignSettings(git.SigningKeyFormatOpenPGP) + assert.Nil(t, css) + }) + + t.Run("GitGlobalSettings", func(t *testing.T) { + css := git.GlobalCommitSignSettings.Value() + assert.False(t, css.Sign) + assert.Equal(t, git.SigningKeyFormatOpenPGP, css.Format) + css = getGitGlobalCommitSignSettings(git.SigningKeyFormatOpenPGP) + assert.Nil(t, css) + }) +} + func TestParseCommitWithSSHSignature(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase())