├── .github └── main.workflow ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── _config.yml ├── deployment.bats └── entrypoint.sh /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Test rsync" { 2 | on = "push" 3 | resolves = ["Bats", "Shellcheck"] 4 | } 5 | 6 | action "Shellcheck" { 7 | uses = "actions/bin/shellcheck@1b3c130914f7b20890bf159306137d994a4c39d0" 8 | args = "*.sh" 9 | } 10 | 11 | action "Write sha" { 12 | uses = "actions/bin/sh@db72a46c8ce298e5d2c3a51861e20c455581524f" 13 | args = ["echo $GITHUB_SHA > index.html"] 14 | } 15 | 16 | action "Deploy with rsync" { 17 | uses = "./" 18 | needs = "Write sha" 19 | secrets = [ 20 | "SSH_PRIVATE_KEY", 21 | "SSH_PUBLIC_KEY" 22 | ] 23 | env = { 24 | HOST_NAME = "karli.rrze.uni-erlangen.de" 25 | HOST_IP = "131.188.16.138" 26 | HOST_FINGERPRINT = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFHJVSekYKuF5pMKyHe1jS9mUkXMWoqNQe0TTs2sY1OQj379e6eqVSqGZe+9dKWzL5MRFpIiySRKgvxuHhaPQU4=" 27 | } 28 | args = [ 29 | "$GITHUB_WORKSPACE/index.html", 30 | "pfs400wm@$HOST_NAME:/proj/websource/docs/FAU/fakultaet/phil/www.datascience.phil.fau.de/websource/rsync" 31 | ] 32 | } 33 | 34 | action "Download deployed assets" { 35 | needs = "Deploy with rsync" 36 | uses = "actions/bin/curl@dd02a4bc5ee52c16bbc916d162075370a83d755c" 37 | args = [ 38 | "http://datascience.phil.fau.de/rsync", 39 | "--output index2.html" 40 | ] 41 | } 42 | 43 | action "Bats" { 44 | needs = "Download deployed assets" 45 | uses = "actions/bin/bats@bd85fd8c369e36eb918c888218aa95469b69daba" 46 | args = "*.bats" 47 | } 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | index.html 2 | index2.html 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stable-20190122-slim 2 | 3 | LABEL "maintainer"="Maximilian Held " 4 | LABEL "repository"="http://github.com/maxheld83/rsync" 5 | LABEL "homepage"="https://www.maxheld.de/rsync/" 6 | 7 | LABEL "com.github.actions.name"="Rsync Deploy" 8 | LABEL "com.github.actions.description"="Deploy to a remote server with rsync via ssh." 9 | LABEL "com.github.actions.icon"="upload-cloud" 10 | LABEL "com.github.actions.color"="orange" 11 | 12 | RUN apt-get update && \ 13 | apt-get install -y \ 14 | openssh-client \ 15 | rsync && \ 16 | rm -rf /var/lib/apt/lists/* 17 | 18 | ADD entrypoint.sh /entrypoint.sh 19 | ENTRYPOINT ["/entrypoint.sh"] 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maximilian Held 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action for Deploying via `rsync` Over `ssh` 2 | 3 | [![Actions Status](https://wdp9fww0r9.execute-api.us-west-2.amazonaws.com/production/badge/maxheld83/rsync)](https://github.com/maxheld83/rsync/actions) 4 | [![GitHubActions](https://img.shields.io/badge/as%20seen%20on%20-GitHubActions-blue.svg)](https://github-actions.netlify.com/rsync) 5 | [![View Action](https://img.shields.io/badge/view-action-blue.svg)](https://github.com/marketplace/actions/rsync-deploy) 6 | 7 | Sometimes, you might want to use `rsync` inside GitHub actions, such as for deploying static assets to some old school webserver over ssh. 8 | This is your action. 9 | 10 | It allows you to transfer files *from* your working directory (`/github/workspace`) *to* some server using `rsync` over `ssh`. 11 | Helpfully, `/github/workspace` includes a copy of your repository *source*, as well as any build artefacts left behind by previous workflow steps (= other actions you ran before). 12 | 13 | 14 | ## Disclaimer 15 | 16 | GitHub actions is still [in limited public beta](https://github.com/features/actions) and advises against [usage in production](https://developer.github.com/actions/). 17 | 18 | This action requires ssh private keys (see secrets), and **may thus be vulnerable**. 19 | The ssh authentification **may need improvement** (see [issues](https://github.com/maxheld83/rsync/)). 20 | 21 | 22 | ## Secrets 23 | 24 | This action requires two secrets to authenticate over ssh: 25 | 26 | - `SSH_PRIVATE_KEY` 27 | - `SSH_PUBLIC_KEY` 28 | 29 | You get both of these from the server you interact with. 30 | 31 | Remember to never commit these keys, but [provide them through the GitHub UI](https://developer.github.com/actions/creating-workflows/storing-secrets/) (repository settings/secrets). 32 | 33 | 34 | ## Environment Variables 35 | 36 | This action requires three environment variables used to register the target server in `$HOME/.ssh/known_hosts`. 37 | This is to make sure that the action is talking to a trusted server. 38 | 39 | **`known_hosts` verification currently fails and is overriden, see [issue 1](https://github.com/maxheld83/rsync/issues/1)**. 40 | 41 | - `HOST_NAME` (the name of the server you wish to deploy to, such as `foo.example.com`) 42 | - `HOST_IP` (the IP of the server you wish to deploy to, such as `111.111.11.111`) 43 | - `HOST_FINGERPRINT` (the fingerprint of the server you wish to deploy to, can have different formats) 44 | 45 | The `HOST_NAME` is *also* used in the below required arguments. 46 | 47 | 48 | ## Required Arguments 49 | 50 | `rsync` requires: 51 | 52 | - `SRC`: source directory, relative path *from* `/github/workspace` 53 | - `[USER@]HOST::DEST`: target user (optional), target server, and directory from root *on* that target server. 54 | Remember you can reuse the environment variable `$HOST_NAME`. 55 | 56 | For action `rsync` options, see `entrypoint.sh` in the source. 57 | For more options and documentation on `rsync`, see [https://rsync.samba.org](https://rsync.samba.org). 58 | 59 | 60 | ## Example Usage 61 | 62 | ``` 63 | action "Deploy with rsync" { 64 | uses = "maxheld83/rsync@v0.1.1" 65 | needs = "Write sha" 66 | secrets = [ 67 | "SSH_PRIVATE_KEY", 68 | "SSH_PUBLIC_KEY" 69 | ] 70 | env = { 71 | HOST_NAME = "foo.example.com" 72 | HOST_IP = "111.111.11.111" 73 | HOST_FINGERPRINT = "ecdsa-sha2-nistp256 AAAA..." 74 | } 75 | args = [ 76 | "$GITHUB_WORKSPACE/index.html", 77 | "alice@$HOST_NAME:path/to/destination" 78 | ] 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /deployment.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | @test "deployed assets equal commit SHA" { 4 | # curl is not available here, so this is from prior step 5 | result="$(head -1 index2.html)" 6 | [ "$result" = "$GITHUB_SHA" ] 7 | } 8 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit on error. Append "|| true" if you expect an error. 4 | set -o errexit # same as -e 5 | # Exit on error inside any functions or subshells. 6 | set -o errtrace 7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR 8 | set -o nounset 9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip` 10 | set -o pipefail 11 | 12 | printf '\033[33m Warning: This action does not currently support host verification; verification is disabled. \n \033[0m\n' 13 | printf -- 'Setting up SSH... ' 14 | 15 | ssh_path="$HOME/.ssh" 16 | mkdir "$ssh_path" 17 | touch "$ssh_path/known_hosts" 18 | 19 | echo "$SSH_PRIVATE_KEY" > "$ssh_path/deploy_key" 20 | echo "$SSH_PUBLIC_KEY" > "$ssh_path/deploy_key.pub" 21 | chmod 700 "$ssh_path" 22 | chmod 600 "$ssh_path/known_hosts" 23 | chmod 600 "$ssh_path/deploy_key" 24 | chmod 600 "$ssh_path/deploy_key.pub" 25 | 26 | eval "$(ssh-agent -s)" 27 | ssh-add "$ssh_path/deploy_key" 28 | 29 | printf -- 'Recording known host... ' 30 | # below key was created by running the below line from inside karli.rrze 31 | # ssh-keyscan -t ecdsa-sha2-nistp256 karli.rrze.uni-erlangen.de 32 | # below line actually seems ineffectual; we still get "host key verification failed" 33 | echo "$HOST_NAME,$HOST_IP $HOST_FINGERPRINT" \ 34 | >> "$ssh_path/known_hosts" 35 | # $HOST_NAME is used in the above as well as in the below; that's why it is an env 36 | 37 | # "args" from main.workflow get append to below call 38 | # these include source, user, $HOST and target 39 | printf -- 'Uploading assets... ' 40 | sh -c "rsync --progress --verbose --recursive --delete-after --quiet -e 'ssh -o StrictHostKeyChecking=no' $*" 41 | 42 | printf -- '\033[32m Deployment successful! \033[0m\n' 43 | printf -- '\n' 44 | --------------------------------------------------------------------------------