Compare commits

...

47 Commits

Author SHA1 Message Date
appleboy 7d0a886109 refactor: remove unnecessary line setting FilePath field to .host
- Remove the line that sets the `FilePath` field to `.host`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-01-27 11:22:04 +08:00
Bo-Yi Wu a83bebeafe refactor: refactor environment variable naming
- Rename environment variables to include `_PROXY_` in their names

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-21 09:35:37 +08:00
Bo-Yi Wu a41d4afc40 chore(protocol): improve IPv6 address. (#268)
* docs: improve documentation and configuration handling

- Clarify valid values for the IP protocol in usage messages for both main application and proxy settings

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* test: improve IPv6 command execution tests

- Add a new test function `TestCommandWithIPv6` to check command execution with an IPv6 address
- Initialize test variables and expected output for the IPv6 command test
- Set up a `Plugin` struct with IPv6 host, user, port, key path, script, and command timeout for testing
- Verify that `plugin.Exec()` returns `nil` (no error) in the IPv6 test
- Assert that the output of the command execution matches the expected output in the IPv6 test

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* test: enhance test suite and CI robustness

- Add support for IPv6 protocol in `TestCommandWithIPv6` test case in `plugin_test.go`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update2

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update3

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update4

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update5

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update5

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* update5

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

---------

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-21 09:27:49 +08:00
Bo-Yi Wu 91fd4f8071 chore: update golang.org/x/crypto to v0.18.0 in go.mod file
- Update golang.org/x/crypto from v0.17.0 to v0.18.0 in the go.mod file

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-11 20:53:31 +08:00
Bo-Yi Wu b34fffdbd3 feat: update plugin functionality in main.go and plugin.go files
- Add a new flag to the main.go file
- Add a new field to the Plugin type in the plugin.go file
- Remove two lines from the plugin_test.go file

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-07 17:44:54 +08:00
Bo-Yi Wu d217773bac test: increase test coverage for SudoCommand function
- Add a test for the SudoCommand function

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-07 17:40:23 +08:00
Bo-Yi Wu ae023d7aa6 chore: update sudoers file for improved security and permissions management
- Add `requiretty` to the `Defaults` in sudoers
- Allow `drone-scp` to run commands without password prompt

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-07 17:21:59 +08:00
Bo-Yi Wu 222545746b chore: refactor build and deployment processes
- Add `sudo` to the apk add command in the lint workflow
- Add SSH server setup to the Makefile

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-07 17:13:16 +08:00
Bo-Yi Wu a5f89304fd chore: update golang.org/x/sys to v0.16.0 in go.mod file
- Update the version of `golang.org/x/sys` from `v0.15.0` to `v0.16.0` in the `go.mod` file

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-07 13:38:54 +08:00
Bo-Yi Wu a9cfc0c134 chore: update external dependencies to latest versions
- Update the version of `github.com/appleboy/easyssh-proxy` from `v1.4.1-0.20231106031702-5666e2ea5156` to `v1.5.0`
- Update the version of `github.com/urfave/cli/v2` from `v2.26.0` to `v2.27.1`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-01-01 13:53:45 +08:00
Bo-Yi Wu 13ba21acf6 chore: update dependencies to latest versions
- Update `github.com/urfave/cli` dependency from `v2.25.7` to `v2.26.0`
- Upgrade `golang.org/x/crypto` from `v0.14.0` to `v0.17.0`
- Bump `github.com/cpuguy83/go-md2man` from `v2.0.2` to `v2.0.3`
- Update `github.com/xrash/smetrics` to a newer commit
- Update `golang.org/x/sys` from `v0.14.0` to `v0.15.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-26 13:33:32 +08:00
Bo-Yi Wu e270b033d1 ci: update dependencies and workflows
- Update the Golang version in the lint workflow from `1.19-alpine` to `1.21-alpine`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-26 13:29:44 +08:00
Bo-Yi Wu aa9314a009 chore: add default user for enhanced security (#267)
- Add a new `.hadolint.yaml` configuration file with specific rule ignores
- Update the Dockerfile to install `ca-certificates` without a fixed version
- Add commands to create a `deploy` user and group with UID and GID `1000`, set home directory, and set ownership
- Set the Docker container to run as the `deploy` user with UID and GID `1000`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-12-26 13:29:22 +08:00
Bo-Yi Wu 037e0231ac chore: update dependencies to latest versions
- Update the `go-version` in the lint.yml file from `^1` to `^1.21`
- Update the version of `github.com/appleboy/easyssh-proxy` in the go.mod file from `v1.4.0` to `v1.4.1-0.20231106031702-5666e2ea5156`
- Update the version of `golang.org/x/crypto` in the go.mod file from `v0.10.0` to `v0.14.0`
- Update the version of `golang.org/x/sys` in the go.mod file from `v0.9.0` to `v0.14.0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-11-06 11:20:51 +08:00
Bo-Yi Wu ddf1b161aa chore: refactor GitHub Actions workflows
- Fix a typo in the cron expression for the codeql.yml workflow
- Change the language specification from ['go'] to ['go'] in the codeql.yml workflow
- Change the version specification from 'v*' to 'v*' in the docker.yml workflow
- Change the branch specification from 'master' to 'master' in the docker.yml workflow
- Change the go-version specification from '^1' to '^1.21' in the docker.yml workflow
- Remove the name "Set up QEMU" in the docker.yml workflow
- Remove the name "Set up Docker Buildx" in the docker.yml workflow
- Remove the name "Login to Docker Hub" in the docker.yml workflow
- Remove the name "Login to GitHub Container Registry" in the docker.yml workflow
- Remove the name "Docker meta" in the docker.yml workflow
- Remove the name "Build and push" in the docker.yml workflow
- Change the version specification from '*' to '*' in the goreleaser.yml workflow
- Remove the name "Checkout" in the goreleaser.yml workflow
- Remove the name "Setup go" in the goreleaser.yml workflow
- Change the go-version specification from '^1' to '^1' in the goreleaser.yml workflow
- Remove the name "Run GoReleaser" in the goreleaser.yml workflow
- Change the go-version specification from '^1' to '^1' in the lint.yml workflow

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-10-25 10:52:46 +08:00
Bo-Yi Wu 32510c86bf feat: implement and test all environment variables functionality (#264)
- Add a new flag `allenvs` to pass all environment variables to the shell script
- Implement the `AllEnvs` functionality in the `exec` function
- Add a new function `findEnvs` to find all environment variables with specified prefixes
- Add tests for the `findEnvs` function and the `AllEnvs` functionality
2023-07-23 09:41:09 +08:00
appleboy 80cecf1ed3 refactor: improve code clarity and logging functionality
- Add a comment to clarify the purpose of the `format` function
- Add a comment to clarify the purpose of the `log` function
- Modify the `log` function to always print the message, removing the previous conditional statement

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-07-23 07:30:08 +08:00
appleboy c7dd9890fa chore: improve performance and test coverage across OSs
- Update easyssh-proxy dependency from v1.3.11 to v1.4.0

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-06-23 23:43:57 +08:00
Yoan Tournade 905bb4cb1a chore: allows to specify IP protocol (#261)
* Allows to specify IP protocol, including IPv4 only

* Add tests forcing IPv4 or IPv6
2023-06-23 16:45:44 +08:00
Bo-Yi Wu 066b72ac09 chore: update dependencies and improve test accuracy
- Update urfave/cli/v2 from v2.25.5 to v2.25.7
- Update golang.org/x/crypto from v0.9.0 to v0.10.0
- Update golang.org/x/sys from v0.8.0 to v0.9.0 (indirect)

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-06-21 16:25:15 +08:00
Bo-Yi Wu b33ad90151 chore: improve API efficiency and test robustness
- Update ca-certificates version from `20220614-r4` to `20230506-r0`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-06-04 16:46:53 +08:00
Bo-Yi Wu c4f4d0f112 chore: improve performance and update dependencies
- Add `bin` to .gitignore
- Change output path for the executable in Makefile
- Update `github.com/stretchr/testify` to v1.8.4
- Update `github.com/urfave/cli/v2` to v2.25.5

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-06-04 16:44:10 +08:00
appleboy 8b81da22bc chore: update dependencies and improve test tolerance
- Update `github.com/urfave/cli/v2` dependency from `v2.25.3` to `v2.25.4`
- Update `golang.org/x/crypto` dependency from `v0.8.0` to `v0.9.0`

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-29 21:07:06 +08:00
appleboy ba70ad67ca ci: improve release process and test robustness
- Add extra_files with .xz glob pattern to .goreleaser.yaml

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 08:16:02 +08:00
appleboy 73fa4739e3 chore: optimize codebase with latest library updates
- Update `github.com/urfave/cli/v2` from `v2.25.1` to `v2.25.3`
- Update `golang.org/x/sys` from `v0.7.0` to `v0.8.0` (indirect)

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 08:00:17 +08:00
appleboy 0a721bdfff build: optimize binary size and improve test accuracy
- Add a post-build hook to compress the generated binary with `xz` at level 9 compression

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 07:57:07 +08:00
appleboy a7c7568d70 feat: improve API usage and test coverage across platforms
- Add an option to include extra pre-existing files in the release with a specified file format (`.xz`)

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-06 07:51:54 +08:00
appleboy bc8c96633a chore: improve API usage and test accuracy
- Add "strconv" import
- Update app copyright to use the current year

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2023-05-01 11:56:09 +08:00
Bo-Yi.Wu 30b18520ed refactor(setting): reorder format. 2023-04-15 06:25:31 +08:00
Bo-Yi Wu 67a2631616 docs: improve clarity of Usage message in main.go
- Modify the `Usage` message in main.go

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-04-13 09:48:46 +08:00
Alexey Smirnov fdc4c8de43 fix: example with secrets (#178) 2023-04-13 09:39:43 +08:00
Bo-Yi Wu 49542638c6 refactor: set default environment variables format in plugin (#253)
- Add `INPUT_ENVS_FORMAT` to the list of environment variables in `main.go`
- Define `envsFormat` variable in `plugin.go`
- Add default value for `Config.EnvsFormat` in `plugin.go` `Exec()` function

fix https://github.com/appleboy/drone-ssh/pull/235
2023-04-13 09:32:31 +08:00
Vladimir Sigalkin 6464d9999f chore: flexible configuration of environment value transfer (#235)
**Reason:**
I have to use drone-ssh to work with Windows SSH. Initially, drone-ssh is written so that it transmits environment variables through the `export` command. Which makes it unsuitable for working with Power Shell.

**Solution:**
I have added a new option to configure environment variable commands formatting, with default value: `export {NAME}={VALUE}`. When I use drone-ssh with PowerShell I set this option like this: `$env:{NAME} = {VALUE}`.
2023-04-13 09:13:07 +08:00
Bo-Yi Wu 4aabfc90dd chore: upgrade Dependencies to Latest Versions
- Upgrade easyssh-proxy from v1.3.9 to v1.3.10
- Upgrade testify from v1.8.1 to v1.8.2
- Upgrade crypto from v0.7.0 to v0.8.0
- Upgrade sys from v0.6.0 to v0.7.0

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-04-13 09:09:37 +08:00
Bo-Yi Wu b9cfca60e9 refactor: standardize environment variables naming conventions (#252)
- Modify the `EnvVars` slice to include `INPUT_` prefix when needed
- Remove unused environment variables from the `EnvVars` slice
- Update the `EnvVars` slice to include `PROXY_` prefix when needed
- Modify the `EnvVars` slice to include `PLUGIN_SSH_CIPHERS` as `PROXY_SSH_CIPHERS`
- Modify the `EnvVars` slice to include `PLUGIN_PROXY_USE_INSECURE_CIPHER` as `PROXY_SSH_USE_INSECURE_CIPHER`
- Modify the `EnvVars` slice to include `PLUGIN_PROXY_FINGERPRINT` as `PROXY_SSH_FINGERPRINT`
- Remove the environment variable `PROXY_HOST`
- Modify the `EnvVars` slice to include `PLUGIN_DEBUG` as `INPUT_DEBUG`

* https://github.com/appleboy/ssh-action/issues/53#issuecomment-1184700432
* https://github.com/appleboy/ssh-action/issues/32#issuecomment-1184700363
* https://github.com/appleboy/ssh-action/issues/213
2023-04-13 09:08:12 +08:00
Bo-Yi Wu a8d30dc133 feat: refactor code for parallel execution on multiple hosts (#249)
- Add `trimValues` function for cleaning up slice values
- Remove unused `wg.Done()` call
- Modify `Exec` function to launch goroutines for each host in `Config.Host`
- Add test for `ScriptStop` with multiple hosts and sync mode

refer to: https://github.com/appleboy/ssh-action/issues/233
2023-04-04 16:56:50 +08:00
Bo-Yi.Wu f733bb5ebf chore: remove Hadolint configuration file
- Delete the `.hadolint.yaml` file.

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-04 15:39:10 +08:00
Bo-Yi.Wu b0ddeb9413 chore: update container security measures
- Add Open Container Initiative labels for image source, description, and licenses
- Update `apk` command to include specific version of `ca-certificates`

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-04-04 15:38:42 +08:00
Bo-Yi Wu 8c5d17d83d chore: refactor release process to use main.Version flag
- Change the `drone-ssh` version flag to `main.Version` in `.goreleaser.yaml`

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-03-29 08:59:31 +08:00
Bo-Yi Wu 050e0e6efd docs: use ghcr.io/appleboy/drone-ssh image for SSH connections
- Update the `image` field to use `ghcr.io/appleboy/drone-ssh` in DOCS.md
- Update the `image` field to use `ghcr.io/appleboy/drone-ssh` in README.md

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2023-03-28 14:43:00 +08:00
Bo-Yi Wu f01d5d9454 chore(deps): update go.sum 2023-03-28 14:23:20 +08:00
Bo-Yi.Wu c004469746 ci: upgrade setup-go action and remove release binary action
- Remove release binary github action
- Upgrade setup-go action from v3 to v4 in docker, goreleaser, and lint github actions

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-03-27 22:02:48 +08:00
Bo-Yi.Wu bc2dac669a chore: refactor installation command for drone-ssh using go install
- Update `drone-ssh` installation command to use `go install` instead of `go get`

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-03-27 22:01:11 +08:00
Albert Wang 541508632d chore: remove dotenv autoloading (#243) 2023-03-27 21:56:04 +08:00
Bo-Yi.Wu 22cd751b47 chore: update third-party libraries for improved security and performance
- Update urfave/cli to version 2.25.1
- Update golang.org/x/crypto to version 0.7.0
- Update golang.org/x/sys to version 0.6.0 (indirect)

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-03-27 21:52:44 +08:00
Bo-Yi.Wu 5a6a923356 build: configure cross-platform builds with Goreleaser
- Add a new file `.goreleaser.yaml`
- Configure builds for multiple operating systems and architectures
- Set flags and ldflags for the builds
- Add a binary name template for the builds
- Add an archive format
- Add a checksum template
- Add a snapshot template

Signed-off-by: Bo-Yi.Wu <appleboy.tw@gmail.com>
2023-03-27 21:51:52 +08:00
Bo-Yi Wu 1a95b5f1b3 chore(auth): allow use password and key at same time (#240) 2023-02-28 17:04:39 +08:00
18 changed files with 673 additions and 248 deletions
-24
View File
@@ -1,24 +0,0 @@
name: Release Binary
on:
push:
branches:
- master
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
container: techknowlogick/xgo:go-1.19.x
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
# - name: Release binary
# run: |
# ls -al
# make release
+17 -17
View File
@@ -13,12 +13,12 @@ name: "CodeQL"
on:
push:
branches: [ master ]
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [master]
schedule:
- cron: '41 23 * * 6'
- cron: "41 23 * * 6"
jobs:
analyze:
@@ -32,23 +32,23 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
language: ["go"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+12 -17
View File
@@ -5,54 +5,50 @@ on:
branches:
- master
tags:
- 'v*'
- "v*"
pull_request:
branches:
- 'master'
- "master"
jobs:
build-docker:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: '^1'
go-version: "^1.21"
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build binary
run : |
run: |
make build_linux_amd64
make build_linux_arm
make build_linux_arm64
-
name: Set up QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
-
name: Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GitHub Container Registry
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Docker meta
- name: Docker meta
id: docker-meta
uses: docker/metadata-action@v4
with:
@@ -65,8 +61,7 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
-
name: Build and push
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
+6 -9
View File
@@ -3,7 +3,7 @@ name: Goreleaser
on:
push:
tags:
- '*'
- "*"
permissions:
contents: write
@@ -12,19 +12,16 @@ jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
-
name: Setup go
uses: actions/setup-go@v3
- name: Setup go
uses: actions/setup-go@v4
with:
go-version: '^1'
go-version: "^1"
-
name: Run GoReleaser
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v4
with:
# either 'goreleaser' (default) or 'goreleaser-pro'
+4 -4
View File
@@ -9,9 +9,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Setup go
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: '^1'
go-version: "^1.21"
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup golangci-lint
@@ -27,14 +27,14 @@ jobs:
testing:
runs-on: ubuntu-latest
container: golang:1.19-alpine
container: golang:1.21-alpine
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: setup sshd server
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
- name: testing
+1
View File
@@ -29,3 +29,4 @@ release
drone-ssh
.cover
dist
bin
+99
View File
@@ -0,0 +1,99 @@
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- darwin
- linux
- windows
- freebsd
goarch:
- amd64
- arm
- arm64
goarm:
- "5"
- "6"
- "7"
ignore:
- goos: darwin
goarch: arm
- goos: darwin
goarch: ppc64le
- goos: darwin
goarch: s390x
- goos: windows
goarch: ppc64le
- goos: windows
goarch: s390x
- goos: windows
goarch: arm
goarm: "5"
- goos: windows
goarch: arm
goarm: "6"
- goos: windows
goarch: arm
goarm: "7"
- goos: windows
goarch: arm64
- goos: freebsd
goarch: ppc64le
- goos: freebsd
goarch: s390x
- goos: freebsd
goarch: arm
goarm: "5"
- goos: freebsd
goarch: arm
goarm: "6"
- goos: freebsd
goarch: arm
goarm: "7"
- goos: freebsd
goarch: arm64
flags:
- -trimpath
ldflags:
- -s -w
- -X main.Version={{.Version}}
binary: >-
{{ .ProjectName }}-
{{- if .IsSnapshot }}{{ .Branch }}-
{{- else }}{{- .Version }}-{{ end }}
{{- .Os }}-
{{- if eq .Arch "amd64" }}amd64
{{- else if eq .Arch "amd64_v1" }}amd64
{{- else if eq .Arch "386" }}386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}-{{ .Arm }}{{ end }}
no_unique_dist_dir: true
hooks:
post:
- cmd: xz -k -9 {{ .Path }}
dir: ./dist/
archives:
- format: binary
name_template: "{{ .Binary }}"
allow_different_binary_count: true
checksum:
name_template: 'checksums.txt'
extra_files:
- glob: ./**.xz
snapshot:
name_template: "{{ incpatch .Version }}"
release:
# You can add extra pre-existing files to the release.
# The filename on the release will be the last part of the path (base).
# If another file with the same name exists, the last one found will be used.
#
# Templates: allowed
extra_files:
- glob: ./**.xz
+1
View File
@@ -1,2 +1,3 @@
ignored:
- DL3018
- DL3008
+35 -15
View File
@@ -5,14 +5,14 @@ author: appleboy
tags: [ deploy, publish, ssh ]
repo: appleboy/drone-ssh
logo: term.svg
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
---
Use the SSH plugin to execute commands on a remote server. The below pipeline configuration demonstrates simple usage:
```yaml
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -27,7 +27,7 @@ Example configuration in your `.drone.yml` file for multiple hosts:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host:
+ - foo.com
@@ -44,7 +44,7 @@ Example configuration for multiple hosts with different port:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host:
+ - foo.com:1234
@@ -61,7 +61,7 @@ Example configuration for command timeout, default value is 60 seconds:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -77,7 +77,7 @@ Example configuration for execute commands on a remote server using SSHProxyC
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -96,7 +96,7 @@ Example configuration using password from secrets:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -112,7 +112,7 @@ Example configuration using ssh key from secrets:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -128,27 +128,28 @@ Example configuration for exporting custom secrets:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
environment:
commit: ${DRONE_BUILD_NUMBER}
# MUST BE in UPPERCASE
COMMIT:
from_secret: commit
settings:
host: foo.com
username: root
password: 1234
port: 22
+ envs:
- aws_access_key_id
# can be in lowercase (uppercased in code)
- commit
script:
- export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
- echo $commit
- echo $COMMIT
```
Example configuration for stoping script after first failure:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -164,7 +165,7 @@ Example configuration for passphrase which protecting a private key:
```diff
- name: ssh commands
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
@@ -177,6 +178,23 @@ Example configuration for passphrase which protecting a private key:
- echo "you can't see the steps."
```
Example configuration for forcing protocol to IPv4 only:
```diff
- name: ssh commands
image: ghcr.io/appleboy/drone-ssh
settings:
host: foo.com
username: root
password: 1234
port: 22
+ protocol: tcp4
script:
- echo hello
- echo world
```
## Secret Reference
| Key | Description |
@@ -196,6 +214,7 @@ Example configuration for passphrase which protecting a private key:
|-----|-------------|
| `host` | target hostname or IP |
| `port` | ssh port of target host |
| `protocol` | IP protocol to use: either tcp, tcp4 or tcp6 |
| `username` | account for target host user |
| `password` | password for target host user |
| `key` | plain text of user private key |
@@ -207,6 +226,7 @@ Example configuration for passphrase which protecting a private key:
| `command_timeout` | Command timeout is the maximum amount of time for the execute commands, default is 10 minutes. |
| `proxy_host` | proxy hostname or IP |
| `proxy_port` | ssh port of proxy host |
| `proxy_protocol` | IP protocol to use for the proxy: either tcp, tcp4 or tcp6 |
| `proxy_username` | account for proxy host user |
| `proxy_password` | password for proxy host user |
| `proxy_key` | plain text of proxy private key |
+12 -1
View File
@@ -81,7 +81,7 @@ install: $(GOFILES)
build: $(EXECUTABLE)
$(EXECUTABLE): $(GOFILES)
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o $@
$(GO) build -v -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o bin/$@
build_linux_amd64:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -a -tags '$(TAGS)' -ldflags '$(EXTLDFLAGS)-s -w $(LDFLAGS)' -o release/linux/amd64/$(DEPLOY_IMAGE)
@@ -104,10 +104,21 @@ ssh-server:
cat tests/.ssh/test.pub >> /home/drone-scp/.ssh/authorized_keys
chmod 600 /home/drone-scp/.ssh/authorized_keys
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
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/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 &
coverage:
+6 -7
View File
@@ -23,7 +23,7 @@ information and a listing of the available options please take a look at [the do
```diff
pipeline:
scp:
image: appleboy/drone-scp
image: ghcr.io/appleboy/drone-ssh
settings:
host:
- example1.com
@@ -49,7 +49,7 @@ The pre-compiled binaries can be downloaded from [release page](https://github.c
With `Go` installed
```sh
go get -u -v github.com/appleboy/drone-ssh
go install github.com/appleboy/drone-ssh@latest
```
or build the binary with the following command:
@@ -85,7 +85,7 @@ docker run --rm \
-e PLUGIN_SCRIPT=whoami \
-v $(pwd):$(pwd) \
-w $(pwd) \
appleboy/drone-ssh
ghcr.io/appleboy/drone-ssh
```
## Mount key from file path
@@ -99,7 +99,7 @@ Mount private key in `volumes` setting of `.drone.yml` config
```diff
pipeline:
ssh:
image: appleboy/drone-ssh
image: ghcr.io/appleboy/drone-ssh
host: xxxxx.com
username: deploy
+ volumes:
@@ -118,8 +118,7 @@ See [DOCS.md](./DOCS.md) for examples and full configuration options
Configuration options are loaded from multiple sources:
0. Hardcoded drone-ssh defaults. See [main.go CLI Flags](https://github.com/appleboy/drone-ssh/blob/6d9d6acc6aef1f9166118c6ba8bd214d3a582bdb/main.go#L39) for more information.
1. From a `.env` [dotenv](https://github.com/joho/godotenv) file at the root of the repository tested by drone.
2. From a dotenv file at a path specified by the `PLUGIN_ENV_FILE` environment variable.
3. From your `.drone.yml` Drone configuration.
1. From a dotenv file at a path specified by the `PLUGIN_ENV_FILE` environment variable.
2. From your `.drone.yml` Drone configuration.
Later sources override previous sources, i.e. if `PORT` is set in an `.env` file committed in the repository or created by previous test steps, it will override the default set `main.go`.
+21
View File
@@ -8,9 +8,30 @@ LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
org.label-schema.vendor="Bo-Yi Wu" \
org.label-schema.schema-version="1.0"
LABEL org.opencontainers.image.source=https://github.com/appleboy/drone-ssh
LABEL org.opencontainers.image.description="Execute commands on a remote host through SSH"
LABEL org.opencontainers.image.licenses=MIT
RUN apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
RUN addgroup \
-S -g 1000 \
deploy && \
adduser \
-S -H -D \
-h /home/deploy \
-s /bin/sh \
-u 1000 \
-G deploy \
deploy
RUN mkdir -p /home/deploy && \
chown deploy:deploy /home/deploy
# deploy:deploy
USER 1000:1000
COPY release/${TARGETOS}/${TARGETARCH}/drone-ssh /bin/
ENTRYPOINT ["/bin/drone-ssh"]
+7 -7
View File
@@ -3,21 +3,21 @@ module github.com/appleboy/drone-ssh
go 1.18
require (
github.com/appleboy/easyssh-proxy v1.3.9
github.com/appleboy/easyssh-proxy v1.5.0
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.8.1
github.com/urfave/cli/v2 v2.24.4
golang.org/x/crypto v0.6.0
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.27.1
golang.org/x/crypto v0.18.0
)
require (
github.com/ScaleFT/sshkeys v1.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/sys v0.5.0 // indirect
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
golang.org/x/sys v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+15 -25
View File
@@ -1,10 +1,9 @@
github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5/go.mod h1:gxOHeajFfvGQh/fxlC8oOKBe23xnnJTif00IFFbiT+o=
github.com/ScaleFT/sshkeys v1.2.0 h1:5BRp6rTVIhJzXT3VcUQrKgXR8zWA3sOsNeuyW15WUA8=
github.com/ScaleFT/sshkeys v1.2.0/go.mod h1:gxOHeajFfvGQh/fxlC8oOKBe23xnnJTif00IFFbiT+o=
github.com/appleboy/easyssh-proxy v1.3.9 h1:b+sVSTz+cVFvfA23HQywMMpm0s5g3gH7jYdBcQqaCQI=
github.com/appleboy/easyssh-proxy v1.3.9/go.mod h1:G1eQomBEME7NWKA3hE49s5HsT44S5fn0aBxX7k9Yjug=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/appleboy/easyssh-proxy v1.5.0 h1:OYdSPvYQN3mhnsMH5I2OF1TgwSEcSq33kvjQfTwvZww=
github.com/appleboy/easyssh-proxy v1.5.0/go.mod h1:zcEMrStH91/tcUn3gUGP0KpQwUYLm8tX/Ook1AH98uc=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -17,36 +16,27 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU=
github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
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-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
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/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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+98 -65
View File
@@ -3,11 +3,11 @@ package main
import (
"log"
"os"
"strconv"
"time"
"github.com/appleboy/easyssh-proxy"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
"github.com/urfave/cli/v2"
)
@@ -27,7 +27,7 @@ func main() {
app := cli.NewApp()
app.Name = "Drone SSH"
app.Usage = "Executing remote ssh commands"
app.Copyright = "Copyright (c) 2019 Bo-Yi Wu"
app.Copyright = "Copyright (c) " + strconv.Itoa(time.Now().Year()) + " Bo-Yi Wu"
app.Authors = []*cli.Author{
{
Name: "Bo-Yi Wu",
@@ -37,15 +37,54 @@ func main() {
app.Action = run
app.Version = Version
app.Flags = []cli.Flag{
&cli.StringSliceFlag{
Name: "host",
Aliases: []string{"H"},
Usage: "connect to host",
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "INPUT_HOST"},
},
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "connect to port",
EnvVars: []string{"PLUGIN_PORT", "SSH_PORT", "INPUT_PORT"},
Value: 22,
},
&cli.StringFlag{
Name: "protocol",
Usage: "The IP protocol to use. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
EnvVars: []string{"PLUGIN_PROTOCOL", "SSH_PROTOCOL", "INPUT_PROTOCOL"},
Value: "tcp",
},
&cli.StringFlag{
Name: "username",
Aliases: []string{"user", "u"},
Usage: "connect as user",
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SSH_USERNAME", "INPUT_USERNAME"},
Value: "root",
},
&cli.StringFlag{
Name: "password",
Aliases: []string{"P"},
Usage: "user password",
EnvVars: []string{"PLUGIN_PASSWORD", "SSH_PASSWORD", "INPUT_PASSWORD"},
},
&cli.DurationFlag{
Name: "timeout",
Aliases: []string{"t"},
Usage: "connection timeout",
EnvVars: []string{"PLUGIN_TIMEOUT", "SSH_TIMEOUT", "INPUT_TIMEOUT"},
Value: 30 * time.Second,
},
&cli.StringFlag{
Name: "ssh-key",
Usage: "private ssh key",
EnvVars: []string{"PLUGIN_SSH_KEY", "PLUGIN_KEY", "SSH_KEY", "KEY", "INPUT_KEY"},
EnvVars: []string{"PLUGIN_SSH_KEY", "PLUGIN_KEY", "SSH_KEY", "INPUT_KEY"},
},
&cli.StringFlag{
Name: "ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "PASSPHRASE", "INPUT_PASSPHRASE"},
EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "INPUT_PASSPHRASE"},
},
&cli.StringFlag{
Name: "key-path",
@@ -53,72 +92,38 @@ func main() {
Usage: "ssh private key path",
EnvVars: []string{"PLUGIN_KEY_PATH", "SSH_KEY_PATH", "INPUT_KEY_PATH"},
},
&cli.StringFlag{
Name: "username",
Aliases: []string{"user", "u"},
Usage: "connect as user",
EnvVars: []string{"PLUGIN_USERNAME", "PLUGIN_USER", "SSH_USERNAME", "USERNAME", "INPUT_USERNAME"},
Value: "root",
},
&cli.StringFlag{
Name: "password",
Aliases: []string{"P"},
Usage: "user password",
EnvVars: []string{"PLUGIN_PASSWORD", "SSH_PASSWORD", "PASSWORD", "INPUT_PASSWORD"},
},
&cli.StringSliceFlag{
Name: "ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVars: []string{"PLUGIN_CIPHERS", "SSH_CIPHERS", "CIPHERS", "INPUT_CIPHERS"},
EnvVars: []string{"PLUGIN_CIPHERS", "SSH_CIPHERS", "INPUT_CIPHERS"},
},
&cli.BoolFlag{
Name: "useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVars: []string{"PLUGIN_USE_INSECURE_CIPHER", "SSH_USE_INSECURE_CIPHER", "USE_INSECURE_CIPHER", "INPUT_USE_INSECURE_CIPHER"},
EnvVars: []string{"PLUGIN_USE_INSECURE_CIPHER", "SSH_USE_INSECURE_CIPHER", "INPUT_USE_INSECURE_CIPHER"},
},
&cli.StringFlag{
Name: "fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
EnvVars: []string{"PLUGIN_FINGERPRINT", "SSH_FINGERPRINT", "FINGERPRINT", "INPUT_FINGERPRINT"},
},
&cli.StringSliceFlag{
Name: "host",
Aliases: []string{"H"},
Usage: "connect to host",
EnvVars: []string{"PLUGIN_HOST", "SSH_HOST", "HOST", "INPUT_HOST"},
FilePath: ".host",
},
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "connect to port",
EnvVars: []string{"PLUGIN_PORT", "SSH_PORT", "PORT", "INPUT_PORT"},
Value: 22,
EnvVars: []string{"PLUGIN_FINGERPRINT", "SSH_FINGERPRINT", "INPUT_FINGERPRINT"},
},
&cli.BoolFlag{
Name: "sync",
Usage: "sync mode",
EnvVars: []string{"PLUGIN_SYNC", "SYNC", "INPUT_SYNC"},
},
&cli.DurationFlag{
Name: "timeout",
Aliases: []string{"t"},
Usage: "connection timeout",
EnvVars: []string{"PLUGIN_TIMEOUT", "SSH_TIMEOUT", "TIMEOUT", "INPUT_TIMEOUT"},
Value: 30 * time.Second,
EnvVars: []string{"PLUGIN_SYNC", "INPUT_SYNC"},
},
&cli.DurationFlag{
Name: "command.timeout",
Aliases: []string{"T"},
Usage: "command timeout",
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
Value: 10 * time.Minute,
},
&cli.StringSliceFlag{
Name: "script",
Aliases: []string{"s"},
Usage: "execute commands",
EnvVars: []string{"PLUGIN_SCRIPT", "SSH_SCRIPT", "SCRIPT"},
EnvVars: []string{"PLUGIN_SCRIPT", "SSH_SCRIPT"},
},
&cli.StringFlag{
Name: "script.string",
@@ -128,22 +133,24 @@ func main() {
&cli.BoolFlag{
Name: "script.stop",
Usage: "stop script after first failure",
EnvVars: []string{"PLUGIN_SCRIPT_STOP", "STOP", "INPUT_SCRIPT_STOP"},
EnvVars: []string{"PLUGIN_SCRIPT_STOP", "INPUT_SCRIPT_STOP"},
},
&cli.StringFlag{
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
Name: "proxy.host",
Usage: "connect to host of proxy",
EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "INPUT_PROXY_HOST"},
},
&cli.StringFlag{
Name: "proxy.ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "PROXY_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
Name: "proxy.port",
Usage: "connect to port of proxy",
EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "INPUT_PROXY_PORT"},
Value: "22",
},
&cli.StringFlag{
Name: "proxy.key-path",
Usage: "ssh private key path of proxy",
EnvVars: []string{"PLUGIN_PROXY_KEY_PATH", "PROXY_SSH_KEY_PATH", "INPUT_PROXY_KEY_PATH"},
Name: "proxy.protocol",
Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
EnvVars: []string{"PLUGIN_PROXY_PROTOCOL", "SSH_PROXY_PROTOCOL", "INPUT_PROXY_PROTOCOL"},
Value: "tcp",
},
&cli.StringFlag{
Name: "proxy.username",
@@ -157,15 +164,19 @@ func main() {
EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "INPUT_PROXY_PASSWORD"},
},
&cli.StringFlag{
Name: "proxy.host",
Usage: "connect to host of proxy",
EnvVars: []string{"PLUGIN_PROXY_HOST", "PROXY_SSH_HOST", "INPUT_PROXY_HOST"},
Name: "proxy.ssh-key",
Usage: "private ssh key of proxy",
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
},
&cli.StringFlag{
Name: "proxy.port",
Usage: "connect to port of proxy",
EnvVars: []string{"PLUGIN_PROXY_PORT", "PROXY_SSH_PORT", "INPUT_PROXY_PORT"},
Value: "22",
Name: "proxy.ssh-passphrase",
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
},
&cli.StringFlag{
Name: "proxy.key-path",
Usage: "ssh private key path of proxy",
EnvVars: []string{"PLUGIN_PROXY_KEY_PATH", "PROXY_SSH_KEY_PATH", "INPUT_PROXY_KEY_PATH"},
},
&cli.DurationFlag{
Name: "proxy.timeout",
@@ -175,17 +186,17 @@ func main() {
&cli.StringSliceFlag{
Name: "proxy.ciphers",
Usage: "The allowed cipher algorithms. If unspecified then a sensible",
EnvVars: []string{"PLUGIN_PROXY_CIPHERS", "SSH_PROXY_CIPHERS", "PROXY_CIPHERS", "INPUT_PROXY_CIPHERS"},
EnvVars: []string{"PLUGIN_PROXY_CIPHERS", "PROXY_SSH_CIPHERS", "INPUT_PROXY_CIPHERS"},
},
&cli.BoolFlag{
Name: "proxy.useInsecureCipher",
Usage: "include more ciphers with use_insecure_cipher",
EnvVars: []string{"PLUGIN_PROXY_USE_INSECURE_CIPHER", "SSH_PROXY_USE_INSECURE_CIPHER", "PROXY_USE_INSECURE_CIPHER", "INPUT_PROXY_USE_INSECURE_CIPHER"},
EnvVars: []string{"PLUGIN_PROXY_USE_INSECURE_CIPHER", "PROXY_SSH_USE_INSECURE_CIPHER", "INPUT_PROXY_USE_INSECURE_CIPHER"},
},
&cli.StringFlag{
Name: "proxy.fingerprint",
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
EnvVars: []string{"PLUGIN_PROXY_FINGERPRINT", "SSH_PROXY_FINGERPRINT", "PROXY_FINGERPRINT", "INPUT_PROXY_FINGERPRINT"},
EnvVars: []string{"PLUGIN_PROXY_FINGERPRINT", "PROXY_SSH_FINGERPRINT", "PROXY_FINGERPRINT", "INPUT_PROXY_FINGERPRINT"},
},
&cli.StringSliceFlag{
Name: "envs",
@@ -195,7 +206,23 @@ func main() {
&cli.BoolFlag{
Name: "debug",
Usage: "debug mode",
EnvVars: []string{"PLUGIN_DEBUG", "DEBUG", "INPUT_DEBUG"},
EnvVars: []string{"PLUGIN_DEBUG", "INPUT_DEBUG"},
},
&cli.StringFlag{
Name: "envs.format",
Usage: "flexible configuration of environment value transfer",
EnvVars: []string{"PLUGIN_ENVS_FORMAT", "INPUT_ENVS_FORMAT"},
Value: envsFormat,
},
&cli.BoolFlag{
Name: "allenvs",
Usage: "pass all environment variable to shell script",
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"},
},
}
@@ -242,6 +269,7 @@ func run(c *cli.Context) error {
if s := c.String("script.string"); s != "" {
scripts = append(scripts, s)
}
plugin := Plugin{
Config: Config{
Key: c.String("ssh-key"),
@@ -252,15 +280,19 @@ func run(c *cli.Context) error {
Fingerprint: c.String("fingerprint"),
Host: c.StringSlice("host"),
Port: c.Int("port"),
Protocol: easyssh.Protocol(c.String("protocol")),
Timeout: c.Duration("timeout"),
CommandTimeout: c.Duration("command.timeout"),
Script: scripts,
ScriptStop: c.Bool("script.stop"),
Envs: c.StringSlice("envs"),
EnvsFormat: c.String("envs.format"),
Debug: c.Bool("debug"),
Sync: c.Bool("sync"),
Ciphers: c.StringSlice("ciphers"),
UseInsecureCipher: c.Bool("useInsecureCipher"),
AllEnvs: c.Bool("allenvs"),
RequireTty: c.Bool("request-pty"),
Proxy: easyssh.DefaultConfig{
Key: c.String("proxy.ssh-key"),
KeyPath: c.String("proxy.key-path"),
@@ -270,6 +302,7 @@ func run(c *cli.Context) error {
Fingerprint: c.String("proxy.fingerprint"),
Server: c.String("proxy.host"),
Port: c.String("proxy.port"),
Protocol: easyssh.Protocol(c.String("proxy.protocol")),
Timeout: c.Duration("proxy.timeout"),
Ciphers: c.StringSlice("proxy.ciphers"),
UseInsecureCipher: c.Bool("proxy.useInsecureCipher"),
+95 -39
View File
@@ -17,7 +17,7 @@ var (
errMissingHost = errors.New("Error: missing server host")
errMissingPasswordOrKey = errors.New("Error: can't connect without a private SSH key or password")
errCommandTimeOut = errors.New("Error: command timeout")
errSetPasswordandKey = errors.New("can't set password and key at the same time")
envsFormat = "export {NAME}={VALUE}"
)
type (
@@ -30,6 +30,7 @@ type (
Password string
Host []string
Port int
Protocol easyssh.Protocol
Fingerprint string
Timeout time.Duration
CommandTimeout time.Duration
@@ -41,6 +42,9 @@ type (
Sync bool
Ciphers []string
UseInsecureCipher bool
EnvsFormat string
AllEnvs bool
RequireTty bool
}
// Plugin structure
@@ -57,7 +61,9 @@ func escapeArg(arg string) string {
func (p Plugin) hostPort(host string) (string, string) {
hosts := strings.Split(host, ":")
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]
port = hosts[1]
}
@@ -66,6 +72,7 @@ func (p Plugin) hostPort(host string) (string, string) {
}
func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
defer wg.Done()
host, port := p.hostPort(host)
// Create MakeConfig instance with remote username, server address and path to private key.
ssh := &easyssh.MakeConfig{
@@ -73,6 +80,7 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
User: p.Config.Username,
Password: p.Config.Password,
Port: port,
Protocol: p.Config.Protocol,
Key: p.Config.Key,
KeyPath: p.Config.KeyPath,
Passphrase: p.Config.Passphrase,
@@ -80,11 +88,13 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
Ciphers: p.Config.Ciphers,
Fingerprint: p.Config.Fingerprint,
UseInsecureCipher: p.Config.UseInsecureCipher,
RequestPty: p.Config.RequireTty,
Proxy: easyssh.DefaultConfig{
Server: p.Config.Proxy.Server,
User: p.Config.Proxy.User,
Password: p.Config.Proxy.Password,
Port: p.Config.Proxy.Port,
Protocol: p.Config.Proxy.Protocol,
Key: p.Config.Proxy.Key,
KeyPath: p.Config.Proxy.KeyPath,
Passphrase: p.Config.Proxy.Passphrase,
@@ -100,10 +110,14 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
p.log(host, "======END======")
env := []string{}
if p.Config.AllEnvs {
allenvs := findEnvs("DRONE_", "PLUGIN_", "INPUT_", "GITHUB_")
p.Config.Envs = append(p.Config.Envs, allenvs...)
}
for _, key := range p.Config.Envs {
key = strings.ToUpper(key)
if val, found := os.LookupEnv(key); found {
env = append(env, "export "+key+"="+escapeArg(val))
env = append(env, p.format(p.Config.EnvsFormat, "{NAME}", key, "{VALUE}", escapeArg(val)))
}
}
@@ -118,53 +132,61 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
if err != nil {
errChannel <- err
} else {
// read from the output channel until the done signal is passed
isTimeout := true
loop:
for {
select {
case isTimeout = <-doneChan:
break loop
case outline := <-stdoutChan:
if outline != "" {
p.log(host, "out:", outline)
}
case errline := <-stderrChan:
if errline != "" {
p.log(host, "err:", errline)
}
case err = <-errChan:
return
}
// read from the output channel until the done signal is passed
isTimeout := true
loop:
for {
select {
case isTimeout = <-doneChan:
break loop
case outline := <-stdoutChan:
if outline != "" {
p.log(host, "out:", outline)
}
}
// get exit code or command error.
if err != nil {
errChannel <- err
}
// command time out
if !isTimeout {
errChannel <- errCommandTimeOut
case errline := <-stderrChan:
if errline != "" {
p.log(host, "err:", errline)
}
case err = <-errChan:
}
}
wg.Done()
// get exit code or command error.
if err != nil {
errChannel <- err
}
// command time out
if !isTimeout {
errChannel <- errCommandTimeOut
}
}
// format string
func (p Plugin) format(format string, args ...string) string {
r := strings.NewReplacer(args...)
return r.Replace(format)
}
// log output to console
func (p Plugin) log(host string, message ...interface{}) {
if p.Writer == nil {
p.Writer = os.Stdout
}
if count := len(p.Config.Host); count == 1 {
fmt.Fprintf(p.Writer, "%s", fmt.Sprintln(message...))
} else {
fmt.Fprintf(p.Writer, "%s: %s", host, fmt.Sprintln(message...))
return
}
fmt.Fprintf(p.Writer, "%s: %s", host, fmt.Sprintln(message...))
}
// Exec executes the plugin.
func (p Plugin) Exec() error {
p.Config.Host = trimValues(p.Config.Host)
if len(p.Config.Host) == 0 {
return errMissingHost
}
@@ -173,18 +195,22 @@ func (p Plugin) Exec() error {
return errMissingPasswordOrKey
}
if len(p.Config.Key) != 0 && len(p.Config.Password) != 0 {
return errSetPasswordandKey
if p.Config.EnvsFormat == "" {
p.Config.EnvsFormat = envsFormat
}
wg := sync.WaitGroup{}
wg.Add(len(p.Config.Host))
errChannel := make(chan error)
finished := make(chan struct{})
for _, host := range p.Config.Host {
if p.Config.Sync {
p.exec(host, &wg, errChannel)
} else {
if p.Config.Sync {
go func() {
for _, host := range p.Config.Host {
p.exec(host, &wg, errChannel)
}
}()
} else {
for _, host := range p.Config.Host {
go p.exec(host, &wg, errChannel)
}
}
@@ -235,3 +261,33 @@ func (p Plugin) scriptCommands() []string {
return commands
}
func trimValues(keys []string) []string {
var newKeys []string
for _, value := range keys {
value = strings.TrimSpace(value)
if len(value) == 0 {
continue
}
newKeys = append(newKeys, value)
}
return newKeys
}
// Find all envs from specified prefix
func findEnvs(prefix ...string) []string {
envs := []string{}
for _, e := range os.Environ() {
for _, p := range prefix {
if strings.HasPrefix(e, p) {
e = strings.Split(e, "=")[0]
envs = append(envs, e)
break
}
}
}
return envs
}
+242 -18
View File
@@ -38,23 +38,6 @@ func TestMissingKeyOrPassword(t *testing.T) {
assert.Equal(t, errMissingPasswordOrKey, err)
}
func TestSetPasswordAndKey(t *testing.T) {
plugin := Plugin{
Config{
Host: []string{"localhost"},
Username: "ubuntu",
Password: "1234",
Key: "1234",
},
os.Stdout,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, errSetPasswordandKey, err)
}
func TestIncorrectPassword(t *testing.T) {
plugin := Plugin{
Config: Config{
@@ -130,6 +113,40 @@ func TestSSHScriptFromKeyFile(t *testing.T) {
assert.Nil(t, err)
}
func TestSSHIPv4Only(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"localhost", "127.0.0.1"},
Username: "drone-scp",
Port: 22,
Protocol: easyssh.PROTOCOL_TCP4,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami", "ls -al"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.Nil(t, err)
}
func TestSSHIPv6OnlyError(t *testing.T) {
plugin := Plugin{
Config: Config{
Host: []string{"127.0.0.1"},
Username: "drone-scp",
Port: 22,
Protocol: easyssh.PROTOCOL_TCP6,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{"whoami", "ls -al"},
CommandTimeout: 60 * time.Second,
},
}
err := plugin.Exec()
assert.NotNil(t, err)
}
func TestStreamFromSSHCommand(t *testing.T) {
plugin := Plugin{
Config: Config{
@@ -457,6 +474,41 @@ func TestFingerprint(t *testing.T) {
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestScriptStopWithMultipleHostAndSyncMode(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
mkdir a/b/c
mkdir d/e/f
======END======
err: mkdir: can't create directory 'a/b/c': No such file or directory
`
)
plugin := Plugin{
Config: Config{
Host: []string{"", "localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/id_rsa",
Script: []string{
"mkdir a/b/c",
"mkdir d/e/f",
},
CommandTimeout: 10 * time.Second,
ScriptStop: true,
Sync: true,
},
Writer: &buffer,
}
err := plugin.Exec()
assert.NotNil(t, err)
assert.Equal(t, unindent(expected), unindent(buffer.String()))
}
func TestScriptStop(t *testing.T) {
var (
buffer bytes.Buffer
@@ -745,7 +797,8 @@ func TestPlugin_hostPort(t *testing.T) {
name: "different port",
fields: fields{
Config: Config{
Port: 22,
Port: 22,
Protocol: easyssh.PROTOCOL_TCP4,
},
},
args: args{
@@ -754,6 +807,20 @@ func TestPlugin_hostPort(t *testing.T) {
wantHost: "localhost",
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 {
t.Run(tt.name, func(t *testing.T) {
@@ -771,3 +838,160 @@ func TestPlugin_hostPort(t *testing.T) {
})
}
}
func TestFindEnvs(t *testing.T) {
testEnvs := []string{
"INPUT_FOO",
"INPUT_BAR",
"NO_PREFIX",
"INPUT_FOOBAR",
}
origEnviron := os.Environ()
os.Clearenv()
for _, env := range testEnvs {
os.Setenv(env, "dummyValue")
}
defer func() {
os.Clearenv()
for _, env := range origEnviron {
pair := strings.SplitN(env, "=", 2)
os.Setenv(pair[0], pair[1])
}
}()
t.Run("Find single prefix", func(t *testing.T) {
expected := []string{"INPUT_FOO", "INPUT_BAR", "INPUT_FOOBAR"}
result := findEnvs("INPUT_")
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, but got %v", expected, result)
}
})
t.Run("Find multiple prefixes", func(t *testing.T) {
expected := []string{"INPUT_FOO", "INPUT_BAR", "NO_PREFIX", "INPUT_FOOBAR"}
result := findEnvs("INPUT_", "NO_PREFIX")
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, but got %v", expected, result)
}
})
t.Run("Find non-existing prefix", func(t *testing.T) {
expected := []string{}
result := findEnvs("NON_EXISTING_")
if !reflect.DeepEqual(result, expected) {
t.Errorf("Expected %v, but got %v", expected, result)
}
})
}
func TestAllEnvs(t *testing.T) {
var (
buffer bytes.Buffer
expected = `
======CMD======
echo "[${INPUT_1}]"
echo "[${GITHUB_2}]"
echo "[${PLUGIN_3}]"
======END======
out: [foobar]
out: [foobar]
out: [foobar]
`
)
os.Setenv("INPUT_1", `foobar`)
os.Setenv("GITHUB_2", `foobar`)
os.Setenv("PLUGIN_3", `foobar`)
plugin := Plugin{
Config: Config{
Host: []string{"localhost"},
Username: "drone-scp",
Port: 22,
KeyPath: "./tests/.ssh/test",
Passphrase: "1234",
AllEnvs: true,
Script: []string{
`echo "[${INPUT_1}]"`,
`echo "[${GITHUB_2}]"`,
`echo "[${PLUGIN_3}]"`,
},
CommandTimeout: 10 * time.Second,
Proxy: easyssh.DefaultConfig{
Server: "localhost",
User: "drone-scp",
Port: "22",
KeyPath: "./tests/.ssh/id_rsa",
},
},
Writer: &buffer,
}
err := plugin.Exec()
assert.Nil(t, err)
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()))
// }
+2
View File
@@ -0,0 +1,2 @@
Defaults requiretty
drone-scp ALL=(ALL) NOPASSWD:ALL