Compare commits

...

28 Commits

Author SHA1 Message Date
Burnett01 ce5f41df10 chore: EOL of version 7.0.2 and 7.1.0 2026-05-23 19:41:31 +02:00
Burnett01 2f1450c0da chore: EOL of version 7.0.2 and 7.1.0 2026-05-23 19:38:37 +02:00
Burnett01 09d0f6ee87 chore: EOL of version 7.0.2 and 7.1.0 2026-05-23 19:36:57 +02:00
Burnett01 66257cad6b Release/8.0.5 (#101)
* feat: Update base image to Alpine 3.23.4

Alpine 3.23.4 fixes the following:

musl
CVE-2026-6042
CVE-2026-40200

openssl
CVE-2026-31790
CVE-2026-28387
CVE-2026-28388
CVE-2026-28389
CVE-2026-28390
CVE-2026-31789

* chore: Update supported versions in SECURITY.md

* chore: Update README for Alpine and version changes

* chore: Update copyright years in LICENSE file

Updated copyright years for Joshua Piper and Burnett01.
2026-04-17 18:50:35 +02:00
Steven 27212fc826 chore(readme): Version upgrade to 8.0.4 2026-02-04 20:48:49 +01:00
Steven dc0d5d44c4 Release/8.0.4 (#100)
* chore(deps): bump alpine from 3.23.2 to 3.23.3 (#99)

Bumps alpine from 3.23.2 to 3.23.3.

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: 3.23.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(action): Version 8.0.4 (alpine upgrade 3.23.3)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-04 20:38:53 +01:00
Steven cccc35d762 chore(action): update description to match modern facts 2026-01-15 23:15:06 +01:00
Steven 2ad5f95a8a chore(funding): create funding yaml 2026-01-15 23:12:32 +01:00
Steven 115573f97b chore(readme): mention deprecation of 7.0.2 too 2026-01-15 22:59:55 +01:00
Steven 7659d600d8 feat(release): 8.0.3 (v8) - bump alpine from 3.23.0 to 3.23.2 (#97) (#98)
* chore(deps): bump alpine from 3.23.0 to 3.23.2

Bumps alpine from 3.23.0 to 3.23.2.

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: 3.23.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...



* chore(docs): update Alpine version to 3.23.2 in README and SECURITY files

* chore(docs): update current version to 8.0.3 in README

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 21:55:43 +01:00
Steven 81be6cf6d7 chore: add deprecation notice, move release channels to top 2025-12-09 21:22:31 +01:00
Steven 178d2ea600 chore: deprecation notice 2025-12-09 14:45:28 +01:00
Steven 241aa321a8 chore: add support cycles 2025-12-07 14:02:36 +01:00
Steven 80e4fa792e chore: update readme
- advise users to always use secrets
- simplified examples
- other adjustments
2025-12-07 13:51:46 +01:00
Steven 0c902521b8 Release/8.0.2 (#93)
* fix: only attempt to create dir if not yet exists

On self-hosted runners it can happen that an action (docker container) is cached. This leads to the script trying to create the .ssh dir despite it already existing. The action then fails.

* fix: only attempt to create file if it doesn't exist yet

On self-hosted runners it can happen that an action (docker container) is cached, resulting in aborting this script because the know_hosts file already exists. 
This if clause fixes it.
Setting permissions is intentionally outside the if clause because in all cases we want to reset perms.

* fix: reverting printf in favor of echo

Like in commit 2c22263 we are using echo again instead of printf because some runners can't function properly with it.

* chore: 8.0.2

* chore: readme changes
2025-12-07 12:59:02 +01:00
Steven 68d1fd5150 chore: 8.0.1 2025-12-06 21:44:40 +00:00
Steven 2c22263f9c fix: regression - using echo instead of printf again #90
It was found via #90 and #89 that using printf causes problems.
In the previous version 7.1.0 we used echo instead of printf - hence we are bringing this back for version 8.0.x
2025-12-06 22:33:01 +01:00
Steven 8a39558686 feat: add README for SSH agent and known_hosts management scripts 2025-12-06 19:19:48 +00:00
Steven 0f1cb7924d fix: permissions of docker-rsync scripts 2025-12-06 19:19:26 +00:00
Steven 05a269aeea v8 - 8.0.0 (#88)
* feat: latest Alpine 3.23.0
* feat: latest Rsync 3.4.1-r1
* feat: integrate [rsync-docker](https://github.com/JoshPiper/rsync-docker/) 3rd party into this action as 1st party code (no more dependency, better audit, single source of truth)
   - backported:
       - agent-start
       - agent-stop
       - agent-askpass
       - agent-add
       - hosts-add
       - hosts-clear
   - new added: 
       - ssh-init
       - hosts-init
   - improved: 
     - stricter permissions on .ssh/ folder (700) and known_hosts (600)
     - use set -eu in all scipts
* feat: new ``strict_host_keys`` option to enable support for strict host key verification. Default: false (to keep backward compatibility)
* feat: new ``debug`` option to see the commands executed (-x) by this action
* feat: this action is now scanned for vulnerabilities by Snyk
* feat; this action is now scanned by CodeQL for Q/A
* feat: this action now performs CI tasks such as Validation, Linting and Unit Tests
* fix: various shell syntax for robustness
* fix: use printf and redirect output to non-stdout instead of echo in sensitive code locations
* refactor: use $HOME instead of tilde ~ for robustness
* feat: cross-platform support
* chore: Deprecate 7.0.2
* chore: EOL 7.0.0 & 7.0.1
2025-12-06 16:57:20 +01:00
Steven 92961b5880 feat: always force-upgrade alpine openssl
Force upgrade the alpines openssl to  3.5.4-r0 in order to tackle CVE-2025-9230 (low)
CVE-2025-9231 (low)
CVE-2025-9232 (low)

See: 
https://github.com/Burnett01/rsync-deployments/security/code-scanning/7

https://github.com/Burnett01/rsync-deployments/security/code-scanning/8

https://github.com/Burnett01/rsync-deployments/security/code-scanning/9
2025-10-07 19:04:58 +02:00
Steven 96abc27e05 fix: snyk-docker-vulnerability-scan sarif
See https://github.com/github/codeql-action/issues/2187#issuecomment-2043220400
2025-10-07 18:55:29 +02:00
Steven 7e729bf4dd fix: snyk-docker-vulnerability-scan sarif
See https://github.com/github/codeql-action/issues/2187#issuecomment-2043220400
2025-10-07 18:53:39 +02:00
Steven c23b68a9ef chore: snyk output sarif file content 2025-10-07 18:45:23 +02:00
Steven 3e83373c59 fix: snyk-docker-vulnerability-scan sarif
caused by github/codeql-action#3156
2025-10-07 18:33:54 +02:00
Steven da6a0e1f57 fix: snyk-docker-vulnerability-scan sarif
caused by github/codeql-action#3156
2025-10-07 18:30:41 +02:00
Steven 0b92d76269 fix: snyk-docker-vulnerability-scan sarif
caused by https://github.com/github/codeql-action/issues/3156
2025-10-07 18:10:15 +02:00
Copilot 78cbabbd5c chore: adjust troubleshooting section for missing rsync on remote host (#86)
* Adjust troubleshooting section for missing rsync on remote host

Co-authored-by: Burnett01 <1208707+Burnett01@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Burnett01 <1208707+Burnett01@users.noreply.github.com>
2025-09-23 21:08:48 +02:00
20 changed files with 453 additions and 95 deletions
+5
View File
@@ -0,0 +1,5 @@
Dockerfile
LICENSE
*.md
.git*
.github*
+15
View File
@@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
tab_width = 4
indent_size = 4
indent_style = space
max_line_length = 9999
insert_final_newline = true
trim_trailing_whitespace = true
[*.{yml,yaml}]
tab_width = 2
indent_size = 2
+1
View File
@@ -0,0 +1 @@
github: [burnett01]
@@ -30,7 +30,12 @@ jobs:
with:
image: burnett01/rsync-deployments
args: --file=Dockerfile
- name: Output sarif file
run: cat snyk.sarif
- name: fix security-severity "null" to "0" for valid sarif format
run: |
sed -i 's/"security-severity": "null"/"security-severity": "0"/g' snyk.sarif
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: snyk.sarif
+8 -5
View File
@@ -1,11 +1,14 @@
# drinternet/rsync@v1.5.1
FROM drinternet/rsync@sha256:e61f4047577b566872764fa39299092adeab691efb3884248dbd6495dc926527
FROM alpine:3.23.4@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11 AS base
RUN apk update && apk add --no-cache --upgrade rsync openssh openssl busybox
# always force-upgrade rsync to get the latest security fixes
RUN apk update && apk add --no-cache --upgrade rsync
RUN rm -rf /var/cache/apk/*
# Copy entrypoint
COPY docker-rsync/* /bin/
RUN chmod +x /bin/agent-* /bin/ssh-* /bin/hosts-*
FROM base AS build
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
+2 -1
View File
@@ -1,7 +1,8 @@
MIT License
Copyright (c) 2019-2022 Contention
Copyright (c) 2019-2025 Burnett01
Copyright (c) 2019-2026 Joshua Piper (Dr Internet)
Copyright (c) 2019-2026 Burnett01
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+135 -57
View File
@@ -6,24 +6,63 @@
[![Dependabot Updates](https://github.com/Burnett01/rsync-deployments/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/Burnett01/rsync-deployments/actions/workflows/dependabot/dependabot-updates)
This GitHub Action (amd64) deploys files in `GITHUB_WORKSPACE` to a remote folder via rsync over ssh.
This cross-platform GitHub Action deploys files in [`path`](#inputs) (relative to `GITHUB_WORKSPACE`) to a remote folder via rsync over ssh.
Use this action in a CD workflow which leaves deployable code in `GITHUB_WORKSPACE`.
Use this action in a CD workflow which leaves deployable code in `GITHUB_WORKSPACE`, such [actions/checkout](https://github.com/actions/checkout).
The base-image [drinternet/rsync](https://github.com/JoshPiper/rsync-docker/) of this action is very small and is based on Alpine 3.22.1 (no cache) which results in fast deployments.
The base-image of this action is very small and based on **Alpine 3.23.4** (no cache) which results in fast deployments.
Alpine version: [3.22.1](https://alpinelinux.org/posts/Alpine-3.19.8-3.20.7-3.21.4-3.22.1-released.html)
Rsync version: [3.4.1-r0](https://download.samba.org/pub/rsync/NEWS#3.4.1)
Alpine version: [3.23.4](https://www.alpinelinux.org/posts/Alpine-3.20.10-3.21.7-3.22.4-3.23.4-released.html)
Rsync version: [3.4.1-r1](https://download.samba.org/pub/rsync/NEWS#3.4.1)
## Current Version: v8 (8.0.5)
### Release channels:
| Version | Purpose | Immutable |
| ------- | ------------------ | ------------------ |
| ``v8`` (recommended) | latest MAJOR (pointer to 8.MINOR.PATCH) | no |
| 8.0.5 | latest MAJOR+MINOR+PATCH | yes |
Check [SECURITY.md](SECURITY.md) for support cycles.
---
## How it works
```yml
name: DEPLOY
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: rsync deployments
uses: burnett01/rsync-deployments@v8
with:
switches: -avzr --delete
path: src/
remote_path: ${{ secrets.REMOTE_PATH }} # ex: /var/www/html/
remote_host: ${{ secrets.REMOTE_HOST }} # ex: example.com
remote_port: ${{ secrets.REMOTE_PORT }} # ex: 22
remote_user: ${{ secrets.REMOTE_USER }} # ex: ubuntu
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
```
## Inputs
- `debug`* - Whether to enable debug output. ("true" / "false") - Default: "false"
- `switches`* - The first is for any initial/required rsync flags, eg: `-avzr --delete`
- `rsh` - Remote shell commands
- `legacy_allow_rsa_hostkeys` - Enables support for legacy RSA host keys on OpenSSH 8.8+. ("true" / "false")
- `strict_hostkeys_checking` - Enables support for strict hostkeys (fingerprint) checking. ("true" / "false") - Default: "false"
- `legacy_allow_rsa_hostkeys` - Enables support for legacy RSA host keys on OpenSSH 8.8+. ("true" / "false") - Default: "false"
- `path` - The source path. Defaults to GITHUB_WORKSPACE and is relative to it
@@ -49,10 +88,10 @@ This action needs secret variables for the ssh private key of your key pair. The
For simplicity, we are using `REMOTE_*` as the secret variables throughout the examples.
## Current Version: 7.1.0
## Example usage
For better **security** always use secrets for remote_host, remote_port, remote_user and remote_path inputs.
Simple:
```yml
@@ -66,55 +105,36 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: rsync deployments
uses: burnett01/rsync-deployments@7.1.0
uses: burnett01/rsync-deployments@v8
with:
switches: -avzr --delete
path: src/
remote_path: /var/www/html/
remote_host: example.com
remote_user: debian
remote_path: ${{ secrets.REMOTE_PATH }} # ex: /var/www/html/
remote_host: ${{ secrets.REMOTE_HOST }} # ex: example.com
remote_port: ${{ secrets.REMOTE_PORT }} # ex: 22
remote_user: ${{ secrets.REMOTE_USER }} # ex: ubuntu
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
```
Advanced:
Advanced (with filters etc):
```yml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: rsync deployments
uses: burnett01/rsync-deployments@7.1.0
uses: burnett01/rsync-deployments@v8
with:
switches: -avzr --delete --exclude="" --include="" --filter=""
path: src/
remote_path: /var/www/html/
remote_host: example.com
remote_port: 5555
remote_user: debian
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
```
For better **security**, I suggest you create additional secrets for remote_host, remote_port, remote_user and remote_path inputs.
```yml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: rsync deployments
uses: burnett01/rsync-deployments@7.1.0
with:
switches: -avzr --delete
path: src/
remote_path: ${{ secrets.REMOTE_PATH }}
remote_host: ${{ secrets.REMOTE_HOST }}
remote_port: ${{ secrets.REMOTE_PORT }}
remote_user: ${{ secrets.REMOTE_USER }}
remote_path: ${{ secrets.REMOTE_PATH }} # ex: /var/www/html/
remote_host: ${{ secrets.REMOTE_HOST }} # ex: example.com
remote_port: ${{ secrets.REMOTE_PORT }} # ex: 22
remote_user: ${{ secrets.REMOTE_USER }} # ex: ubuntu
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
```
@@ -125,16 +145,16 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: rsync deployments
uses: burnett01/rsync-deployments@7.1.0
uses: burnett01/rsync-deployments@v8
with:
switches: -avzr --delete
path: src/
remote_path: ${{ secrets.REMOTE_PATH }}
remote_host: ${{ secrets.REMOTE_HOST }}
remote_port: ${{ secrets.REMOTE_PORT }}
remote_user: ${{ secrets.REMOTE_USER }}
remote_path: ${{ secrets.REMOTE_PATH }} # ex: /var/www/html/
remote_host: ${{ secrets.REMOTE_HOST }} # ex: example.com
remote_port: ${{ secrets.REMOTE_PORT }} # ex: 22
remote_user: ${{ secrets.REMOTE_USER }} # ex: ubuntu
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
remote_key_pass: ${{ secrets.REMOTE_PRIVATE_KEY_PASS }}
```
@@ -151,17 +171,17 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: rsync deployments
uses: burnett01/rsync-deployments@7.1.0
uses: burnett01/rsync-deployments@v8
with:
switches: -avzr --delete
legacy_allow_rsa_hostkeys: "true"
path: src/
remote_path: ${{ secrets.REMOTE_PATH }}
remote_host: ${{ secrets.REMOTE_HOST }}
remote_port: ${{ secrets.REMOTE_PORT }}
remote_user: ${{ secrets.REMOTE_USER }}
remote_path: ${{ secrets.REMOTE_PATH }} # ex: /var/www/html/
remote_host: ${{ secrets.REMOTE_HOST }} # ex: example.com
remote_port: ${{ secrets.REMOTE_PORT }} # ex: 22
remote_user: ${{ secrets.REMOTE_USER }} # ex: ubuntu
remote_key: ${{ secrets.REMOTE_PRIVATE_KEY }}
```
@@ -238,24 +258,82 @@ More advanced examples:
- https://github.com/Burnett01/rsync-deployments/issues/71
- https://github.com/Burnett01/rsync-deployments/issues/52
### Missing rsync on Remote Host
If the action fails with "rsync: command not found" or similar errors, rsync is not installed on your remote server. Install it using your system's package manager:
**Ubuntu/Debian:**
```bash
sudo apt-get update && sudo apt-get install rsync
```
**CentOS/RHEL/Rocky/AlmaLinux:**
```bash
sudo yum install rsync
# OR on newer versions:
sudo dnf install rsync
```
**Alpine Linux:**
```bash
sudo apk add rsync
```
---
## Versions
## Version 7.0.2
## Version 8.0.4
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/7.0.2 (alpine 3.19.1)
- https://github.com/Burnett01/rsync-deployments/tree/8.0.4 (alpine 3.23.3)
## Version 8.0.3
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/8.0.3 (alpine 3.23.2)
## Version 8.0.2
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/8.0.2 (alpine 3.23.0)
## Version 8.0.1 (EOL)
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/8.0.1 (alpine 3.23.0)
## Version 8.0.0 (EOL due to regression -> fixed via 8.0.1 & 8.0.2)
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/8.0.0 (alpine 3.23.0)
## Version 7.1.0 (EOL)
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/7.1.0 (alpine 3.22.1)
## Version 7.0.2 (EOL)
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/7.0.2 (alpine 3.22.1)
---
## Version 7.0.0 & 7.0.1 (DEPRECATED)
## Version 7.0.0 & 7.0.1 (EOL)
Check here:
- https://github.com/Burnett01/rsync-deployments/tree/7.0.0 (alpine 3.19.1)
- https://github.com/Burnett01/rsync-deployments/tree/7.0.1 (alpine 3.19.1)
- https://github.com/Burnett01/rsync-deployments/tree/7.0.1 (alpine 3.22.1)
---
@@ -316,7 +394,7 @@ Please note that version 1.0 has reached end of life state.
## Acknowledgements
+ This project is a fork of [Contention/rsync-deployments](https://github.com/Contention/rsync-deployments)
+ Base image [JoshPiper/rsync-docker](https://github.com/JoshPiper/rsync-docker)
+ docker-rsync [JoshPiper/rsync-docker](https://github.com/JoshPiper/rsync-docker)
---
+26 -12
View File
@@ -1,21 +1,35 @@
# Security Policy
The Docker image and code quality are regularly checked for vulnerabilities and CVEs by Snyk and CodeQL.
## Supported Versions
The following versions are currently being supported with security updates:
| Version | Supported | Rsync version |
| ------- | ------------------ | ------------------ |
| 7.1.0 | :white_check_mark: | >= 3.4.1 |
| 7.0.2 | :white_check_mark: | >= 3.4.0 |
| 7.0.1 | :warning: DEPRECATED | < 3.4.0 |
| 7.0.0 | :warning: DEPRECATED | < 3.4.0|
| 6.x | :x: EOL |< 3.4.0|
| 5.x | :x: EOL |< 3.4.0|
| 4.x | :x: EOL |< 3.4.0|
| 3.0 | :x: EOL |< 3.4.0|
| 2.0 | :x: EOL |< 3.4.0|
| 1.0 | :x: EOL |< 3.4.0|
| Version | Supported | Rsync version | Alpine version | Support Until |
| ------- | ------------------ | ------------------ | ------------------ | ------------------ |
| (``v8``) 8.0.5 | :white_check_mark: | >= 3.4.1-r1 | 3.23.4 | LTS (2026-*) |
| 8.0.4 | :white_check_mark: | >= 3.4.1-r1 | 3.23.3 | LTS (2026) |
| 8.0.3 | :white_check_mark: | >= 3.4.1-r1 | 3.23.2 | LTS (2026) |
| 8.0.2 | :white_check_mark: | >= 3.4.1-r1 | 3.23.0 | LTS (2026) |
| 8.0.1 | :x: EOL | >= 3.4.1-r1 | 3.23.0 | † Apr, 1st 2026 |
| 8.0.0 | :x: EOL (due to regression #90) | >= 3.4.1-r1 | 3.23.0 | † Dec, 6th 2025 |
| 7.1.0 | :x: EOL | >= 3.4.1-r0 | 3.22.1 | † June, 1st 2026 ([deprecation notice](https://github.com/Burnett01/rsync-deployments/discussions/96)) |
| 7.0.2 | :x: EOL | >= 3.4.0-r0 | 3.22.1 | † June, 1st 2026 ([deprecation notice](https://github.com/Burnett01/rsync-deployments/discussions/96)) |
| 7.0.1 | :x: EOL | < 3.4.0 | 3.22.1 | † Dec, 6th 2025 |
| 7.0.0 | :x: EOL | < 3.4.0| 3.19.1 | † Dec, 6th 2025 |
| 6.x | :x: EOL |< 3.4.0| 3.17.2 | † 2024 |
| 5.x | :x: EOL |< 3.4.0| 3.11 - 3.14.1 - 3.15 - 3.16 - 3.17.2 | † 2024 |
| 4.x | :x: EOL |< 3.4.0| 3.11 | † |
| 3.0 | :x: EOL |< 3.4.0| N/A | † |
| 2.0 | :x: EOL |< 3.4.0| Ubuntu | † |
| 1.0 | :x: EOL |< 3.4.0| Ubuntu | † |
### Terminology
EOL = End of life (no support/no updates)
DEPRECATED = Close to EOL (support/no updates)
## Reporting a Vulnerability
+9 -1
View File
@@ -1,5 +1,5 @@
name: 'Rsync Deployments Action'
description: 'GitHub Action for deploying code via rsync over ssh'
description: 'GitHub Action for deploying code via rsync over ssh securely - used by 5k+ workflows!'
author: 'Burnett01'
inputs:
switches:
@@ -13,6 +13,10 @@ inputs:
description: 'Enables support for legacy RSA host keys on OpenSSH 8.8+'
required: false
default: 'false'
strict_hostkeys_checking:
description: 'Controls strict host keys checking'
required: false
default: 'false'
path:
description: 'The local path'
required: false
@@ -37,6 +41,10 @@ inputs:
description: 'The remote key passphrase'
required: false
default: ''
debug:
description: 'Debug the action'
required: false
default: 'false'
runs:
using: 'docker'
image: 'Dockerfile'
+40
View File
@@ -0,0 +1,40 @@
# Scripts
Shell-scripts to help with managing SSH agents and known hosts files.
### SSH Management
#### ssh-init
This command create the ``$HOME/.ssh`` folder with default permissions ``700``.
### SSH-Agent Management
#### agent-start
This command starts the SSH agent, if it isn't already started (SSH_AGENT_PID set or ssh agent ID file found).
It takes one optional argument, for the name of the agent to be started. Defaults to "default".
This program needs to be source'd to work correctly.
`source agent-start "default"`
#### agent-stop
This command stops the SSH agent, if it is started (SSH_AGENT_PID set or ssh agent ID file found).
It takes one optional argument, for the name of the agent to be stopped. Defaults to "default".
`agent-stop "my-agent-name"`
#### agent-add
This command adds a key to the currently running SSH agent. The key is taken from stdin, and the agent used is that in SSH_AGENT_PID.
#### agent-askpass
This command is called by ssh-add when the [SSH_ASKPASS](https://man.openbsd.org/ssh-add.1#ENVIRONMENT) variable is set active. The command returns the SSH_PASS to [ssh-askpass(1)](https://man.openbsd.org/ssh-askpass.1).
This command is ignored by ssh-add if the key does not require a passphrase.
### known_hosts management
#### hosts-init
This command creates the known_hosts file (``$HOME/.ssh/known_hosts``) with default permission ``600``.
#### hosts-add
This command adds an entry to the known hosts file, and ensures its permissions are correct. It takes one argument, which is the new key to add.
#### hosts-clear
This command truncates the known_hosts file.
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
set -eu
source agent-start "${1:-default}"
cat - | tr -d '\r' | DISPLAY=1 SSH_ASKPASS=agent-askpass ssh-add - >/dev/null
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -eu
echo "$SSH_PASS"
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
set -eu
FOLDER=${1:-default}
STORE_PATH="/tmp/ssh-agent/$FOLDER"
mkdir -p "$STORE_PATH"
if [ -z "${SSH_AGENT_PID:-}" ]; then
if [ -f "$STORE_PATH/id" ]; then
SSH_AGENT_PID=$(cat "$STORE_PATH/id")
export SSH_AGENT_PID
SSH_AUTH_SOCK=$(cat "$STORE_PATH/sock")
export SSH_AUTH_SOCK
else
eval "$(ssh-agent)" > /dev/null
echo "$SSH_AGENT_PID" > "$STORE_PATH"/id
echo "$SSH_AUTH_SOCK" > "$STORE_PATH"/sock
fi
fi
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
set -eu
if [ ! -z "$SSH_AGENT_PID" ]; then
# Here, the environment is set already, just kill the script.
eval $(ssh-agent -k) >/dev/null
exit $?
else
# The env isn't set, construct the file path.
FOLDER=${1:-default}
STORE_PATH="/tmp/ssh-agent/$FOLDER"
if [ ! -d "$STORE_PATH" ]; then
echo "Store Path $STORE_PATH doesn't exist!" >&2
exit 1
fi
# And check our files exist.
if [ -f "$STORE_PATH/id" ]; then
# Grab our PID and socket.
SSH_AGENT_PID=$(cat "$STORE_PATH/id")
export SSH_AGENT_PID
rm "$STORE_PATH/id"
SSH_AUTH_SOCK=$(cat "$STORE_PATH/sock")
export SSH_AUTH_SOCK
rm "$STORE_PATH/sock"
rmdir "$STORE_PATH"
eval $(ssh-agent -k) >/dev/null
exit $?
else
echo "SSH_AGENT_PID not set, $STORE_PATH/id doesn't exist!" >&2
exit 1
fi
fi
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -eu
echo "$@" >> $HOME/.ssh/known_hosts
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -eu
truncate -s 0 $HOME/.ssh/known_hosts
+9
View File
@@ -0,0 +1,9 @@
#!/bin/sh
set -eu
if [ ! -f "$HOME/.ssh/known_hosts" ]; then
touch $HOME/.ssh/known_hosts
fi
chmod 600 $HOME/.ssh/known_hosts
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
set -eu
if [ ! -d "$HOME/.ssh" ]; then
mkdir -m 700 $HOME/.ssh
fi
+38 -8
View File
@@ -1,25 +1,55 @@
#!/bin/sh
set -eu
if [ "${INPUT_DEBUG:-false}" = "true" ]; then
set -x
fi
if [ -z "$(echo "$INPUT_REMOTE_PATH" | awk '{$1=$1};1')" ]; then
echo "The remote_path can not be empty. see: github.com/Burnett01/rsync-deployments/issues/44"
exit 1
fi
# Initialize SSH and known hosts.
source ssh-init
source hosts-init
# Start the SSH agent and load key.
source agent-start "$GITHUB_ACTION"
echo "$INPUT_REMOTE_KEY" | SSH_PASS="$INPUT_REMOTE_KEY_PASS" agent-add
# Add strict errors.
set -eu
# Variables.
LEGACY_RSA_HOSTKEYS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
LEGACY_RSA_HOSTKEYS=$([ "$INPUT_LEGACY_ALLOW_RSA_HOSTKEYS" = "true" ] && echo "$LEGACY_RSA_HOSTKEYS" || echo "")
LEGACY_RSA_HOSTKEYS=""
if [ "${INPUT_LEGACY_ALLOW_RSA_HOSTKEYS:-false}" = "true" ]; then
LEGACY_RSA_HOSTKEYS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
fi
SWITCHES="$INPUT_SWITCHES"
RSH="ssh -o StrictHostKeyChecking=no $LEGACY_RSA_HOSTKEYS -p $INPUT_REMOTE_PORT $INPUT_RSH"
STRICT_HOSTKEYS_CHECKING="-o StrictHostKeyChecking=no"
if [ "${INPUT_STRICT_HOSTKEYS_CHECKING:-false}" = "true" ]; then
STRICT_HOSTKEYS_CHECKING="-o UserKnownHostsFile=$HOME/.ssh/known_hosts -o StrictHostKeyChecking=yes"
key="$(ssh-keyscan -p "$INPUT_REMOTE_PORT" "$INPUT_REMOTE_HOST" 2>/dev/null | sed '/^#/d')" || key=""
if [ -n "$key" ]; then
# fingerprint verification
echo "$key" | ssh-keygen -lf -
# add to known hosts
echo "$key" | while IFS= read -r line; do hosts-add "$line"; done
else
echo "Warning: failed to fetch host key for $INPUT_REMOTE_HOST" >&2
exit 1
fi
fi
RSH="ssh $STRICT_HOSTKEYS_CHECKING $LEGACY_RSA_HOSTKEYS -p $INPUT_REMOTE_PORT $INPUT_RSH"
LOCAL_PATH="$GITHUB_WORKSPACE/$INPUT_PATH"
DSN="$INPUT_REMOTE_USER@$INPUT_REMOTE_HOST"
# Deploy.
sh -c "rsync $SWITCHES -e '$RSH' $LOCAL_PATH $DSN:$INPUT_REMOTE_PATH"
sh -c "rsync $INPUT_SWITCHES -e '$RSH' $LOCAL_PATH $DSN:$INPUT_REMOTE_PATH"
# Clean up.
source agent-stop "$GITHUB_ACTION"
source hosts-clear
exit 0
+73 -10
View File
@@ -1,12 +1,13 @@
#!/usr/bin/env bats
setup() {
# Create a dummy ssh agent and agent-add for sourcing
# Create dummy binaries for sourcing
echo 'echo "source"' > source
echo 'echo "agent started"' > agent-start
echo 'echo "key added"' > agent-add
chmod +x agent-start agent-add
chmod +x source agent-start agent-add
# Create a dummy rsync to capture its arguments
# Create dummy rsync binary to capture its arguments
echo 'echo "rsync $@"' > rsync
chmod +x rsync
@@ -14,7 +15,7 @@ setup() {
}
teardown() {
rm -f agent-start agent-add rsync
rm -f source agent-start agent-add rsync ssh-keyscan hosts-add
}
@test "fails if INPUT_REMOTE_PATH is empty" {
@@ -35,13 +36,14 @@ teardown() {
export INPUT_RSH=""
export INPUT_PATH=""
export INPUT_REMOTE_USER="user"
export INPUT_REMOTE_HOST="host"
export INPUT_REMOTE_HOST="localhost.local"
export GITHUB_WORKSPACE="/tmp"
export DSN="user@host"
export DSN="user@localhost.local"
export LOCAL_PATH="/tmp/"
run ./entrypoint.sh
[[ "${output}" == *"HostKeyAlgorithms=+ssh-rsa"* ]]
[[ "${output}" == *"rsync -avz -e ssh -o StrictHostKeyChecking=no -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -p 22 /tmp/ user@localhost.local:remote/"* ]]
}
@test "does not include legacy RSA switches when not allowed" {
@@ -55,11 +57,72 @@ teardown() {
export INPUT_RSH=""
export INPUT_PATH=""
export INPUT_REMOTE_USER="user"
export INPUT_REMOTE_HOST="host"
export INPUT_REMOTE_HOST="localhost.local"
export GITHUB_WORKSPACE="/tmp"
export DSN="user@host"
export DSN="user@localhost.local"
export LOCAL_PATH="/tmp/"
run ./entrypoint.sh
[[ "${output}" != *"HostKeyAlgorithms=+ssh-rsa"* ]]
[[ "${output}" == *"rsync -avz -e ssh -o StrictHostKeyChecking=no -p 22 /tmp/ user@localhost.local:remote/"* ]]
}
@test "includes STRICT_HOSTKEYS_CHECKING switches when allowed" {
# Set a fake HOME dir
local -r HOME="/tmp"
export INPUT_LEGACY_ALLOW_RSA_HOSTKEYS="false"
export INPUT_STRICT_HOSTKEYS_CHECKING="true"
export INPUT_REMOTE_PATH="remote/"
export INPUT_REMOTE_KEY="dummy"
export INPUT_REMOTE_KEY_PASS="dummy"
export GITHUB_ACTION="dummy"
export INPUT_SWITCHES="-avz"
export INPUT_REMOTE_PORT="22"
export INPUT_RSH=""
export INPUT_PATH=""
export INPUT_REMOTE_USER="user"
export INPUT_REMOTE_HOST="localhost.local"
export GITHUB_WORKSPACE="/tmp"
export DSN="user@localhost.local"
export LOCAL_PATH="/tmp/"
# Generate a mock key pair to test ssh-keyscan (entrypoint.sh:32)
rm -f "$HOME/mockKeyPair" "$HOME/mockKeyPair.pub" \
&& ssh-keygen -t ed25519 -f "$HOME/mockKeyPair" -N '' -q -C '' \
&& mockPublicKey=$(< "$HOME/mockKeyPair.pub")
# Create dummy ssh-keyscan binary to return $mockPublicKey
echo "echo 'localhost.local $mockPublicKey #Mock 1'" > ssh-keyscan
chmod +x ssh-keyscan
# Create dummy hosts-add binary to capture its arguments
echo 'echo "hosts-add $@"' > hosts-add
chmod +x hosts-add
run ./entrypoint.sh
[[ "${output}" == *"hosts-add localhost.local ssh-ed25519"* ]]
[[ "${output}" == *"rsync -avz -e ssh -o UserKnownHostsFile=/tmp/.ssh/known_hosts -o StrictHostKeyChecking=yes -p 22 /tmp/ user@localhost.local:remote/"* ]]
}
@test "does not includes STRICT_HOSTKEYS_CHECKING switches when not allowed" {
export INPUT_LEGACY_ALLOW_RSA_HOSTKEYS="false"
export INPUT_STRICT_HOSTKEYS_CHECKING="false"
export INPUT_REMOTE_PATH="remote/"
export INPUT_REMOTE_KEY="dummy"
export INPUT_REMOTE_KEY_PASS="dummy"
export GITHUB_ACTION="dummy"
export INPUT_SWITCHES="-avz"
export INPUT_REMOTE_PORT="22"
export INPUT_RSH=""
export INPUT_PATH=""
export INPUT_REMOTE_USER="user"
export INPUT_REMOTE_HOST="localhost.local"
export GITHUB_WORKSPACE="/tmp"
export DSN="user@localhost.local"
export LOCAL_PATH="/tmp/"
run ./entrypoint.sh
[[ "${output}" == *"rsync -avz -e ssh -o StrictHostKeyChecking=no -p 22 /tmp/ user@localhost.local:remote/"* ]]
}