diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..f3dfaf1 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,42 @@ +on: + pull_request: + branches: + - main +jobs: + test: + strategy: + fail-fast: false + matrix: + os: + - macos-15 + - ubuntu-24.04 + - windows-2025 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Setup SSH key + uses: ./ + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + log-public-key: false + - name: Check known hosts file + uses: pyTooling/Actions/with-post-step@9ceefdbf5dceae8c441fc393ed82344c7ca8bbdb # v3.1.1 + env: + SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }} + with: + main: | + sh check.sh + post: | + sh post_check.sh + - name: Install docker (Missing on MacOS) + if: runner.os == 'macos' + shell: bash + run: | + brew install --cask docker + - name: Deploy over SSH + shell: bash + env: + DOCKER_HOST: ${{ secrets.DOCKER_HOST }} + run: | + sh deploy.sh \ No newline at end of file diff --git a/action.sh b/action.sh index ed17dfa..33ea4fa 100755 --- a/action.sh +++ b/action.sh @@ -1,4 +1,10 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +set -e + +SSH_KNOWN_HOSTS_FILE="${HOME}/.ssh/known_hosts" + +mkdir -p "$(dirname "${SSH_KNOWN_HOSTS_FILE}")" if [ -z "${SSH_HOST}" ] && [ -z "${SSH_KNOWN_HOSTS}" ]; then echo ":error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Input validation::\ @@ -11,6 +17,7 @@ else Both 'ssh-host' and 'ssh-known-hosts' inputs are set. Using 'ssh-known-hosts'." fi echo "${SSH_KNOWN_HOSTS}" >> "${SSH_KNOWN_HOSTS_FILE}" + echo "::notice file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Notice::${SSH_KNOWN_HOSTS_FILE} has been created." else echo "::warning file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Security risk::\ If an ssh_known_hosts file is constructed using ssh-keyscan without verifying the keys, \ @@ -19,17 +26,20 @@ ssh-keyscan can help in the detection of tampered keyfiles or man in the middle the ssh_known_hosts file was created." if [ -z "${SSH_KEY_TYPE}" ]; then - if ! ssh-keyscan "${SSH_HOST}" >> "${SSH_KNOWN_HOSTS_FILE}"; then + if ! ssh-keyscan "${SSH_HOST} | grep -o '^[^#]*'" >> "${SSH_KNOWN_HOSTS_FILE}"; then echo "::error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=SSH Keyscan Failed::\ Failed to scan SSH host keys for ${SSH_HOST}" exit 1 fi else - if ! ssh-keyscan -t "${SSH_KEY_TYPE}" "${SSH_HOST}" >> "${SSH_KNOWN_HOSTS_FILE}"; then + if ! ssh-keyscan -t "${SSH_KEY_TYPE}" "${SSH_HOST}" | grep -o '^[^#]*' >> "${SSH_KNOWN_HOSTS_FILE}"; then echo "::error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=SSH Keyscan Failed::\ Failed to scan SSH host keys for ${SSH_HOST}" exit 1 fi fi + echo "::notice file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Notice::${SSH_KNOWN_HOSTS_FILE} has been created." fi fi + +unset SSH_KNOWN_HOSTS_FILE \ No newline at end of file diff --git a/action.yml b/action.yml index b2a000c..8df59cb 100644 --- a/action.yml +++ b/action.yml @@ -9,7 +9,6 @@ inputs: Specify the type of the key to fetch from the scanned hosts. The possible values are “ecdsa”, “ed25519”, “ecdsa-sk”, “ed25519-sk”, or “rsa”. Multiple values may be specified by separating them with commas. The default is to fetch all the above key types. required: false - default: 'rsa' ssh-known-hosts: description: 'Predefined known hosts to be added directly.' required: false @@ -36,17 +35,6 @@ inputs: runs: using: 'composite' steps: - - uses: pyTooling/Actions/with-post-step@9ceefdbf5dceae8c441fc393ed82344c7ca8bbdb # v3.1.1 - env: - SSH_HOST: ${{ inputs.ssh-host }} - SSH_KEY_TYPE: ${{ inputs.ssh-key-type }} - SSH_KNOWN_HOSTS: ${{ inputs.ssh-known-hosts }} - SSH_KNOWN_HOSTS_FILE: '~/.ssh/known_hosts' - with: - main: | - ./action.sh - post: | - ./post_action.sh - uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387 # v0.9.0 with: ssh-private-key: ${{ inputs.ssh-private-key }} @@ -55,4 +43,14 @@ runs: ssh-agent-cmd: ${{ inputs.ssh-agent-cmd }} ssh-add-cmd: ${{ inputs.ssh-add-cmd }} git-cmd: ${{ inputs.git-cmd }} + - uses: pyTooling/Actions/with-post-step@9ceefdbf5dceae8c441fc393ed82344c7ca8bbdb # v3.1.1 + env: + SSH_HOST: ${{ inputs.ssh-host }} + SSH_KEY_TYPE: ${{ inputs.ssh-key-type }} + SSH_KNOWN_HOSTS: ${{ inputs.ssh-known-hosts }} + with: + main: | + sh action.sh + post: | + sh post_action.sh diff --git a/check.sh b/check.sh new file mode 100755 index 0000000..5d6d82a --- /dev/null +++ b/check.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +if [ ! -s "${HOME}/.ssh/known_hosts" ]; then + echo "::error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Assertion Error::\ +~/.ssh/known_hosts is missing or empty." + exit 1 +fi \ No newline at end of file diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..694cb94 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +# renovate: datasource=docker depname=traefik/whoami versioning=docker +WHOAMI_VERSION="v1.10" +CONTAINER_NAME="${RUNNER_OS}-whoami" +docker run --detach --publish-all --name "${CONTAINER_NAME}" traefik/whoami:"${WHOAMI_VERSION}" +docker stop "${CONTAINER_NAME}" +docker rm "${CONTAINER_NAME}" + +unset WHOAMI_VERSION +unset CONTAINER_NAME \ No newline at end of file diff --git a/post_action.sh b/post_action.sh index 9ef0fe0..09ca77f 100755 --- a/post_action.sh +++ b/post_action.sh @@ -1,10 +1,14 @@ -#!/usr/bin/env bash - -if [ -z "${SSH_KNOWN_HOSTS_FILE}" ]; then - echo "::error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Notice::\ -${SSH_KNOWN_HOSTS_FILE} environment variable must be set." -else - rm -rf "${SSH_KNOWN_HOSTS_FILE}" - echo "::notice file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Notice::\ -${SSH_KNOWN_HOSTS_FILE} has been removed." -fi \ No newline at end of file +#!/usr/bin/env sh + +SSH_KNOWN_HOSTS_FILE="${HOME}/.ssh/known_hosts" +TEMP_FILE="/tmp/718f4157-5493-43b2-837b-3ccb27f78e7b" + +sed '$ d' "${SSH_KNOWN_HOSTS_FILE}" > "${TEMP_FILE}" +cat "${TEMP_FILE}" > "${SSH_KNOWN_HOSTS_FILE}" +rm -rf "${TEMP_FILE}" + +echo "::notice file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Notice::\ +${SSH_KNOWN_HOSTS_FILE} has been cleaned." + +unset SSH_KNOWN_HOSTS_FILE +unset TEMP_FILE \ No newline at end of file diff --git a/post_check.sh b/post_check.sh new file mode 100755 index 0000000..d8c7dc5 --- /dev/null +++ b/post_check.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +SSH_KNOWN_HOSTS_FILE="${HOME}/.ssh/known_hosts" + +if ! grep -q "${SSH_KNOWN_HOSTS}" "${SSH_KNOWN_HOSTS_FILE}" ; then + echo "::error file=$(basename "$0"),line=${LINENO},endLine=${LINENO},title=Assertion Error::\ +${SSH_KNOWN_HOSTS_FILE} file should not contain the ssh fingerprint after the job." + exit 1 +fi + +unset SSH_KNOWN_HOSTS_FILE \ No newline at end of file