From ab13efdd26ebb9c4c932413b34970d4d2ed6e599 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Fri, 29 Aug 2025 21:07:59 +0200 Subject: [PATCH 1/5] Fix SSH signing key path will be displayed in the pull request UI --- routers/web/repo/issue_view.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index d0064e763ef82..834a55eac5c79 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -8,10 +8,12 @@ import ( "math/big" "net/http" "net/url" + "os" "sort" "strconv" activities_model "code.gitea.io/gitea/models/activities" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -494,7 +496,24 @@ func preparePullViewSigning(ctx *context.Context, issue *issues_model.Issue) { if ctx.Doer != nil { sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitHeadRefName()) ctx.Data["WillSign"] = sign - ctx.Data["SigningKey"] = key + switch key.Format { + case git.SigningKeyFormatOpenPGP: + ctx.Data["SigningKey"] = key.KeyID + case git.SigningKeyFormatSSH: + content, readErr := os.ReadFile(key.KeyID) + if readErr != nil { + log.Error("Error whilst reading public key of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), readErr) + ctx.Data["SigningKey"] = "Unknown" + } else { + var fingerprintErr error + ctx.Data["SigningKey"], fingerprintErr = asymkey_model.CalcFingerprint(string(content)) + if fingerprintErr != nil { + log.Error("Error whilst generating public key fingerprint of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), fingerprintErr) + } else { + ctx.Data["SigningKey"] = "Unknown" + } + } + } if err != nil { if asymkey_service.IsErrWontSign(err) { ctx.Data["WontSignReason"] = err.(*asymkey_service.ErrWontSign).Reason From 75ae4152e9b7c63d61fa7fed74fd33cc35648768 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Fri, 29 Aug 2025 21:42:58 +0200 Subject: [PATCH 2/5] fix key is null --- routers/web/repo/issue_view.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 834a55eac5c79..28b7aea6b02d6 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -496,21 +496,23 @@ func preparePullViewSigning(ctx *context.Context, issue *issues_model.Issue) { if ctx.Doer != nil { sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitHeadRefName()) ctx.Data["WillSign"] = sign - switch key.Format { - case git.SigningKeyFormatOpenPGP: - ctx.Data["SigningKey"] = key.KeyID - case git.SigningKeyFormatSSH: - content, readErr := os.ReadFile(key.KeyID) - if readErr != nil { - log.Error("Error whilst reading public key of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), readErr) - ctx.Data["SigningKey"] = "Unknown" - } else { - var fingerprintErr error - ctx.Data["SigningKey"], fingerprintErr = asymkey_model.CalcFingerprint(string(content)) - if fingerprintErr != nil { - log.Error("Error whilst generating public key fingerprint of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), fingerprintErr) - } else { + if key != nil { + switch key.Format { + case git.SigningKeyFormatOpenPGP: + ctx.Data["SigningKey"] = key.KeyID + case git.SigningKeyFormatSSH: + content, readErr := os.ReadFile(key.KeyID) + if readErr != nil { + log.Error("Error whilst reading public key of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), readErr) ctx.Data["SigningKey"] = "Unknown" + } else { + var fingerprintErr error + ctx.Data["SigningKey"], fingerprintErr = asymkey_model.CalcFingerprint(string(content)) + if fingerprintErr != nil { + log.Error("Error whilst generating public key fingerprint of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), fingerprintErr) + } else { + ctx.Data["SigningKey"] = "Unknown" + } } } } From ff48860a9ca35fdfb6d3132a1591f75db249c8fd Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Sat, 30 Aug 2025 11:51:10 +0200 Subject: [PATCH 3/5] handle scenario described in feedback * move logic into a shared function --- models/asymkey/display_key.go | 23 +++++++++++++++++++++++ routers/web/repo/issue_view.go | 24 ++++-------------------- services/context/repo.go | 12 +++++++++--- 3 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 models/asymkey/display_key.go diff --git a/models/asymkey/display_key.go b/models/asymkey/display_key.go new file mode 100644 index 0000000000000..574ebc94198a6 --- /dev/null +++ b/models/asymkey/display_key.go @@ -0,0 +1,23 @@ +package asymkey + +import ( + "os" + + "code.gitea.io/gitea/modules/git" +) + +func GetDisplaySigningKey(key *git.SigningKey) (string, error) { + if key != nil { + switch key.Format { + case git.SigningKeyFormatOpenPGP: + return key.KeyID, nil + case git.SigningKeyFormatSSH: + content, readErr := os.ReadFile(key.KeyID) + if readErr != nil { + return "", readErr + } + return CalcFingerprint(string(content)) + } + } + return "", nil +} diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 28b7aea6b02d6..e081f1cbbbe1f 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -8,7 +8,6 @@ import ( "math/big" "net/http" "net/url" - "os" "sort" "strconv" @@ -496,26 +495,11 @@ func preparePullViewSigning(ctx *context.Context, issue *issues_model.Issue) { if ctx.Doer != nil { sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitHeadRefName()) ctx.Data["WillSign"] = sign - if key != nil { - switch key.Format { - case git.SigningKeyFormatOpenPGP: - ctx.Data["SigningKey"] = key.KeyID - case git.SigningKeyFormatSSH: - content, readErr := os.ReadFile(key.KeyID) - if readErr != nil { - log.Error("Error whilst reading public key of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), readErr) - ctx.Data["SigningKey"] = "Unknown" - } else { - var fingerprintErr error - ctx.Data["SigningKey"], fingerprintErr = asymkey_model.CalcFingerprint(string(content)) - if fingerprintErr != nil { - log.Error("Error whilst generating public key fingerprint of pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), fingerprintErr) - } else { - ctx.Data["SigningKey"] = "Unknown" - } - } - } + displayKeyID, displayKeyIDErr := asymkey_model.GetDisplaySigningKey(key) + if displayKeyIDErr != nil { + log.Error("Error whilst getting the display keyID: %s", displayKeyIDErr.Error()) } + ctx.Data["SigningKey"] = displayKeyID if err != nil { if asymkey_service.IsErrWontSign(err) { ctx.Data["WontSignReason"] = err.(*asymkey_service.ErrWontSign).Reason diff --git a/services/context/repo.go b/services/context/repo.go index afc6de9b1666d..a16add5ac8ed1 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -14,6 +14,7 @@ import ( "path" "strings" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" @@ -99,7 +100,7 @@ type CommitFormOptions struct { UserCanPush bool RequireSigned bool WillSign bool - SigningKey *git.SigningKey + SigningKey string WontSignReason string CanCreatePullRequest bool CanCreateBasePullRequest bool @@ -139,7 +140,7 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r protectionRequireSigned = protectedBranch.RequireSignedCommits } - willSign, signKeyID, _, err := asymkey_service.SignCRUDAction(ctx, targetRepo.RepoPath(), doer, targetRepo.RepoPath(), refName.String()) + willSign, signKey, _, err := asymkey_service.SignCRUDAction(ctx, targetRepo.RepoPath(), doer, targetRepo.RepoPath(), refName.String()) wontSignReason := "" if asymkey_service.IsErrWontSign(err) { wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason) @@ -155,6 +156,11 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r canCreateBasePullRequest := targetRepo.BaseRepo != nil && targetRepo.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) canCreatePullRequest := targetRepo.UnitEnabled(ctx, unit_model.TypePullRequests) || canCreateBasePullRequest + displayKeyID, displayKeyIDErr := asymkey_model.GetDisplaySigningKey(signKey) + if displayKeyIDErr != nil { + log.Error("Error whilst getting the display keyID: %s", displayKeyIDErr.Error()) + } + opts := &CommitFormOptions{ TargetRepo: targetRepo, WillSubmitToFork: submitToForkedRepo, @@ -162,7 +168,7 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r UserCanPush: canPushWithProtection, RequireSigned: protectionRequireSigned, WillSign: willSign, - SigningKey: signKeyID, + SigningKey: displayKeyID, WontSignReason: wontSignReason, CanCreatePullRequest: canCreatePullRequest, From 2bcb14ca10093ae8f6a10841ebb991535372ff08 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Sat, 30 Aug 2025 12:03:36 +0200 Subject: [PATCH 4/5] fix --- models/asymkey/display_key.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/models/asymkey/display_key.go b/models/asymkey/display_key.go index 574ebc94198a6..e6917a86dbd48 100644 --- a/models/asymkey/display_key.go +++ b/models/asymkey/display_key.go @@ -1,3 +1,6 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + package asymkey import ( From 51081d9406a21981a0fb9c162be6567f0f29301e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 11 Sep 2025 08:47:57 +0800 Subject: [PATCH 5/5] refactor --- models/asymkey/display_key.go | 26 ------------- models/asymkey/gpg_key_commit_verification.go | 2 +- models/asymkey/key_display.go | 37 +++++++++++++++++++ modules/git/key.go | 11 ++++++ routers/web/repo/issue_view.go | 6 +-- services/context/repo.go | 23 +++++------- templates/repo/commit_sign_badge.tmpl | 4 +- templates/repo/editor/commit_form.tmpl | 8 ++-- .../issue/view_content/pull_merge_box.tmpl | 2 +- 9 files changed, 67 insertions(+), 52 deletions(-) delete mode 100644 models/asymkey/display_key.go create mode 100644 models/asymkey/key_display.go diff --git a/models/asymkey/display_key.go b/models/asymkey/display_key.go deleted file mode 100644 index e6917a86dbd48..0000000000000 --- a/models/asymkey/display_key.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2025 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package asymkey - -import ( - "os" - - "code.gitea.io/gitea/modules/git" -) - -func GetDisplaySigningKey(key *git.SigningKey) (string, error) { - if key != nil { - switch key.Format { - case git.SigningKeyFormatOpenPGP: - return key.KeyID, nil - case git.SigningKeyFormatSSH: - content, readErr := os.ReadFile(key.KeyID) - if readErr != nil { - return "", readErr - } - return CalcFingerprint(string(content)) - } - } - return "", nil -} diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index b85374e07351b..375b703f7b3ce 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -25,7 +25,7 @@ type CommitVerification struct { SigningUser *user_model.User // if Verified, then SigningUser is non-nil CommittingUser *user_model.User // if Verified, then CommittingUser is non-nil SigningEmail string - SigningKey *GPGKey + SigningKey *GPGKey // FIXME: need to refactor it to a new name like "SigningGPGKey", it is also used in some templates SigningSSHKey *PublicKey TrustStatus string } diff --git a/models/asymkey/key_display.go b/models/asymkey/key_display.go new file mode 100644 index 0000000000000..ee17553b5b4fa --- /dev/null +++ b/models/asymkey/key_display.go @@ -0,0 +1,37 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package asymkey + +import ( + "os" + + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +func GetDisplaySigningKey(key *git.SigningKey) string { + if key == nil || key.Format == "" { + return "" + } + + switch key.Format { + case git.SigningKeyFormatOpenPGP: + return key.KeyID + case git.SigningKeyFormatSSH: + content, err := os.ReadFile(key.KeyID) + if err != nil { + log.Error("Unable to read SSH key %s: %v", key.KeyID, err) + return "(Unable to read SSH key)" + } + display, err := CalcFingerprint(string(content)) + if err != nil { + log.Error("Unable to calculate fingerprint for SSH key %s: %v", key.KeyID, err) + return "(Unable to calculate fingerprint for SSH key)" + } + return display + } + setting.PanicInDevOrTesting("Unknown signing key format: %s", key.Format) + return "(Unknown key format)" +} diff --git a/modules/git/key.go b/modules/git/key.go index 2513c048b7cbd..8c14742f34ac9 100644 --- a/modules/git/key.go +++ b/modules/git/key.go @@ -3,13 +3,24 @@ package git +import "code.gitea.io/gitea/modules/setting" + // Based on https://git-scm.com/docs/git-config#Documentation/git-config.txt-gpgformat const ( SigningKeyFormatOpenPGP = "openpgp" // for GPG keys, the expected default of git cli SigningKeyFormatSSH = "ssh" ) +// SigningKey represents an instance key info which will be used to sign git commits. +// FIXME: need to refactor it to a new name, this name conflicts with the variable names for "asymkey.GPGKey" in many places. type SigningKey struct { KeyID string Format string } + +func (s *SigningKey) String() string { + // Do not expose KeyID + // In case the key is a file path and the struct is rendered in a template, then the server path will be exposed. + setting.PanicInDevOrTesting("don't call SigningKey.String() - it exposes the KeyID which might be a local file path") + return "SigningKey:" + s.Format +} diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index e081f1cbbbe1f..d9f6c33e3fbc5 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -495,11 +495,7 @@ func preparePullViewSigning(ctx *context.Context, issue *issues_model.Issue) { if ctx.Doer != nil { sign, key, _, err := asymkey_service.SignMerge(ctx, pull, ctx.Doer, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitHeadRefName()) ctx.Data["WillSign"] = sign - displayKeyID, displayKeyIDErr := asymkey_model.GetDisplaySigningKey(key) - if displayKeyIDErr != nil { - log.Error("Error whilst getting the display keyID: %s", displayKeyIDErr.Error()) - } - ctx.Data["SigningKey"] = displayKeyID + ctx.Data["SigningKeyMergeDisplay"] = asymkey_model.GetDisplaySigningKey(key) if err != nil { if asymkey_service.IsErrWontSign(err) { ctx.Data["WontSignReason"] = err.(*asymkey_service.ErrWontSign).Reason diff --git a/services/context/repo.go b/services/context/repo.go index a16add5ac8ed1..04ddba70fe07b 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -100,7 +100,7 @@ type CommitFormOptions struct { UserCanPush bool RequireSigned bool WillSign bool - SigningKey string + SigningKeyFormDisplay string WontSignReason string CanCreatePullRequest bool CanCreateBasePullRequest bool @@ -156,20 +156,15 @@ func PrepareCommitFormOptions(ctx *Context, doer *user_model.User, targetRepo *r canCreateBasePullRequest := targetRepo.BaseRepo != nil && targetRepo.BaseRepo.UnitEnabled(ctx, unit_model.TypePullRequests) canCreatePullRequest := targetRepo.UnitEnabled(ctx, unit_model.TypePullRequests) || canCreateBasePullRequest - displayKeyID, displayKeyIDErr := asymkey_model.GetDisplaySigningKey(signKey) - if displayKeyIDErr != nil { - log.Error("Error whilst getting the display keyID: %s", displayKeyIDErr.Error()) - } - opts := &CommitFormOptions{ - TargetRepo: targetRepo, - WillSubmitToFork: submitToForkedRepo, - CanCommitToBranch: canCommitToBranch, - UserCanPush: canPushWithProtection, - RequireSigned: protectionRequireSigned, - WillSign: willSign, - SigningKey: displayKeyID, - WontSignReason: wontSignReason, + TargetRepo: targetRepo, + WillSubmitToFork: submitToForkedRepo, + CanCommitToBranch: canCommitToBranch, + UserCanPush: canPushWithProtection, + RequireSigned: protectionRequireSigned, + WillSign: willSign, + SigningKeyFormDisplay: asymkey_model.GetDisplaySigningKey(signKey), + WontSignReason: wontSignReason, CanCreatePullRequest: canCreatePullRequest, CanCreateBasePullRequest: canCreateBasePullRequest, diff --git a/templates/repo/commit_sign_badge.tmpl b/templates/repo/commit_sign_badge.tmpl index 02089d7a4c338..895d0fa0627c0 100644 --- a/templates/repo/commit_sign_badge.tmpl +++ b/templates/repo/commit_sign_badge.tmpl @@ -8,7 +8,7 @@ so this template should be kept as small as possbile, DO NOT put large component */}} {{- $commit := $.Commit -}} {{- $commitBaseLink := $.CommitBaseLink -}} -{{- $verification := $.CommitSignVerification -}} +{{- $verification := $.CommitSignVerification -}}{{- /* asymkey.CommitVerification */ -}} {{- $extraClass := "" -}} {{- $verified := false -}} @@ -50,7 +50,7 @@ so this template should be kept as small as possbile, DO NOT put large component {{- if $verification.SigningSSHKey -}} {{- $msgSigningKey = print (ctx.Locale.Tr "repo.commits.ssh_key_fingerprint") ": " $verification.SigningSSHKey.Fingerprint -}} - {{- else if $verification.SigningKey -}} + {{- else if $verification.SigningKey -}}{{- /* asymkey.GPGKey */ -}} {{- $msgSigningKey = print (ctx.Locale.Tr "repo.commits.gpg_key_id") ": " $verification.SigningKey.PaddedKeyID -}} {{- end -}} {{- end -}} diff --git a/templates/repo/editor/commit_form.tmpl b/templates/repo/editor/commit_form.tmpl index 3e4482f9e2f9c..10872f8af7452 100644 --- a/templates/repo/editor/commit_form.tmpl +++ b/templates/repo/editor/commit_form.tmpl @@ -1,13 +1,15 @@
{{ctx.AvatarUtils.Avatar .SignedUser 40 "commit-avatar"}}
-

{{- if .CommitFormOptions.WillSign}} - {{svg "octicon-lock" 24}} +

+ {{- if .CommitFormOptions.WillSign}} + {{svg "octicon-lock" 24}} {{ctx.Locale.Tr "repo.editor.commit_signed_changes"}} {{- else}} {{svg "octicon-unlock" 24}} {{ctx.Locale.Tr "repo.editor.commit_changes"}} - {{- end}}

+ {{- end}} +
diff --git a/templates/repo/issue/view_content/pull_merge_box.tmpl b/templates/repo/issue/view_content/pull_merge_box.tmpl index 113bfb732ecee..b0ac24c9f6c3f 100644 --- a/templates/repo/issue/view_content/pull_merge_box.tmpl +++ b/templates/repo/issue/view_content/pull_merge_box.tmpl @@ -188,7 +188,7 @@ {{if .WillSign}}
{{svg "octicon-lock" 16 "text green"}} - {{ctx.Locale.Tr "repo.signing.will_sign" .SigningKey}} + {{ctx.Locale.Tr "repo.signing.will_sign" .SigningKeyMergeDisplay}}
{{else if .IsSigned}}