Skip to content

Refactor: Convert Docker action to composite action for speed and add… #4

Refactor: Convert Docker action to composite action for speed and add…

Refactor: Convert Docker action to composite action for speed and add… #4

Workflow file for this run

name: Test Composite Action
on: [push, pull_request]
jobs:
test-action:
runs-on: ubuntu-latest
services:
sshd:
image: rastasheep/ubuntu-sshd:22.04 # Pinned version
ports:
- 2222:22
# We will configure the sshd service using a step below
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Generate SSH keys & Configure Service Container
id: ssh_setup # Give an id to this step to reference its outputs
run: |
# Generate SSH keys
ssh-keygen -t rsa -b 2048 -f test_ssh_key -N ""
sudo apt-get update && sudo apt-get install -y sshpass netcat-openbsd
echo "Waiting for SSH service (localhost:2222) to be ready..."
MAX_WAIT_ATTEMPTS=12 # Wait for up to 60 seconds (12 * 5s)
CURRENT_WAIT_ATTEMPT=0
until nc -zv localhost 2222; do
CURRENT_WAIT_ATTEMPT=$((CURRENT_WAIT_ATTEMPT+1))
if [ $CURRENT_WAIT_ATTEMPT -gt $MAX_WAIT_ATTEMPTS ]; then
echo "Service sshd on port 2222 did not become available."
exit 1
fi
echo "Waiting for port 2222... attempt $CURRENT_WAIT_ATTEMPT"
sleep 5
done
echo "SSH service port is open."
echo "Ensuring /root/.ssh directory exists on service container..."
sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "mkdir -p /root/.ssh && chmod 700 /root/.ssh" || { echo "Failed to create /root/.ssh on service container"; exit 1; }
echo "Attempting to copy SSH public key to service container..."
MAX_SCP_ATTEMPTS=5
COUNT=0
while [ $COUNT -lt $MAX_SCP_ATTEMPTS ]; do
sshpass -p root scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P 2222 ./test_ssh_key.pub root@localhost:/root/.ssh/authorized_keys && break
COUNT=$((COUNT+1))
echo "SSH key copy attempt $COUNT failed. Retrying in 5s..."
sleep 5
done
if [ $COUNT -eq $MAX_SCP_ATTEMPTS ]; then
echo "Failed to copy SSH key to service container after $MAX_SCP_ATTEMPTS attempts."
# For debugging, show if the .ssh directory exists
sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "ls -la /root/ && ls -la /root/.ssh/" || echo "Failed to list /root/.ssh on service."
exit 1
fi
echo "Copied generated public key to service container's /root/.ssh/authorized_keys."
# Output keys for other steps
# Need to escape multi-line private key for ::set-output (deprecated) or GITHUB_OUTPUT
# Using GITHUB_OUTPUT format
echo "private_key<<EOF" >> $GITHUB_OUTPUT
cat test_ssh_key >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "public_key=$(cat test_ssh_key.pub)" >> $GITHUB_OUTPUT
echo "Generated and set SSH key outputs for use in subsequent steps."
- name: Setup Mock Docker Command
run: |
echo '#!/bin/bash' > ./docker_mock.sh
echo 'echo "DOCKER_MOCK_CALLED_WITH: $@" >> /tmp/docker_calls.log' >> ./docker_mock.sh
echo 'if [[ "$1" == "context" && "$2" == "create" ]]; then echo "Context created"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "context" && "$2" == "use" ]]; then echo "Context used"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "ps" ]]; then echo "CONTAINER ID IMAGE COMMAND"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "login" ]]; then echo "Login Succeeded"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "compose" && "$3" == "pull" ]]; then echo "Pulling done"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "compose" ]]; then echo "Compose command executed"; exit 0; fi' >> ./docker_mock.sh
echo 'if [[ "$1" == "stack" && "$2" == "deploy" ]]; then echo "Stack deploy command executed"; exit 0; fi' >> ./docker_mock.sh
echo 'exit 0' >> ./docker_mock.sh
chmod +x ./docker_mock.sh
sudo ln -sf "$PWD/docker_mock.sh" /usr/local/bin/docker
echo "Mock Docker command setup at /usr/local/bin/docker. Calls logged to /tmp/docker_calls.log"
# Ensure log file is clean before first test
rm -f /tmp/docker_calls.log
# --- Test Case 1: Basic SSH and Docker Context (Compose ps) ---
- name: Test 1 - Basic SSH, Docker Context, Compose
uses: ./ # Uses the composite action in the root of the repository
with:
remote_docker_host: root@localhost
ssh_port: 2222
ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }}
ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }}
args: "ps" # For docker compose ps
- name: Verify Test 1
shell: bash
run: |
echo "Verifying Test 1..."
if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi
cat /tmp/docker_calls.log
grep -q "DOCKER_MOCK_CALLED_WITH: context create remote --docker host=ssh://root@localhost:2222" /tmp/docker_calls.log || exit 1
grep -q "DOCKER_MOCK_CALLED_WITH: context use remote" /tmp/docker_calls.log || exit 1
grep -q "DOCKER_MOCK_CALLED_WITH: ps" /tmp/docker_calls.log || exit 1 # From action's context setup test
grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml pull" /tmp/docker_calls.log || exit 1
grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml ps" /tmp/docker_calls.log || exit 1
echo "Test 1 Verification Successful"
rm -f /tmp/docker_calls.log
# --- Test Case 2: Upload Directory ---
- name: Test 2 - Upload Directory
uses: ./
with:
remote_docker_host: root@localhost
ssh_port: 2222
ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }}
ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }}
upload_directory: 'true'
docker_compose_directory: '.github' # Upload this directory for testing
args: "ps" # Dummy args for compose
post_upload_command: "mkdir -p /tmp && echo 'post_upload_executed' > /tmp/post_upload.txt"
- name: Verify Test 2
shell: bash
run: |
echo "Verifying Test 2..."
sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "ls -d /root/.github/workflows" || (echo "Uploaded directory not found" && exit 1)
sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "cat /tmp/post_upload.txt | grep 'post_upload_executed'" || (echo "Post upload command verification failed" && exit 1)
echo "Test 2 Verification Successful"
sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "rm -rf /root/.github /tmp/post_upload.txt"
rm -f /tmp/docker_calls.log
# --- Test Case 3: Docker Swarm Mode ---
- name: Test 3 - Docker Swarm Mode
uses: ./
with:
remote_docker_host: root@localhost
ssh_port: 2222
ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }}
ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }}
docker_swarm: 'true'
args: "deploy --prune myapp" # Example swarm args
compose_file_path: "docker-stack.yml"
- name: Verify Test 3
shell: bash
run: |
echo "Verifying Test 3..."
if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi
cat /tmp/docker_calls.log
grep -q "DOCKER_MOCK_CALLED_WITH: deploy --prune myapp stack deploy --compose-file docker-stack.yml" /tmp/docker_calls.log || exit 1
echo "Test 3 Verification Successful"
rm -f /tmp/docker_calls.log
# --- Test Case 4: Docker Login ---
- name: Test 4 - Docker Login
uses: ./
with:
remote_docker_host: root@localhost
ssh_port: 2222
ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }}
ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }}
args: "ps" # Dummy args
docker_login_user: "testuser"
docker_login_password: "testpassword"
docker_login_registry: "fakeregistry.com"
- name: Verify Test 4
shell: bash
run: |
echo "Verifying Test 4..."
if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi
cat /tmp/docker_calls.log
grep -q "DOCKER_MOCK_CALLED_WITH: login -u testuser --password-stdin fakeregistry.com" /tmp/docker_calls.log || exit 1
echo "Test 4 Verification Successful"
rm -f /tmp/docker_calls.log
# --- Test Case 5: Tailscale SSH (mocked - verifies action proceeds without explicit key inputs) ---
- name: Test 5 - Tailscale SSH
uses: ./
with:
remote_docker_host: root@localhost # Still need for Docker context setup
ssh_port: 2222
tailscale_ssh: 'true'
args: "ps"
# ssh_private_key and ssh_public_key are intentionally omitted for this test case
- name: Verify Test 5
shell: bash
run: |
echo "Verifying Test 5 (Tailscale SSH mode)..."
if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi
cat /tmp/docker_calls.log
# Essential Docker commands should still be logged by the mock
grep -q "DOCKER_MOCK_CALLED_WITH: context create remote --docker host=ssh://root@localhost:2222" /tmp/docker_calls.log || exit 1
grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml ps" /tmp/docker_calls.log || exit 1
echo "Test 5 Verification Successful"
rm -f /tmp/docker_calls.log