Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit afdd28d

Browse files
authored
Merge pull request #687 from smithrobs/sshconfig
check .ssh/config for host and port overrides; fixes #629
2 parents e903763 + 264d094 commit afdd28d

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

plumbing/transport/ssh/common.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,26 @@ package ssh
44
import (
55
"fmt"
66
"reflect"
7+
"strconv"
78

89
"gopkg.in/src-d/go-git.v4/plumbing/transport"
910
"gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common"
1011

12+
"github.com/kevinburke/ssh_config"
1113
"golang.org/x/crypto/ssh"
1214
)
1315

1416
// DefaultClient is the default SSH client.
1517
var DefaultClient = NewClient(nil)
1618

19+
// DefaultSSHConfig is the reader used to access parameters stored in the
20+
// system's ssh_config files. If nil all the ssh_config are ignored.
21+
var DefaultSSHConfig sshConfig = ssh_config.DefaultUserSettings
22+
23+
type sshConfig interface {
24+
Get(alias, key string) string
25+
}
26+
1727
// NewClient creates a new SSH client with an optional *ssh.ClientConfig.
1828
func NewClient(config *ssh.ClientConfig) transport.Transport {
1929
return common.NewClient(&runner{config: config})
@@ -121,6 +131,10 @@ func (c *command) connect() error {
121131
}
122132

123133
func (c *command) getHostWithPort() string {
134+
if addr, found := c.doGetHostWithPortFromSSHConfig(); found {
135+
return addr
136+
}
137+
124138
host := c.endpoint.Host
125139
port := c.endpoint.Port
126140
if port <= 0 {
@@ -130,6 +144,35 @@ func (c *command) getHostWithPort() string {
130144
return fmt.Sprintf("%s:%d", host, port)
131145
}
132146

147+
func (c *command) doGetHostWithPortFromSSHConfig() (addr string, found bool) {
148+
if DefaultSSHConfig == nil {
149+
return
150+
}
151+
152+
host := c.endpoint.Host
153+
port := c.endpoint.Port
154+
155+
configHost := DefaultSSHConfig.Get(c.endpoint.Host, "Hostname")
156+
if configHost != "" {
157+
host = configHost
158+
found = true
159+
}
160+
161+
if !found {
162+
return
163+
}
164+
165+
configPort := DefaultSSHConfig.Get(c.endpoint.Host, "Port")
166+
if configPort != "" {
167+
if i, err := strconv.Atoi(configPort); err == nil {
168+
port = i
169+
}
170+
}
171+
172+
addr = fmt.Sprintf("%s:%d", host, port)
173+
return
174+
}
175+
133176
func (c *command) setAuthFromEndpoint() error {
134177
var err error
135178
c.auth, err = DefaultAuthBuilder(c.endpoint.User)

plumbing/transport/ssh/common_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package ssh
33
import (
44
"testing"
55

6+
"github.com/kevinburke/ssh_config"
7+
68
"golang.org/x/crypto/ssh"
79

810
. "gopkg.in/check.v1"
11+
"gopkg.in/src-d/go-git.v4/plumbing/transport"
912
)
1013

1114
func Test(t *testing.T) { TestingT(t) }
@@ -39,3 +42,67 @@ func (s *SuiteCommon) TestOverrideConfigKeep(c *C) {
3942
overrideConfig(config, target)
4043
c.Assert(target.User, Equals, "foo")
4144
}
45+
46+
func (s *SuiteCommon) TestDefaultSSHConfig(c *C) {
47+
defer func() {
48+
DefaultSSHConfig = ssh_config.DefaultUserSettings
49+
}()
50+
51+
DefaultSSHConfig = &mockSSHConfig{map[string]map[string]string{
52+
"github.com": map[string]string{
53+
"Hostname": "foo.local",
54+
"Port": "42",
55+
},
56+
}}
57+
58+
ep, err := transport.NewEndpoint("git@github.com:foo/bar.git")
59+
c.Assert(err, IsNil)
60+
61+
cmd := &command{endpoint: ep}
62+
c.Assert(cmd.getHostWithPort(), Equals, "foo.local:42")
63+
}
64+
65+
func (s *SuiteCommon) TestDefaultSSHConfigNil(c *C) {
66+
defer func() {
67+
DefaultSSHConfig = ssh_config.DefaultUserSettings
68+
}()
69+
70+
DefaultSSHConfig = nil
71+
72+
ep, err := transport.NewEndpoint("git@github.com:foo/bar.git")
73+
c.Assert(err, IsNil)
74+
75+
cmd := &command{endpoint: ep}
76+
c.Assert(cmd.getHostWithPort(), Equals, "github.com:22")
77+
}
78+
79+
func (s *SuiteCommon) TestDefaultSSHConfigWildcard(c *C) {
80+
defer func() {
81+
DefaultSSHConfig = ssh_config.DefaultUserSettings
82+
}()
83+
84+
DefaultSSHConfig = &mockSSHConfig{Values: map[string]map[string]string{
85+
"*": map[string]string{
86+
"Port": "42",
87+
},
88+
}}
89+
90+
ep, err := transport.NewEndpoint("git@github.com:foo/bar.git")
91+
c.Assert(err, IsNil)
92+
93+
cmd := &command{endpoint: ep}
94+
c.Assert(cmd.getHostWithPort(), Equals, "github.com:22")
95+
}
96+
97+
type mockSSHConfig struct {
98+
Values map[string]map[string]string
99+
}
100+
101+
func (c *mockSSHConfig) Get(alias, key string) string {
102+
a, ok := c.Values[alias]
103+
if !ok {
104+
return c.Values["*"][key]
105+
}
106+
107+
return a[key]
108+
}

0 commit comments

Comments
 (0)