Add `NewCredentialSSHKeyFromSigner` (#706)
This change adds `NewCredentialSSHKeyFromSigner`, which allows idiomatic
use of SSH keys from Go. This also lets us spin off an SSH server in the
tests.
(cherry picked from commit abf02bc7d7
)
This commit is contained in:
parent
57d9083efe
commit
5e09ac76e8
|
@ -34,6 +34,7 @@ jobs:
|
||||||
GOPATH: /home/runner/work/git2go
|
GOPATH: /home/runner/work/git2go
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
make build-libgit2-static
|
make build-libgit2-static
|
||||||
go get -tags static -t github.com/${{ github.repository }}/...
|
go get -tags static -t github.com/${{ github.repository }}/...
|
||||||
go build -tags static github.com/${{ github.repository }}/...
|
go build -tags static github.com/${{ github.repository }}/...
|
||||||
|
@ -62,6 +63,7 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
make build-libgit2-static
|
make build-libgit2-static
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make TEST_ARGS=-test.v test-static
|
run: make TEST_ARGS=-test.v test-static
|
||||||
|
@ -84,6 +86,7 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
make build-libgit2-dynamic
|
make build-libgit2-dynamic
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make TEST_ARGS=-test.v test-dynamic
|
run: make TEST_ARGS=-test.v test-dynamic
|
||||||
|
@ -106,6 +109,7 @@ jobs:
|
||||||
- name: Build libgit2
|
- name: Build libgit2
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
sudo ./script/build-libgit2.sh --dynamic --system
|
sudo ./script/build-libgit2.sh --dynamic --system
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make TEST_ARGS=-test.v test
|
run: make TEST_ARGS=-test.v test
|
||||||
|
@ -128,6 +132,7 @@ jobs:
|
||||||
- name: Build libgit2
|
- name: Build libgit2
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
sudo ./script/build-libgit2.sh --static --system
|
sudo ./script/build-libgit2.sh --static --system
|
||||||
- name: Test
|
- name: Test
|
||||||
run: go test --count=1 --tags "static,system_libgit2" ./...
|
run: go test --count=1 --tags "static,system_libgit2" ./...
|
||||||
|
|
|
@ -8,6 +8,7 @@ go:
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||||
- make build-libgit2-static
|
- make build-libgit2-static
|
||||||
- go get --tags "static" ./...
|
- go get --tags "static" ./...
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,16 @@ package git
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
void _go_git_populate_credential_ssh_custom(git_cred_ssh_custom *cred);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import "unsafe"
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
type CredType uint
|
type CredType uint
|
||||||
|
|
||||||
|
@ -89,3 +96,61 @@ func NewCredDefault() (int, Cred) {
|
||||||
ret := C.git_cred_default_new(&cred.ptr)
|
ret := C.git_cred_default_new(&cred.ptr)
|
||||||
return int(ret), cred
|
return int(ret), cred
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type credentialSSHCustomData struct {
|
||||||
|
signer ssh.Signer
|
||||||
|
}
|
||||||
|
|
||||||
|
//export credentialSSHCustomFree
|
||||||
|
func credentialSSHCustomFree(cred *C.git_cred_ssh_custom) {
|
||||||
|
if cred == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
C.free(unsafe.Pointer(cred.username))
|
||||||
|
C.free(unsafe.Pointer(cred.publickey))
|
||||||
|
pointerHandles.Untrack(cred.payload)
|
||||||
|
C.free(unsafe.Pointer(cred))
|
||||||
|
}
|
||||||
|
|
||||||
|
//export credentialSSHSignCallback
|
||||||
|
func credentialSSHSignCallback(
|
||||||
|
errorMessage **C.char,
|
||||||
|
sig **C.uchar,
|
||||||
|
sig_len *C.size_t,
|
||||||
|
data *C.uchar,
|
||||||
|
data_len C.size_t,
|
||||||
|
handle unsafe.Pointer,
|
||||||
|
) C.int {
|
||||||
|
signer := pointerHandles.Get(handle).(*credentialSSHCustomData).signer
|
||||||
|
signature, err := signer.Sign(rand.Reader, C.GoBytes(unsafe.Pointer(data), C.int(data_len)))
|
||||||
|
if err != nil {
|
||||||
|
return setCallbackError(errorMessage, err)
|
||||||
|
}
|
||||||
|
*sig = (*C.uchar)(C.CBytes(signature.Blob))
|
||||||
|
*sig_len = C.size_t(len(signature.Blob))
|
||||||
|
return C.int(ErrorCodeOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCredentialSSHKeyFromSigner creates new SSH credentials using the provided signer.
|
||||||
|
func NewCredentialSSHKeyFromSigner(username string, signer ssh.Signer) (*Cred, error) {
|
||||||
|
publicKey := signer.PublicKey().Marshal()
|
||||||
|
|
||||||
|
ccred := (*C.git_cred_ssh_custom)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_cred_ssh_custom{}))))
|
||||||
|
ccred.parent.credtype = C.GIT_CREDTYPE_SSH_CUSTOM
|
||||||
|
ccred.username = C.CString(username)
|
||||||
|
ccred.publickey = (*C.char)(C.CBytes(publicKey))
|
||||||
|
ccred.publickey_len = C.size_t(len(publicKey))
|
||||||
|
C._go_git_populate_credential_ssh_custom(ccred)
|
||||||
|
|
||||||
|
data := credentialSSHCustomData{
|
||||||
|
signer: signer,
|
||||||
|
}
|
||||||
|
ccred.payload = pointerHandles.Track(&data)
|
||||||
|
|
||||||
|
cred := Cred{
|
||||||
|
ptr: &ccred.parent,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cred, nil
|
||||||
|
}
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -1,3 +1,9 @@
|
||||||
module github.com/libgit2/git2go/v27
|
module github.com/libgit2/git2go/v27
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
|
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
|
||||||
|
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
279
remote_test.go
279
remote_test.go
|
@ -1,8 +1,21 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListRemotes(t *testing.T) {
|
func TestListRemotes(t *testing.T) {
|
||||||
|
@ -184,3 +197,269 @@ func TestRemotePrune(t *testing.T) {
|
||||||
t.Fatal("Expected error getting a pruned reference")
|
t.Fatal("Expected error getting a pruned reference")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newChannelPipe(t *testing.T, w io.Writer, wg *sync.WaitGroup) (*os.File, error) {
|
||||||
|
pr, pw, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
_, err := io.Copy(w, pr)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
t.Logf("Failed to copy: %v", err)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return pw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startSSHServer(t *testing.T, hostKey ssh.Signer, authorizedKeys []ssh.PublicKey) net.Listener {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
marshaledAuthorizedKeys := make([][]byte, len(authorizedKeys))
|
||||||
|
for i, authorizedKey := range authorizedKeys {
|
||||||
|
marshaledAuthorizedKeys[i] = authorizedKey.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &ssh.ServerConfig{
|
||||||
|
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
marshaledPubKey := pubKey.Marshal()
|
||||||
|
for _, marshaledAuthorizedKey := range marshaledAuthorizedKeys {
|
||||||
|
if bytes.Equal(marshaledPubKey, marshaledAuthorizedKey) {
|
||||||
|
return &ssh.Permissions{
|
||||||
|
// Record the public key used for authentication.
|
||||||
|
Extensions: map[string]string{
|
||||||
|
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("unknown public key for %q:\n\t%+v\n\t%+v\n", c.User(), pubKey.Marshal(), authorizedKeys)
|
||||||
|
return nil, fmt.Errorf("unknown public key for %q", c.User())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
config.AddHostKey(hostKey)
|
||||||
|
|
||||||
|
listener, err := net.Listen("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to listen for connection: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
nConn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Logf("Failed to accept incoming connection: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer nConn.Close()
|
||||||
|
|
||||||
|
conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("failed to handshake: %+v, %+v", conn, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The incoming Request channel must be serviced.
|
||||||
|
go func() {
|
||||||
|
for newRequest := range reqs {
|
||||||
|
t.Logf("new request %v", newRequest)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Service only the first channel request
|
||||||
|
newChannel := <-chans
|
||||||
|
defer func() {
|
||||||
|
for newChannel := range chans {
|
||||||
|
t.Logf("new channel %v", newChannel)
|
||||||
|
newChannel.Reject(ssh.UnknownChannelType, "server closing")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Channels have a type, depending on the application level
|
||||||
|
// protocol intended. In the case of a shell, the type is
|
||||||
|
// "session" and ServerShell may be used to present a simple
|
||||||
|
// terminal interface.
|
||||||
|
if newChannel.ChannelType() != "session" {
|
||||||
|
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channel, requests, err := newChannel.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Could not accept channel: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer channel.Close()
|
||||||
|
|
||||||
|
// Sessions have out-of-band requests such as "shell",
|
||||||
|
// "pty-req" and "env". Here we handle only the
|
||||||
|
// "exec" request.
|
||||||
|
req := <-requests
|
||||||
|
if req.Type != "exec" {
|
||||||
|
req.Reply(false, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// RFC 4254 Section 6.5.
|
||||||
|
var payload struct {
|
||||||
|
Command string
|
||||||
|
}
|
||||||
|
if err := ssh.Unmarshal(req.Payload, &payload); err != nil {
|
||||||
|
t.Logf("invalid payload on channel %v: %v", channel, err)
|
||||||
|
req.Reply(false, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args, err := shlex.Split(payload.Command)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("invalid command on channel %v: %v", channel, err)
|
||||||
|
req.Reply(false, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(args) < 2 || (args[0] != "git-upload-pack" && args[0] != "git-receive-pack") {
|
||||||
|
t.Logf("invalid command (%v) on channel %v: %v", args, channel, err)
|
||||||
|
req.Reply(false, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Reply(true, nil)
|
||||||
|
|
||||||
|
go func(in <-chan *ssh.Request) {
|
||||||
|
for req := range in {
|
||||||
|
t.Logf("draining request %v", req)
|
||||||
|
}
|
||||||
|
}(requests)
|
||||||
|
|
||||||
|
// The first parameter is the (absolute) path of the repository.
|
||||||
|
args[1] = "./testdata" + args[1]
|
||||||
|
|
||||||
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
cmd.Stdin = channel
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
stdoutPipe, err := newChannelPipe(t, channel, &wg)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Failed to create stdout pipe: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd.Stdout = stdoutPipe
|
||||||
|
stderrPipe, err := newChannelPipe(t, channel.Stderr(), &wg)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Failed to create stderr pipe: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd.Stderr = stderrPipe
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
channel.CloseWrite()
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Failed to start %v: %v", args, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the process has started, we need to close the write end of the
|
||||||
|
// pipes from this process so that we can know when the child has done
|
||||||
|
// writing to it.
|
||||||
|
stdoutPipe.Close()
|
||||||
|
stderrPipe.Close()
|
||||||
|
|
||||||
|
timer := time.AfterFunc(5*time.Second, func() {
|
||||||
|
t.Log("process timed out, terminating")
|
||||||
|
cmd.Process.Kill()
|
||||||
|
})
|
||||||
|
defer timer.Stop()
|
||||||
|
|
||||||
|
err = cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Failed to run %v: %v", args, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoteSSH(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
pubKeyUsername := "testuser"
|
||||||
|
|
||||||
|
hostPrivKey, err := rsa.GenerateKey(rand.Reader, 512)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to generate the host RSA private key: %v", err)
|
||||||
|
}
|
||||||
|
hostSigner, err := ssh.NewSignerFromKey(hostPrivKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to generate SSH hostSigner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey, err := rsa.GenerateKey(rand.Reader, 512)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to generate the user RSA private key: %v", err)
|
||||||
|
}
|
||||||
|
signer, err := ssh.NewSignerFromKey(privKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to generate SSH signer: %v", err)
|
||||||
|
}
|
||||||
|
// This is in the format "xx:xx:xx:...", so we remove the colons so that it
|
||||||
|
// matches the fmt.Sprintf() below.
|
||||||
|
// Note that not all libssh2 implementations support the SHA256 fingerprint,
|
||||||
|
// so we use MD5 here for testing.
|
||||||
|
publicKeyFingerprint := strings.Replace(ssh.FingerprintLegacyMD5(hostSigner.PublicKey()), ":", "", -1)
|
||||||
|
|
||||||
|
listener := startSSHServer(t, hostSigner, []ssh.PublicKey{signer.PublicKey()})
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
certificateCheckCallbackCalled := false
|
||||||
|
fetchOpts := FetchOptions{
|
||||||
|
RemoteCallbacks: RemoteCallbacks{
|
||||||
|
CertificateCheckCallback: func(cert *Certificate, valid bool, hostname string) ErrorCode {
|
||||||
|
hostkeyFingerprint := fmt.Sprintf("%x", cert.Hostkey.HashMD5[:])
|
||||||
|
if hostkeyFingerprint != publicKeyFingerprint {
|
||||||
|
t.Logf("server hostkey %q, want %q", hostkeyFingerprint, publicKeyFingerprint)
|
||||||
|
return ErrorCodeAuth
|
||||||
|
}
|
||||||
|
certificateCheckCallbackCalled = true
|
||||||
|
return ErrorCodeOK
|
||||||
|
},
|
||||||
|
CredentialsCallback: func(url, username string, allowedTypes CredType) (ErrorCode, *Cred) {
|
||||||
|
if allowedTypes&(CredTypeSshKey|CredTypeSshCustom) != 0 {
|
||||||
|
cred, err := NewCredentialSSHKeyFromSigner(pubKeyUsername, signer)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("failed to create credentials: %v", err)
|
||||||
|
return ErrorCodeAuth, nil
|
||||||
|
}
|
||||||
|
return ErrorCodeOK, cred
|
||||||
|
}
|
||||||
|
t.Logf("unknown credential type %+v", allowedTypes)
|
||||||
|
return ErrorCodeAuth, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
remote, err := repo.Remotes.Create(
|
||||||
|
"origin",
|
||||||
|
fmt.Sprintf("ssh://%s@%s/TestGitRepository", pubKeyUsername, listener.Addr().String()),
|
||||||
|
)
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer remote.Free()
|
||||||
|
|
||||||
|
err = remote.Fetch(nil, &fetchOpts, "")
|
||||||
|
checkFatal(t, err)
|
||||||
|
if !certificateCheckCallbackCalled {
|
||||||
|
t.Fatalf("CertificateCheckCallback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
heads, err := remote.Ls()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if len(heads) == 0 {
|
||||||
|
t.Error("Expected remote heads")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -62,11 +62,11 @@ cmake -DTHREADSAFE=ON \
|
||||||
-DCMAKE_BUILD_TYPE="RelWithDebInfo" \
|
-DCMAKE_BUILD_TYPE="RelWithDebInfo" \
|
||||||
-DCMAKE_INSTALL_PREFIX="${BUILD_INSTALL_PREFIX}" \
|
-DCMAKE_INSTALL_PREFIX="${BUILD_INSTALL_PREFIX}" \
|
||||||
-DDEPRECATE_HARD=ON \
|
-DDEPRECATE_HARD=ON \
|
||||||
"${VENDORED_PATH}" &&
|
"${VENDORED_PATH}"
|
||||||
|
|
||||||
if which gmake nproc >/dev/null && [ -f Makefile ]; then
|
if which make nproc >/dev/null && [ -f Makefile ]; then
|
||||||
# Make the build parallel if gmake is available and cmake used Makefiles.
|
# Make the build parallel if make is available and cmake used Makefiles.
|
||||||
exec gmake "-j$(nproc --all)" install
|
exec make "-j$(nproc --all)" install
|
||||||
|
else
|
||||||
|
exec cmake --build . --target install
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec cmake --build . --target install
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ref: refs/heads/master
|
|
@ -0,0 +1,6 @@
|
||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
|
[remote "origin"]
|
||||||
|
url = https://github.com/libgit2/TestGitRepository
|
|
@ -0,0 +1 @@
|
||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,6 @@
|
||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
|
@ -0,0 +1,8 @@
|
||||||
|
0966a434eb1a025db6b71485ab63a3bfbea520b6 refs/heads/first-merge
|
||||||
|
49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master
|
||||||
|
42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 refs/heads/no-parent
|
||||||
|
d96c4e80345534eccee5ac7b07fc7603b56124cb refs/tags/annotated_tag
|
||||||
|
c070ad8c08840c8116da865b2d65593a6bb9cd2a refs/tags/annotated_tag^{}
|
||||||
|
55a1a760df4b86a02094a904dfa511deb5655905 refs/tags/blob
|
||||||
|
8f50ba15d49353813cc6e20298002c0d17b0a9ee refs/tags/commit_tree
|
||||||
|
6e0c7bdb9b4ed93212491ee778ca1c65047cab4e refs/tags/nearly-dangling
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
||||||
|
P pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.pack
|
||||||
|
|
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.bitmap
vendored
Normal file
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.bitmap
vendored
Normal file
Binary file not shown.
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.idx
vendored
Normal file
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.idx
vendored
Normal file
Binary file not shown.
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.pack
vendored
Normal file
BIN
testdata/TestGitRepository.git/objects/pack/pack-ccace4e169a0858c13d9ae781a91d76fc33769b8.pack
vendored
Normal file
Binary file not shown.
|
@ -0,0 +1,9 @@
|
||||||
|
# pack-refs with: peeled fully-peeled sorted
|
||||||
|
0966a434eb1a025db6b71485ab63a3bfbea520b6 refs/heads/first-merge
|
||||||
|
49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master
|
||||||
|
42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 refs/heads/no-parent
|
||||||
|
d96c4e80345534eccee5ac7b07fc7603b56124cb refs/tags/annotated_tag
|
||||||
|
^c070ad8c08840c8116da865b2d65593a6bb9cd2a
|
||||||
|
55a1a760df4b86a02094a904dfa511deb5655905 refs/tags/blob
|
||||||
|
8f50ba15d49353813cc6e20298002c0d17b0a9ee refs/tags/commit_tree
|
||||||
|
6e0c7bdb9b4ed93212491ee778ca1c65047cab4e refs/tags/nearly-dangling
|
|
@ -0,0 +1 @@
|
||||||
|
49322bb17d3acc9146f98c97d078513228bbf3c0
|
23
wrapper.c
23
wrapper.c
|
@ -403,6 +403,29 @@ void _go_git_writestream_free(git_writestream *stream)
|
||||||
stream->free(stream);
|
stream->free(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int credential_ssh_sign_callback(
|
||||||
|
LIBSSH2_SESSION *session,
|
||||||
|
unsigned char **sig, size_t *sig_len,
|
||||||
|
const unsigned char *data, size_t data_len,
|
||||||
|
void **abstract)
|
||||||
|
{
|
||||||
|
char *error_message = NULL;
|
||||||
|
const int ret = credentialSSHSignCallback(
|
||||||
|
&error_message,
|
||||||
|
sig,
|
||||||
|
sig_len,
|
||||||
|
(unsigned char *)data,
|
||||||
|
data_len,
|
||||||
|
(void *)*(uintptr_t *)abstract);
|
||||||
|
return set_callback_error(error_message, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _go_git_populate_credential_ssh_custom(git_cred_ssh_custom *cred)
|
||||||
|
{
|
||||||
|
cred->parent.free = (void (*)(git_cred *))credentialSSHCustomFree;
|
||||||
|
cred->sign_callback = credential_ssh_sign_callback;
|
||||||
|
}
|
||||||
|
|
||||||
int _go_git_odb_write_pack(git_odb_writepack **out, git_odb *db, void *progress_payload)
|
int _go_git_odb_write_pack(git_odb_writepack **out, git_odb *db, void *progress_payload)
|
||||||
{
|
{
|
||||||
return git_odb_write_pack(out, db, transfer_progress_callback, progress_payload);
|
return git_odb_write_pack(out, db, transfer_progress_callback, progress_payload);
|
||||||
|
|
Loading…
Reference in New Issue