mirror of
https://github.com/Burnett01/rsync-deployments.git
synced 2026-09-20 05:35:54 +08:00
Compare commits
23 Commits
copilot/fix-85
...
8.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
| dc0d5d44c4 | |||
| cccc35d762 | |||
| 2ad5f95a8a | |||
| 115573f97b | |||
| 7659d600d8 | |||
| 81be6cf6d7 | |||
| 178d2ea600 | |||
| 241aa321a8 | |||
| 80e4fa792e | |||
| 0c902521b8 | |||
| 68d1fd5150 | |||
| 2c22263f9c | |||
| 8a39558686 | |||
| 0f1cb7924d | |||
| 05a269aeea | |||
| 92961b5880 | |||
| 96abc27e05 | |||
| 7e729bf4dd | |||
| c23b68a9ef | |||
| 3e83373c59 | |||
| da6a0e1f57 | |||
| 0b92d76269 | |||
| 78cbabbd5c |
@@ -0,0 +1,5 @@
|
||||
Dockerfile
|
||||
LICENSE
|
||||
*.md
|
||||
.git*
|
||||
.github*
|
||||
@@ -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
|
||||
@@ -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
@@ -1,11 +1,14 @@
|
||||
# drinternet/rsync@v1.5.1
|
||||
FROM drinternet/rsync@sha256:e61f4047577b566872764fa39299092adeab691efb3884248dbd6495dc926527
|
||||
FROM alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 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
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2022 Contention
|
||||
Copyright (c) 2019-2025 Joshua Piper (Dr Internet)
|
||||
Copyright (c) 2019-2025 Burnett01
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
||||
@@ -6,24 +6,66 @@
|
||||
[](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.3** (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.3](https://www.alpinelinux.org/posts/Alpine-3.20.9-3.21.6-3.22.3-3.23.3-released.html)
|
||||
Rsync version: [3.4.1-r1](https://download.samba.org/pub/rsync/NEWS#3.4.1)
|
||||
|
||||
## Current Version: v8 (8.0.3)
|
||||
|
||||
### Release channels:
|
||||
|
||||
| Version | Purpose | Immutable |
|
||||
| ------- | ------------------ | ------------------ |
|
||||
| ``v8`` (recommended) | latest MAJOR (pointer to 8.MINOR.PATCH) | no |
|
||||
| 8.0.3 | latest MINOR+PATCH | yes |
|
||||
| 7.1.0 | previous MAJOR+MINOR ([deprecation notice](https://github.com/Burnett01/rsync-deployments/discussions/96)) | yes |
|
||||
| 7.0.2 | previous MAJOR+PATCH ([deprecation notice](https://github.com/Burnett01/rsync-deployments/discussions/96)) | no |
|
||||
|
||||
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 +91,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 +108,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 +148,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 +174,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 +261,58 @@ 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.0 (EOL due to regression -> fixed via 8.0.1 & 8.0.2)
|
||||
|
||||
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.0 (alpine 3.23.0)
|
||||
|
||||
## Version 7.1.0
|
||||
|
||||
Check here:
|
||||
|
||||
- https://github.com/Burnett01/rsync-deployments/tree/7.1.0 (alpine 3.22.1)
|
||||
|
||||
|
||||
## Version 7.0.2 (DEPRECATED)
|
||||
|
||||
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 +373,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)
|
||||
|
||||
---
|
||||
|
||||
|
||||
+25
-12
@@ -1,21 +1,34 @@
|
||||
# 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.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 | :white_check_mark: | >= 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 | :warning: DEPRECATED | >= 3.4.1-r0 | 3.22.1 | June, 1st 2026 ([deprecation notice](https://github.com/Burnett01/rsync-deployments/discussions/96)) |
|
||||
| 7.0.2 | :warning: DEPRECATED | >= 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
@@ -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'
|
||||
|
||||
@@ -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.
|
||||
Executable
+6
@@ -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
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
echo "$SSH_PASS"
|
||||
Executable
+21
@@ -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
|
||||
Executable
+37
@@ -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
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
echo "$@" >> $HOME/.ssh/known_hosts
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
truncate -s 0 $HOME/.ssh/known_hosts
|
||||
Executable
+9
@@ -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
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
if [ ! -d "$HOME/.ssh" ]; then
|
||||
mkdir -m 700 $HOME/.ssh
|
||||
fi
|
||||
+38
-8
@@ -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
@@ -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/"* ]]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user