diff --git a/.gitea/workflows/test-build.yaml b/.gitea/workflows/test-build.yaml index 8a31e09..6cf57ca 100644 --- a/.gitea/workflows/test-build.yaml +++ b/.gitea/workflows/test-build.yaml @@ -2,6 +2,11 @@ name: Test Actions (self-test) on: workflow_dispatch: {} + workflow_run: + workflows: + - Build and Push Runner Images + types: + - completed push: branches: - main @@ -19,6 +24,7 @@ env: jobs: test-build-push-amd64: name: AMD64 - Build tiny multi-arch image (${{ matrix.runner }}) + if: ${{ gitea.event_name != 'workflow_run' || gitea.event.workflow_run.conclusion == 'success' }} runs-on: ${{ matrix.runner }} strategy: matrix: @@ -62,6 +68,7 @@ jobs: test-build-push-arm64: name: ARM64 - Build tiny multi-arch image (${{ matrix.runner }}) + if: ${{ gitea.event_name != 'workflow_run' || gitea.event.workflow_run.conclusion == 'success' }} runs-on: ${{ matrix.runner }} strategy: matrix: @@ -103,96 +110,62 @@ jobs: echo "${MANIFEST}" | grep -q "linux/arm64" || { echo "missing linux/arm64"; exit 1; } echo "self-test PASSED: multi-arch image built and pushed" - test-k8s-amd64: - name: AMD64 - Test Kubernetes actions (${{ matrix.runner }}) + test-k8s: + name: Test Kubernetes actions (${{ matrix.runner }}) + if: ${{ gitea.event_name != 'workflow_run' || gitea.event.workflow_run.conclusion == 'success' }} runs-on: ${{ matrix.runner }} strategy: matrix: - runner: [runner-slim-amd64, runner-full-amd64] + runner: [runner-slim-amd64, runner-full-amd64, runner-slim-arm64, runner-full-arm64] + env: + TEST_NAMESPACE: pipeline-actions-test-${{ gitea.run_id }}-${{ matrix.runner }} steps: - name: Check out repository uses: actions/checkout@v4 - - name: Apply test manifests + - name: Create isolated test namespace + shell: bash + run: | + printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml + kubectl --kubeconfig=kubeconfig.yaml create namespace "${TEST_NAMESPACE}" + + - name: Apply test manifest uses: https://git.ivanch.me/ivanch/pipeline-actions/kubectl-apply@main with: kube_config: ${{ secrets.KUBE_CONFIG }} - manifests: tests/manifests/test-namespace.yaml,tests/manifests/test-deployment.yaml + manifest: tests/manifests/test-deployment.yaml + namespace: ${{ env.TEST_NAMESPACE }} - name: Restart test deployment uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main with: kube_config: ${{ secrets.KUBE_CONFIG }} deployment_name: pipeline-actions-test - namespace: pipeline-actions-test + namespace: ${{ env.TEST_NAMESPACE }} - name: Verify deployment rollout status shell: bash run: | - printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml - kubectl --kubeconfig=kubeconfig.yaml rollout status deployment/pipeline-actions-test -n pipeline-actions-test --timeout=60s + kubectl --kubeconfig=kubeconfig.yaml rollout status deployment/pipeline-actions-test -n "${TEST_NAMESPACE}" --timeout=60s - name: Clean up Kubernetes resources if: always() shell: bash run: | - if [ -f kubeconfig.yaml ]; then - kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true - kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false - else + if [ ! -f kubeconfig.yaml ]; then printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml - kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true - kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false fi + kubectl --kubeconfig=kubeconfig.yaml delete namespace "${TEST_NAMESPACE}" --ignore-not-found=true --wait=true --timeout=120s - test-k8s-arm64: - name: ARM64 - Test Kubernetes actions (${{ matrix.runner }}) + test-ssh: + name: Test SSH deploy action (${{ matrix.runner }}) + if: ${{ gitea.event_name != 'workflow_run' || gitea.event.workflow_run.conclusion == 'success' }} runs-on: ${{ matrix.runner }} strategy: matrix: - runner: [runner-slim-arm64, runner-full-arm64] - steps: - - name: Check out repository - uses: actions/checkout@v4 - - - name: Apply test manifests - uses: https://git.ivanch.me/ivanch/pipeline-actions/kubectl-apply@main - with: - kube_config: ${{ secrets.KUBE_CONFIG }} - manifests: tests/manifests/test-namespace.yaml,tests/manifests/test-deployment.yaml - - - name: Restart test deployment - uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main - with: - kube_config: ${{ secrets.KUBE_CONFIG }} - deployment_name: pipeline-actions-test - namespace: pipeline-actions-test - - - name: Verify deployment rollout status - shell: bash - run: | - printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml - kubectl --kubeconfig=kubeconfig.yaml rollout status deployment/pipeline-actions-test -n pipeline-actions-test --timeout=60s - - - name: Clean up Kubernetes resources - if: always() - shell: bash - run: | - if [ -f kubeconfig.yaml ]; then - kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true - kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false - else - printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml - kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true - kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false - fi - - test-ssh-amd64: - name: AMD64 - Test SSH deploy action (${{ matrix.runner }}) - runs-on: ${{ matrix.runner }} - strategy: - matrix: - runner: [runner-slim-amd64, runner-full-amd64] + runner: [runner-slim-amd64, runner-full-amd64, runner-slim-arm64, runner-full-arm64] + env: + TEST_ID: pipeline-actions-ssh-${{ gitea.run_id }}-${{ matrix.runner }} steps: - name: Check out repository uses: actions/checkout@v4 @@ -200,30 +173,32 @@ jobs: - name: Install and configure SSH server shell: bash run: | - sudo apt-get update - sudo apt-get install -y openssh-server + if [ "$(id -u)" -ne 0 ]; then + echo "::error::The SSH self-test requires a root runner container." + exit 1 + fi - # Ensure privilege separation directory exists - sudo mkdir -p /run/sshd + if command -v apk >/dev/null 2>&1; then + apk add --no-cache openssh-server + elif command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -y && apt-get install -y openssh-server + else + echo "::error::No supported package manager (apk or apt-get) was found." + exit 1 + fi - # Generate host keys if missing - sudo ssh-keygen -A - - # Start sshd on a custom port 2222 to avoid port conflicts on the runner host - sudo /usr/sbin/sshd -p 2222 -o "ListenAddress 127.0.0.1" -o "UsePAM yes" - - # Configure passwordless SSH login for current user - mkdir -p ~/.ssh + mkdir -p /run/sshd ~/.ssh + ssh-keygen -A + rm -f ~/.ssh/id_test ~/.ssh/id_test.pub ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_test cat ~/.ssh/id_test.pub >> ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys + "$(command -v sshd)" -p 2222 -o "ListenAddress 127.0.0.1" - # Establish environment variables for subsequent steps echo "SSH_USER=$(whoami)" >> "$GITHUB_ENV" - echo "TEST_REMOTE_DIR=$HOME/ssh_deploy_test" >> "$GITHUB_ENV" - - # Write the private key to GitHub/Gitea env securely using multiline syntax + echo "TEST_REMOTE_DIR=${HOME}/${TEST_ID}" >> "$GITHUB_ENV" echo "SSH_PRIVATE_KEY<> "$GITHUB_ENV" cat ~/.ssh/id_test >> "$GITHUB_ENV" echo "EOF" >> "$GITHUB_ENV" @@ -237,12 +212,11 @@ jobs: shell: bash run: | mkdir -p "${TEST_REMOTE_DIR}" - # We write a compose file containing nginx:latest - cat > "${TEST_REMOTE_DIR}/docker-compose.yml" <<'EOF' + cat > "${TEST_REMOTE_DIR}/docker-compose.yml" <> ~/.ssh/authorized_keys - chmod 700 ~/.ssh - chmod 600 ~/.ssh/authorized_keys - - # Establish environment variables for subsequent steps - echo "SSH_USER=$(whoami)" >> "$GITHUB_ENV" - echo "TEST_REMOTE_DIR=$HOME/ssh_deploy_test" >> "$GITHUB_ENV" - - # Write the private key to GitHub/Gitea env securely using multiline syntax - echo "SSH_PRIVATE_KEY<> "$GITHUB_ENV" - cat ~/.ssh/id_test >> "$GITHUB_ENV" - echo "EOF" >> "$GITHUB_ENV" - - - name: Verify SSH localhost access - shell: bash - run: | - ssh -p 2222 -i ~/.ssh/id_test -o StrictHostKeyChecking=accept-new "${SSH_USER}@127.0.0.1" "echo 'Localhost SSH OK'" - - - name: Set up remote compose directory and files - shell: bash - run: | - mkdir -p "${TEST_REMOTE_DIR}" - # We write a compose file containing nginx:latest - cat > "${TEST_REMOTE_DIR}/docker-compose.yml" <<'EOF' - services: - test-nginx: - image: nginx:latest - container_name: pipeline-actions-ssh-test - restart: always - EOF - - - name: Deploy via composite action with image override - uses: https://git.ivanch.me/ivanch/pipeline-actions/ssh-deploy@main - with: - ssh_host: "127.0.0.1" - ssh_port: "2222" - ssh_username: ${{ env.SSH_USER }} - ssh_key: ${{ env.SSH_PRIVATE_KEY }} - remote_dir: ${{ env.TEST_REMOTE_DIR }} - image: "nginx" - image_tag: "alpine" - - - name: Verify container started and image pin succeeded - shell: bash - run: | - echo "Checking container status..." - docker ps -a - STATUS=$(docker ps --filter "name=pipeline-actions-ssh-test" --format "{{.Status}}") - echo "Container status: ${STATUS}" - echo "${STATUS}" | grep -q "Up" || { echo "Container is not running"; exit 1; } - - echo "Checking image pin..." - IMAGE_USED=$(docker inspect pipeline-actions-ssh-test --format '{{.Config.Image}}') + IMAGE_USED=$(docker inspect "${TEST_ID}" --format '{{.Config.Image}}') echo "Container is using image: ${IMAGE_USED}" echo "${IMAGE_USED}" | grep -q "nginx:alpine" || { echo "Image pin failed"; exit 1; } echo "self-test PASSED: container is running and using nginx:alpine" diff --git a/build-and-push/action.yaml b/build-and-push/action.yaml index 9f0ee8f..d0a8e3d 100644 --- a/build-and-push/action.yaml +++ b/build-and-push/action.yaml @@ -53,6 +53,31 @@ inputs: runs: using: composite steps: + - name: Ensure Docker CLI and Buildx are installed + shell: bash + run: | + if ! command -v docker >/dev/null 2>&1; then + echo "Docker CLI not found, attempting to install it with Buildx..." + if command -v apk >/dev/null 2>&1; then + apk add --no-cache docker-cli docker-cli-buildx + elif command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -y && apt-get install -y docker.io docker-buildx + elif command -v dnf >/dev/null 2>&1; then + dnf install -y docker-cli docker-buildx + elif command -v yum >/dev/null 2>&1; then + yum install -y docker docker-buildx + else + echo "::error::Docker CLI is missing and no supported package manager (apk, apt-get, dnf, yum) was found." + exit 1 + fi + fi + + if ! docker buildx version >/dev/null 2>&1; then + echo "::error::Docker Buildx is required but is not installed." + exit 1 + fi + - name: Log in to Container Registry shell: bash env: diff --git a/tests/manifests/test-deployment.yaml b/tests/manifests/test-deployment.yaml index f3fc80c..8fd72ad 100644 --- a/tests/manifests/test-deployment.yaml +++ b/tests/manifests/test-deployment.yaml @@ -2,7 +2,6 @@ apiVersion: apps/v1 kind: Deployment metadata: name: pipeline-actions-test - namespace: pipeline-actions-test spec: replicas: 1 selector: diff --git a/tests/manifests/test-namespace.yaml b/tests/manifests/test-namespace.yaml deleted file mode 100644 index 79ba8d3..0000000 --- a/tests/manifests/test-namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: pipeline-actions-test