mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-14 21:15:18 +08:00
Merge 9ab4910c37 into 7190519fb3
This commit is contained in:
commit
4fb4211e3d
@ -323,14 +323,6 @@ func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, err
|
||||
return strings.TrimSpace(commitID), nil
|
||||
}
|
||||
|
||||
// GetRepositoryDefaultPublicGPGKey returns the default public key for this commit
|
||||
func (c *Commit) GetRepositoryDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings, error) {
|
||||
if c.repo == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return c.repo.GetDefaultPublicGPGKey(forceUpdate)
|
||||
}
|
||||
|
||||
func IsStringLikelyCommitID(objFmt ObjectFormat, s string, minLength ...int) bool {
|
||||
maxLen := 64 // sha256
|
||||
if objFmt != nil {
|
||||
|
||||
102
modules/git/gpg.go
Normal file
102
modules/git/gpg.go
Normal file
@ -0,0 +1,102 @@
|
||||
// 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"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
)
|
||||
|
||||
// GPGSettings represents the default GPG settings for this repository
|
||||
type GPGSettings struct {
|
||||
Sign bool
|
||||
KeyID string
|
||||
Email string
|
||||
Name string
|
||||
PublicKeyContent string
|
||||
Format string
|
||||
}
|
||||
|
||||
// LoadPublicKeyContent will load the key from gpg
|
||||
func (gpgSettings *GPGSettings) LoadPublicKeyContent() error {
|
||||
if gpgSettings.PublicKeyContent != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if gpgSettings.Format == SigningKeyFormatSSH {
|
||||
content, err := os.ReadFile(gpgSettings.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read SSH public key file: %s, %w", gpgSettings.KeyID, err)
|
||||
}
|
||||
gpgSettings.PublicKeyContent = string(content)
|
||||
return nil
|
||||
}
|
||||
content, stderr, err := process.GetManager().Exec(
|
||||
"gpg -a --export",
|
||||
"gpg", "-a", "--export", gpgSettings.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get default signing key: %s, %s, %w", gpgSettings.KeyID, stderr, err)
|
||||
}
|
||||
gpgSettings.PublicKeyContent = content
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
loadPublicGPGKeyMutex sync.RWMutex
|
||||
globalGPGSettings *GPGSettings
|
||||
)
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
loadPublicGPGKeyMutex.Lock()
|
||||
defer loadPublicGPGKeyMutex.Unlock()
|
||||
|
||||
if globalGPGSettings != nil && !forceUpdate {
|
||||
return globalGPGSettings, nil
|
||||
}
|
||||
|
||||
globalGPGSettings = &GPGSettings{
|
||||
Sign: true,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@ -32,23 +32,23 @@ func (s *SigningKey) String() string {
|
||||
}
|
||||
|
||||
// GetSigningKey returns the KeyID and git Signature for the repo
|
||||
func GetSigningKey(ctx context.Context, repoPath string) (*SigningKey, *Signature) {
|
||||
func GetSigningKey(ctx context.Context) (*SigningKey, *Signature) {
|
||||
if setting.Repository.Signing.SigningKey == "none" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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", "--get", "commit.gpgsign").WithDir(repoPath).RunStdString(ctx)
|
||||
value, _, _ := gitcmd.NewCommand("config", "--global", "--get", "commit.gpgsign").RunStdString(ctx)
|
||||
sign, valid := ParseBool(strings.TrimSpace(value))
|
||||
if !sign || !valid {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
format, _, _ := gitcmd.NewCommand("config", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").WithDir(repoPath).RunStdString(ctx)
|
||||
signingKey, _, _ := gitcmd.NewCommand("config", "--get", "user.signingkey").WithDir(repoPath).RunStdString(ctx)
|
||||
signingName, _, _ := gitcmd.NewCommand("config", "--get", "user.name").WithDir(repoPath).RunStdString(ctx)
|
||||
signingEmail, _, _ := gitcmd.NewCommand("config", "--get", "user.email").WithDir(repoPath).RunStdString(ctx)
|
||||
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
|
||||
|
||||
@ -20,16 +20,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
)
|
||||
|
||||
// GPGSettings represents the default GPG settings for this repository
|
||||
type GPGSettings struct {
|
||||
Sign bool
|
||||
KeyID string
|
||||
Email string
|
||||
Name string
|
||||
PublicKeyContent string
|
||||
Format string
|
||||
}
|
||||
|
||||
const prettyLogFormat = `--pretty=format:%H`
|
||||
|
||||
func (repo *Repository) ShowPrettyFormatLogToList(ctx context.Context, revisionRange string) ([]*Commit, error) {
|
||||
|
||||
@ -32,7 +32,6 @@ type Repository struct {
|
||||
|
||||
gogitRepo *gogit.Repository
|
||||
gogitStorage *filesystem.Storage
|
||||
gpgSettings *GPGSettings
|
||||
|
||||
Ctx context.Context
|
||||
LastCommitCache *LastCommitCache
|
||||
|
||||
@ -23,8 +23,6 @@ type Repository struct {
|
||||
|
||||
tagCache *ObjectCache[*Tag]
|
||||
|
||||
gpgSettings *GPGSettings
|
||||
|
||||
batchInUse bool
|
||||
batch *Batch
|
||||
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
)
|
||||
|
||||
// LoadPublicKeyContent will load the key from gpg
|
||||
func (gpgSettings *GPGSettings) LoadPublicKeyContent() error {
|
||||
if gpgSettings.Format == SigningKeyFormatSSH {
|
||||
content, err := os.ReadFile(gpgSettings.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read SSH public key file: %s, %w", gpgSettings.KeyID, err)
|
||||
}
|
||||
gpgSettings.PublicKeyContent = string(content)
|
||||
return nil
|
||||
}
|
||||
content, stderr, err := process.GetManager().Exec(
|
||||
"gpg -a --export",
|
||||
"gpg", "-a", "--export", gpgSettings.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get default signing key: %s, %s, %w", gpgSettings.KeyID, stderr, err)
|
||||
}
|
||||
gpgSettings.PublicKeyContent = content
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDefaultPublicGPGKey will return and cache the default public GPG settings for this repository
|
||||
func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings, error) {
|
||||
if repo.gpgSettings != nil && !forceUpdate {
|
||||
return repo.gpgSettings, nil
|
||||
}
|
||||
|
||||
gpgSettings := &GPGSettings{
|
||||
Sign: true,
|
||||
}
|
||||
|
||||
value, _, _ := gitcmd.NewCommand("config", "--get", "commit.gpgsign").WithDir(repo.Path).RunStdString(repo.Ctx)
|
||||
sign, valid := ParseBool(strings.TrimSpace(value))
|
||||
if !sign || !valid {
|
||||
gpgSettings.Sign = false
|
||||
repo.gpgSettings = gpgSettings
|
||||
return gpgSettings, nil
|
||||
}
|
||||
|
||||
signingKey, _, _ := gitcmd.NewCommand("config", "--get", "user.signingkey").WithDir(repo.Path).RunStdString(repo.Ctx)
|
||||
gpgSettings.KeyID = strings.TrimSpace(signingKey)
|
||||
|
||||
format, _, _ := gitcmd.NewCommand("config", "--default", SigningKeyFormatOpenPGP, "--get", "gpg.format").WithDir(repo.Path).RunStdString(repo.Ctx)
|
||||
gpgSettings.Format = strings.TrimSpace(format)
|
||||
|
||||
defaultEmail, _, _ := gitcmd.NewCommand("config", "--get", "user.email").WithDir(repo.Path).RunStdString(repo.Ctx)
|
||||
gpgSettings.Email = strings.TrimSpace(defaultEmail)
|
||||
|
||||
defaultName, _, _ := gitcmd.NewCommand("config", "--get", "user.name").WithDir(repo.Path).RunStdString(repo.Ctx)
|
||||
gpgSettings.Name = strings.TrimSpace(defaultName)
|
||||
|
||||
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repo.gpgSettings = gpgSettings
|
||||
return repo.gpgSettings, nil
|
||||
}
|
||||
@ -9,6 +9,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
)
|
||||
|
||||
func GetSigningKey(ctx context.Context, repo Repository) (*git.SigningKey, *git.Signature) {
|
||||
return git.GetSigningKey(ctx, repoPath(repo))
|
||||
func GetSigningKey(ctx context.Context) (*git.SigningKey, *git.Signature) {
|
||||
return git.GetSigningKey(ctx)
|
||||
}
|
||||
|
||||
@ -10,13 +10,8 @@ import (
|
||||
)
|
||||
|
||||
func getSigningKey(ctx *context.APIContext, expectedFormat string) {
|
||||
// if the handler is in the repo's route group, get the repo's signing key
|
||||
// otherwise, get the global signing key
|
||||
path := ""
|
||||
if ctx.Repo != nil && ctx.Repo.Repository != nil {
|
||||
path = ctx.Repo.Repository.RepoPath()
|
||||
}
|
||||
content, format, err := asymkey_service.PublicSigningKey(ctx, path)
|
||||
// get the global signing key
|
||||
content, format, err := asymkey_service.PublicSigningKey(ctx)
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
return
|
||||
|
||||
@ -61,7 +61,7 @@ func SettingsCtxData(ctx *context.Context) {
|
||||
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
|
||||
ctx.Data["CanConvertFork"] = ctx.Repo.Repository.IsFork && ctx.Doer.CanCreateRepoIn(ctx.Repo.Repository.Owner)
|
||||
|
||||
signing, _ := gitrepo.GetSigningKey(ctx, ctx.Repo.Repository)
|
||||
signing, _ := gitrepo.GetSigningKey(ctx)
|
||||
ctx.Data["SigningKeyAvailable"] = signing != nil
|
||||
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
@ -104,7 +104,7 @@ func SettingsPost(ctx *context.Context) {
|
||||
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
|
||||
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
|
||||
|
||||
signing, _ := gitrepo.GetSigningKey(ctx, ctx.Repo.Repository)
|
||||
signing, _ := gitrepo.GetSigningKey(ctx)
|
||||
ctx.Data["SigningKeyAvailable"] = signing != nil
|
||||
ctx.Data["SigningSettings"] = setting.Repository.Signing
|
||||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
|
||||
|
||||
@ -162,7 +162,7 @@ func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer *
|
||||
}
|
||||
}
|
||||
|
||||
defaultGPGSettings, err := c.GetRepositoryDefaultPublicGPGKey(false)
|
||||
defaultGPGSettings, err := git.GetDefaultPublicGPGKey(ctx, false)
|
||||
if err != nil {
|
||||
log.Error("Error getting default public gpg key: %v", err)
|
||||
} else if defaultGPGSettings == nil {
|
||||
|
||||
@ -108,34 +108,34 @@ func IsErrWontSign(err error) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// PublicSigningKey gets the public signing key within a provided repository directory
|
||||
func PublicSigningKey(ctx context.Context, repoPath string) (content, format string, err error) {
|
||||
signingKey, _ := git.GetSigningKey(ctx, repoPath)
|
||||
// PublicSigningKey gets the public signing key
|
||||
func PublicSigningKey(ctx context.Context) (content, format string, err error) {
|
||||
signingKey, _ := git.GetSigningKey(ctx)
|
||||
if signingKey == nil {
|
||||
return "", "", nil
|
||||
}
|
||||
if signingKey.Format == git.SigningKeyFormatSSH {
|
||||
content, err := os.ReadFile(signingKey.KeyID)
|
||||
if err != nil {
|
||||
log.Error("Unable to read SSH public key file in %s: %s, %v", repoPath, signingKey, err)
|
||||
log.Error("Unable to read SSH public key file: %s, %v", signingKey, err)
|
||||
return "", signingKey.Format, err
|
||||
}
|
||||
return string(content), signingKey.Format, nil
|
||||
}
|
||||
|
||||
content, stderr, err := process.GetManager().ExecDir(ctx, -1, repoPath,
|
||||
content, stderr, err := process.GetManager().ExecDir(ctx, -1, setting.Git.HomePath,
|
||||
"gpg --export -a", "gpg", "--export", "-a", signingKey.KeyID)
|
||||
if err != nil {
|
||||
log.Error("Unable to get default signing key in %s: %s, %s, %v", repoPath, signingKey, stderr, err)
|
||||
log.Error("Unable to get default signing key: %s, %s, %v", signingKey, stderr, err)
|
||||
return "", signingKey.Format, err
|
||||
}
|
||||
return content, signingKey.Format, nil
|
||||
}
|
||||
|
||||
// SignInitialCommit determines if we should sign the initial commit to this repository
|
||||
func SignInitialCommit(ctx context.Context, repoPath string, u *user_model.User) (bool, *git.SigningKey, *git.Signature, error) {
|
||||
func SignInitialCommit(ctx context.Context, u *user_model.User) (bool, *git.SigningKey, *git.Signature, error) {
|
||||
rules := signingModeFromStrings(setting.Repository.Signing.InitialCommit)
|
||||
signingKey, sig := git.GetSigningKey(ctx, repoPath)
|
||||
signingKey, sig := git.GetSigningKey(ctx)
|
||||
if signingKey == nil {
|
||||
return false, nil, nil, &ErrWontSign{noKey}
|
||||
}
|
||||
@ -171,7 +171,7 @@ Loop:
|
||||
// SignWikiCommit determines if we should sign the commits to this repository wiki
|
||||
func SignWikiCommit(ctx context.Context, repo *repo_model.Repository, u *user_model.User) (bool, *git.SigningKey, *git.Signature, error) {
|
||||
rules := signingModeFromStrings(setting.Repository.Signing.Wiki)
|
||||
signingKey, sig := gitrepo.GetSigningKey(ctx, repo.WikiStorageRepo())
|
||||
signingKey, sig := gitrepo.GetSigningKey(ctx)
|
||||
if signingKey == nil {
|
||||
return false, nil, nil, &ErrWontSign{noKey}
|
||||
}
|
||||
@ -222,9 +222,9 @@ Loop:
|
||||
}
|
||||
|
||||
// SignCRUDAction determines if we should sign a CRUD commit to this repository
|
||||
func SignCRUDAction(ctx context.Context, repoPath string, u *user_model.User, tmpBasePath, parentCommit string) (bool, *git.SigningKey, *git.Signature, error) {
|
||||
func SignCRUDAction(ctx context.Context, u *user_model.User, tmpBasePath, parentCommit string) (bool, *git.SigningKey, *git.Signature, error) {
|
||||
rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions)
|
||||
signingKey, sig := git.GetSigningKey(ctx, repoPath)
|
||||
signingKey, sig := git.GetSigningKey(ctx)
|
||||
if signingKey == nil {
|
||||
return false, nil, nil, &ErrWontSign{noKey}
|
||||
}
|
||||
@ -288,7 +288,7 @@ func SignMerge(ctx context.Context, pr *issues_model.PullRequest, u *user_model.
|
||||
}
|
||||
repo := pr.BaseRepo
|
||||
|
||||
signingKey, signer := gitrepo.GetSigningKey(ctx, repo)
|
||||
signingKey, signer := gitrepo.GetSigningKey(ctx)
|
||||
if signingKey == nil {
|
||||
return false, nil, nil, &ErrWontSign{noKey}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r
|
||||
protectionRequireSigned = protectedBranch.RequireSignedCommits
|
||||
}
|
||||
|
||||
willSign, signKey, _, err := asymkey_service.SignCRUDAction(ctx, targetRepo.RepoPath(), doer, targetRepo.RepoPath(), refName.String())
|
||||
willSign, signKey, _, err := asymkey_service.SignCRUDAction(ctx, doer, targetRepo.RepoPath(), refName.String())
|
||||
wontSignReason := ""
|
||||
if asymkey_service.IsErrWontSign(err) {
|
||||
wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason)
|
||||
|
||||
@ -95,7 +95,7 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode
|
||||
}
|
||||
}
|
||||
if protectedBranch != nil && protectedBranch.RequireSignedCommits {
|
||||
_, _, _, err := asymkey_service.SignCRUDAction(ctx, repo.RepoPath(), doer, repo.RepoPath(), opts.OldBranch)
|
||||
_, _, _, err := asymkey_service.SignCRUDAction(ctx, doer, repo.RepoPath(), opts.OldBranch)
|
||||
if err != nil {
|
||||
if !asymkey_service.IsErrWontSign(err) {
|
||||
return err
|
||||
|
||||
@ -303,9 +303,9 @@ func (t *TemporaryUploadRepository) CommitTree(ctx context.Context, opts *Commit
|
||||
var key *git.SigningKey
|
||||
var signer *git.Signature
|
||||
if opts.ParentCommitID != "" {
|
||||
sign, key, signer, _ = asymkey_service.SignCRUDAction(ctx, t.repo.RepoPath(), opts.DoerUser, t.basePath, opts.ParentCommitID)
|
||||
sign, key, signer, _ = asymkey_service.SignCRUDAction(ctx, opts.DoerUser, t.basePath, opts.ParentCommitID)
|
||||
} else {
|
||||
sign, key, signer, _ = asymkey_service.SignInitialCommit(ctx, t.repo.RepoPath(), opts.DoerUser)
|
||||
sign, key, signer, _ = asymkey_service.SignInitialCommit(ctx, opts.DoerUser)
|
||||
}
|
||||
if sign {
|
||||
if key.Format != "" {
|
||||
|
||||
@ -686,7 +686,7 @@ func VerifyBranchProtection(ctx context.Context, repo *repo_model.Repository, do
|
||||
}
|
||||
}
|
||||
if protectedBranch.RequireSignedCommits {
|
||||
_, _, _, err := asymkey_service.SignCRUDAction(ctx, repo.RepoPath(), doer, repo.RepoPath(), branchName)
|
||||
_, _, _, err := asymkey_service.SignCRUDAction(ctx, doer, repo.RepoPath(), branchName)
|
||||
if err != nil {
|
||||
if !asymkey_service.IsErrWontSign(err) {
|
||||
return err
|
||||
|
||||
@ -41,7 +41,7 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
|
||||
cmd := gitcmd.NewCommand("commit", "--message=Initial commit").
|
||||
AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email)
|
||||
|
||||
sign, key, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
|
||||
sign, key, signer, _ := asymkey_service.SignInitialCommit(ctx, u)
|
||||
if sign {
|
||||
if key.Format != "" {
|
||||
cmd.AddConfig("gpg.format", key.Format)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user