mirror of
https://github.com/appleboy/drone-ssh.git
synced 2026-06-16 14:49:25 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d0a886109 | |||
| a83bebeafe | |||
| a41d4afc40 | |||
| 91fd4f8071 | |||
| b34fffdbd3 | |||
| d217773bac | |||
| ae023d7aa6 | |||
| 222545746b | |||
| a5f89304fd |
@@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
- name: setup sshd server
|
- name: setup sshd server
|
||||||
run: |
|
run: |
|
||||||
apk add git make curl perl bash build-base zlib-dev ucl-dev
|
apk add git make curl perl bash build-base zlib-dev ucl-dev sudo
|
||||||
make ssh-server
|
make ssh-server
|
||||||
|
|
||||||
- name: testing
|
- name: testing
|
||||||
|
|||||||
@@ -104,10 +104,21 @@ ssh-server:
|
|||||||
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
|
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
|
||||||
chmod 600 /home/drone-scp/.ssh/authorized_keys
|
chmod 600 /home/drone-scp/.ssh/authorized_keys
|
||||||
chown -R drone-scp /home/drone-scp/.ssh
|
chown -R drone-scp /home/drone-scp/.ssh
|
||||||
|
# add public key to root user
|
||||||
|
mkdir -p /root/.ssh
|
||||||
|
chmod 700 /root/.ssh
|
||||||
|
cat tests/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
|
||||||
|
cat tests/.ssh/test.pub >> /root/.ssh/authorized_keys
|
||||||
|
chmod 600 /root/.ssh/authorized_keys
|
||||||
|
# Append the following entry to run ALL command without a password for a user named drone-scp:
|
||||||
|
cat tests/sudoers >> /etc/sudoers.d/sudoers
|
||||||
|
# install ssh and start server
|
||||||
apk add --update openssh openrc
|
apk add --update openssh openrc
|
||||||
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
|
rm -rf /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_dsa_key
|
||||||
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
|
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
|
||||||
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
|
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
|
||||||
|
sed -i 's/^#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/g' /etc/ssh/sshd_config
|
||||||
|
sed -i 's/^#ListenAddress ::/ListenAddress ::/g' /etc/ssh/sshd_config
|
||||||
./tests/entrypoint.sh /usr/sbin/sshd -D &
|
./tests/entrypoint.sh /usr/sbin/sshd -D &
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ require (
|
|||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/urfave/cli/v2 v2.27.1
|
github.com/urfave/cli/v2 v2.27.1
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.18.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -18,6 +18,6 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,15 +25,15 @@ github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7v
|
|||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -38,11 +38,10 @@ func main() {
|
|||||||
app.Version = Version
|
app.Version = Version
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "host",
|
Name: "host",
|
||||||
Aliases: []string{"H"},
|
Aliases: []string{"H"},
|
||||||
Usage: "connect to host",
|
Usage: "connect to host",
|
||||||
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
|
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
|
||||||
FilePath: ".host",
|
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "port",
|
Name: "port",
|
||||||
@@ -53,7 +52,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "protocol",
|
Name: "protocol",
|
||||||
Usage: "The IP protocol to use. Default to tcp (both IPv4 and IPv6).",
|
Usage: "The IP protocol to use. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
|
||||||
EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
|
EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
|
||||||
Value: "tcp",
|
Value: "tcp",
|
||||||
},
|
},
|
||||||
@@ -149,8 +148,8 @@ func main() {
|
|||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.protocol",
|
Name: "proxy.protocol",
|
||||||
Usage: "The IP protocol to use for the proxy. Default to tcp (both IPv4 and IPv6).",
|
Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
|
||||||
EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
|
EnvVars: []string{"PLUGIN_PROXY_PROTOCOL", "SSH_PROXY_PROTOCOL", "INPUT_PROXY_PROTOCOL"},
|
||||||
Value: "tcp",
|
Value: "tcp",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
@@ -220,6 +219,11 @@ func main() {
|
|||||||
Usage: "pass all environment variable to shell script",
|
Usage: "pass all environment variable to shell script",
|
||||||
EnvVars: []string{"PLUGIN_ALLENVS", "INPUT_ALLENVS"},
|
EnvVars: []string{"PLUGIN_ALLENVS", "INPUT_ALLENVS"},
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "request-pty",
|
||||||
|
Usage: "request a pseudo-terminal from the server",
|
||||||
|
EnvVars: []string{"PLUGIN_REQUEST_PTY", "INPUT_REQUEST_PTY"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override a template
|
// Override a template
|
||||||
@@ -288,6 +292,7 @@ func run(c *cli.Context) error {
|
|||||||
Ciphers: c.StringSlice("ciphers"),
|
Ciphers: c.StringSlice("ciphers"),
|
||||||
UseInsecureCipher: c.Bool("useInsecureCipher"),
|
UseInsecureCipher: c.Bool("useInsecureCipher"),
|
||||||
AllEnvs: c.Bool("allenvs"),
|
AllEnvs: c.Bool("allenvs"),
|
||||||
|
RequireTty: c.Bool("request-pty"),
|
||||||
Proxy: easyssh.DefaultConfig{
|
Proxy: easyssh.DefaultConfig{
|
||||||
Key: c.String("proxy.ssh-key"),
|
Key: c.String("proxy.ssh-key"),
|
||||||
KeyPath: c.String("proxy.key-path"),
|
KeyPath: c.String("proxy.key-path"),
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ type (
|
|||||||
UseInsecureCipher bool
|
UseInsecureCipher bool
|
||||||
EnvsFormat string
|
EnvsFormat string
|
||||||
AllEnvs bool
|
AllEnvs bool
|
||||||
|
RequireTty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin structure
|
// Plugin structure
|
||||||
@@ -60,7 +61,9 @@ func escapeArg(arg string) string {
|
|||||||
func (p Plugin) hostPort(host string) (string, string) {
|
func (p Plugin) hostPort(host string) (string, string) {
|
||||||
hosts := strings.Split(host, ":")
|
hosts := strings.Split(host, ":")
|
||||||
port := strconv.Itoa(p.Config.Port)
|
port := strconv.Itoa(p.Config.Port)
|
||||||
if len(hosts) > 1 {
|
if len(hosts) > 1 &&
|
||||||
|
(p.Config.Protocol == easyssh.PROTOCOL_TCP ||
|
||||||
|
p.Config.Protocol == easyssh.PROTOCOL_TCP4) {
|
||||||
host = hosts[0]
|
host = hosts[0]
|
||||||
port = hosts[1]
|
port = hosts[1]
|
||||||
}
|
}
|
||||||
@@ -85,6 +88,7 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
|
|||||||
Ciphers: p.Config.Ciphers,
|
Ciphers: p.Config.Ciphers,
|
||||||
Fingerprint: p.Config.Fingerprint,
|
Fingerprint: p.Config.Fingerprint,
|
||||||
UseInsecureCipher: p.Config.UseInsecureCipher,
|
UseInsecureCipher: p.Config.UseInsecureCipher,
|
||||||
|
RequestPty: p.Config.RequireTty,
|
||||||
Proxy: easyssh.DefaultConfig{
|
Proxy: easyssh.DefaultConfig{
|
||||||
Server: p.Config.Proxy.Server,
|
Server: p.Config.Proxy.Server,
|
||||||
User: p.Config.Proxy.User,
|
User: p.Config.Proxy.User,
|
||||||
|
|||||||
+77
-1
@@ -797,7 +797,8 @@ func TestPlugin_hostPort(t *testing.T) {
|
|||||||
name: "different port",
|
name: "different port",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
Port: 22,
|
Port: 22,
|
||||||
|
Protocol: easyssh.PROTOCOL_TCP4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
@@ -806,6 +807,20 @@ func TestPlugin_hostPort(t *testing.T) {
|
|||||||
wantHost: "localhost",
|
wantHost: "localhost",
|
||||||
wantPort: "443",
|
wantPort: "443",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ipv6",
|
||||||
|
fields: fields{
|
||||||
|
Config: Config{
|
||||||
|
Port: 22,
|
||||||
|
Protocol: easyssh.PROTOCOL_TCP6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
h: "::1",
|
||||||
|
},
|
||||||
|
wantHost: "::1",
|
||||||
|
wantPort: "22",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -919,3 +934,64 @@ out: [foobar]
|
|||||||
|
|
||||||
assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSudoCommand(t *testing.T) {
|
||||||
|
var (
|
||||||
|
buffer bytes.Buffer
|
||||||
|
expected = `
|
||||||
|
======CMD======
|
||||||
|
sudo su - -c "whoami"
|
||||||
|
======END======
|
||||||
|
out: root
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin := Plugin{
|
||||||
|
Config: Config{
|
||||||
|
Host: []string{"localhost"},
|
||||||
|
Username: "drone-scp",
|
||||||
|
Port: 22,
|
||||||
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
|
Script: []string{
|
||||||
|
`sudo su - -c "whoami"`,
|
||||||
|
},
|
||||||
|
CommandTimeout: 10 * time.Second,
|
||||||
|
RequireTty: true,
|
||||||
|
},
|
||||||
|
Writer: &buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, plugin.Exec())
|
||||||
|
assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: TestCommandWithIPv6 is not working on github actions.
|
||||||
|
// func TestCommandWithIPv6(t *testing.T) {
|
||||||
|
// var (
|
||||||
|
// buffer bytes.Buffer
|
||||||
|
// expected = `
|
||||||
|
// ======CMD======
|
||||||
|
// whoami
|
||||||
|
// ======END======
|
||||||
|
// out: drone-scp
|
||||||
|
// `
|
||||||
|
// )
|
||||||
|
|
||||||
|
// plugin := Plugin{
|
||||||
|
// Config: Config{
|
||||||
|
// Host: []string{"::1"},
|
||||||
|
// Username: "drone-scp",
|
||||||
|
// Port: 22,
|
||||||
|
// KeyPath: "./tests/.ssh/id_rsa",
|
||||||
|
// Script: []string{
|
||||||
|
// "whoami",
|
||||||
|
// },
|
||||||
|
// Protocol: easyssh.PROTOCOL_TCP6,
|
||||||
|
// CommandTimeout: 10 * time.Second,
|
||||||
|
// },
|
||||||
|
// Writer: &buffer,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// assert.Nil(t, plugin.Exec())
|
||||||
|
// assert.Equal(t, unindent(expected), unindent(buffer.String()))
|
||||||
|
// }
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Defaults requiretty
|
||||||
|
drone-scp ALL=(ALL) NOPASSWD:ALL
|
||||||
Reference in New Issue
Block a user