commit signing hell

This commit is contained in:
Ian Gulliver
2026-10-18 22:55:23 -07:00
parent 95389d0d92
commit 380e533ef4
8 changed files with 402 additions and 280 deletions
+29 -6
View File
@@ -177,7 +177,7 @@ func UnmergedChanges(worktree, target string) (Unmerged, error) {
return u, nil
}
func SquashCommit(repo, worktree, target, message string, env []string) (string, error) {
func SquashCommit(repo, worktree, target, message string, env []string, sign func(payload []byte) ([]byte, error)) (string, error) {
checkedOut, err := run(repo, "symbolic-ref", "--short", "HEAD")
if err != nil {
return "", err
@@ -226,18 +226,41 @@ func SquashCommit(repo, worktree, target, message string, env []string) (string,
return "", nil
}
args := []string{"commit-tree", lines[0], "-p", head, "-m", message}
sign, stderr, code, err := runCode(repo, nil, "config", "--type=bool", "--get", "commit.gpgsign")
commit, err := runEnv(repo, env, "commit-tree", lines[0], "-p", head, "-m", message)
if err != nil {
return "", err
}
signing, stderr, code, err := runCode(repo, nil, "config", "--type=bool", "--get", "commit.gpgsign")
if err != nil {
return "", err
}
if code != 0 && code != 1 {
return "", fmt.Errorf("git config --get commit.gpgsign: exit status %d: %s", code, stderr)
}
if sign == "true" {
args = append(args, "-S")
if signing != "true" {
return commit, nil
}
return runEnv(repo, env, args...)
return signCommit(repo, commit, sign)
}
func signCommit(repo, commit string, sign func(payload []byte) ([]byte, error)) (string, error) {
cmd := exec.Command("git", "cat-file", "commit", commit)
cmd.Dir = repo
payload, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("git cat-file commit %s: %w", commit, err)
}
sig, err := sign(payload)
if err != nil {
return "", fmt.Errorf("signing the commit: %w", err)
}
eoh := strings.Index(string(payload), "\n\n")
if eoh < 0 {
return "", fmt.Errorf("commit %s has no message", commit)
}
header := "gpgsig " + strings.ReplaceAll(strings.TrimSuffix(string(sig), "\n"), "\n", "\n ") + "\n"
signed := string(payload[:eoh+1]) + header + string(payload[eoh+1:])
return runInput(repo, nil, signed, "hash-object", "-t", "commit", "-w", "--stdin")
}
const Remote = "origin"