// +build ssh
package ssh
import (
"fmt"
"io/ioutil"
"net"
"os"
"golang.org/x/crypto/ssh/agent"
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v4/clients/common"
"gopkg.in/src-d/go-git.v4/core"
)
type SuiteRemote struct{}
var _ = Suite(&SuiteRemote{})
const (
fixRepo = "git@github.com:tyba/git-fixture.git"
fixRepoBadVcs = "www.example.com"
fixRepoNonGit = "https://code.google.com/p/go"
fixGitRepoNonGithub = "https://bitbucket.org/user/repo.git"
)
func (s *SuiteRemote) TestConnect(c *C) {
r := NewGitUploadPackService()
c.Assert(r.Connect(fixRepo), Equals, ErrAuthRequired)
}
// We will use a running ssh agent for testing
// ssh authentication.
type sshAgentConn struct {
pipe net.Conn
auth *PublicKeysCallback
}
// Opens a pipe with the ssh agent and uses the pipe
// as the implementer of the public key callback function.
func newSSHAgentConn() (*sshAgentConn, error) {
pipe, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
return nil, err
}
return &sshAgentConn{
pipe: pipe,
auth: &PublicKeysCallback{
User: "git",
Callback: agent.NewClient(pipe).Signers,
},
}, nil
}
// Closes the pipe with the ssh agent
func (c *sshAgentConn) close() error {
return c.pipe.Close()
}
func (s *SuiteRemote) SetUpSuite(c *C) {
if os.Getenv("SSH_AUTH_SOCK") == "" {
c.Skip("SSH_AUTH_SOCK is not set")
}
}
func (s *SuiteRemote) TestConnectWithPublicKeysCallback(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
c.Assert(r.connected, Equals, true)
c.Assert(r.auth, Equals, agent.auth)
}
func (s *SuiteRemote) TestConnectBadVcs(c *C) {
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepoBadVcs, nil), ErrorMatches, fmt.Sprintf(".*%s.*", fixRepoBadVcs))
}
func (s *SuiteRemote) TestConnectNonGit(c *C) {
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepoNonGit, nil), Equals, ErrUnsupportedVCS)
}
func (s *SuiteRemote) TestConnectNonGithub(c *C) {
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixGitRepoNonGithub, nil), Equals, ErrUnsupportedRepo)
}
// A mock implementation of client.common.AuthMethod
// to test non ssh auth method detection.
type mockAuth struct{}
func (*mockAuth) Name() string { return "" }
func (*mockAuth) String() string { return "" }
func (s *SuiteRemote) TestConnectWithAuthWrongType(c *C) {
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, &mockAuth{}), Equals, ErrInvalidAuthMethod)
c.Assert(r.connected, Equals, false)
}
func (s *SuiteRemote) TestAlreadyConnected(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), Equals, ErrAlreadyConnected)
c.Assert(r.connected, Equals, true)
}
func (s *SuiteRemote) TestDisconnect(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.connected, Equals, false)
}
func (s *SuiteRemote) TestDisconnectedWhenNonConnected(c *C) {
r := NewGitUploadPackService()
c.Assert(r.Disconnect(), Equals, ErrNotConnected)
}
func (s *SuiteRemote) TestAlreadyDisconnected(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.Disconnect(), Equals, ErrNotConnected)
c.Assert(r.connected, Equals, false)
}
func (s *SuiteRemote) TestServeralConnections(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.connected, Equals, true)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.connected, Equals, false)
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
c.Assert(r.connected, Equals, true)
c.Assert(r.Disconnect(), IsNil)
c.Assert(r.connected, Equals, false)
}
func (s *SuiteRemote) TestInfoNotConnected(c *C) {
r := NewGitUploadPackService()
_, err := r.Info()
c.Assert(err, Equals, ErrNotConnected)
}
func (s *SuiteRemote) TestDefaultBranch(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
info, err := r.Info()
c.Assert(err, IsNil)
c.Assert(info.Capabilities.SymbolicReference("HEAD"), Equals, "refs/heads/master")
}
func (s *SuiteRemote) TestCapabilities(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
info, err := r.Info()
c.Assert(err, IsNil)
c.Assert(info.Capabilities.Get("agent").Values, HasLen, 1)
}
func (s *SuiteRemote) TestFetchNotConnected(c *C) {
r := NewGitUploadPackService()
pr := &common.GitUploadPackRequest{}
pr.Want(core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
_, err := r.Fetch(pr)
c.Assert(err, Equals, ErrNotConnected)
}
func (s *SuiteRemote) TestFetch(c *C) {
agent, err := newSSHAgentConn()
c.Assert(err, IsNil)
defer func() { c.Assert(agent.close(), IsNil) }()
r := NewGitUploadPackService()
c.Assert(r.ConnectWithAuth(fixRepo, agent.auth), IsNil)
defer func() { c.Assert(r.Disconnect(), IsNil) }()
pr := &common.GitUploadPackRequest{}
pr.Want(core.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
reader, err := r.Fetch(pr)
c.Assert(err, IsNil)
b, err := ioutil.ReadAll(reader)
c.Assert(err, IsNil)
c.Assert(b, HasLen, 85374)
}