Fix: Use valid Docker tag for SSHD service in test workflow #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Test Composite Action | |
on: [push, pull_request] | |
jobs: | |
test-action: | |
runs-on: ubuntu-latest | |
services: | |
sshd: | |
image: rastasheep/ubuntu-sshd:jammy # Updated to jammy for Ubuntu 22.04 | |
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 |