Skip to content

Commit d425923

Browse files
author
Paulo Gomes
authored
Merge pull request #707 from pjbgf/libgit2_panic
libgit2: recover from git2go panic
2 parents a952c25 + d86ea25 commit d425923

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

pkg/git/libgit2/checkout.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type CheckoutBranch struct {
6161
}
6262

6363
func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
64-
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
64+
repo, err := safeClone(url, path, &git2go.CloneOptions{
6565
FetchOptions: git2go.FetchOptions{
6666
DownloadTags: git2go.DownloadTagsNone,
6767
RemoteCallbacks: RemoteCallbacks(ctx, opts),
@@ -94,7 +94,7 @@ type CheckoutTag struct {
9494
}
9595

9696
func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
97-
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
97+
repo, err := safeClone(url, path, &git2go.CloneOptions{
9898
FetchOptions: git2go.FetchOptions{
9999
DownloadTags: git2go.DownloadTagsAll,
100100
RemoteCallbacks: RemoteCallbacks(ctx, opts),
@@ -118,7 +118,7 @@ type CheckoutCommit struct {
118118
}
119119

120120
func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
121-
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
121+
repo, err := safeClone(url, path, &git2go.CloneOptions{
122122
FetchOptions: git2go.FetchOptions{
123123
DownloadTags: git2go.DownloadTagsNone,
124124
RemoteCallbacks: RemoteCallbacks(ctx, opts),
@@ -150,7 +150,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g
150150
return nil, fmt.Errorf("semver parse error: %w", err)
151151
}
152152

153-
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
153+
repo, err := safeClone(url, path, &git2go.CloneOptions{
154154
FetchOptions: git2go.FetchOptions{
155155
DownloadTags: git2go.DownloadTagsAll,
156156
RemoteCallbacks: RemoteCallbacks(ctx, opts),
@@ -239,6 +239,19 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g
239239
return buildCommit(cc, "refs/tags/"+t), nil
240240
}
241241

242+
// safeClone wraps git2go calls with panic recovering logic, ensuring
243+
// a predictable execution path for callers.
244+
func safeClone(url, path string, cloneOpts *git2go.CloneOptions) (repo *git2go.Repository, err error) {
245+
defer func() {
246+
if r := recover(); r != nil {
247+
err = fmt.Errorf("recovered from git2go panic: %v", r)
248+
}
249+
}()
250+
251+
repo, err = git2go.Clone(url, path, cloneOpts)
252+
return
253+
}
254+
242255
// checkoutDetachedDwim attempts to perform a detached HEAD checkout by first DWIMing the short name
243256
// to get a concrete reference, and then calling checkoutDetachedHEAD.
244257
func checkoutDetachedDwim(repo *git2go.Repository, name string) (*git2go.Commit, error) {

pkg/git/libgit2/checkout_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -506,3 +506,42 @@ func TestCheckout_ED25519(t *testing.T) {
506506
_, err = branchCheckoutStrat.Checkout(ctx, tmpDir, repoURL, authOpts)
507507
g.Expect(err).To(BeNil())
508508
}
509+
510+
func TestSafeClone(t *testing.T) {
511+
g := NewWithT(t)
512+
513+
// Create a git test server.
514+
server, err := gittestserver.NewTempGitServer()
515+
g.Expect(err).ToNot(HaveOccurred())
516+
defer os.RemoveAll(server.Root())
517+
server.Auth("test-user", "test-pswd")
518+
server.AutoCreate()
519+
520+
server.KeyDir(filepath.Join(server.Root(), "keys"))
521+
g.Expect(server.ListenSSH()).To(Succeed())
522+
523+
go func() {
524+
server.StartSSH()
525+
}()
526+
defer server.StopSSH()
527+
528+
sshURL := server.SSHAddress()
529+
repoURL := sshURL + "/test.git"
530+
531+
u, err := url.Parse(sshURL)
532+
g.Expect(err).NotTo(HaveOccurred())
533+
g.Expect(u.Host).ToNot(BeEmpty())
534+
535+
repo, err := safeClone(repoURL, t.TempDir(), &git2go.CloneOptions{
536+
FetchOptions: git2go.FetchOptions{
537+
RemoteCallbacks: git2go.RemoteCallbacks{
538+
CertificateCheckCallback: func(cert *git2go.Certificate, valid bool, hostname string) error {
539+
panic("Oops!")
540+
},
541+
},
542+
}})
543+
544+
g.Expect(repo).To(BeNil())
545+
g.Expect(err).To(HaveOccurred())
546+
g.Expect(err.Error()).Should(ContainSubstring("recovered from git2go panic"))
547+
}

pkg/minio/minio_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import (
3939
const (
4040
objectName string = "test.yaml"
4141
objectEtag string = "2020beab5f1711919157756379622d1d"
42-
region string = "us-east-1"
42+
region string = "us-west-2"
4343
)
4444

4545
var (

0 commit comments

Comments
 (0)