mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-26 20:43:46 +00:00
c8660364d9
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 <wxiaoguang@gmail.com> Co-authored-by: silverwind <me@silverwind.io>
79 lines
2.4 KiB
Go
79 lines
2.4 KiB
Go
// Copyright 2015 The Gogs Authors. All rights reserved.
|
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package git
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"gitea.dev/modules/git/gitcmd"
|
|
"gitea.dev/modules/process"
|
|
"gitea.dev/modules/util"
|
|
)
|
|
|
|
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]
|
|
}
|
|
|
|
func (css *CommitSignSettings) PublicKeyContent() (string, error) {
|
|
cached := css.cachedPublicKeyContent.Load()
|
|
if cached != nil {
|
|
return *cached, nil
|
|
}
|
|
|
|
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", css.KeyID, err)
|
|
}
|
|
s := string(content)
|
|
css.cachedPublicKeyContent.Store(&s)
|
|
return s, nil
|
|
}
|
|
|
|
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", css.KeyID, stderr, err)
|
|
}
|
|
css.cachedPublicKeyContent.Store(&content)
|
|
return content, nil
|
|
}
|
|
|
|
var GlobalCommitSignSettings = util.OnceValue[*CommitSignSettings]{
|
|
Func: func() *CommitSignSettings {
|
|
ctx := context.Background()
|
|
css := &CommitSignSettings{}
|
|
|
|
// 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"
|
|
|
|
signingKey, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.signingkey").RunStdString(ctx)
|
|
css.KeyID = strings.TrimSpace(signingKey)
|
|
css.Sign = css.Sign && css.KeyID != ""
|
|
|
|
format, _, _ := gitcmd.NewCommand("config", "--global", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").RunStdString(ctx)
|
|
css.Format = strings.TrimSpace(format)
|
|
|
|
defaultEmail, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.email").RunStdString(ctx)
|
|
css.Email = strings.TrimSpace(defaultEmail)
|
|
|
|
defaultName, _, _ := gitcmd.NewCommand("config", "--global", "--get", "user.name").RunStdString(ctx)
|
|
css.Name = strings.TrimSpace(defaultName)
|
|
return css
|
|
},
|
|
}
|