From d7a27eb63a6bf4d22f4aef50b389eb400e07dd5f Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Wed, 20 May 2026 17:22:46 -0300 Subject: [PATCH 01/27] Create WF for integration testing --- .../workflows/check_integration_tools.yaml | 472 ++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 .github/workflows/check_integration_tools.yaml diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml new file mode 100644 index 00000000..eef80fc7 --- /dev/null +++ b/.github/workflows/check_integration_tools.yaml @@ -0,0 +1,472 @@ +run-name: >- + ${{ github.event_name == 'workflow_dispatch' + && format('Docker Integration Test - Manual {0} on {1}', inputs.deployment_type, inputs.pr_head_ref) + || format('Docker Integration Test - #{0} {1}', github.event.issue.number, github.event.issue.title) }} +name: PR Check - Docker Integration Tests + +on: + issue_comment: + types: [created] + workflow_dispatch: + inputs: + pr_head_ref: + description: 'Branch of wazuh-docker to test' + required: true + type: string + automation_reference: + description: 'Branch of wazuh-automation to use' + required: false + default: 'main' + type: string + deployment_type: + description: 'Deployment type to test' + required: true + type: choice + options: + - single-node + - multi-node + - both + +permissions: + id-token: write + contents: read + pull-requests: write + issues: write + checks: write + +env: + AUTOMATION_REFERENCE: ${{ inputs.automation_reference || 'main' }} + ALLOCATOR_PATH: /tmp/allocator_instance + REGION: us-east-1 + +jobs: + # ------------------------------------------------------------------------- + # Job 1: Parse PR info and determine which deployment(s) to test + # + # Available commands (checked longest-match first to avoid substring collision): + # /test-docker-single — test single-node deployment + # /test-docker-multi — test multi-node deployment + # /test-docker — test both single-node and multi-node + # ------------------------------------------------------------------------- + get_pr_info: + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.issue.state == 'open' && + !github.event.issue.draft && + (contains(github.event.comment.body, '/test-docker-single') || + contains(github.event.comment.body, '/test-docker-multi') || + contains(github.event.comment.body, '/test-docker')) + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.pr_data.outputs.pr_number }} + pr_head_ref: ${{ steps.pr_data.outputs.pr_head_ref }} + pr_head_sha: ${{ steps.pr_data.outputs.pr_head_sha }} + check_run_id: ${{ steps.create_check.outputs.result }} + deployment_matrix: ${{ steps.parse_command.outputs.deployment_matrix }} + check_name: ${{ steps.parse_command.outputs.check_name }} + + steps: + - name: React to comment + uses: actions/github-script@v7 + with: + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'rocket' + }); + + - name: Extract PR data + id: pr_data + env: + GH_TOKEN: ${{ github.token }} + run: | + PR_NUMBER="${{ github.event.issue.number }}" + PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${PR_NUMBER}) + PR_HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref') + PR_HEAD_SHA=$(echo "$PR_DATA" | jq -r '.head.sha') + echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT + echo "pr_head_ref=${PR_HEAD_REF}" >> $GITHUB_OUTPUT + echo "pr_head_sha=${PR_HEAD_SHA}" >> $GITHUB_OUTPUT + + - name: Parse command and set deployment metadata + id: parse_command + run: | + COMMENT_BODY="${{ github.event.comment.body }}" + # Check longest match first to avoid /test-docker matching /test-docker-single + if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then + echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check (Single-Node)' >> $GITHUB_OUTPUT + elif echo "$COMMENT_BODY" | grep -q '/test-docker-multi'; then + echo 'deployment_matrix=["multi-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check (Multi-Node)' >> $GITHUB_OUTPUT + elif echo "$COMMENT_BODY" | grep -q '/test-docker'; then + echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check' >> $GITHUB_OUTPUT + fi + + - name: Create check run + id: create_check + uses: actions/github-script@v7 + env: + HEAD_SHA: ${{ steps.pr_data.outputs.pr_head_sha }} + CHECK_NAME: ${{ steps.parse_command.outputs.check_name }} + COMMENT_BODY: ${{ github.event.comment.body }} + with: + script: | + const { data: check } = await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: process.env.CHECK_NAME, + head_sha: process.env.HEAD_SHA, + status: 'in_progress', + started_at: new Date().toISOString(), + details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + output: { + title: `🔨 Running ${process.env.CHECK_NAME}...`, + summary: `Triggered by comment: \`${process.env.COMMENT_BODY}\``, + text: 'Allocating instance and running Docker integration tests' + } + }); + console.log('Check run created:', check.id); + return check.id; + + # ------------------------------------------------------------------------- + # Job 2: For each deployment type — provision VM, deploy Docker stack, test, + # collect results, and clean up. + # ------------------------------------------------------------------------- + docker_test: + needs: [get_pr_info] + if: | + always() && + (needs.get_pr_info.result == 'success' || github.event_name == 'workflow_dispatch') + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + deployment_type: ${{ fromJSON( + github.event_name == 'workflow_dispatch' + && (inputs.deployment_type == 'both' && '["single-node","multi-node"]' + || format('["{0}"]', inputs.deployment_type)) + || needs.get_pr_info.outputs.deployment_matrix + ) }} + + steps: + # ----------------------------------------------------------------------- + # Setup + # ----------------------------------------------------------------------- + - name: Resolve PR head ref + id: ctx + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "pr_head_ref=${{ inputs.pr_head_ref }}" >> $GITHUB_OUTPUT + else + echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT + fi + + - name: Checkout wazuh-automation + uses: actions/checkout@v4 + with: + repository: wazuh/wazuh-automation + ref: ${{ env.AUTOMATION_REFERENCE }} + token: ${{ secrets.GH_CLONE_TOKEN }} + path: wazuh-automation + + - name: Checkout wazuh-docker PR branch + uses: actions/checkout@v4 + with: + ref: ${{ steps.ctx.outputs.pr_head_ref }} + path: wazuh-docker + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install requirements + run: | + pip install -r wazuh-automation/deployability/deps/requirements.txt + pip install -r wazuh-automation/integration-test-module/requirements.txt + pip install -e wazuh-automation/integration-test-module/ + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }} + aws-region: ${{ env.REGION }} + + # ----------------------------------------------------------------------- + # Provision: allocate VM and extract SSH credentials + # ----------------------------------------------------------------------- + - name: Allocate instance + id: allocate + run: | + mkdir -p ${{ env.ALLOCATOR_PATH }} + python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action create \ + --provider aws \ + --size xlarge \ + --composite-name ubuntu-24-amd64 \ + --working-dir ${{ env.ALLOCATOR_PATH }} \ + --track-output ${{ env.ALLOCATOR_PATH }}/track.yml \ + --inventory-output ${{ env.ALLOCATOR_PATH }}/inventory.yml \ + --instance-name gha_${{ github.run_id }}_docker_${{ matrix.deployment_type }} \ + --label-team devops \ + --label-termination-date 1d + + sed -n '/hosts:/,/^[^ ]/p' ${{ env.ALLOCATOR_PATH }}/inventory.yml \ + | grep "ansible_" \ + | sed 's/^[ ]*//g' \ + > ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml + sed 's/: */=/g' ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml \ + > ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + sed -i 's/-o StrictHostKeyChecking=no/"-o StrictHostKeyChecking=no"/g' \ + ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + + - name: Set SSH credentials from inventory + run: | + find ${{ env.ALLOCATOR_PATH }} -name '*-key-*' -exec chmod 600 {} \; + source ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + echo "SSH_HOST=$ansible_host" >> $GITHUB_ENV + echo "SSH_PORT=$ansible_port" >> $GITHUB_ENV + echo "SSH_USER=$ansible_user" >> $GITHUB_ENV + echo "SSH_KEY=$ansible_ssh_private_key_file" >> $GITHUB_ENV + + - name: Set SSH/SCP helper env vars + run: | + echo "SSH_OPTS=-o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=20 -p ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV + echo "SCP_OPTS=-o StrictHostKeyChecking=no -P ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV + echo "REMOTE=${{ env.SSH_USER }}@${{ env.SSH_HOST }}" >> $GITHUB_ENV + + # ----------------------------------------------------------------------- + # Install Docker CE on the remote VM + # ----------------------------------------------------------------------- + - name: Install Docker CE + run: | + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + curl -fsSL https://get.docker.com | sudo sh + sudo systemctl enable --now docker + " + + # ----------------------------------------------------------------------- + # Deploy: copy wazuh-docker and start the stack + # ----------------------------------------------------------------------- + - name: Copy wazuh-docker to VM + run: | + scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" + + - name: Start Docker Compose + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + cd /tmp/wazuh-docker/${DEPLOYMENT} + sudo docker compose up -d 2>&1 | tee /tmp/docker-compose-up.log + " + + - name: Wait for containers healthy + timeout-minutes: 15 + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + echo 'Waiting for all containers to be healthy...' + for i in \$(seq 1 90); do + TOTAL=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps -q 2>/dev/null | wc -l) + HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ + | grep -E '(healthy|\(healthy\))' | wc -l) + NOT_HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ + | grep -vE '(healthy|\(healthy\)|NAME|^$)' | grep -v 'nginx' | wc -l) + + if [ \"\$NOT_HEALTHY\" -eq 0 ] && [ \"\$TOTAL\" -gt 0 ]; then + echo \"All containers healthy after \${i} x 10s attempts (total: \$TOTAL)\" + exit 0 + fi + echo \" attempt \$i: \$HEALTHY healthy, \$NOT_HEALTHY not yet healthy (total: \$TOTAL)\" + sleep 10 + done + echo 'ERROR: containers not healthy after 15 minutes' + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps + exit 1 + " + + # ----------------------------------------------------------------------- + # Run integration tests + # ----------------------------------------------------------------------- + - name: Run tests + id: run_tests + continue-on-error: true + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + test_runner \ + --test-type "docker-${DEPLOYMENT}" \ + --deployment-type "docker-${DEPLOYMENT}" \ + --ssh-host "${{ env.SSH_HOST }}" \ + --ssh-port "${{ env.SSH_PORT }}" \ + --ssh-key-path "${{ env.SSH_KEY }}" \ + --ssh-username "${{ env.SSH_USER }}" \ + --log-level INFO \ + --output github \ + --output-file "test-results-docker-${DEPLOYMENT}.github" + + # ----------------------------------------------------------------------- + # Collect logs on failure + # ----------------------------------------------------------------------- + - name: Collect Docker logs on failure + if: failure() || steps.run_tests.outcome == 'failure' + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml logs --no-color 2>&1 + " > docker-logs-${DEPLOYMENT}.txt || true + + - name: Upload Docker logs + if: failure() || steps.run_tests.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: docker-logs-${{ matrix.deployment_type }}-${{ github.run_id }} + path: docker-logs-*.txt + retention-days: 7 + + # ----------------------------------------------------------------------- + # Reporting + # ----------------------------------------------------------------------- + - name: Create step summary + if: always() + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + echo "## Docker Integration Test Results — ${DEPLOYMENT}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f "test-results-docker-${DEPLOYMENT}.github" ]; then + cat "test-results-docker-${DEPLOYMENT}.github" >> $GITHUB_STEP_SUMMARY + else + echo "No test results file found." >> $GITHUB_STEP_SUMMARY + fi + + - name: Post PR comment with results + if: always() && github.event_name == 'issue_comment' + uses: actions/github-script@v7 + env: + DEPLOYMENT: ${{ matrix.deployment_type }} + RUN_OUTCOME: ${{ steps.run_tests.outcome }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const deployment = process.env.DEPLOYMENT; + const outcome = process.env.RUN_OUTCOME; + const marker = ``; + + let body = `${marker}\n## Docker Integration Tests — \`${deployment}\`\n\n`; + body += outcome === 'success' + ? '✅ **All tests passed!**\n\n' + : '❌ **Some tests failed**\n\n'; + + const resultsFile = `test-results-docker-${deployment}.github`; + try { + if (fs.existsSync(resultsFile)) { + body += '### Results\n\n' + fs.readFileSync(resultsFile, 'utf8') + '\n\n'; + } + } catch (e) { + console.log('Could not read results file:', e.message); + } + body += `- **Workflow:** [View Details](${context.payload.repository.html_url}/actions/runs/${context.runId})\n`; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(c => + c.user.type === 'Bot' && c.body.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body: body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body, + }); + } + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-docker-${{ matrix.deployment_type }}-${{ github.run_id }} + path: test-results-docker-${{ matrix.deployment_type }}.github + retention-days: 7 + + # ----------------------------------------------------------------------- + # Cleanup: always stop stack and deallocate VM + # ----------------------------------------------------------------------- + - name: Stop Docker Compose + if: always() + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml down -v || true + " || true + + - name: Configure AWS credentials for cleanup + if: always() + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-session-name: docker-cleanup-${{ github.run_id }}-${{ matrix.deployment_type }} + aws-region: ${{ env.REGION }} + + - name: Deallocate instance + if: always() + run: | + python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action delete \ + --track-output ${{ env.ALLOCATOR_PATH }}/track.yml + + # ------------------------------------------------------------------------- + # Job 3: Update the GitHub check run (issue_comment trigger only) + # ------------------------------------------------------------------------- + update_check: + needs: [get_pr_info, docker_test] + if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success' + runs-on: ubuntu-latest + steps: + - name: Update check run + uses: actions/github-script@v7 + env: + DOCKER_RESULT: ${{ needs.docker_test.result }} + CHECK_NAME: ${{ needs.get_pr_info.outputs.check_name }} + CHECK_RUN_ID: ${{ needs.get_pr_info.outputs.check_run_id }} + with: + script: | + const result = process.env.DOCKER_RESULT; + const conclusionMap = { + success: { conclusion: 'success', icon: '✅', summary: 'All Docker integration tests passed.' }, + failure: { conclusion: 'failure', icon: '❌', summary: 'One or more Docker integration tests failed.' }, + cancelled: { conclusion: 'cancelled', icon: 'âšī¸', summary: 'Workflow was cancelled.' }, + }; + const { conclusion, icon, summary } = conclusionMap[result] ?? conclusionMap.failure; + const label = conclusion.charAt(0).toUpperCase() + conclusion.slice(1); + await github.rest.checks.update({ + owner: context.repo.owner, + repo: context.repo.repo, + check_run_id: parseInt(process.env.CHECK_RUN_ID), + status: 'completed', + conclusion, + completed_at: new Date().toISOString(), + output: { + title: `${icon} ${process.env.CHECK_NAME} — ${label}`, + summary, + text: `[View workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + } + }); From d168d7d86f366ca314e30aac603ce466a273f133 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Wed, 20 May 2026 17:23:43 -0300 Subject: [PATCH 02/27] Upload WF only for test --- .github/workflows/4_bumper_repository.yml | 552 +++++++++++++++++----- 1 file changed, 441 insertions(+), 111 deletions(-) diff --git a/.github/workflows/4_bumper_repository.yml b/.github/workflows/4_bumper_repository.yml index c932fc35..eef80fc7 100644 --- a/.github/workflows/4_bumper_repository.yml +++ b/.github/workflows/4_bumper_repository.yml @@ -1,142 +1,472 @@ -name: Repository bumper 4.x -run-name: Bump ${{ github.ref_name }} (${{ inputs.id }}) +run-name: >- + ${{ github.event_name == 'workflow_dispatch' + && format('Docker Integration Test - Manual {0} on {1}', inputs.deployment_type, inputs.pr_head_ref) + || format('Docker Integration Test - #{0} {1}', github.event.issue.number, github.event.issue.title) }} +name: PR Check - Docker Integration Tests on: + issue_comment: + types: [created] workflow_dispatch: inputs: - version: - description: 'Target version (e.g. 1.2.3)' - default: '' - required: false - type: string - stage: - description: 'Version stage (e.g. alpha0)' - default: '' - required: false - type: string - tag: - description: 'Change branches references to tag-like references (e.g. v4.12.0-alpha7)' - default: false - required: false - type: boolean - issue-link: - description: 'Issue link in format https://github.com/wazuh//issues/' + pr_head_ref: + description: 'Branch of wazuh-docker to test' required: true type: string - id: - description: 'Optional identifier for the run' + automation_reference: + description: 'Branch of wazuh-automation to use' required: false + default: 'main' type: string + deployment_type: + description: 'Deployment type to test' + required: true + type: choice + options: + - single-node + - multi-node + - both + +permissions: + id-token: write + contents: read + pull-requests: write + issues: write + checks: write + +env: + AUTOMATION_REFERENCE: ${{ inputs.automation_reference || 'main' }} + ALLOCATOR_PATH: /tmp/allocator_instance + REGION: us-east-1 jobs: - bump: - name: Repository bumper 4.x - runs-on: ubuntu-24.04 - permissions: - contents: write - pull-requests: write - - env: - CI_COMMIT_AUTHOR: wazuhci - CI_COMMIT_EMAIL: 22834044+wazuhci@users.noreply.github.com - CI_GPG_PRIVATE_KEY: ${{ secrets.CI_WAZUHCI_GPG_PRIVATE }} - GH_TOKEN: ${{ secrets.CI_WAZUHCI_BUMPER_TOKEN }} - BUMP_SCRIPT_PATH: tools/repository_bumper.sh - BUMP_LOG_PATH: tools + # ------------------------------------------------------------------------- + # Job 1: Parse PR info and determine which deployment(s) to test + # + # Available commands (checked longest-match first to avoid substring collision): + # /test-docker-single — test single-node deployment + # /test-docker-multi — test multi-node deployment + # /test-docker — test both single-node and multi-node + # ------------------------------------------------------------------------- + get_pr_info: + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + github.event.issue.state == 'open' && + !github.event.issue.draft && + (contains(github.event.comment.body, '/test-docker-single') || + contains(github.event.comment.body, '/test-docker-multi') || + contains(github.event.comment.body, '/test-docker')) + runs-on: ubuntu-latest + outputs: + pr_number: ${{ steps.pr_data.outputs.pr_number }} + pr_head_ref: ${{ steps.pr_data.outputs.pr_head_ref }} + pr_head_sha: ${{ steps.pr_data.outputs.pr_head_sha }} + check_run_id: ${{ steps.create_check.outputs.result }} + deployment_matrix: ${{ steps.parse_command.outputs.deployment_matrix }} + check_name: ${{ steps.parse_command.outputs.check_name }} steps: - - name: Dump event payload - run: | - cat $GITHUB_EVENT_PATH | jq '.inputs' - - - name: Set up GPG key - id: signing_setup - run: | - echo "${{ env.CI_GPG_PRIVATE_KEY }}" | gpg --batch --import - KEY_ID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/ {print $5; exit}') - echo "gpg_key_id=$KEY_ID" >> $GITHUB_OUTPUT - - - name: Set up git - run: | - git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}" - git config --global user.email "${{ env.CI_COMMIT_EMAIL }}" - git config --global commit.gpgsign true - git config --global user.signingkey "${{ steps.signing_setup.outputs.gpg_key_id }}" - echo "use-agent" >> ~/.gnupg/gpg.conf - echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf - echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf - echo RELOADAGENT | gpg-connect-agent - export DEBIAN_FRONTEND=noninteractive - export GPG_TTY=$(tty) - - - name: Checkout repository - uses: actions/checkout@v6 + - name: React to comment + uses: actions/github-script@v7 with: - # Using workflow-specific GITHUB_TOKEN because currently CI_WAZUHCI_BUMPER_TOKEN - # doesn't have all the necessary permissions - token: ${{ env.GH_TOKEN }} + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'rocket' + }); - - name: Determine branch name - id: vars + - name: Extract PR data + id: pr_data env: - VERSION: ${{ inputs.version }} - STAGE: ${{ inputs.stage }} - TAG: ${{ inputs.tag }} + GH_TOKEN: ${{ github.token }} run: | - script_params="" - version=${{ env.VERSION }} - stage=${{ env.STAGE }} - tag=${{ env.TAG }} + PR_NUMBER="${{ github.event.issue.number }}" + PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${PR_NUMBER}) + PR_HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref') + PR_HEAD_SHA=$(echo "$PR_DATA" | jq -r '.head.sha') + echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT + echo "pr_head_ref=${PR_HEAD_REF}" >> $GITHUB_OUTPUT + echo "pr_head_sha=${PR_HEAD_SHA}" >> $GITHUB_OUTPUT - # Both version and stage provided - if [[ -n "$version" && -n "$stage" && "$tag" != "true" ]]; then - script_params="--version ${version} --stage ${stage}" - elif [[ -n "$version" && -n "$stage" && "$tag" == "true" ]]; then - script_params="--version ${version} --stage ${stage} --tag ${tag}" + - name: Parse command and set deployment metadata + id: parse_command + run: | + COMMENT_BODY="${{ github.event.comment.body }}" + # Check longest match first to avoid /test-docker matching /test-docker-single + if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then + echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check (Single-Node)' >> $GITHUB_OUTPUT + elif echo "$COMMENT_BODY" | grep -q '/test-docker-multi'; then + echo 'deployment_matrix=["multi-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check (Multi-Node)' >> $GITHUB_OUTPUT + elif echo "$COMMENT_BODY" | grep -q '/test-docker'; then + echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT + echo 'check_name=Docker Integration Check' >> $GITHUB_OUTPUT fi - issue_number=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}') - BRANCH_NAME="enhancement/wqa${issue_number}-bump-${{ github.ref_name }}" - echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT - echo "script_params=${script_params}" >> $GITHUB_OUTPUT + - name: Create check run + id: create_check + uses: actions/github-script@v7 + env: + HEAD_SHA: ${{ steps.pr_data.outputs.pr_head_sha }} + CHECK_NAME: ${{ steps.parse_command.outputs.check_name }} + COMMENT_BODY: ${{ github.event.comment.body }} + with: + script: | + const { data: check } = await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: process.env.CHECK_NAME, + head_sha: process.env.HEAD_SHA, + status: 'in_progress', + started_at: new Date().toISOString(), + details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + output: { + title: `🔨 Running ${process.env.CHECK_NAME}...`, + summary: `Triggered by comment: \`${process.env.COMMENT_BODY}\``, + text: 'Allocating instance and running Docker integration tests' + } + }); + console.log('Check run created:', check.id); + return check.id; - - name: Create and switch to bump branch + # ------------------------------------------------------------------------- + # Job 2: For each deployment type — provision VM, deploy Docker stack, test, + # collect results, and clean up. + # ------------------------------------------------------------------------- + docker_test: + needs: [get_pr_info] + if: | + always() && + (needs.get_pr_info.result == 'success' || github.event_name == 'workflow_dispatch') + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + deployment_type: ${{ fromJSON( + github.event_name == 'workflow_dispatch' + && (inputs.deployment_type == 'both' && '["single-node","multi-node"]' + || format('["{0}"]', inputs.deployment_type)) + || needs.get_pr_info.outputs.deployment_matrix + ) }} + + steps: + # ----------------------------------------------------------------------- + # Setup + # ----------------------------------------------------------------------- + - name: Resolve PR head ref + id: ctx run: | - git checkout -b ${{ steps.vars.outputs.branch_name }} + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "pr_head_ref=${{ inputs.pr_head_ref }}" >> $GITHUB_OUTPUT + else + echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT + fi - - name: Make version bump changes + - name: Checkout wazuh-automation + uses: actions/checkout@v4 + with: + repository: wazuh/wazuh-automation + ref: ${{ env.AUTOMATION_REFERENCE }} + token: ${{ secrets.GH_CLONE_TOKEN }} + path: wazuh-automation + + - name: Checkout wazuh-docker PR branch + uses: actions/checkout@v4 + with: + ref: ${{ steps.ctx.outputs.pr_head_ref }} + path: wazuh-docker + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install requirements run: | - echo "Running bump script" - bash ${{ env.BUMP_SCRIPT_PATH }} ${{ steps.vars.outputs.script_params }} + pip install -r wazuh-automation/deployability/deps/requirements.txt + pip install -r wazuh-automation/integration-test-module/requirements.txt + pip install -e wazuh-automation/integration-test-module/ - - name: Commit and push changes + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }} + aws-region: ${{ env.REGION }} + + # ----------------------------------------------------------------------- + # Provision: allocate VM and extract SSH credentials + # ----------------------------------------------------------------------- + - name: Allocate instance + id: allocate run: | - git add . - git commit -m "feat: bump ${{ github.ref_name }}" - git push origin ${{ steps.vars.outputs.branch_name }} + mkdir -p ${{ env.ALLOCATOR_PATH }} + python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action create \ + --provider aws \ + --size xlarge \ + --composite-name ubuntu-24-amd64 \ + --working-dir ${{ env.ALLOCATOR_PATH }} \ + --track-output ${{ env.ALLOCATOR_PATH }}/track.yml \ + --inventory-output ${{ env.ALLOCATOR_PATH }}/inventory.yml \ + --instance-name gha_${{ github.run_id }}_docker_${{ matrix.deployment_type }} \ + --label-team devops \ + --label-termination-date 1d - - name: Create pull request - id: create_pr + sed -n '/hosts:/,/^[^ ]/p' ${{ env.ALLOCATOR_PATH }}/inventory.yml \ + | grep "ansible_" \ + | sed 's/^[ ]*//g' \ + > ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml + sed 's/: */=/g' ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml \ + > ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + sed -i 's/-o StrictHostKeyChecking=no/"-o StrictHostKeyChecking=no"/g' \ + ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + + - name: Set SSH credentials from inventory run: | - gh auth setup-git - PR_URL=$(gh pr create \ - --title "Bump ${{ github.ref_name }} branch" \ - --body "Issue: ${{ inputs.issue-link }}" \ - --base ${{ github.ref_name }} \ - --head ${{ steps.vars.outputs.branch_name }}) + find ${{ env.ALLOCATOR_PATH }} -name '*-key-*' -exec chmod 600 {} \; + source ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml + echo "SSH_HOST=$ansible_host" >> $GITHUB_ENV + echo "SSH_PORT=$ansible_port" >> $GITHUB_ENV + echo "SSH_USER=$ansible_user" >> $GITHUB_ENV + echo "SSH_KEY=$ansible_ssh_private_key_file" >> $GITHUB_ENV - echo "Pull request created: ${PR_URL}" - echo "pull_request_url=${PR_URL}" >> $GITHUB_OUTPUT - - - name: Merge pull request + - name: Set SSH/SCP helper env vars run: | - # Any checks for the PR are bypassed since the branch is expected to be functional (i.e. the bump process does not introduce any bugs) - gh pr merge "${{ steps.create_pr.outputs.pull_request_url }}" --merge --admin + echo "SSH_OPTS=-o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=20 -p ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV + echo "SCP_OPTS=-o StrictHostKeyChecking=no -P ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV + echo "REMOTE=${{ env.SSH_USER }}@${{ env.SSH_HOST }}" >> $GITHUB_ENV - - name: Show logs + # ----------------------------------------------------------------------- + # Install Docker CE on the remote VM + # ----------------------------------------------------------------------- + - name: Install Docker CE run: | - echo "Bump complete." - echo "Branch: ${{ steps.vars.outputs.branch_name }}" - echo "PR: ${{ steps.create_pr.outputs.pull_request_url }}" - echo "Bumper scripts logs:" - cat ${BUMP_LOG_PATH}/repository_bumper*log \ No newline at end of file + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + curl -fsSL https://get.docker.com | sudo sh + sudo systemctl enable --now docker + " + + # ----------------------------------------------------------------------- + # Deploy: copy wazuh-docker and start the stack + # ----------------------------------------------------------------------- + - name: Copy wazuh-docker to VM + run: | + scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" + + - name: Start Docker Compose + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + cd /tmp/wazuh-docker/${DEPLOYMENT} + sudo docker compose up -d 2>&1 | tee /tmp/docker-compose-up.log + " + + - name: Wait for containers healthy + timeout-minutes: 15 + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + echo 'Waiting for all containers to be healthy...' + for i in \$(seq 1 90); do + TOTAL=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps -q 2>/dev/null | wc -l) + HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ + | grep -E '(healthy|\(healthy\))' | wc -l) + NOT_HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ + | grep -vE '(healthy|\(healthy\)|NAME|^$)' | grep -v 'nginx' | wc -l) + + if [ \"\$NOT_HEALTHY\" -eq 0 ] && [ \"\$TOTAL\" -gt 0 ]; then + echo \"All containers healthy after \${i} x 10s attempts (total: \$TOTAL)\" + exit 0 + fi + echo \" attempt \$i: \$HEALTHY healthy, \$NOT_HEALTHY not yet healthy (total: \$TOTAL)\" + sleep 10 + done + echo 'ERROR: containers not healthy after 15 minutes' + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps + exit 1 + " + + # ----------------------------------------------------------------------- + # Run integration tests + # ----------------------------------------------------------------------- + - name: Run tests + id: run_tests + continue-on-error: true + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + test_runner \ + --test-type "docker-${DEPLOYMENT}" \ + --deployment-type "docker-${DEPLOYMENT}" \ + --ssh-host "${{ env.SSH_HOST }}" \ + --ssh-port "${{ env.SSH_PORT }}" \ + --ssh-key-path "${{ env.SSH_KEY }}" \ + --ssh-username "${{ env.SSH_USER }}" \ + --log-level INFO \ + --output github \ + --output-file "test-results-docker-${DEPLOYMENT}.github" + + # ----------------------------------------------------------------------- + # Collect logs on failure + # ----------------------------------------------------------------------- + - name: Collect Docker logs on failure + if: failure() || steps.run_tests.outcome == 'failure' + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml logs --no-color 2>&1 + " > docker-logs-${DEPLOYMENT}.txt || true + + - name: Upload Docker logs + if: failure() || steps.run_tests.outcome == 'failure' + uses: actions/upload-artifact@v4 + with: + name: docker-logs-${{ matrix.deployment_type }}-${{ github.run_id }} + path: docker-logs-*.txt + retention-days: 7 + + # ----------------------------------------------------------------------- + # Reporting + # ----------------------------------------------------------------------- + - name: Create step summary + if: always() + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + echo "## Docker Integration Test Results — ${DEPLOYMENT}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ -f "test-results-docker-${DEPLOYMENT}.github" ]; then + cat "test-results-docker-${DEPLOYMENT}.github" >> $GITHUB_STEP_SUMMARY + else + echo "No test results file found." >> $GITHUB_STEP_SUMMARY + fi + + - name: Post PR comment with results + if: always() && github.event_name == 'issue_comment' + uses: actions/github-script@v7 + env: + DEPLOYMENT: ${{ matrix.deployment_type }} + RUN_OUTCOME: ${{ steps.run_tests.outcome }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const deployment = process.env.DEPLOYMENT; + const outcome = process.env.RUN_OUTCOME; + const marker = ``; + + let body = `${marker}\n## Docker Integration Tests — \`${deployment}\`\n\n`; + body += outcome === 'success' + ? '✅ **All tests passed!**\n\n' + : '❌ **Some tests failed**\n\n'; + + const resultsFile = `test-results-docker-${deployment}.github`; + try { + if (fs.existsSync(resultsFile)) { + body += '### Results\n\n' + fs.readFileSync(resultsFile, 'utf8') + '\n\n'; + } + } catch (e) { + console.log('Could not read results file:', e.message); + } + body += `- **Workflow:** [View Details](${context.payload.repository.html_url}/actions/runs/${context.runId})\n`; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(c => + c.user.type === 'Bot' && c.body.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body: body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: body, + }); + } + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-docker-${{ matrix.deployment_type }}-${{ github.run_id }} + path: test-results-docker-${{ matrix.deployment_type }}.github + retention-days: 7 + + # ----------------------------------------------------------------------- + # Cleanup: always stop stack and deallocate VM + # ----------------------------------------------------------------------- + - name: Stop Docker Compose + if: always() + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml down -v || true + " || true + + - name: Configure AWS credentials for cleanup + if: always() + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-session-name: docker-cleanup-${{ github.run_id }}-${{ matrix.deployment_type }} + aws-region: ${{ env.REGION }} + + - name: Deallocate instance + if: always() + run: | + python3 wazuh-automation/deployability/modules/allocation/main.py \ + --action delete \ + --track-output ${{ env.ALLOCATOR_PATH }}/track.yml + + # ------------------------------------------------------------------------- + # Job 3: Update the GitHub check run (issue_comment trigger only) + # ------------------------------------------------------------------------- + update_check: + needs: [get_pr_info, docker_test] + if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success' + runs-on: ubuntu-latest + steps: + - name: Update check run + uses: actions/github-script@v7 + env: + DOCKER_RESULT: ${{ needs.docker_test.result }} + CHECK_NAME: ${{ needs.get_pr_info.outputs.check_name }} + CHECK_RUN_ID: ${{ needs.get_pr_info.outputs.check_run_id }} + with: + script: | + const result = process.env.DOCKER_RESULT; + const conclusionMap = { + success: { conclusion: 'success', icon: '✅', summary: 'All Docker integration tests passed.' }, + failure: { conclusion: 'failure', icon: '❌', summary: 'One or more Docker integration tests failed.' }, + cancelled: { conclusion: 'cancelled', icon: 'âšī¸', summary: 'Workflow was cancelled.' }, + }; + const { conclusion, icon, summary } = conclusionMap[result] ?? conclusionMap.failure; + const label = conclusion.charAt(0).toUpperCase() + conclusion.slice(1); + await github.rest.checks.update({ + owner: context.repo.owner, + repo: context.repo.repo, + check_run_id: parseInt(process.env.CHECK_RUN_ID), + status: 'completed', + conclusion, + completed_at: new Date().toISOString(), + output: { + title: `${icon} ${process.env.CHECK_NAME} — ${label}`, + summary, + text: `[View workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` + } + }); From d47e4a43e92000fd52bc7dd57fdbc131cdbcccd9 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Wed, 20 May 2026 17:25:34 -0300 Subject: [PATCH 03/27] Revert change maded for tests --- .github/workflows/4_bumper_repository.yml | 554 +++++----------------- 1 file changed, 112 insertions(+), 442 deletions(-) diff --git a/.github/workflows/4_bumper_repository.yml b/.github/workflows/4_bumper_repository.yml index eef80fc7..c932fc35 100644 --- a/.github/workflows/4_bumper_repository.yml +++ b/.github/workflows/4_bumper_repository.yml @@ -1,472 +1,142 @@ -run-name: >- - ${{ github.event_name == 'workflow_dispatch' - && format('Docker Integration Test - Manual {0} on {1}', inputs.deployment_type, inputs.pr_head_ref) - || format('Docker Integration Test - #{0} {1}', github.event.issue.number, github.event.issue.title) }} -name: PR Check - Docker Integration Tests +name: Repository bumper 4.x +run-name: Bump ${{ github.ref_name }} (${{ inputs.id }}) on: - issue_comment: - types: [created] workflow_dispatch: inputs: - pr_head_ref: - description: 'Branch of wazuh-docker to test' - required: true - type: string - automation_reference: - description: 'Branch of wazuh-automation to use' + version: + description: 'Target version (e.g. 1.2.3)' + default: '' required: false - default: 'main' type: string - deployment_type: - description: 'Deployment type to test' + stage: + description: 'Version stage (e.g. alpha0)' + default: '' + required: false + type: string + tag: + description: 'Change branches references to tag-like references (e.g. v4.12.0-alpha7)' + default: false + required: false + type: boolean + issue-link: + description: 'Issue link in format https://github.com/wazuh//issues/' required: true - type: choice - options: - - single-node - - multi-node - - both - -permissions: - id-token: write - contents: read - pull-requests: write - issues: write - checks: write - -env: - AUTOMATION_REFERENCE: ${{ inputs.automation_reference || 'main' }} - ALLOCATOR_PATH: /tmp/allocator_instance - REGION: us-east-1 + type: string + id: + description: 'Optional identifier for the run' + required: false + type: string jobs: - # ------------------------------------------------------------------------- - # Job 1: Parse PR info and determine which deployment(s) to test - # - # Available commands (checked longest-match first to avoid substring collision): - # /test-docker-single — test single-node deployment - # /test-docker-multi — test multi-node deployment - # /test-docker — test both single-node and multi-node - # ------------------------------------------------------------------------- - get_pr_info: - if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - github.event.issue.state == 'open' && - !github.event.issue.draft && - (contains(github.event.comment.body, '/test-docker-single') || - contains(github.event.comment.body, '/test-docker-multi') || - contains(github.event.comment.body, '/test-docker')) - runs-on: ubuntu-latest - outputs: - pr_number: ${{ steps.pr_data.outputs.pr_number }} - pr_head_ref: ${{ steps.pr_data.outputs.pr_head_ref }} - pr_head_sha: ${{ steps.pr_data.outputs.pr_head_sha }} - check_run_id: ${{ steps.create_check.outputs.result }} - deployment_matrix: ${{ steps.parse_command.outputs.deployment_matrix }} - check_name: ${{ steps.parse_command.outputs.check_name }} + bump: + name: Repository bumper 4.x + runs-on: ubuntu-24.04 + permissions: + contents: write + pull-requests: write + + env: + CI_COMMIT_AUTHOR: wazuhci + CI_COMMIT_EMAIL: 22834044+wazuhci@users.noreply.github.com + CI_GPG_PRIVATE_KEY: ${{ secrets.CI_WAZUHCI_GPG_PRIVATE }} + GH_TOKEN: ${{ secrets.CI_WAZUHCI_BUMPER_TOKEN }} + BUMP_SCRIPT_PATH: tools/repository_bumper.sh + BUMP_LOG_PATH: tools steps: - - name: React to comment - uses: actions/github-script@v7 + - name: Dump event payload + run: | + cat $GITHUB_EVENT_PATH | jq '.inputs' + + - name: Set up GPG key + id: signing_setup + run: | + echo "${{ env.CI_GPG_PRIVATE_KEY }}" | gpg --batch --import + KEY_ID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/ {print $5; exit}') + echo "gpg_key_id=$KEY_ID" >> $GITHUB_OUTPUT + + - name: Set up git + run: | + git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}" + git config --global user.email "${{ env.CI_COMMIT_EMAIL }}" + git config --global commit.gpgsign true + git config --global user.signingkey "${{ steps.signing_setup.outputs.gpg_key_id }}" + echo "use-agent" >> ~/.gnupg/gpg.conf + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf + echo RELOADAGENT | gpg-connect-agent + export DEBIAN_FRONTEND=noninteractive + export GPG_TTY=$(tty) + + - name: Checkout repository + uses: actions/checkout@v6 with: - script: | - await github.rest.reactions.createForIssueComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: context.payload.comment.id, - content: 'rocket' - }); + # Using workflow-specific GITHUB_TOKEN because currently CI_WAZUHCI_BUMPER_TOKEN + # doesn't have all the necessary permissions + token: ${{ env.GH_TOKEN }} - - name: Extract PR data - id: pr_data + - name: Determine branch name + id: vars env: - GH_TOKEN: ${{ github.token }} + VERSION: ${{ inputs.version }} + STAGE: ${{ inputs.stage }} + TAG: ${{ inputs.tag }} run: | - PR_NUMBER="${{ github.event.issue.number }}" - PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${PR_NUMBER}) - PR_HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref') - PR_HEAD_SHA=$(echo "$PR_DATA" | jq -r '.head.sha') - echo "pr_number=${PR_NUMBER}" >> $GITHUB_OUTPUT - echo "pr_head_ref=${PR_HEAD_REF}" >> $GITHUB_OUTPUT - echo "pr_head_sha=${PR_HEAD_SHA}" >> $GITHUB_OUTPUT + script_params="" + version=${{ env.VERSION }} + stage=${{ env.STAGE }} + tag=${{ env.TAG }} - - name: Parse command and set deployment metadata - id: parse_command - run: | - COMMENT_BODY="${{ github.event.comment.body }}" - # Check longest match first to avoid /test-docker matching /test-docker-single - if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then - echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT - echo 'check_name=Docker Integration Check (Single-Node)' >> $GITHUB_OUTPUT - elif echo "$COMMENT_BODY" | grep -q '/test-docker-multi'; then - echo 'deployment_matrix=["multi-node"]' >> $GITHUB_OUTPUT - echo 'check_name=Docker Integration Check (Multi-Node)' >> $GITHUB_OUTPUT - elif echo "$COMMENT_BODY" | grep -q '/test-docker'; then - echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT - echo 'check_name=Docker Integration Check' >> $GITHUB_OUTPUT + # Both version and stage provided + if [[ -n "$version" && -n "$stage" && "$tag" != "true" ]]; then + script_params="--version ${version} --stage ${stage}" + elif [[ -n "$version" && -n "$stage" && "$tag" == "true" ]]; then + script_params="--version ${version} --stage ${stage} --tag ${tag}" fi - - name: Create check run - id: create_check - uses: actions/github-script@v7 - env: - HEAD_SHA: ${{ steps.pr_data.outputs.pr_head_sha }} - CHECK_NAME: ${{ steps.parse_command.outputs.check_name }} - COMMENT_BODY: ${{ github.event.comment.body }} - with: - script: | - const { data: check } = await github.rest.checks.create({ - owner: context.repo.owner, - repo: context.repo.repo, - name: process.env.CHECK_NAME, - head_sha: process.env.HEAD_SHA, - status: 'in_progress', - started_at: new Date().toISOString(), - details_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, - output: { - title: `🔨 Running ${process.env.CHECK_NAME}...`, - summary: `Triggered by comment: \`${process.env.COMMENT_BODY}\``, - text: 'Allocating instance and running Docker integration tests' - } - }); - console.log('Check run created:', check.id); - return check.id; + issue_number=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}') + BRANCH_NAME="enhancement/wqa${issue_number}-bump-${{ github.ref_name }}" + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + echo "script_params=${script_params}" >> $GITHUB_OUTPUT - # ------------------------------------------------------------------------- - # Job 2: For each deployment type — provision VM, deploy Docker stack, test, - # collect results, and clean up. - # ------------------------------------------------------------------------- - docker_test: - needs: [get_pr_info] - if: | - always() && - (needs.get_pr_info.result == 'success' || github.event_name == 'workflow_dispatch') - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - deployment_type: ${{ fromJSON( - github.event_name == 'workflow_dispatch' - && (inputs.deployment_type == 'both' && '["single-node","multi-node"]' - || format('["{0}"]', inputs.deployment_type)) - || needs.get_pr_info.outputs.deployment_matrix - ) }} - - steps: - # ----------------------------------------------------------------------- - # Setup - # ----------------------------------------------------------------------- - - name: Resolve PR head ref - id: ctx + - name: Create and switch to bump branch run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "pr_head_ref=${{ inputs.pr_head_ref }}" >> $GITHUB_OUTPUT - else - echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT - fi + git checkout -b ${{ steps.vars.outputs.branch_name }} - - name: Checkout wazuh-automation - uses: actions/checkout@v4 - with: - repository: wazuh/wazuh-automation - ref: ${{ env.AUTOMATION_REFERENCE }} - token: ${{ secrets.GH_CLONE_TOKEN }} - path: wazuh-automation - - - name: Checkout wazuh-docker PR branch - uses: actions/checkout@v4 - with: - ref: ${{ steps.ctx.outputs.pr_head_ref }} - path: wazuh-docker - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Install requirements + - name: Make version bump changes run: | - pip install -r wazuh-automation/deployability/deps/requirements.txt - pip install -r wazuh-automation/integration-test-module/requirements.txt - pip install -e wazuh-automation/integration-test-module/ + echo "Running bump script" + bash ${{ env.BUMP_SCRIPT_PATH }} ${{ steps.vars.outputs.script_params }} - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }} - aws-region: ${{ env.REGION }} - - # ----------------------------------------------------------------------- - # Provision: allocate VM and extract SSH credentials - # ----------------------------------------------------------------------- - - name: Allocate instance - id: allocate + - name: Commit and push changes run: | - mkdir -p ${{ env.ALLOCATOR_PATH }} - python3 wazuh-automation/deployability/modules/allocation/main.py \ - --action create \ - --provider aws \ - --size xlarge \ - --composite-name ubuntu-24-amd64 \ - --working-dir ${{ env.ALLOCATOR_PATH }} \ - --track-output ${{ env.ALLOCATOR_PATH }}/track.yml \ - --inventory-output ${{ env.ALLOCATOR_PATH }}/inventory.yml \ - --instance-name gha_${{ github.run_id }}_docker_${{ matrix.deployment_type }} \ - --label-team devops \ - --label-termination-date 1d + git add . + git commit -m "feat: bump ${{ github.ref_name }}" + git push origin ${{ steps.vars.outputs.branch_name }} - sed -n '/hosts:/,/^[^ ]/p' ${{ env.ALLOCATOR_PATH }}/inventory.yml \ - | grep "ansible_" \ - | sed 's/^[ ]*//g' \ - > ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml - sed 's/: */=/g' ${{ env.ALLOCATOR_PATH }}/inventory_vars_raw.yml \ - > ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml - sed -i 's/-o StrictHostKeyChecking=no/"-o StrictHostKeyChecking=no"/g' \ - ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml - - - name: Set SSH credentials from inventory + - name: Create pull request + id: create_pr run: | - find ${{ env.ALLOCATOR_PATH }} -name '*-key-*' -exec chmod 600 {} \; - source ${{ env.ALLOCATOR_PATH }}/inventory_vars.yml - echo "SSH_HOST=$ansible_host" >> $GITHUB_ENV - echo "SSH_PORT=$ansible_port" >> $GITHUB_ENV - echo "SSH_USER=$ansible_user" >> $GITHUB_ENV - echo "SSH_KEY=$ansible_ssh_private_key_file" >> $GITHUB_ENV + gh auth setup-git + PR_URL=$(gh pr create \ + --title "Bump ${{ github.ref_name }} branch" \ + --body "Issue: ${{ inputs.issue-link }}" \ + --base ${{ github.ref_name }} \ + --head ${{ steps.vars.outputs.branch_name }}) - - name: Set SSH/SCP helper env vars + echo "Pull request created: ${PR_URL}" + echo "pull_request_url=${PR_URL}" >> $GITHUB_OUTPUT + + - name: Merge pull request run: | - echo "SSH_OPTS=-o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=20 -p ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV - echo "SCP_OPTS=-o StrictHostKeyChecking=no -P ${{ env.SSH_PORT }} -i ${{ env.SSH_KEY }}" >> $GITHUB_ENV - echo "REMOTE=${{ env.SSH_USER }}@${{ env.SSH_HOST }}" >> $GITHUB_ENV + # Any checks for the PR are bypassed since the branch is expected to be functional (i.e. the bump process does not introduce any bugs) + gh pr merge "${{ steps.create_pr.outputs.pull_request_url }}" --merge --admin - # ----------------------------------------------------------------------- - # Install Docker CE on the remote VM - # ----------------------------------------------------------------------- - - name: Install Docker CE + - name: Show logs run: | - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - curl -fsSL https://get.docker.com | sudo sh - sudo systemctl enable --now docker - " - - # ----------------------------------------------------------------------- - # Deploy: copy wazuh-docker and start the stack - # ----------------------------------------------------------------------- - - name: Copy wazuh-docker to VM - run: | - scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" - - - name: Start Docker Compose - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - cd /tmp/wazuh-docker/${DEPLOYMENT} - sudo docker compose up -d 2>&1 | tee /tmp/docker-compose-up.log - " - - - name: Wait for containers healthy - timeout-minutes: 15 - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - echo 'Waiting for all containers to be healthy...' - for i in \$(seq 1 90); do - TOTAL=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps -q 2>/dev/null | wc -l) - HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ - | grep -E '(healthy|\(healthy\))' | wc -l) - NOT_HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ - | grep -vE '(healthy|\(healthy\)|NAME|^$)' | grep -v 'nginx' | wc -l) - - if [ \"\$NOT_HEALTHY\" -eq 0 ] && [ \"\$TOTAL\" -gt 0 ]; then - echo \"All containers healthy after \${i} x 10s attempts (total: \$TOTAL)\" - exit 0 - fi - echo \" attempt \$i: \$HEALTHY healthy, \$NOT_HEALTHY not yet healthy (total: \$TOTAL)\" - sleep 10 - done - echo 'ERROR: containers not healthy after 15 minutes' - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps - exit 1 - " - - # ----------------------------------------------------------------------- - # Run integration tests - # ----------------------------------------------------------------------- - - name: Run tests - id: run_tests - continue-on-error: true - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - test_runner \ - --test-type "docker-${DEPLOYMENT}" \ - --deployment-type "docker-${DEPLOYMENT}" \ - --ssh-host "${{ env.SSH_HOST }}" \ - --ssh-port "${{ env.SSH_PORT }}" \ - --ssh-key-path "${{ env.SSH_KEY }}" \ - --ssh-username "${{ env.SSH_USER }}" \ - --log-level INFO \ - --output github \ - --output-file "test-results-docker-${DEPLOYMENT}.github" - - # ----------------------------------------------------------------------- - # Collect logs on failure - # ----------------------------------------------------------------------- - - name: Collect Docker logs on failure - if: failure() || steps.run_tests.outcome == 'failure' - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml logs --no-color 2>&1 - " > docker-logs-${DEPLOYMENT}.txt || true - - - name: Upload Docker logs - if: failure() || steps.run_tests.outcome == 'failure' - uses: actions/upload-artifact@v4 - with: - name: docker-logs-${{ matrix.deployment_type }}-${{ github.run_id }} - path: docker-logs-*.txt - retention-days: 7 - - # ----------------------------------------------------------------------- - # Reporting - # ----------------------------------------------------------------------- - - name: Create step summary - if: always() - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - echo "## Docker Integration Test Results — ${DEPLOYMENT}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - if [ -f "test-results-docker-${DEPLOYMENT}.github" ]; then - cat "test-results-docker-${DEPLOYMENT}.github" >> $GITHUB_STEP_SUMMARY - else - echo "No test results file found." >> $GITHUB_STEP_SUMMARY - fi - - - name: Post PR comment with results - if: always() && github.event_name == 'issue_comment' - uses: actions/github-script@v7 - env: - DEPLOYMENT: ${{ matrix.deployment_type }} - RUN_OUTCOME: ${{ steps.run_tests.outcome }} - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - const deployment = process.env.DEPLOYMENT; - const outcome = process.env.RUN_OUTCOME; - const marker = ``; - - let body = `${marker}\n## Docker Integration Tests — \`${deployment}\`\n\n`; - body += outcome === 'success' - ? '✅ **All tests passed!**\n\n' - : '❌ **Some tests failed**\n\n'; - - const resultsFile = `test-results-docker-${deployment}.github`; - try { - if (fs.existsSync(resultsFile)) { - body += '### Results\n\n' + fs.readFileSync(resultsFile, 'utf8') + '\n\n'; - } - } catch (e) { - console.log('Could not read results file:', e.message); - } - body += `- **Workflow:** [View Details](${context.payload.repository.html_url}/actions/runs/${context.runId})\n`; - - const { data: comments } = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - }); - - const existing = comments.find(c => - c.user.type === 'Bot' && c.body.includes(marker) - ); - - if (existing) { - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existing.id, - body: body, - }); - } else { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: body, - }); - } - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-docker-${{ matrix.deployment_type }}-${{ github.run_id }} - path: test-results-docker-${{ matrix.deployment_type }}.github - retention-days: 7 - - # ----------------------------------------------------------------------- - # Cleanup: always stop stack and deallocate VM - # ----------------------------------------------------------------------- - - name: Stop Docker Compose - if: always() - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml down -v || true - " || true - - - name: Configure AWS credentials for cleanup - if: always() - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - role-session-name: docker-cleanup-${{ github.run_id }}-${{ matrix.deployment_type }} - aws-region: ${{ env.REGION }} - - - name: Deallocate instance - if: always() - run: | - python3 wazuh-automation/deployability/modules/allocation/main.py \ - --action delete \ - --track-output ${{ env.ALLOCATOR_PATH }}/track.yml - - # ------------------------------------------------------------------------- - # Job 3: Update the GitHub check run (issue_comment trigger only) - # ------------------------------------------------------------------------- - update_check: - needs: [get_pr_info, docker_test] - if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success' - runs-on: ubuntu-latest - steps: - - name: Update check run - uses: actions/github-script@v7 - env: - DOCKER_RESULT: ${{ needs.docker_test.result }} - CHECK_NAME: ${{ needs.get_pr_info.outputs.check_name }} - CHECK_RUN_ID: ${{ needs.get_pr_info.outputs.check_run_id }} - with: - script: | - const result = process.env.DOCKER_RESULT; - const conclusionMap = { - success: { conclusion: 'success', icon: '✅', summary: 'All Docker integration tests passed.' }, - failure: { conclusion: 'failure', icon: '❌', summary: 'One or more Docker integration tests failed.' }, - cancelled: { conclusion: 'cancelled', icon: 'âšī¸', summary: 'Workflow was cancelled.' }, - }; - const { conclusion, icon, summary } = conclusionMap[result] ?? conclusionMap.failure; - const label = conclusion.charAt(0).toUpperCase() + conclusion.slice(1); - await github.rest.checks.update({ - owner: context.repo.owner, - repo: context.repo.repo, - check_run_id: parseInt(process.env.CHECK_RUN_ID), - status: 'completed', - conclusion, - completed_at: new Date().toISOString(), - output: { - title: `${icon} ${process.env.CHECK_NAME} — ${label}`, - summary, - text: `[View workflow run](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})` - } - }); + echo "Bump complete." + echo "Branch: ${{ steps.vars.outputs.branch_name }}" + echo "PR: ${{ steps.create_pr.outputs.pull_request_url }}" + echo "Bumper scripts logs:" + cat ${BUMP_LOG_PATH}/repository_bumper*log \ No newline at end of file From 3811e886a0bba50970ad891d5dc27d0f786c03fa Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 10:39:45 -0300 Subject: [PATCH 04/27] Fix matrix input --- .../workflows/check_integration_tools.yaml | 90 +++++++++++-------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index eef80fc7..5a914b17 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -97,13 +97,13 @@ jobs: COMMENT_BODY="${{ github.event.comment.body }}" # Check longest match first to avoid /test-docker matching /test-docker-single if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then - echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT + echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT echo 'check_name=Docker Integration Check (Single-Node)' >> $GITHUB_OUTPUT elif echo "$COMMENT_BODY" | grep -q '/test-docker-multi'; then - echo 'deployment_matrix=["multi-node"]' >> $GITHUB_OUTPUT + echo 'deployment_matrix=["multi-node"]' >> $GITHUB_OUTPUT echo 'check_name=Docker Integration Check (Multi-Node)' >> $GITHUB_OUTPUT elif echo "$COMMENT_BODY" | grep -q '/test-docker'; then - echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT + echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT echo 'check_name=Docker Integration Check' >> $GITHUB_OUTPUT fi @@ -134,38 +134,53 @@ jobs: return check.id; # ------------------------------------------------------------------------- - # Job 2: For each deployment type — provision VM, deploy Docker stack, test, - # collect results, and clean up. + # Job 2: Resolve context (pr_head_ref + deployment matrix) for both triggers. + # Mirrors the role of build_tools in check_integration_tools.yaml. # ------------------------------------------------------------------------- - docker_test: + prepare: needs: [get_pr_info] if: | always() && (needs.get_pr_info.result == 'success' || github.event_name == 'workflow_dispatch') runs-on: ubuntu-latest + outputs: + pr_head_ref: ${{ steps.ctx.outputs.pr_head_ref }} + deployment_matrix: ${{ steps.ctx.outputs.deployment_matrix }} + + steps: + - name: Resolve context + id: ctx + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "pr_head_ref=${{ inputs.pr_head_ref }}" >> $GITHUB_OUTPUT + DEPLOY_TYPE="${{ inputs.deployment_type }}" + if [ "$DEPLOY_TYPE" = "both" ]; then + echo 'deployment_matrix=["single-node","multi-node"]' >> $GITHUB_OUTPUT + else + echo "deployment_matrix=[\"${DEPLOY_TYPE}\"]" >> $GITHUB_OUTPUT + fi + else + echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT + echo "deployment_matrix=${{ needs.get_pr_info.outputs.deployment_matrix }}" >> $GITHUB_OUTPUT + fi + + # ------------------------------------------------------------------------- + # Job 3: For each deployment type — provision VM, deploy Docker stack, test, + # collect results, and clean up. + # ------------------------------------------------------------------------- + docker_test: + needs: [get_pr_info, prepare] + if: always() && needs.prepare.result == 'success' + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - deployment_type: ${{ fromJSON( - github.event_name == 'workflow_dispatch' - && (inputs.deployment_type == 'both' && '["single-node","multi-node"]' - || format('["{0}"]', inputs.deployment_type)) - || needs.get_pr_info.outputs.deployment_matrix - ) }} + deployment_type: ${{ fromJSON(needs.prepare.outputs.deployment_matrix) }} steps: # ----------------------------------------------------------------------- # Setup # ----------------------------------------------------------------------- - - name: Resolve PR head ref - id: ctx - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "pr_head_ref=${{ inputs.pr_head_ref }}" >> $GITHUB_OUTPUT - else - echo "pr_head_ref=${{ needs.get_pr_info.outputs.pr_head_ref }}" >> $GITHUB_OUTPUT - fi - - name: Checkout wazuh-automation uses: actions/checkout@v4 with: @@ -177,7 +192,7 @@ jobs: - name: Checkout wazuh-docker PR branch uses: actions/checkout@v4 with: - ref: ${{ steps.ctx.outputs.pr_head_ref }} + ref: ${{ needs.prepare.outputs.pr_head_ref }} path: wazuh-docker - name: Set up Python 3.12 @@ -208,7 +223,7 @@ jobs: python3 wazuh-automation/deployability/modules/allocation/main.py \ --action create \ --provider aws \ - --size xlarge \ + --size large \ --composite-name ubuntu-24-amd64 \ --working-dir ${{ env.ALLOCATOR_PATH }} \ --track-output ${{ env.ALLOCATOR_PATH }}/track.yml \ @@ -271,23 +286,23 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + cd /tmp/wazuh-docker/${DEPLOYMENT} echo 'Waiting for all containers to be healthy...' for i in \$(seq 1 90); do - TOTAL=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps -q 2>/dev/null | wc -l) - HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ - | grep -E '(healthy|\(healthy\))' | wc -l) - NOT_HEALTHY=\$(sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps 2>/dev/null \ - | grep -vE '(healthy|\(healthy\)|NAME|^$)' | grep -v 'nginx' | wc -l) - - if [ \"\$NOT_HEALTHY\" -eq 0 ] && [ \"\$TOTAL\" -gt 0 ]; then - echo \"All containers healthy after \${i} x 10s attempts (total: \$TOTAL)\" + NOT_HEALTHY=\$(sudo docker compose ps 2>/dev/null \ + | tail -n +2 \ + | grep -v 'nginx' \ + | grep -vcE '(healthy|\(healthy\))') + if [ \"\$NOT_HEALTHY\" -eq 0 ]; then + echo \"All containers healthy after \${i} x 10s attempts\" + sudo docker compose ps exit 0 fi - echo \" attempt \$i: \$HEALTHY healthy, \$NOT_HEALTHY not yet healthy (total: \$TOTAL)\" + echo \" attempt \$i: \$NOT_HEALTHY container(s) not yet healthy\" sleep 10 done echo 'ERROR: containers not healthy after 15 minutes' - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml ps + sudo docker compose ps exit 1 " @@ -318,7 +333,8 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml logs --no-color 2>&1 + cd /tmp/wazuh-docker/${DEPLOYMENT} + sudo docker compose logs --no-color 2>&1 " > docker-logs-${DEPLOYMENT}.txt || true - name: Upload Docker logs @@ -415,7 +431,7 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - sudo docker compose -f /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml down -v || true + cd /tmp/wazuh-docker/${DEPLOYMENT} && sudo docker compose down -v || true " || true - name: Configure AWS credentials for cleanup @@ -434,10 +450,10 @@ jobs: --track-output ${{ env.ALLOCATOR_PATH }}/track.yml # ------------------------------------------------------------------------- - # Job 3: Update the GitHub check run (issue_comment trigger only) + # Job 4: Update the GitHub check run (issue_comment trigger only) # ------------------------------------------------------------------------- update_check: - needs: [get_pr_info, docker_test] + needs: [get_pr_info, prepare, docker_test] if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success' runs-on: ubuntu-latest steps: From e774a93f9ac64c143f16c3ac4a1fbd945c515782 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 10:53:37 -0300 Subject: [PATCH 05/27] Fix github secrets --- .github/workflows/check_integration_tools.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 5a914b17..838b83a7 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -209,7 +209,7 @@ jobs: - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }} role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }} aws-region: ${{ env.REGION }} @@ -438,7 +438,7 @@ jobs: if: always() uses: aws-actions/configure-aws-credentials@v4 with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }} role-session-name: docker-cleanup-${{ github.run_id }}-${{ matrix.deployment_type }} aws-region: ${{ env.REGION }} From 13cad85988d6e818965f72f17afe7768cf830eec Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 12:39:34 -0300 Subject: [PATCH 06/27] Add debug to critical steps --- .../workflows/check_integration_tools.yaml | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 838b83a7..ff115bdb 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -273,12 +273,33 @@ jobs: run: | scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" + - name: Show deployment config + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + echo '=== Files in deployment directory ===' + ls -la /tmp/wazuh-docker/${DEPLOYMENT}/ + echo '' + echo '=== Images referenced in docker-compose.yml ===' + grep 'image:' /tmp/wazuh-docker/${DEPLOYMENT}/docker-compose.yml || echo '(none found)' + echo '' + echo '=== Docker version ===' + sudo docker version --format 'Client: {{.Client.Version}} Server: {{.Server.Version}}' + " + - name: Start Docker Compose run: | DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + set -eo pipefail cd /tmp/wazuh-docker/${DEPLOYMENT} + echo '=== Pulling images (docker compose pull) ===' + sudo docker compose pull 2>&1 + echo '=== Starting stack (docker compose up -d) ===' sudo docker compose up -d 2>&1 | tee /tmp/docker-compose-up.log + echo '' + echo '=== Initial container status ===' + sudo docker compose ps " - name: Wait for containers healthy @@ -287,7 +308,18 @@ jobs: DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " cd /tmp/wazuh-docker/${DEPLOYMENT} - echo 'Waiting for all containers to be healthy...' + + echo '=== Verifying containers started ===' + TOTAL=\$(sudo docker compose ps 2>/dev/null | tail -n +2 | wc -l | tr -d ' ') + if [ \"\$TOTAL\" -eq 0 ]; then + echo 'ERROR: No containers are running — docker compose up may have failed' + sudo docker compose ps + sudo docker compose logs --no-color 2>&1 | tail -50 + exit 1 + fi + echo \"Found \$TOTAL container(s), waiting for healthy status...\" + echo '' + for i in \$(seq 1 90); do NOT_HEALTHY=\$(sudo docker compose ps 2>/dev/null \ | tail -n +2 \ @@ -298,11 +330,16 @@ jobs: sudo docker compose ps exit 0 fi - echo \" attempt \$i: \$NOT_HEALTHY container(s) not yet healthy\" + echo \" attempt \$i/90: \$NOT_HEALTHY container(s) not yet healthy\" + if [ \"\$(( i % 6 ))\" -eq 0 ]; then + echo ' --- current status ---' + sudo docker compose ps + fi sleep 10 done echo 'ERROR: containers not healthy after 15 minutes' sudo docker compose ps + sudo docker compose logs --no-color 2>&1 | tail -100 exit 1 " @@ -328,6 +365,18 @@ jobs: # ----------------------------------------------------------------------- # Collect logs on failure # ----------------------------------------------------------------------- + - name: Show test outcome + if: always() + run: | + echo "Run tests outcome: ${{ steps.run_tests.outcome }}" + DEPLOYMENT="${{ matrix.deployment_type }}" + if [ -f "test-results-docker-${DEPLOYMENT}.github" ]; then + echo "=== Test results file ===" + cat "test-results-docker-${DEPLOYMENT}.github" + else + echo "WARNING: no test results file found (test_runner may have failed before writing output)" + fi + - name: Collect Docker logs on failure if: failure() || steps.run_tests.outcome == 'failure' run: | From aa275c4f1ef5b4c8220894bcd893118275ee4968 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 15:06:09 -0300 Subject: [PATCH 07/27] Add steps for certificates creation --- .../workflows/check_integration_tools.yaml | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index ff115bdb..f388506a 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -287,6 +287,83 @@ jobs: sudo docker version --format 'Client: {{.Client.Version}} Server: {{.Server.Version}}' " + - name: Configure VM for Wazuh Indexer + run: | + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + sudo sysctl -w vm.max_map_count=262144 + echo 'vm.max_map_count = '\$(cat /proc/sys/vm/max_map_count) + " + + - name: Upload certificate config + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + if [ "$DEPLOYMENT" = "single-node" ]; then + printf '%s\n' \ + 'nodes:' \ + ' indexer:' \ + ' - name: wazuh.indexer' \ + ' dns: wazuh.indexer' \ + ' manager:' \ + ' - name: wazuh.manager' \ + ' dns: wazuh.manager' \ + ' dashboard:' \ + ' - name: wazuh.dashboard' \ + ' dns: wazuh.dashboard' \ + > /tmp/wazuh-cert-config.yml + else + printf '%s\n' \ + 'nodes:' \ + ' indexer:' \ + ' - name: wazuh1.indexer' \ + ' dns: wazuh1.indexer' \ + ' - name: wazuh2.indexer' \ + ' dns: wazuh2.indexer' \ + ' - name: wazuh3.indexer' \ + ' dns: wazuh3.indexer' \ + ' manager:' \ + ' - name: wazuh.master' \ + ' dns: wazuh.master' \ + ' node_type: master' \ + ' - name: wazuh.worker' \ + ' dns: wazuh.worker' \ + ' node_type: worker' \ + ' dashboard:' \ + ' - name: wazuh.dashboard' \ + ' dns: wazuh.dashboard' \ + > /tmp/wazuh-cert-config.yml + fi + echo "=== config.yml to upload ===" + cat /tmp/wazuh-cert-config.yml + scp ${{ env.SCP_OPTS }} /tmp/wazuh-cert-config.yml "${{ env.REMOTE }}:/tmp/wazuh-docker/${DEPLOYMENT}/config.yml" + + - name: Generate SSL certificates + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + set -e + cd /tmp/wazuh-docker/${DEPLOYMENT} + + echo '=== Extracting Wazuh version ===' + WAZUH_VERSION=\$(grep '^WAZUH_VERSION=' /tmp/wazuh-docker/.env | cut -d= -f2) + MAJOR_MINOR=\$(echo \"\$WAZUH_VERSION\" | cut -d. -f1-2) + echo \"Version: \$WAZUH_VERSION (packages path: \$MAJOR_MINOR)\" + + echo '' + echo '=== Downloading wazuh-certs-tool.sh ===' + curl -fsSL -o wazuh-certs-tool.sh \ + \"https://packages.wazuh.com/\${MAJOR_MINOR}/wazuh-certs-tool-\${WAZUH_VERSION}-1.sh\" + chmod +x wazuh-certs-tool.sh + echo 'Downloaded OK' + + echo '' + echo '=== Running certificate generation ===' + sudo bash /tmp/wazuh-docker/tools/utils/deployment/certificates-conf.sh --cert --copy --priv + + echo '' + echo '=== Generated certificate files ===' + find ./config -name '*.pem' | sort + " + - name: Start Docker Compose run: | DEPLOYMENT="${{ matrix.deployment_type }}" From 306acecc489b6e54d43fc1837b402861c1090643 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 15:59:41 -0300 Subject: [PATCH 08/27] Add dev flag to parse revision beta1 --- .../workflows/check_integration_tools.yaml | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index f388506a..85579017 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -26,6 +26,11 @@ on: - single-node - multi-node - both + patch_beta_images: + description: 'Patch image tags to use pre-release suffix (-beta1-latest). Disable once release images are published.' + required: false + default: true + type: boolean permissions: id-token: write @@ -267,8 +272,34 @@ jobs: " # ----------------------------------------------------------------------- - # Deploy: copy wazuh-docker and start the stack + # Deploy: optionally patch image tags, copy wazuh-docker and start the stack # ----------------------------------------------------------------------- + - name: Patch image tags for pre-release + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + # Use input when available; hardcoded true otherwise (e.g. dispatched from main + # which does not yet define patch_beta_images). + PATCH="${{ inputs.patch_beta_images }}" + [ -z "$PATCH" ] && PATCH=true + if [ "$PATCH" != "true" ]; then + echo "patch_beta_images=false — skipping image tag patching" + exit 0 + fi + + VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") + STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") + if [ -z "$STAGE" ]; then + echo "VERSION.json has no stage field — release image, no patching needed" + exit 0 + fi + + IMAGE_TAG="${VERSION}-${STAGE}-latest" + COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" + echo "Patching ${COMPOSE}: image tag → ${IMAGE_TAG}" + sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${IMAGE_TAG}|g" "$COMPOSE" + echo "=== Patched image lines ===" + grep 'image:' "$COMPOSE" + - name: Copy wazuh-docker to VM run: | scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" @@ -343,15 +374,21 @@ jobs: set -e cd /tmp/wazuh-docker/${DEPLOYMENT} - echo '=== Extracting Wazuh version ===' - WAZUH_VERSION=\$(grep '^WAZUH_VERSION=' /tmp/wazuh-docker/.env | cut -d= -f2) - MAJOR_MINOR=\$(echo \"\$WAZUH_VERSION\" | cut -d. -f1-2) - echo \"Version: \$WAZUH_VERSION (packages path: \$MAJOR_MINOR)\" + echo '=== Extracting Wazuh version and stage ===' + VERSION=\$(python3 -c \"import json; d=json.load(open('/tmp/wazuh-docker/VERSION.json')); print(d['version'])\") + STAGE=\$(python3 -c \"import json; d=json.load(open('/tmp/wazuh-docker/VERSION.json')); print(d.get('stage',''))\") + MAJOR_MINOR=\$(echo \"\$VERSION\" | cut -d. -f1-2) + echo \"Version: \$VERSION Stage: \$STAGE\" echo '' echo '=== Downloading wazuh-certs-tool.sh ===' - curl -fsSL -o wazuh-certs-tool.sh \ - \"https://packages.wazuh.com/\${MAJOR_MINOR}/wazuh-certs-tool-\${WAZUH_VERSION}-1.sh\" + if [ -n \"\$STAGE\" ]; then + CERT_TOOL_URL=\"https://packages-staging.xdrsiem.wazuh.info/pre-release/\${MAJOR_MINOR}.x/installation-assistant/wazuh-certs-tool-\${VERSION}-\${STAGE}.sh\" + else + CERT_TOOL_URL=\"https://packages.wazuh.com/\${MAJOR_MINOR}/wazuh-certs-tool-\${VERSION}-1.sh\" + fi + echo \"URL: \$CERT_TOOL_URL\" + curl -fsSL -o wazuh-certs-tool.sh \"\$CERT_TOOL_URL\" chmod +x wazuh-certs-tool.sh echo 'Downloaded OK' From 89174ffc6158eec905c3da853921d3a4d9312747 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 18:38:09 -0300 Subject: [PATCH 09/27] Generate all files and then copy into VM all together --- .../workflows/check_integration_tools.yaml | 124 +++++++++--------- 1 file changed, 61 insertions(+), 63 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 85579017..6685ffd5 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -300,6 +300,67 @@ jobs: echo "=== Patched image lines ===" grep 'image:' "$COMPOSE" + - name: Prepare cert tool and config + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") + STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") + MAJOR=$(echo "$VERSION" | cut -d. -f1) + + echo "Version: $VERSION Stage: ${STAGE:-}" + + # Download cert tool once on the runner, copy to VM via the main SCP + if [ -n "$STAGE" ]; then + CERT_TOOL_URL="https://packages-staging.xdrsiem.wazuh.info/pre-release/${MAJOR}.x/installation-assistant/wazuh-certs-tool-${VERSION}-${STAGE}.sh" + else + CERT_TOOL_URL="https://packages.wazuh.com/${MAJOR}.$(echo "$VERSION" | cut -d. -f2)/wazuh-certs-tool-${VERSION}-1.sh" + fi + echo "Downloading cert tool: $CERT_TOOL_URL" + curl -fsSL -o "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "$CERT_TOOL_URL" + chmod +x "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" + echo "Downloaded OK" + + # Write config.yml directly into the deployment directory + if [ "$DEPLOYMENT" = "single-node" ]; then + printf '%s\n' \ + 'nodes:' \ + ' indexer:' \ + ' - name: wazuh.indexer' \ + ' dns: wazuh.indexer' \ + ' manager:' \ + ' - name: wazuh.manager' \ + ' dns: wazuh.manager' \ + ' dashboard:' \ + ' - name: wazuh.dashboard' \ + ' dns: wazuh.dashboard' \ + > "wazuh-docker/${DEPLOYMENT}/config.yml" + else + printf '%s\n' \ + 'nodes:' \ + ' indexer:' \ + ' - name: wazuh1.indexer' \ + ' dns: wazuh1.indexer' \ + ' - name: wazuh2.indexer' \ + ' dns: wazuh2.indexer' \ + ' - name: wazuh3.indexer' \ + ' dns: wazuh3.indexer' \ + ' manager:' \ + ' - name: wazuh.master' \ + ' dns: wazuh.master' \ + ' node_type: master' \ + ' - name: wazuh.worker' \ + ' dns: wazuh.worker' \ + ' node_type: worker' \ + ' dashboard:' \ + ' - name: wazuh.dashboard' \ + ' dns: wazuh.dashboard' \ + > "wazuh-docker/${DEPLOYMENT}/config.yml" + fi + echo "=== config.yml ===" + cat "wazuh-docker/${DEPLOYMENT}/config.yml" + echo "=== Files ready to copy ===" + ls -la "wazuh-docker/${DEPLOYMENT}/" + - name: Copy wazuh-docker to VM run: | scp ${{ env.SCP_OPTS }} -r wazuh-docker "${{ env.REMOTE }}:/tmp/wazuh-docker" @@ -325,77 +386,14 @@ jobs: echo 'vm.max_map_count = '\$(cat /proc/sys/vm/max_map_count) " - - name: Upload certificate config - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - if [ "$DEPLOYMENT" = "single-node" ]; then - printf '%s\n' \ - 'nodes:' \ - ' indexer:' \ - ' - name: wazuh.indexer' \ - ' dns: wazuh.indexer' \ - ' manager:' \ - ' - name: wazuh.manager' \ - ' dns: wazuh.manager' \ - ' dashboard:' \ - ' - name: wazuh.dashboard' \ - ' dns: wazuh.dashboard' \ - > /tmp/wazuh-cert-config.yml - else - printf '%s\n' \ - 'nodes:' \ - ' indexer:' \ - ' - name: wazuh1.indexer' \ - ' dns: wazuh1.indexer' \ - ' - name: wazuh2.indexer' \ - ' dns: wazuh2.indexer' \ - ' - name: wazuh3.indexer' \ - ' dns: wazuh3.indexer' \ - ' manager:' \ - ' - name: wazuh.master' \ - ' dns: wazuh.master' \ - ' node_type: master' \ - ' - name: wazuh.worker' \ - ' dns: wazuh.worker' \ - ' node_type: worker' \ - ' dashboard:' \ - ' - name: wazuh.dashboard' \ - ' dns: wazuh.dashboard' \ - > /tmp/wazuh-cert-config.yml - fi - echo "=== config.yml to upload ===" - cat /tmp/wazuh-cert-config.yml - scp ${{ env.SCP_OPTS }} /tmp/wazuh-cert-config.yml "${{ env.REMOTE }}:/tmp/wazuh-docker/${DEPLOYMENT}/config.yml" - - name: Generate SSL certificates run: | DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " set -e cd /tmp/wazuh-docker/${DEPLOYMENT} - - echo '=== Extracting Wazuh version and stage ===' - VERSION=\$(python3 -c \"import json; d=json.load(open('/tmp/wazuh-docker/VERSION.json')); print(d['version'])\") - STAGE=\$(python3 -c \"import json; d=json.load(open('/tmp/wazuh-docker/VERSION.json')); print(d.get('stage',''))\") - MAJOR_MINOR=\$(echo \"\$VERSION\" | cut -d. -f1-2) - echo \"Version: \$VERSION Stage: \$STAGE\" - - echo '' - echo '=== Downloading wazuh-certs-tool.sh ===' - if [ -n \"\$STAGE\" ]; then - CERT_TOOL_URL=\"https://packages-staging.xdrsiem.wazuh.info/pre-release/\${MAJOR_MINOR}.x/installation-assistant/wazuh-certs-tool-\${VERSION}-\${STAGE}.sh\" - else - CERT_TOOL_URL=\"https://packages.wazuh.com/\${MAJOR_MINOR}/wazuh-certs-tool-\${VERSION}-1.sh\" - fi - echo \"URL: \$CERT_TOOL_URL\" - curl -fsSL -o wazuh-certs-tool.sh \"\$CERT_TOOL_URL\" - chmod +x wazuh-certs-tool.sh - echo 'Downloaded OK' - - echo '' echo '=== Running certificate generation ===' sudo bash /tmp/wazuh-docker/tools/utils/deployment/certificates-conf.sh --cert --copy --priv - echo '' echo '=== Generated certificate files ===' find ./config -name '*.pem' | sort From d888b01e9e1d48a05ad17ad15b002c5aa831a890 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 19:52:22 -0300 Subject: [PATCH 10/27] Fix certificate greneration --- .../workflows/check_integration_tools.yaml | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 6685ffd5..79d744d9 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -397,6 +397,12 @@ jobs: echo '' echo '=== Generated certificate files ===' find ./config -name '*.pem' | sort + echo '' + echo '=== Certificate subjects ===' + for pem in \$(find ./config -name '*.pem' ! -name '*-key.pem' | sort); do + echo -n \"\$pem: \" + sudo openssl x509 -in \"\$pem\" -noout -subject -issuer 2>/dev/null || echo '(not a cert / key file)' + done " - name: Start Docker Compose @@ -405,15 +411,25 @@ jobs: ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " set -eo pipefail cd /tmp/wazuh-docker/${DEPLOYMENT} - echo '=== Pulling images (docker compose pull) ===' - sudo docker compose pull 2>&1 - echo '=== Starting stack (docker compose up -d) ===' sudo docker compose up -d 2>&1 | tee /tmp/docker-compose-up.log echo '' echo '=== Initial container status ===' sudo docker compose ps " + - name: Show indexer logs on failure + if: failure() + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + cd /tmp/wazuh-docker/${DEPLOYMENT} + echo '=== docker compose ps ===' + sudo docker compose ps + echo '' + echo '=== wazuh.indexer logs ===' + sudo docker compose logs wazuh.indexer 2>&1 + " || true + - name: Wait for containers healthy timeout-minutes: 15 run: | From 1bb1ddda73e2e8fdd5bc2a5a420fbf4e1621304b Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 21 May 2026 20:58:48 -0300 Subject: [PATCH 11/27] Log certificates permission --- .github/workflows/check_integration_tools.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 79d744d9..f6e7f5d3 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -393,7 +393,7 @@ jobs: set -e cd /tmp/wazuh-docker/${DEPLOYMENT} echo '=== Running certificate generation ===' - sudo bash /tmp/wazuh-docker/tools/utils/deployment/certificates-conf.sh --cert --copy --priv + sudo bash /tmp/wazuh-docker/tools/utils/deployment/certificates-conf.sh --cert --copy echo '' echo '=== Generated certificate files ===' find ./config -name '*.pem' | sort @@ -405,6 +405,15 @@ jobs: done " + - name: Verify certificate permissions + run: | + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + echo '=== Certificate permissions before compose up ===' + find /tmp/wazuh-docker/${DEPLOYMENT}/config -name '*.pem' \ + -exec ls -la {} \; 2>/dev/null | sort || echo '(no .pem files found)' + " + - name: Start Docker Compose run: | DEPLOYMENT="${{ matrix.deployment_type }}" From d46f24c7079a60204d04d16dbeb0f4204e704475 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 22 May 2026 18:27:31 -0300 Subject: [PATCH 12/27] Add version for test version --- .github/workflows/check_integration_tools.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index f6e7f5d3..3507dc90 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -319,6 +319,7 @@ jobs: curl -fsSL -o "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "$CERT_TOOL_URL" chmod +x "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" echo "Downloaded OK" + echo "WAZUH_VERSION=${VERSION}" >> $GITHUB_ENV # Write config.yml directly into the deployment directory if [ "$DEPLOYMENT" = "single-node" ]; then @@ -495,6 +496,7 @@ jobs: --ssh-port "${{ env.SSH_PORT }}" \ --ssh-key-path "${{ env.SSH_KEY }}" \ --ssh-username "${{ env.SSH_USER }}" \ + --version "${{ env.WAZUH_VERSION }}" \ --log-level INFO \ --output github \ --output-file "test-results-docker-${DEPLOYMENT}.github" From f4f7af55ff91f83738c99a5955fe9855ba429204 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 22 May 2026 19:24:53 -0300 Subject: [PATCH 13/27] Add wait for multi-node delay configurations --- .github/workflows/check_integration_tools.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 3507dc90..2835af72 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -481,6 +481,18 @@ jobs: exit 1 " + - name: Multi-node cluster warm-up wait + if: matrix.deployment_type == 'multi-node' + run: | + echo "Waiting 90s for multi-node OpenSearch cluster to reach steady state..." + sleep 90 + DEPLOYMENT="${{ matrix.deployment_type }}" + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " + cd /tmp/wazuh-docker/${DEPLOYMENT} + echo '=== Container status after warm-up ===' + sudo docker compose ps + " + # ----------------------------------------------------------------------- # Run integration tests # ----------------------------------------------------------------------- From 47287f7ee3adc2e8e196b952e4f36d6aca5f8e10 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Wed, 27 May 2026 18:12:02 -0300 Subject: [PATCH 14/27] Add sleep for dashboard to single and multi node test --- .github/workflows/check_integration_tools.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 2835af72..4067dffd 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -481,11 +481,15 @@ jobs: exit 1 " - - name: Multi-node cluster warm-up wait - if: matrix.deployment_type == 'multi-node' + - name: Cluster warm-up wait run: | - echo "Waiting 90s for multi-node OpenSearch cluster to reach steady state..." - sleep 90 + if [ "${{ matrix.deployment_type }}" = "multi-node" ]; then + WAIT=90 + else + WAIT=60 + fi + echo "Waiting ${WAIT}s for services to reach steady state..." + sleep $WAIT DEPLOYMENT="${{ matrix.deployment_type }}" ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " cd /tmp/wazuh-docker/${DEPLOYMENT} From 2698ef8c2c192cfeb55ec3417ae473e3777c5570 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Wed, 27 May 2026 18:21:07 -0300 Subject: [PATCH 15/27] Add revision tests --- .../workflows/check_integration_tools.yaml | 40 ++++++++----------- VERSION.json | 2 +- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 4067dffd..a2882592 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -26,11 +26,6 @@ on: - single-node - multi-node - both - patch_beta_images: - description: 'Patch image tags to use pre-release suffix (-beta1-latest). Disable once release images are published.' - required: false - default: true - type: boolean permissions: id-token: write @@ -200,6 +195,16 @@ jobs: ref: ${{ needs.prepare.outputs.pr_head_ref }} path: wazuh-docker + - name: Read version info from VERSION.json + run: | + VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") + STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") + REVISION="${STAGE:-1}" + echo "WAZUH_VERSION=${VERSION}" >> $GITHUB_ENV + echo "WAZUH_REVISION=${REVISION}" >> $GITHUB_ENV + echo "WAZUH_STAGE=${STAGE}" >> $GITHUB_ENV + echo "Version: ${VERSION} Revision: ${REVISION}" + - name: Set up Python 3.12 uses: actions/setup-python@v5 with: @@ -277,23 +282,12 @@ jobs: - name: Patch image tags for pre-release run: | DEPLOYMENT="${{ matrix.deployment_type }}" - # Use input when available; hardcoded true otherwise (e.g. dispatched from main - # which does not yet define patch_beta_images). - PATCH="${{ inputs.patch_beta_images }}" - [ -z "$PATCH" ] && PATCH=true - if [ "$PATCH" != "true" ]; then - echo "patch_beta_images=false — skipping image tag patching" - exit 0 - fi - - VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") - STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") + STAGE="${{ env.WAZUH_STAGE }}" if [ -z "$STAGE" ]; then - echo "VERSION.json has no stage field — release image, no patching needed" + echo "No stage in VERSION.json — release image, no patching needed" exit 0 fi - - IMAGE_TAG="${VERSION}-${STAGE}-latest" + IMAGE_TAG="${{ env.WAZUH_VERSION }}-${STAGE}-latest" COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" echo "Patching ${COMPOSE}: image tag → ${IMAGE_TAG}" sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${IMAGE_TAG}|g" "$COMPOSE" @@ -303,11 +297,11 @@ jobs: - name: Prepare cert tool and config run: | DEPLOYMENT="${{ matrix.deployment_type }}" - VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") - STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") + VERSION="${{ env.WAZUH_VERSION }}" + STAGE="${{ env.WAZUH_STAGE }}" MAJOR=$(echo "$VERSION" | cut -d. -f1) - echo "Version: $VERSION Stage: ${STAGE:-}" + echo "Version: ${VERSION} Revision: ${{ env.WAZUH_REVISION }}" # Download cert tool once on the runner, copy to VM via the main SCP if [ -n "$STAGE" ]; then @@ -319,7 +313,6 @@ jobs: curl -fsSL -o "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "$CERT_TOOL_URL" chmod +x "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" echo "Downloaded OK" - echo "WAZUH_VERSION=${VERSION}" >> $GITHUB_ENV # Write config.yml directly into the deployment directory if [ "$DEPLOYMENT" = "single-node" ]; then @@ -513,6 +506,7 @@ jobs: --ssh-key-path "${{ env.SSH_KEY }}" \ --ssh-username "${{ env.SSH_USER }}" \ --version "${{ env.WAZUH_VERSION }}" \ + --revision "${{ env.WAZUH_REVISION }}" \ --log-level INFO \ --output github \ --output-file "test-results-docker-${DEPLOYMENT}.github" diff --git a/VERSION.json b/VERSION.json index 5dc2c235..58649f71 100644 --- a/VERSION.json +++ b/VERSION.json @@ -1,4 +1,4 @@ { "version": "5.0.0", - "stage": "beta1" + "stage": "beta2" } \ No newline at end of file From af388f132a68a8885a3da24c3a0dafefea74671d Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 28 May 2026 20:27:36 -0300 Subject: [PATCH 16/27] Add docker image build and push call --- .../workflows/check_integration_tools.yaml | 132 ++++++++++++++---- 1 file changed, 107 insertions(+), 25 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index a2882592..b3e6fd0b 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -26,6 +26,18 @@ on: - single-node - multi-node - both + version: + description: 'Image version to test (e.g. 5.0.0). Leave empty to build images from VERSION.json.' + required: false + type: string + revision: + description: 'Image tag suffix (e.g. beta2-latest). Required when version is set.' + required: false + type: string + registry: + description: 'Docker registry prefix (e.g. ECR URL). Leave empty for DockerHub.' + required: false + type: string permissions: id-token: write @@ -146,6 +158,8 @@ jobs: outputs: pr_head_ref: ${{ steps.ctx.outputs.pr_head_ref }} deployment_matrix: ${{ steps.ctx.outputs.deployment_matrix }} + wazuh_version: ${{ steps.version.outputs.wazuh_version }} + wazuh_stage: ${{ steps.version.outputs.wazuh_stage }} steps: - name: Resolve context @@ -164,13 +178,54 @@ jobs: echo "deployment_matrix=${{ needs.get_pr_info.outputs.deployment_matrix }}" >> $GITHUB_OUTPUT fi + - name: Checkout wazuh-docker PR branch (VERSION.json only) + uses: actions/checkout@v4 + with: + ref: ${{ steps.ctx.outputs.pr_head_ref }} + sparse-checkout: | + VERSION.json + sparse-checkout-cone-mode: false + + - name: Read version info from VERSION.json + id: version + run: | + VERSION=$(python3 -c "import json; d=json.load(open('VERSION.json')); print(d['version'])") + STAGE=$(python3 -c "import json; d=json.load(open('VERSION.json')); print(d.get('stage',''))") + echo "wazuh_version=${VERSION}" >> $GITHUB_OUTPUT + echo "wazuh_stage=${STAGE}" >> $GITHUB_OUTPUT + echo "Version: ${VERSION} Stage: ${STAGE:-}" + # ------------------------------------------------------------------------- - # Job 3: For each deployment type — provision VM, deploy Docker stack, test, + # Job 3: Build Docker images (only when no explicit version/revision provided). + # Calls Procedure_push_docker_images.yml and pushes to the dev registry. + # ------------------------------------------------------------------------- + build_images: + name: Build Docker images + needs: [prepare] + if: | + always() && + needs.prepare.result == 'success' && + inputs.version == '' + uses: ./.github/workflows/Procedure_push_docker_images.yml + with: + image_tag: "${{ needs.prepare.outputs.wazuh_version }}-${{ needs.prepare.outputs.wazuh_stage }}" + docker_reference: ${{ needs.prepare.outputs.pr_head_ref }} + wazuh_automation_reference: ${{ inputs.automation_reference || 'main' }} + products: "wazuh-manager,wazuh-dashboard,wazuh-indexer" + dev: true + id: "docker-integration-${{ github.run_id }}" + secrets: inherit + + # ------------------------------------------------------------------------- + # Job 4: For each deployment type — provision VM, deploy Docker stack, test, # collect results, and clean up. # ------------------------------------------------------------------------- docker_test: - needs: [get_pr_info, prepare] - if: always() && needs.prepare.result == 'success' + needs: [get_pr_info, prepare, build_images] + if: | + always() && + needs.prepare.result == 'success' && + (needs.build_images.result == 'success' || needs.build_images.result == 'skipped') runs-on: ubuntu-latest strategy: fail-fast: false @@ -195,15 +250,31 @@ jobs: ref: ${{ needs.prepare.outputs.pr_head_ref }} path: wazuh-docker - - name: Read version info from VERSION.json + - name: Resolve image configuration run: | - VERSION=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d['version'])") - STAGE=$(python3 -c "import json; d=json.load(open('wazuh-docker/VERSION.json')); print(d.get('stage',''))") - REVISION="${STAGE:-1}" - echo "WAZUH_VERSION=${VERSION}" >> $GITHUB_ENV - echo "WAZUH_REVISION=${REVISION}" >> $GITHUB_ENV - echo "WAZUH_STAGE=${STAGE}" >> $GITHUB_ENV - echo "Version: ${VERSION} Revision: ${REVISION}" + # Source of truth for cert tool is always VERSION.json (matches wazuh-docker branch) + WAZUH_VERSION="${{ needs.prepare.outputs.wazuh_version }}" + WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" + + if [ -n "${{ inputs.version }}" ]; then + # Case 1a: pre-built images — test a specific set already in a registry + DOCKER_VERSION="${{ inputs.version }}" + DOCKER_REVISION="${{ inputs.revision }}" + DOCKER_REGISTRY="${{ inputs.registry }}" + else + # Case 1b/2: freshly built images pushed to dev registry by build_images job + DOCKER_VERSION="${WAZUH_VERSION}" + DOCKER_REVISION="${WAZUH_STAGE}" + DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + fi + + echo "WAZUH_VERSION=${WAZUH_VERSION}" >> $GITHUB_ENV + echo "WAZUH_STAGE=${WAZUH_STAGE}" >> $GITHUB_ENV + echo "WAZUH_REVISION=${DOCKER_REVISION:-1}" >> $GITHUB_ENV + echo "DOCKER_VERSION=${DOCKER_VERSION}" >> $GITHUB_ENV + echo "DOCKER_REVISION=${DOCKER_REVISION}" >> $GITHUB_ENV + echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> $GITHUB_ENV + echo "Image: ${DOCKER_REGISTRY:+${DOCKER_REGISTRY}/}wazuh/wazuh-*:${DOCKER_VERSION}-${DOCKER_REVISION}" - name: Set up Python 3.12 uses: actions/setup-python@v5 @@ -276,21 +347,32 @@ jobs: sudo systemctl enable --now docker " + - name: Login VM to ECR registry + if: env.DOCKER_REGISTRY != '' + run: | + ECR_PASS=$(aws ecr get-login-password --region ${{ env.REGION }}) + ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" \ + "echo '${ECR_PASS}' | sudo docker login --username AWS --password-stdin ${{ env.DOCKER_REGISTRY }}" + # ----------------------------------------------------------------------- - # Deploy: optionally patch image tags, copy wazuh-docker and start the stack + # Deploy: patch image tags, copy wazuh-docker and start the stack # ----------------------------------------------------------------------- - - name: Patch image tags for pre-release + - name: Patch image tags run: | DEPLOYMENT="${{ matrix.deployment_type }}" - STAGE="${{ env.WAZUH_STAGE }}" - if [ -z "$STAGE" ]; then - echo "No stage in VERSION.json — release image, no patching needed" - exit 0 - fi - IMAGE_TAG="${{ env.WAZUH_VERSION }}-${STAGE}-latest" COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" - echo "Patching ${COMPOSE}: image tag → ${IMAGE_TAG}" - sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${IMAGE_TAG}|g" "$COMPOSE" + VERSION="${{ env.DOCKER_VERSION }}" + REVISION="${{ env.DOCKER_REVISION }}" + REGISTRY="${{ env.DOCKER_REGISTRY }}" + TAG="${VERSION}-${REVISION}" + + if [ -n "$REGISTRY" ]; then + echo "Patching ${COMPOSE}: ${REGISTRY}/wazuh/wazuh-*:${TAG}" + sed -i -E "s|image: (wazuh/wazuh-[^:]+):[^ ]+|image: ${REGISTRY}/\1:${TAG}|g" "$COMPOSE" + else + echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG}" + sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" + fi echo "=== Patched image lines ===" grep 'image:' "$COMPOSE" @@ -301,7 +383,7 @@ jobs: STAGE="${{ env.WAZUH_STAGE }}" MAJOR=$(echo "$VERSION" | cut -d. -f1) - echo "Version: ${VERSION} Revision: ${{ env.WAZUH_REVISION }}" + echo "Cert tool: ${VERSION}-${STAGE} Docker image: ${{ env.DOCKER_VERSION }}-${{ env.DOCKER_REVISION }}" # Download cert tool once on the runner, copy to VM via the main SCP if [ -n "$STAGE" ]; then @@ -505,8 +587,8 @@ jobs: --ssh-port "${{ env.SSH_PORT }}" \ --ssh-key-path "${{ env.SSH_KEY }}" \ --ssh-username "${{ env.SSH_USER }}" \ - --version "${{ env.WAZUH_VERSION }}" \ - --revision "${{ env.WAZUH_REVISION }}" \ + --version "${{ env.DOCKER_VERSION }}" \ + --revision "${{ env.DOCKER_REVISION }}" \ --log-level INFO \ --output github \ --output-file "test-results-docker-${DEPLOYMENT}.github" @@ -651,7 +733,7 @@ jobs: # Job 4: Update the GitHub check run (issue_comment trigger only) # ------------------------------------------------------------------------- update_check: - needs: [get_pr_info, prepare, docker_test] + needs: [get_pr_info, prepare, build_images, docker_test] if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success' runs-on: ubuntu-latest steps: From 29d43e591e283083e8d1aba2f32be0043fa15983 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 28 May 2026 20:36:46 -0300 Subject: [PATCH 17/27] Add registry dev or prod param --- .../workflows/check_integration_tools.yaml | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index b3e6fd0b..22ef97ed 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -31,11 +31,7 @@ on: required: false type: string revision: - description: 'Image tag suffix (e.g. beta2-latest). Required when version is set.' - required: false - type: string - registry: - description: 'Docker registry prefix (e.g. ECR URL). Leave empty for DockerHub.' + description: 'Image revision/stage (e.g. beta2). Required when version is set.' required: false type: string @@ -252,15 +248,15 @@ jobs: - name: Resolve image configuration run: | - # Source of truth for cert tool is always VERSION.json (matches wazuh-docker branch) + # Source of truth for cert tool — always from VERSION.json (pr branch) WAZUH_VERSION="${{ needs.prepare.outputs.wazuh_version }}" WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" if [ -n "${{ inputs.version }}" ]; then - # Case 1a: pre-built images — test a specific set already in a registry + # Case 1a: pre-built images already in the prod registry (DockerHub) DOCKER_VERSION="${{ inputs.version }}" DOCKER_REVISION="${{ inputs.revision }}" - DOCKER_REGISTRY="${{ inputs.registry }}" + DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" else # Case 1b/2: freshly built images pushed to dev registry by build_images job DOCKER_VERSION="${WAZUH_VERSION}" @@ -268,13 +264,13 @@ jobs: DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" fi - echo "WAZUH_VERSION=${WAZUH_VERSION}" >> $GITHUB_ENV - echo "WAZUH_STAGE=${WAZUH_STAGE}" >> $GITHUB_ENV + echo "WAZUH_VERSION=${WAZUH_VERSION}" >> $GITHUB_ENV + echo "WAZUH_STAGE=${WAZUH_STAGE}" >> $GITHUB_ENV echo "WAZUH_REVISION=${DOCKER_REVISION:-1}" >> $GITHUB_ENV - echo "DOCKER_VERSION=${DOCKER_VERSION}" >> $GITHUB_ENV - echo "DOCKER_REVISION=${DOCKER_REVISION}" >> $GITHUB_ENV - echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> $GITHUB_ENV - echo "Image: ${DOCKER_REGISTRY:+${DOCKER_REGISTRY}/}wazuh/wazuh-*:${DOCKER_VERSION}-${DOCKER_REVISION}" + echo "DOCKER_VERSION=${DOCKER_VERSION}" >> $GITHUB_ENV + echo "DOCKER_REVISION=${DOCKER_REVISION}" >> $GITHUB_ENV + echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> $GITHUB_ENV + echo "Image: ${DOCKER_REGISTRY}/wazuh/wazuh-*:${DOCKER_VERSION}-${DOCKER_REVISION}" - name: Set up Python 3.12 uses: actions/setup-python@v5 @@ -348,11 +344,13 @@ jobs: " - name: Login VM to ECR registry - if: env.DOCKER_REGISTRY != '' + if: inputs.version == '' run: | - ECR_PASS=$(aws ecr get-login-password --region ${{ env.REGION }}) + ECR_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + ECR_REGION=$(echo "$ECR_REGISTRY" | cut -d. -f4) + ECR_PASS=$(aws ecr get-login-password --region "$ECR_REGION") ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" \ - "echo '${ECR_PASS}' | sudo docker login --username AWS --password-stdin ${{ env.DOCKER_REGISTRY }}" + "echo '${ECR_PASS}' | sudo docker login --username AWS --password-stdin ${ECR_REGISTRY}" # ----------------------------------------------------------------------- # Deploy: patch image tags, copy wazuh-docker and start the stack @@ -361,17 +359,17 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" - VERSION="${{ env.DOCKER_VERSION }}" - REVISION="${{ env.DOCKER_REVISION }}" + TAG="${{ env.DOCKER_VERSION }}-${{ env.DOCKER_REVISION }}" REGISTRY="${{ env.DOCKER_REGISTRY }}" - TAG="${VERSION}-${REVISION}" - if [ -n "$REGISTRY" ]; then + if [ "$REGISTRY" = "docker.io" ] || [ -z "$REGISTRY" ]; then + # DockerHub: no registry prefix needed + echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG} (DockerHub)" + sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" + else + # Private registry (ECR): add registry prefix echo "Patching ${COMPOSE}: ${REGISTRY}/wazuh/wazuh-*:${TAG}" sed -i -E "s|image: (wazuh/wazuh-[^:]+):[^ ]+|image: ${REGISTRY}/\1:${TAG}|g" "$COMPOSE" - else - echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG}" - sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" fi echo "=== Patched image lines ===" grep 'image:' "$COMPOSE" From df1ef1cb1f9e7e561667639992baf6cdf83d46f5 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 28 May 2026 21:35:13 -0300 Subject: [PATCH 18/27] Add missing param list into build image WF call --- .github/workflows/check_integration_tools.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 22ef97ed..581744c6 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -207,7 +207,7 @@ jobs: image_tag: "${{ needs.prepare.outputs.wazuh_version }}-${{ needs.prepare.outputs.wazuh_stage }}" docker_reference: ${{ needs.prepare.outputs.pr_head_ref }} wazuh_automation_reference: ${{ inputs.automation_reference || 'main' }} - products: "wazuh-manager,wazuh-dashboard,wazuh-indexer" + products: "wazuh-manager,wazuh-dashboard,wazuh-indexer,wazuh-agent" dev: true id: "docker-integration-${{ github.run_id }}" secrets: inherit From fb2148da39cd9e777688d503af335437740c2314 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Thu, 28 May 2026 21:55:05 -0300 Subject: [PATCH 19/27] Add logic to use -latest if dev images --- .github/workflows/check_integration_tools.yaml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 581744c6..203831db 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -359,15 +359,23 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" - TAG="${{ env.DOCKER_VERSION }}-${{ env.DOCKER_REVISION }}" + VERSION="${{ env.DOCKER_VERSION }}" + REVISION="${{ env.DOCKER_REVISION }}" REGISTRY="${{ env.DOCKER_REGISTRY }}" + # build-images.sh appends -latest when dev=true + commit=latest: + # dev=true, 5.0.0-beta2 → 5.0.0-beta2-latest + # dev=false, 5.0.0 → 5.0.0 + if [ -n "$REVISION" ]; then + TAG="${VERSION}-${REVISION}-latest" + else + TAG="${VERSION}" + fi + if [ "$REGISTRY" = "docker.io" ] || [ -z "$REGISTRY" ]; then - # DockerHub: no registry prefix needed echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG} (DockerHub)" sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" else - # Private registry (ECR): add registry prefix echo "Patching ${COMPOSE}: ${REGISTRY}/wazuh/wazuh-*:${TAG}" sed -i -E "s|image: (wazuh/wazuh-[^:]+):[^ ]+|image: ${REGISTRY}/\1:${TAG}|g" "$COMPOSE" fi From 2f4ab3f71e411ef7c460c89ee414743eab0f98d8 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 10:35:13 -0300 Subject: [PATCH 20/27] Fix copilot suggestions --- .github/workflows/check_integration_tools.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 203831db..bd7cebbe 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -101,8 +101,9 @@ jobs: - name: Parse command and set deployment metadata id: parse_command + env: + COMMENT_BODY: ${{ github.event.comment.body }} run: | - COMMENT_BODY="${{ github.event.comment.body }}" # Check longest match first to avoid /test-docker matching /test-docker-single if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT From 9bed763ce55857a8b379b035f7a3b3626e0bacb1 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 10:43:30 -0300 Subject: [PATCH 21/27] Remove steps used for debug --- .../workflows/check_integration_tools.yaml | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index bd7cebbe..f235ac07 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -27,7 +27,7 @@ on: - multi-node - both version: - description: 'Image version to test (e.g. 5.0.0). Leave empty to build images from VERSION.json.' + description: 'Image version to test (e.g. 5.0.0). Leave empty to build images from PR.' required: false type: string revision: @@ -51,7 +51,7 @@ jobs: # ------------------------------------------------------------------------- # Job 1: Parse PR info and determine which deployment(s) to test # - # Available commands (checked longest-match first to avoid substring collision): + # Available commands: # /test-docker-single — test single-node deployment # /test-docker-multi — test multi-node deployment # /test-docker — test both single-node and multi-node @@ -104,7 +104,6 @@ jobs: env: COMMENT_BODY: ${{ github.event.comment.body }} run: | - # Check longest match first to avoid /test-docker matching /test-docker-single if echo "$COMMENT_BODY" | grep -q '/test-docker-single'; then echo 'deployment_matrix=["single-node"]' >> $GITHUB_OUTPUT echo 'check_name=Docker Integration Check (Single-Node)' >> $GITHUB_OUTPUT @@ -143,8 +142,7 @@ jobs: return check.id; # ------------------------------------------------------------------------- - # Job 2: Resolve context (pr_head_ref + deployment matrix) for both triggers. - # Mirrors the role of build_tools in check_integration_tools.yaml. + # Job 2: Prepare context (pr_head_ref + deployment matrix) for both triggers. # ------------------------------------------------------------------------- prepare: needs: [get_pr_info] @@ -249,17 +247,17 @@ jobs: - name: Resolve image configuration run: | - # Source of truth for cert tool — always from VERSION.json (pr branch) + # Get from VERSION.json (for pr branch) WAZUH_VERSION="${{ needs.prepare.outputs.wazuh_version }}" WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" if [ -n "${{ inputs.version }}" ]; then - # Case 1a: pre-built images already in the prod registry (DockerHub) + # Use explicit version/revision provided via workflow_dispatch (e.g. for testing prod images or specific dev images) DOCKER_VERSION="${{ inputs.version }}" DOCKER_REVISION="${{ inputs.revision }}" DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" else - # Case 1b/2: freshly built images pushed to dev registry by build_images job + # Use version from VERSION.json and assume images were built in the previous job and pushed to the dev registry DOCKER_VERSION="${WAZUH_VERSION}" DOCKER_REVISION="${WAZUH_STAGE}" DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" @@ -364,9 +362,6 @@ jobs: REVISION="${{ env.DOCKER_REVISION }}" REGISTRY="${{ env.DOCKER_REGISTRY }}" - # build-images.sh appends -latest when dev=true + commit=latest: - # dev=true, 5.0.0-beta2 → 5.0.0-beta2-latest - # dev=false, 5.0.0 → 5.0.0 if [ -n "$REVISION" ]; then TAG="${VERSION}-${REVISION}-latest" else @@ -392,7 +387,7 @@ jobs: echo "Cert tool: ${VERSION}-${STAGE} Docker image: ${{ env.DOCKER_VERSION }}-${{ env.DOCKER_REVISION }}" - # Download cert tool once on the runner, copy to VM via the main SCP + # Download cert tool once on the runner if [ -n "$STAGE" ]; then CERT_TOOL_URL="https://packages-staging.xdrsiem.wazuh.info/pre-release/${MAJOR}.x/installation-assistant/wazuh-certs-tool-${VERSION}-${STAGE}.sh" else @@ -488,15 +483,6 @@ jobs: done " - - name: Verify certificate permissions - run: | - DEPLOYMENT="${{ matrix.deployment_type }}" - ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" " - echo '=== Certificate permissions before compose up ===' - find /tmp/wazuh-docker/${DEPLOYMENT}/config -name '*.pem' \ - -exec ls -la {} \; 2>/dev/null | sort || echo '(no .pem files found)' - " - - name: Start Docker Compose run: | DEPLOYMENT="${{ matrix.deployment_type }}" From 31d8b1566cb1bfb33181e19b6121e5878eb72db3 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 10:44:59 -0300 Subject: [PATCH 22/27] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53b7f97c..bcd3aec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Added +- Implement the wazuh-docker integration testing module ([#2428](https://github.com/wazuh/wazuh-docker/pull/2428)) - Add revert option into bumper workflow ([#2330](https://github.com/wazuh/wazuh-docker/pull/2330)) - Add checks for artifact_urls.yaml download ([#2315](https://github.com/wazuh/wazuh-docker/pull/2315)) - Add set_as_main option ([#2293](https://github.com/wazuh/wazuh-docker/pull/2293)) From 3f27301ba1c9c8009c343668434219dec76806f0 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 12:12:00 -0300 Subject: [PATCH 23/27] Add registry parameter --- .github/workflows/check_integration_tools.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index f235ac07..222758d9 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -34,6 +34,10 @@ on: description: 'Image revision/stage (e.g. beta2). Required when version is set.' required: false type: string + registry: + description: 'Docker registry (e.g. ECR URL). Leave empty to use DockerHub. Only applies when version is set.' + required: false + type: string permissions: id-token: write @@ -252,10 +256,10 @@ jobs: WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" if [ -n "${{ inputs.version }}" ]; then - # Use explicit version/revision provided via workflow_dispatch (e.g. for testing prod images or specific dev images) + # Explicit version/revision: use provided registry or fall back to DockerHub prod DOCKER_VERSION="${{ inputs.version }}" DOCKER_REVISION="${{ inputs.revision }}" - DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" + DOCKER_REGISTRY="${{ inputs.registry || vars.IMAGE_REGISTRY_PROD }}" else # Use version from VERSION.json and assume images were built in the previous job and pushed to the dev registry DOCKER_VERSION="${WAZUH_VERSION}" @@ -343,9 +347,9 @@ jobs: " - name: Login VM to ECR registry - if: inputs.version == '' + if: inputs.version == '' || inputs.registry != '' run: | - ECR_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + ECR_REGISTRY="${{ env.DOCKER_REGISTRY }}" ECR_REGION=$(echo "$ECR_REGISTRY" | cut -d. -f4) ECR_PASS=$(aws ecr get-login-password --region "$ECR_REGION") ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" \ From f79abbf64a16d14fcc332988771c5367b857279f Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 12:12:05 -0300 Subject: [PATCH 24/27] Add registry parameter --- .../workflows/check_integration_tools.yaml | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 222758d9..2960bb4f 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -35,9 +35,12 @@ on: required: false type: string registry: - description: 'Docker registry (e.g. ECR URL). Leave empty to use DockerHub. Only applies when version is set.' + description: 'Docker registry. ECR for dev versions, DockerHub for prod versions.' required: false - type: string + type: choice + options: + - ERC + - DockerHub permissions: id-token: write @@ -251,17 +254,24 @@ jobs: - name: Resolve image configuration run: | - # Get from VERSION.json (for pr branch) + # Source of truth for cert tool — always from VERSION.json (pr branch) WAZUH_VERSION="${{ needs.prepare.outputs.wazuh_version }}" WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" + # Map registry choice to actual URL (defined once) + if [ "${{ inputs.registry }}" = "ERC" ]; then + SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + else + SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" + fi + if [ -n "${{ inputs.version }}" ]; then - # Explicit version/revision: use provided registry or fall back to DockerHub prod + # Explicit version/revision: use the registry choice mapped above DOCKER_VERSION="${{ inputs.version }}" DOCKER_REVISION="${{ inputs.revision }}" - DOCKER_REGISTRY="${{ inputs.registry || vars.IMAGE_REGISTRY_PROD }}" + DOCKER_REGISTRY="$SELECTED_REGISTRY" else - # Use version from VERSION.json and assume images were built in the previous job and pushed to the dev registry + # Build case: always dev registry (build_images job pushed there) DOCKER_VERSION="${WAZUH_VERSION}" DOCKER_REVISION="${WAZUH_STAGE}" DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" @@ -347,7 +357,7 @@ jobs: " - name: Login VM to ECR registry - if: inputs.version == '' || inputs.registry != '' + if: inputs.version == '' || inputs.registry == 'ERC' run: | ECR_REGISTRY="${{ env.DOCKER_REGISTRY }}" ECR_REGION=$(echo "$ECR_REGISTRY" | cut -d. -f4) From 6dd0716918e9f17690b871a4052ebdb63b80ab22 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 13:11:24 -0300 Subject: [PATCH 25/27] Fix case of registry prod and version y revision parameters inputs --- .github/workflows/check_integration_tools.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 2960bb4f..cc9a46dd 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -376,13 +376,13 @@ jobs: REVISION="${{ env.DOCKER_REVISION }}" REGISTRY="${{ env.DOCKER_REGISTRY }}" - if [ -n "$REVISION" ]; then - TAG="${VERSION}-${REVISION}-latest" + if [ "$REGISTRY" = "${{ vars.IMAGE_REGISTRY_DEV }}" ]; then + TAG="${VERSION}${REVISION:+-${REVISION}}-latest" else - TAG="${VERSION}" + TAG="${VERSION}${REVISION:+-${REVISION}}" fi - if [ "$REGISTRY" = "docker.io" ] || [ -z "$REGISTRY" ]; then + if [ "$REGISTRY" = "${{ vars.IMAGE_REGISTRY_PROD }}" ] || [ -z "$REGISTRY" ]; then echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG} (DockerHub)" sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" else From 7598697f3b6a65d1bc0e5fcd1bf1a163f88c490e Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 15:06:40 -0300 Subject: [PATCH 26/27] Add test cases if only version is pass through input parameter --- .../workflows/check_integration_tools.yaml | 162 ++++++++++++++---- 1 file changed, 127 insertions(+), 35 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index cc9a46dd..28dd49f0 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -27,11 +27,11 @@ on: - multi-node - both version: - description: 'Image version to test (e.g. 5.0.0). Leave empty to build images from PR.' + description: 'Image version to test (e.g. 5.0.0).' required: false type: string - revision: - description: 'Image revision/stage (e.g. beta2). Required when version is set.' + stage: + description: 'Image stage suffix (e.g. beta1, beta2-latest, beta2-). Required when version is set.' required: false type: string registry: @@ -39,7 +39,7 @@ on: required: false type: choice options: - - ERC + - ECR - DockerHub permissions: @@ -197,8 +197,80 @@ jobs: echo "wazuh_stage=${STAGE}" >> $GITHUB_OUTPUT echo "Version: ${VERSION} Stage: ${STAGE:-}" + - name: Show test plan + run: | + WAZUH_VERSION="${{ steps.version.outputs.wazuh_version }}" + WAZUH_STAGE="${{ steps.version.outputs.wazuh_stage }}" + INPUT_VERSION="${{ inputs.version }}" + INPUT_STAGE="${{ inputs.stage }}" + INPUT_REGISTRY="${{ inputs.registry }}" + + echo "=============================================" + echo " DOCKER INTEGRATION TEST PLAN" + echo "=============================================" + echo "" + echo "Branch: ${{ steps.ctx.outputs.pr_head_ref }}" + echo "Trigger: ${{ github.event_name }}" + echo "Deployments: ${{ steps.ctx.outputs.deployment_matrix }}" + echo "" + echo "--- Version info (VERSION.json) ---" + echo "wazuh_version: ${WAZUH_VERSION}" + echo "wazuh_stage: ${WAZUH_STAGE:-}" + echo "" + echo "--- Workflow inputs ---" + echo "version: ${INPUT_VERSION:-}" + echo "stage: ${INPUT_STAGE:-}" + echo "registry: ${INPUT_REGISTRY:-}" + echo "" + + # Determine effective case + if [ -z "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then + DOCKER_VERSION="$WAZUH_VERSION" + DOCKER_STAGE_DISPLAY="${WAZUH_STAGE}" + if [ "$INPUT_REGISTRY" = "ECR" ] || [ "${{ github.event_name }}" = "issue_comment" ]; then + echo "Case: a.1 — No version/stage → BUILD images from PR → push to ECR" + echo "Action: BUILD + push to ECR, then test" + EFFECTIVE_TAG="${DOCKER_VERSION}${DOCKER_STAGE_DISPLAY:+-${DOCKER_STAGE_DISPLAY}}-latest" + EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})" + else + echo "Case: a.2 — No version/stage → PULL from DockerHub" + echo "Action: PULL images (no build)" + EFFECTIVE_TAG="${DOCKER_VERSION}${DOCKER_STAGE_DISPLAY:+-${DOCKER_STAGE_DISPLAY}}" + EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})" + fi + elif [ -n "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then + DOCKER_VERSION="$INPUT_VERSION" + echo "Action: PULL images (no build)" + if [ "$INPUT_REGISTRY" = "ECR" ]; then + echo "Case: b.1 — Version only, ECR → tag = version-latest" + EFFECTIVE_TAG="${DOCKER_VERSION}-latest" + EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})" + else + echo "Case: b.2 — Version only, DockerHub → tag = version" + EFFECTIVE_TAG="${DOCKER_VERSION}" + EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})" + fi + else + echo "Case: c — Version + stage provided as-is (no -latest appended)" + echo "Action: PULL images (no build)" + DOCKER_VERSION="${INPUT_VERSION:-${WAZUH_VERSION}}" + EFFECTIVE_TAG="${DOCKER_VERSION}-${INPUT_STAGE}" + if [ "$INPUT_REGISTRY" = "ECR" ]; then + EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})" + else + EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})" + fi + fi + + echo "" + echo "--- Effective image configuration ---" + echo "Registry: ${EFFECTIVE_REGISTRY}" + echo "Image tag: ${EFFECTIVE_TAG}" + echo "Example image: wazuh/wazuh-manager:${EFFECTIVE_TAG}" + echo "=============================================" + # ------------------------------------------------------------------------- - # Job 3: Build Docker images (only when no explicit version/revision provided). + # Job 3: Build Docker images (only for ECR, when no explicit version/stage provided). # Calls Procedure_push_docker_images.yml and pushes to the dev registry. # ------------------------------------------------------------------------- build_images: @@ -207,7 +279,9 @@ jobs: if: | always() && needs.prepare.result == 'success' && - inputs.version == '' + inputs.version == '' && + inputs.stage == '' && + (inputs.registry == 'ECR' || github.event_name == 'issue_comment') uses: ./.github/workflows/Procedure_push_docker_images.yml with: image_tag: "${{ needs.prepare.outputs.wazuh_version }}-${{ needs.prepare.outputs.wazuh_stage }}" @@ -254,36 +328,62 @@ jobs: - name: Resolve image configuration run: | - # Source of truth for cert tool — always from VERSION.json (pr branch) WAZUH_VERSION="${{ needs.prepare.outputs.wazuh_version }}" WAZUH_STAGE="${{ needs.prepare.outputs.wazuh_stage }}" + INPUT_VERSION="${{ inputs.version }}" + INPUT_STAGE="${{ inputs.stage }}" # Map registry choice to actual URL (defined once) - if [ "${{ inputs.registry }}" = "ERC" ]; then + if [ "${{ inputs.registry }}" = "ECR" ]; then SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" else SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" fi - if [ -n "${{ inputs.version }}" ]; then - # Explicit version/revision: use the registry choice mapped above - DOCKER_VERSION="${{ inputs.version }}" - DOCKER_REVISION="${{ inputs.revision }}" + if [ -z "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then + # Case a: no version, no stage — use VERSION.json + DOCKER_VERSION="$WAZUH_VERSION" + DOCKER_STAGE="$WAZUH_STAGE" + if [ "${{ inputs.registry }}" = "ECR" ] || [ "${{ github.event_name }}" = "issue_comment" ]; then + # Case a.1: ECR / PR comment — images were built by build_images job → tag = version-stage-latest + DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + DOCKER_TAG="${DOCKER_VERSION}${DOCKER_STAGE:+-${DOCKER_STAGE}}-latest" + else + # Case a.2: DockerHub — pull pre-built tag = version-stage + DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" + DOCKER_TAG="${DOCKER_VERSION}${DOCKER_STAGE:+-${DOCKER_STAGE}}" + fi + elif [ -n "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then + # Case b: version only, no stage + DOCKER_VERSION="$INPUT_VERSION" + DOCKER_STAGE="" DOCKER_REGISTRY="$SELECTED_REGISTRY" + if [ "${{ inputs.registry }}" = "ECR" ]; then + # Case b.1: ECR — tag = version-latest + DOCKER_TAG="${DOCKER_VERSION}-latest" + else + # Case b.2: DockerHub — tag = version (no suffix) + DOCKER_TAG="${DOCKER_VERSION}" + fi else - # Build case: always dev registry (build_images job pushed there) - DOCKER_VERSION="${WAZUH_VERSION}" - DOCKER_REVISION="${WAZUH_STAGE}" - DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" + # Case c: version + stage provided as-is (no -latest appended) + DOCKER_VERSION="${INPUT_VERSION:-${WAZUH_VERSION}}" + DOCKER_STAGE="$INPUT_STAGE" + DOCKER_REGISTRY="$SELECTED_REGISTRY" + DOCKER_TAG="${DOCKER_VERSION}-${DOCKER_STAGE}" fi - echo "WAZUH_VERSION=${WAZUH_VERSION}" >> $GITHUB_ENV - echo "WAZUH_STAGE=${WAZUH_STAGE}" >> $GITHUB_ENV - echo "WAZUH_REVISION=${DOCKER_REVISION:-1}" >> $GITHUB_ENV - echo "DOCKER_VERSION=${DOCKER_VERSION}" >> $GITHUB_ENV - echo "DOCKER_REVISION=${DOCKER_REVISION}" >> $GITHUB_ENV - echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> $GITHUB_ENV - echo "Image: ${DOCKER_REGISTRY}/wazuh/wazuh-*:${DOCKER_VERSION}-${DOCKER_REVISION}" + echo "WAZUH_VERSION=${WAZUH_VERSION}" >> $GITHUB_ENV + echo "WAZUH_STAGE=${WAZUH_STAGE}" >> $GITHUB_ENV + echo "DOCKER_VERSION=${DOCKER_VERSION}" >> $GITHUB_ENV + echo "DOCKER_STAGE=${DOCKER_STAGE}" >> $GITHUB_ENV + echo "DOCKER_REGISTRY=${DOCKER_REGISTRY}" >> $GITHUB_ENV + echo "DOCKER_TAG=${DOCKER_TAG}" >> $GITHUB_ENV + + echo "=== Resolved image configuration ===" + echo "Registry: ${DOCKER_REGISTRY}" + echo "Tag: ${DOCKER_TAG}" + echo "Example: wazuh/wazuh-manager:${DOCKER_TAG}" - name: Set up Python 3.12 uses: actions/setup-python@v5 @@ -357,7 +457,7 @@ jobs: " - name: Login VM to ECR registry - if: inputs.version == '' || inputs.registry == 'ERC' + if: inputs.registry == 'ECR' || github.event_name == 'issue_comment' run: | ECR_REGISTRY="${{ env.DOCKER_REGISTRY }}" ECR_REGION=$(echo "$ECR_REGISTRY" | cut -d. -f4) @@ -372,18 +472,11 @@ jobs: run: | DEPLOYMENT="${{ matrix.deployment_type }}" COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml" - VERSION="${{ env.DOCKER_VERSION }}" - REVISION="${{ env.DOCKER_REVISION }}" + TAG="${{ env.DOCKER_TAG }}" REGISTRY="${{ env.DOCKER_REGISTRY }}" - if [ "$REGISTRY" = "${{ vars.IMAGE_REGISTRY_DEV }}" ]; then - TAG="${VERSION}${REVISION:+-${REVISION}}-latest" - else - TAG="${VERSION}${REVISION:+-${REVISION}}" - fi - if [ "$REGISTRY" = "${{ vars.IMAGE_REGISTRY_PROD }}" ] || [ -z "$REGISTRY" ]; then - echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG} (DockerHub)" + echo "Patching ${COMPOSE}: wazuh/wazuh-*:${TAG} (DockerHub, no registry prefix)" sed -i -E "s|(image: wazuh/wazuh-[^:]+:)[^ ]+|\1${TAG}|g" "$COMPOSE" else echo "Patching ${COMPOSE}: ${REGISTRY}/wazuh/wazuh-*:${TAG}" @@ -399,7 +492,7 @@ jobs: STAGE="${{ env.WAZUH_STAGE }}" MAJOR=$(echo "$VERSION" | cut -d. -f1) - echo "Cert tool: ${VERSION}-${STAGE} Docker image: ${{ env.DOCKER_VERSION }}-${{ env.DOCKER_REVISION }}" + echo "Cert tool: ${VERSION}-${STAGE} Docker image: ${{ env.DOCKER_TAG }}" # Download cert tool once on the runner if [ -n "$STAGE" ]; then @@ -595,7 +688,6 @@ jobs: --ssh-key-path "${{ env.SSH_KEY }}" \ --ssh-username "${{ env.SSH_USER }}" \ --version "${{ env.DOCKER_VERSION }}" \ - --revision "${{ env.DOCKER_REVISION }}" \ --log-level INFO \ --output github \ --output-file "test-results-docker-${DEPLOYMENT}.github" From 68a50f2bc572463fc0bc5397c1ef85be2eb5aca2 Mon Sep 17 00:00:00 2001 From: fcaffieri Date: Fri, 29 May 2026 15:47:07 -0300 Subject: [PATCH 27/27] Add test plan to github summary --- .../workflows/check_integration_tools.yaml | 90 +++++++++++-------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/.github/workflows/check_integration_tools.yaml b/.github/workflows/check_integration_tools.yaml index 28dd49f0..048c56ea 100644 --- a/.github/workflows/check_integration_tools.yaml +++ b/.github/workflows/check_integration_tools.yaml @@ -205,54 +205,36 @@ jobs: INPUT_STAGE="${{ inputs.stage }}" INPUT_REGISTRY="${{ inputs.registry }}" - echo "=============================================" - echo " DOCKER INTEGRATION TEST PLAN" - echo "=============================================" - echo "" - echo "Branch: ${{ steps.ctx.outputs.pr_head_ref }}" - echo "Trigger: ${{ github.event_name }}" - echo "Deployments: ${{ steps.ctx.outputs.deployment_matrix }}" - echo "" - echo "--- Version info (VERSION.json) ---" - echo "wazuh_version: ${WAZUH_VERSION}" - echo "wazuh_stage: ${WAZUH_STAGE:-}" - echo "" - echo "--- Workflow inputs ---" - echo "version: ${INPUT_VERSION:-}" - echo "stage: ${INPUT_STAGE:-}" - echo "registry: ${INPUT_REGISTRY:-}" - echo "" - # Determine effective case if [ -z "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then DOCKER_VERSION="$WAZUH_VERSION" DOCKER_STAGE_DISPLAY="${WAZUH_STAGE}" if [ "$INPUT_REGISTRY" = "ECR" ] || [ "${{ github.event_name }}" = "issue_comment" ]; then - echo "Case: a.1 — No version/stage → BUILD images from PR → push to ECR" - echo "Action: BUILD + push to ECR, then test" + CASE="a.1 — No version/stage → BUILD images from PR → push to ECR" + ACTION="BUILD + push to ECR" EFFECTIVE_TAG="${DOCKER_VERSION}${DOCKER_STAGE_DISPLAY:+-${DOCKER_STAGE_DISPLAY}}-latest" EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})" else - echo "Case: a.2 — No version/stage → PULL from DockerHub" - echo "Action: PULL images (no build)" + CASE="a.2 — No version/stage → PULL from DockerHub" + ACTION="PULL (no build)" EFFECTIVE_TAG="${DOCKER_VERSION}${DOCKER_STAGE_DISPLAY:+-${DOCKER_STAGE_DISPLAY}}" EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})" fi elif [ -n "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then DOCKER_VERSION="$INPUT_VERSION" - echo "Action: PULL images (no build)" + ACTION="PULL (no build)" if [ "$INPUT_REGISTRY" = "ECR" ]; then - echo "Case: b.1 — Version only, ECR → tag = version-latest" + CASE="b.1 — Version only, ECR → tag = version-latest" EFFECTIVE_TAG="${DOCKER_VERSION}-latest" EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})" else - echo "Case: b.2 — Version only, DockerHub → tag = version" + CASE="b.2 — Version only, DockerHub → tag = version" EFFECTIVE_TAG="${DOCKER_VERSION}" EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})" fi else - echo "Case: c — Version + stage provided as-is (no -latest appended)" - echo "Action: PULL images (no build)" + CASE="c — Version + stage provided as-is (no -latest appended)" + ACTION="PULL (no build)" DOCKER_VERSION="${INPUT_VERSION:-${WAZUH_VERSION}}" EFFECTIVE_TAG="${DOCKER_VERSION}-${INPUT_STAGE}" if [ "$INPUT_REGISTRY" = "ECR" ]; then @@ -262,12 +244,50 @@ jobs: fi fi - echo "" - echo "--- Effective image configuration ---" - echo "Registry: ${EFFECTIVE_REGISTRY}" - echo "Image tag: ${EFFECTIVE_TAG}" - echo "Example image: wazuh/wazuh-manager:${EFFECTIVE_TAG}" + # Log to stdout echo "=============================================" + echo " DOCKER INTEGRATION TEST PLAN" + echo "=============================================" + echo "Branch: ${{ steps.ctx.outputs.pr_head_ref }}" + echo "Trigger: ${{ github.event_name }}" + echo "Deployments: ${{ steps.ctx.outputs.deployment_matrix }}" + echo "Case: ${CASE}" + echo "Action: ${ACTION}" + echo "Registry: ${EFFECTIVE_REGISTRY}" + echo "Image tag: ${EFFECTIVE_TAG}" + echo "Example: wazuh/wazuh-manager:${EFFECTIVE_TAG}" + echo "=============================================" + + # Write to step summary + { + echo "## Docker Integration Test Plan" + echo "" + echo "| | |" + echo "|---|---|" + echo "| **Branch** | \`${{ steps.ctx.outputs.pr_head_ref }}\` |" + echo "| **Trigger** | \`${{ github.event_name }}\` |" + echo "| **Deployments** | \`${{ steps.ctx.outputs.deployment_matrix }}\` |" + echo "| **Case** | ${CASE} |" + echo "| **Action** | ${ACTION} |" + echo "" + echo "### Image configuration" + echo "" + echo "| | |" + echo "|---|---|" + echo "| **Registry** | ${EFFECTIVE_REGISTRY} |" + echo "| **Tag** | \`${EFFECTIVE_TAG}\` |" + echo "| **Example image** | \`wazuh/wazuh-manager:${EFFECTIVE_TAG}\` |" + echo "" + echo "### Parameters" + echo "" + echo "| | |" + echo "|---|---|" + echo "| **VERSION.json version** | \`${WAZUH_VERSION}\` |" + echo "| **VERSION.json stage** | \`${WAZUH_STAGE:-}\` |" + echo "| **Input version** | \`${INPUT_VERSION:-}\` |" + echo "| **Input stage** | \`${INPUT_STAGE:-}\` |" + echo "| **Input registry** | \`${INPUT_REGISTRY:-}\` |" + } >> "$GITHUB_STEP_SUMMARY" # ------------------------------------------------------------------------- # Job 3: Build Docker images (only for ECR, when no explicit version/stage provided). @@ -341,7 +361,6 @@ jobs: fi if [ -z "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then - # Case a: no version, no stage — use VERSION.json DOCKER_VERSION="$WAZUH_VERSION" DOCKER_STAGE="$WAZUH_STAGE" if [ "${{ inputs.registry }}" = "ECR" ] || [ "${{ github.event_name }}" = "issue_comment" ]; then @@ -349,24 +368,19 @@ jobs: DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}" DOCKER_TAG="${DOCKER_VERSION}${DOCKER_STAGE:+-${DOCKER_STAGE}}-latest" else - # Case a.2: DockerHub — pull pre-built tag = version-stage DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}" DOCKER_TAG="${DOCKER_VERSION}${DOCKER_STAGE:+-${DOCKER_STAGE}}" fi elif [ -n "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then - # Case b: version only, no stage DOCKER_VERSION="$INPUT_VERSION" DOCKER_STAGE="" DOCKER_REGISTRY="$SELECTED_REGISTRY" if [ "${{ inputs.registry }}" = "ECR" ]; then - # Case b.1: ECR — tag = version-latest DOCKER_TAG="${DOCKER_VERSION}-latest" else - # Case b.2: DockerHub — tag = version (no suffix) DOCKER_TAG="${DOCKER_VERSION}" fi else - # Case c: version + stage provided as-is (no -latest appended) DOCKER_VERSION="${INPUT_VERSION:-${WAZUH_VERSION}}" DOCKER_STAGE="$INPUT_STAGE" DOCKER_REGISTRY="$SELECTED_REGISTRY"