Skip to content

Commit 4ce7d8a

Browse files
committed
add support for pressly#104 & pressly#107
1 parent cf2a40d commit 4ce7d8a

File tree

3 files changed

+47
-10
lines changed

3 files changed

+47
-10
lines changed

ssh.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"golang.org/x/crypto/ssh"
1515
"golang.org/x/crypto/ssh/agent"
16+
"golang.org/x/crypto/ssh/terminal"
1617
)
1718

1819
// Client is a wrapper over the SSH connection/sessions.
@@ -29,6 +30,10 @@ type SSHClient struct {
2930
running bool
3031
env string //export FOO="bar"; export BAR="baz";
3132
color string
33+
34+
ask bool // For interactive "ask:root@..."
35+
password string // For config "password: ..."
36+
3237
}
3338

3439
type ErrConnect struct {
@@ -54,6 +59,15 @@ func (c *SSHClient) parseHost(host string) error {
5459
if at := strings.LastIndex(c.host, "@"); at != -1 {
5560
c.user = c.host[:at]
5661
c.host = c.host[at+1:]
62+
63+
// Check if the username starts with "ask:"
64+
c.ask = false
65+
if strings.HasPrefix(c.user, "ask:") {
66+
// Remove "ask:" from the username
67+
c.user = strings.TrimPrefix(c.user, "ask:")
68+
// Set the flag so ConnectWith knows to prompt
69+
c.ask = true
70+
}
5771
}
5872

5973
// Add default user, if not set
@@ -135,11 +149,30 @@ func (c *SSHClient) ConnectWith(host string, dialer SSHDialFunc) error {
135149
return err
136150
}
137151

152+
// 1. Start with Public Keys (SSH Agent + ~/.ssh/id_rsa)
153+
auths := []ssh.AuthMethod{
154+
authMethod,
155+
}
156+
157+
// 2. If a password was provided in Supfile, add it to the list
158+
if c.password != "" {
159+
auths = append(auths, ssh.Password(c.password))
160+
}
161+
162+
// 3. If the user requested an interactive prompt (ask:user@host), ask now
163+
if c.ask {
164+
fmt.Printf("Enter Password for %s@%s: ", c.user, c.host)
165+
pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
166+
if err != nil {
167+
return err
168+
}
169+
fmt.Println("") // Print newline after input
170+
auths = append(auths, ssh.Password(string(pass)))
171+
}
172+
138173
config := &ssh.ClientConfig{
139-
User: c.user,
140-
Auth: []ssh.AuthMethod{
141-
authMethod,
142-
},
174+
User: c.user,
175+
Auth: auths, // Use the combined list of auth methods
143176
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
144177
}
145178

@@ -155,10 +188,10 @@ func (c *SSHClient) ConnectWith(host string, dialer SSHDialFunc) error {
155188
// Run runs the task.Run command remotely on c.host.
156189
func (c *SSHClient) Run(task *Task) error {
157190
if c.running {
158-
return fmt.Errorf("Session already running")
191+
return fmt.Errorf("session already running")
159192
}
160193
if c.sessOpened {
161-
return fmt.Errorf("Session already connected")
194+
return fmt.Errorf("session already connected")
162195
}
163196

164197
sess, err := c.conn.NewSession()

sup.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func (sup *Stackup) Run(network *Network, envVars EnvList, commands ...*Command)
4141
// Create clients for every host (either SSH or Localhost).
4242
var bastion *SSHClient
4343
if network.Bastion != "" {
44-
bastion = &SSHClient{}
44+
bastion = &SSHClient{
45+
password: network.Password,
46+
}
4547
if err := bastion.Connect(network.Bastion); err != nil {
4648
return errors.Wrap(err, "connecting to bastion failed")
4749
}
@@ -71,9 +73,10 @@ func (sup *Stackup) Run(network *Network, envVars EnvList, commands ...*Command)
7173

7274
// SSH client.
7375
remote := &SSHClient{
74-
env: env + `export SUP_HOST="` + host + `";`,
75-
user: network.User,
76-
color: Colors[i%len(Colors)],
76+
env: env + `export SUP_HOST="` + host + `";`,
77+
user: network.User,
78+
color: Colors[i%len(Colors)],
79+
password: network.Password,
7780
}
7881

7982
if bastion != nil {

supfile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Network struct {
2828
Inventory string `yaml:"inventory"`
2929
Hosts []string `yaml:"hosts"`
3030
Bastion string `yaml:"bastion"` // Jump host for the environment
31+
Password string `yaml:"password"`
3132

3233
// Should these live on Hosts too? We'd have to change []string to struct, even in Supfile.
3334
User string // `yaml:"user"`

0 commit comments

Comments
 (0)