Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add SSH signing of commits #1422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
Loading
from

Conversation

roshan
Copy link

@roshan roshan commented Feb 3, 2025

Add support for SSH signing of commits identical to git

This commit supports the equivalent of running git commit -S when using an SSH key to sign. Git allows signing commits with PGP keys (already supported in go-git) and also allows signing via SSH keys when appropriately configured.

How one signs a commit with `git commit -S`
$ echo 'world' >> hello.md &&\
GIT_AUTHOR_DATE="2025-01-30T10:00:00" \
GIT_COMMITTER_DATE="2025-01-30T10:00:00" \
GIT_TRACE=1 \
git commit -S -m "Add world to hello.md" -a
15:05:21.287907 exec-cmd.c:139          trace: resolved executable path from Darwin stack: /Library/Developer/CommandLineTools/usr/bin/git
15:05:21.288536 exec-cmd.c:238          trace: resolved executable dir: /Library/Developer/CommandLineTools/usr/bin
15:05:21.289179 git.c:460               trace: built-in: git commit -S -m 'Add world to hello.md' -a
15:05:21.291569 run-command.c:655       trace: run_command: ssh-keygen -Y sign -n git -f /Users/george/.ssh/id_ed25519.pub /var/folders/9b/92pmw3kx35gc39k132myqnrh0000gp/T//.git_signing_buffer_tmp5jyYqa
15:05:21.299105 run-command.c:655       trace: run_command: git maintenance run --auto --no-quiet
15:05:21.302676 exec-cmd.c:139          trace: resolved executable path from Darwin stack: /Library/Developer/CommandLineTools/usr/libexec/git-core/git
15:05:21.303064 exec-cmd.c:238          trace: resolved executable dir: /Library/Developer/CommandLineTools/usr/libexec/git-core
15:05:21.303562 git.c:460               trace: built-in: git maintenance run --auto --no-quiet
[main f0e8459] Add world to hello.md
 1 file changed, 1 insertion(+)
How one signs a commit with this code
package main

import (
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing/object"
	"github.com/go-git/go-git/v5/plumbing/sign"
)

func main() {
	repo, err := git.PlainOpen("/tmp/repo")
	if err != nil {
		panic(err)
	}

	filePath := filepath.Join("/tmp/repo", "hello.md")
	f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		panic(err)
	}
	if _, err := f.WriteString("world\n"); err != nil {
		panic(err)
	}
	f.Close()

	w, err := repo.Worktree()
	if err != nil {
		panic(err)
	}

	_, err = w.Add("hello.md")
	if err != nil {
		panic(err)
	}

	// Just add signing options directly to CommitOptions
	signer, err := sign.NewSSHSigner("~/.ssh/id_ed25519")
	if err != nil {
		panic(err)
	}
	if signer == nil {
		println(signer)
	}

	pacific, err := time.LoadLocation("America/Los_Angeles")
	if err != nil {
		log.Fatalf("Failed to load location: %v", err)
	}

	commitTime := time.Date(2025, 1, 30, 10, 0, 0, 0, pacific) // Fixed timestamp to compare hashes

	commit, err := w.Commit("Add world to hello.md\n", &git.CommitOptions{
		Author: &object.Signature{
			Name:  "Roshan George",
			Email: "roshan@technologybrother.com",
			When:  commitTime,
		},
		Committer: &object.Signature{
			Name:  "Roshan George",
			Email: "roshan@technologybrother.com",
			When:  commitTime,
		},
		Signer: signer,
	})

	if err != nil {
		panic(err)
	}

	println("Created commit:", commit.String())
}

which results in

$ go run main.go
Created commit: f0e845969b5111d5702c789b311d645db6d32f95
In both cases `git cat-file commit f0e845969b5111d5702c789b311d645db6d32f95` will yield the same thing
git cat-file commit f0e845969b5111d5702c789b311d645db6d32f95
tree ca2a84cb39938f998132a519c5a51ea58f61e957
parent 9ea36ed0ea144e777ba6bd3022d70bf02684ae6b
author Roshan George <roshan@technologybrother.com> 1738260000 -0800
committer Roshan George <roshan@technologybrother.com> 1738260000 -0800
gpgsig -----BEGIN SSH SIGNATURE-----
 U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgsv4P1Kgi/8X6hZ+gemfiQtGSb9
 Urcu7HeA8dWDwXW9oAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
 AAAAQCivvTPR26w4AM+BukWBCQ9fNQ0UUMwi3scjxV5sbFOT3+eRDzddZX8hiwigdzcTOf
 ZZJFiQ68bQZI3PEIBYOAQ=
 -----END SSH SIGNATURE-----

Add world to hello.md

Appropriately setup, this will show up as 'Verified' on Github:

Screenshot 2025-02-03 at 3 10 23 PM

Your contribution checklist

  • You should be able to run the same query using git. We don't accept features that are not implemented in the official git implementation.
  • The expected behavior must match the official git implementation.
  • The actual behavior must be correctly explained with natural language and providing a minimum working example in Go that reproduces it.
  • All PRs must be written in idiomatic Go, formatted according to gofmt, and without any warnings from go vet.
  • They should in general include tests, and those shall pass.
  • If the PR is a bug fix, it has to include a suite of unit tests for the new functionality.
  • If the PR is a new feature, it has to come with a suite of unit tests, that tests the new functionality.
  • In any case, all the PRs have to pass the personal evaluation of at least one of the maintainers of go-git.

@roshan roshan marked this pull request as ready for review February 3, 2025 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant
Morty Proxy This is a proxified and sanitized view of the page, visit original site.