forked from wazuh/wazuh-docker
Resoliving conflicts
This commit is contained in:
@@ -30,7 +30,7 @@ on:
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
name: Repository bumper
|
||||
name: Repository bumper 4.x
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -152,4 +152,4 @@ jobs:
|
||||
echo "Bump skipped: the repository is already at the requested version/stage."
|
||||
fi
|
||||
echo "Bumper scripts logs:"
|
||||
cat ${BUMP_LOG_PATH}/repository_bumper*log
|
||||
cat ${BUMP_LOG_PATH}/repository_bumper*log
|
||||
@@ -0,0 +1,511 @@
|
||||
run-name: Build and push images 5.x - ${{ inputs.dev && 'dev' || 'release' }} - ${{ inputs.id }}
|
||||
name: (5.x) Build and push images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
image_tag:
|
||||
description: 'Docker image tag'
|
||||
default: '5.0.0'
|
||||
required: true
|
||||
docker_reference:
|
||||
description: 'wazuh-docker reference'
|
||||
required: true
|
||||
wazuh_automation_reference:
|
||||
description: 'Branch or tag of the wazuh-automation repository'
|
||||
required: false
|
||||
default: '5.0.0'
|
||||
products:
|
||||
description: 'Comma-separated list of the image names to build and push'
|
||||
default: 'wazuh-manager,wazuh-dashboard,wazuh-indexer,wazuh-agent'
|
||||
required: false
|
||||
type: string
|
||||
commit_list:
|
||||
description: 'Wazuh components revisions (only for dev): json array with commit-hash for each product'
|
||||
type: string
|
||||
default: '["latest", "latest", "latest", "latest"]'
|
||||
assistant_revision:
|
||||
description: 'Revision for Wazuh installation assistant tools like Wazuh password tool (only for dev)'
|
||||
type: string
|
||||
default: 'latest'
|
||||
required: false
|
||||
id:
|
||||
description: "ID used to identify the workflow uniquely."
|
||||
type: string
|
||||
required: false
|
||||
dev:
|
||||
description: "Add tag suffix '-dev' to the image tag ?"
|
||||
type: boolean
|
||||
default: true
|
||||
required: false
|
||||
workflow_call:
|
||||
inputs:
|
||||
image_tag:
|
||||
description: 'Docker image tag'
|
||||
default: '5.0.0'
|
||||
required: true
|
||||
type: string
|
||||
docker_reference:
|
||||
description: 'wazuh-docker reference'
|
||||
required: false
|
||||
type: string
|
||||
wazuh_automation_reference:
|
||||
description: 'Branch or tag of the wazuh-automation repository'
|
||||
required: false
|
||||
default: '5.0.0'
|
||||
type: string
|
||||
products:
|
||||
description: 'Comma-separated list of the image names to build and push'
|
||||
default: 'wazuh-manager,wazuh-dashboard,wazuh-indexer,wazuh-agent'
|
||||
required: false
|
||||
type: string
|
||||
commit_list:
|
||||
description: 'Wazuh components revisions (only for dev): json array with commit-hash for each product'
|
||||
type: string
|
||||
default: '["latest", "latest", "latest", "latest"]'
|
||||
assistant_revision:
|
||||
description: 'Revision for Wazuh installation assistant tools like Wazuh password tool (only for dev)'
|
||||
type: string
|
||||
default: 'latest'
|
||||
required: false
|
||||
id:
|
||||
description: "ID used to identify the workflow uniquely."
|
||||
type: string
|
||||
required: false
|
||||
dev:
|
||||
description: "Add tag suffix '-dev' to the image tag ?"
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
env:
|
||||
LOCAL_ARTIFACT_URLS_FILEPATH: /tmp/${{ vars.ARTIFACT_URL_FILE_NAME }}
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
outputs:
|
||||
WAZUH_COMPONENTS: ${{ steps.compute-outputs.outputs.WAZUH_COMPONENTS }}
|
||||
COMMIT_LIST: ${{ steps.compute-outputs.outputs.COMMIT_LIST }}
|
||||
ALL_PRODUCTS_SELECTED: ${{ steps.compute-outputs.outputs.ALL_PRODUCTS_SELECTED }}
|
||||
|
||||
steps:
|
||||
- name: Print inputs
|
||||
run: |
|
||||
echo "---------------------------------------------"
|
||||
echo "Running 5_build_and_push_images workflow"
|
||||
echo "---------------------------------------------"
|
||||
echo "* BRANCH: ${{ github.ref }}"
|
||||
echo "* COMMIT: ${{ github.sha }}"
|
||||
echo "---------------------------------------------"
|
||||
echo "Inputs provided:"
|
||||
echo "---------------------------------------------"
|
||||
echo "* id: ${{ inputs.id }}"
|
||||
echo "* image_tag: ${{ inputs.image_tag }}"
|
||||
echo "* docker_reference: ${{ inputs.docker_reference }}"
|
||||
echo "* wazuh_automation_reference: ${{ inputs.wazuh_automation_reference }}"
|
||||
echo "* products: ${{ inputs.products }}"
|
||||
echo "* dev: ${{ inputs.dev }}"
|
||||
echo "* commit_list: ${{ inputs.commit_list }}"
|
||||
echo "* assistant_revision: ${{ inputs.assistant_revision }}"
|
||||
echo "---------------------------------------------"
|
||||
|
||||
- name: Set up variables
|
||||
id: compute-outputs
|
||||
env:
|
||||
PRODUCTS_INPUT: ${{ inputs.products }}
|
||||
DEV_INPUT: ${{ inputs.dev }}
|
||||
COMMIT_LIST_INPUT: ${{ inputs.commit_list }}
|
||||
run: |
|
||||
# Use the default list if products is empty
|
||||
PRODUCTS="$PRODUCTS_INPUT"
|
||||
if [[ -z "$PRODUCTS" || "$PRODUCTS" == "null" ]]; then
|
||||
PRODUCTS="wazuh-manager,wazuh-dashboard,wazuh-indexer,wazuh-agent"
|
||||
fi
|
||||
# Check if all 4 core components are present in the string
|
||||
if [[ "$PRODUCTS" == *"wazuh-manager"* && "$PRODUCTS" == *"wazuh-dashboard"* && "$PRODUCTS" == *"wazuh-indexer"* && "$PRODUCTS" == *"wazuh-agent"* ]]; then
|
||||
echo "ALL_PRODUCTS_SELECTED=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ALL_PRODUCTS_SELECTED=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
# Set WAZUH_COMPONENTS
|
||||
# Convert to JSON for the matrix (Your existing logic)
|
||||
IFS=',' read -ra COMPONENTS <<< "$PRODUCTS"
|
||||
JSON_ARRAY=$(printf '%s\n' "${COMPONENTS[@]}" | jq -R . | jq -s -c .)
|
||||
echo "WAZUH_COMPONENTS=$JSON_ARRAY" >> $GITHUB_OUTPUT
|
||||
|
||||
# Set COMMIT_LIST
|
||||
WC_COMMIT_LIST=""
|
||||
if [[ "$DEV_INPUT" == "true" ]]; then
|
||||
if [[ "$COMMIT_LIST_INPUT" != "null" && "$COMMIT_LIST_INPUT" != "" ]]; then
|
||||
WC_COMMIT_LIST="$COMMIT_LIST_INPUT"
|
||||
else
|
||||
# Set commit list to "latest" for all components using WAZUH_COMPONENTS
|
||||
COMPONENTS=($(echo "$WC_JSON_ARRAY" | jq -r '.[]'))
|
||||
WC_COMMIT_LIST="["
|
||||
for i in "${!COMPONENTS[@]}"; do
|
||||
if [ $i -gt 0 ]; then
|
||||
WC_COMMIT_LIST+=" ,"
|
||||
fi
|
||||
WC_COMMIT_LIST+="\"latest\""
|
||||
done
|
||||
WC_COMMIT_LIST+="]"
|
||||
fi
|
||||
echo "Revision list: $WC_COMMIT_LIST"
|
||||
fi
|
||||
echo "COMMIT_LIST=$WC_COMMIT_LIST" >> $GITHUB_OUTPUT
|
||||
|
||||
package-urls:
|
||||
name: generate package urls
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
needs: setup
|
||||
|
||||
env:
|
||||
WORKFLOW_VENV: "${{ github.workspace }}/workflow_venv"
|
||||
GENERATE_PRESIGNED_URLS_SCRIPT_PATH: ${{ github.workspace }}/wazuh-automation/tools/sign_urls/generate_presigned_dev_urls.py
|
||||
PRESIGNED_URLS_SCRIPT_PROCESS: "build_docker"
|
||||
COMMIT_LIST: ${{ inputs.commit_list }}
|
||||
ASSISTANT_REVISION: ${{ inputs.assistant_revision }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.docker_reference }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout wazuh/wazuh-automation repository
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wazuh/wazuh-automation
|
||||
ref: ${{ inputs.wazuh_automation_reference }}
|
||||
token: ${{ secrets.GH_CLONE_TOKEN }}
|
||||
path: wazuh-automation
|
||||
persist-credentials: false
|
||||
|
||||
- name: Configure AWS credentials
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
|
||||
- name: Set up Python
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install and configure python and workflow dependencies
|
||||
if: ${{ inputs.dev == true }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq
|
||||
# Install yq
|
||||
sudo curl -sL "https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64" -o /usr/local/bin/yq
|
||||
sudo chmod +x /usr/local/bin/yq
|
||||
sudo apt-get install -y python3-venv
|
||||
python3 -m venv ${{ env.WORKFLOW_VENV }}
|
||||
source ${{ env.WORKFLOW_VENV }}/bin/activate
|
||||
pip install --upgrade pip
|
||||
pip install pyyaml
|
||||
|
||||
- name: Get Wazuh version
|
||||
if: ${{ inputs.dev == true }}
|
||||
run: |
|
||||
WAZUH_VERSION=$(jq -r '.version' VERSION.json)
|
||||
if ! [[ "$WAZUH_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Invalid version format: $WAZUH_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
WAZUH_MAJOR=$(echo "$WAZUH_VERSION" | cut -d '.' -f 1)
|
||||
WAZUH_MINOR=$(echo "$WAZUH_VERSION" | cut -d '.' -f 1-2)
|
||||
echo "WAZUH_VERSION=$WAZUH_VERSION" >> $GITHUB_ENV
|
||||
echo "WAZUH_MAJOR=$WAZUH_MAJOR" >> $GITHUB_ENV
|
||||
echo "WAZUH_MINOR=$WAZUH_MINOR" >> $GITHUB_ENV
|
||||
|
||||
- name: Get artifacts URLs file
|
||||
if: ${{ inputs.dev == true }}
|
||||
run: |
|
||||
LOCAL_AWS_S3_BUCKET_DEV=${{ vars.AWS_S3_BUCKET_DEV }}
|
||||
echo LOCAL_AWS_S3_BUCKET_DEV=$LOCAL_AWS_S3_BUCKET_DEV >> $GITHUB_ENV
|
||||
|
||||
- name: Generate presigned URLs for artifacts for dev packages
|
||||
if: ${{ inputs.dev == true }}
|
||||
env:
|
||||
WAZUH_COMPONENTS: ${{ needs.setup.outputs.WAZUH_COMPONENTS }}
|
||||
COMMIT_LIST: ${{ needs.setup.outputs.COMMIT_LIST }}
|
||||
run: |
|
||||
source "$WORKFLOW_VENV/bin/activate"
|
||||
SCRIPT_PARAMS="--process $PRESIGNED_URLS_SCRIPT_PROCESS \
|
||||
--wazuh-version $WAZUH_VERSION \
|
||||
--aws-s3-bucket-dev $LOCAL_AWS_S3_BUCKET_DEV \
|
||||
--assistant-revision $ASSISTANT_REVISION "
|
||||
|
||||
|
||||
# Parse components and their revisions
|
||||
COMPONENTS=($(echo "$WAZUH_COMPONENTS" | jq -r '.[]'))
|
||||
REVISIONS=($(echo "$COMMIT_LIST" | jq -r '.[]'))
|
||||
|
||||
# Ensure the number of components matches the number of revisions
|
||||
if [[ ${#COMPONENTS[@]} -ne ${#REVISIONS[@]} ]]; then
|
||||
echo "Error: WAZUH_COMPONENTS and COMMIT_LIST length mismatch." >&2
|
||||
echo " Components: ${#COMPONENTS[@]}, Revisions: ${#REVISIONS[@]}." >&2
|
||||
echo " WAZUH_COMPONENTS=${WAZUH_COMPONENTS}" >&2
|
||||
echo " COMMIT_LIST=${COMMIT_LIST}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Map revisions to component names
|
||||
for i in "${!COMPONENTS[@]}"; do
|
||||
case "${COMPONENTS[$i]}" in
|
||||
wazuh-manager)
|
||||
SCRIPT_PARAMS+="--manager-revision ${REVISIONS[$i]} "
|
||||
;;
|
||||
wazuh-dashboard)
|
||||
SCRIPT_PARAMS+="--dashboard-revision ${REVISIONS[$i]} "
|
||||
;;
|
||||
wazuh-indexer)
|
||||
SCRIPT_PARAMS+="--indexer-revision ${REVISIONS[$i]} "
|
||||
;;
|
||||
wazuh-agent)
|
||||
SCRIPT_PARAMS+="--agent-revision ${REVISIONS[$i]} "
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
python "$GENERATE_PRESIGNED_URLS_SCRIPT_PATH" \
|
||||
$SCRIPT_PARAMS
|
||||
|
||||
- name: Save presigned URLs file to artifact
|
||||
if: ${{ inputs.dev == true }}
|
||||
run: |
|
||||
echo "Uploading presigned URLs artifact..."
|
||||
aws s3 cp "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}" "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_build_and_push_images/${{ github.run_id }}/${{ vars.ARTIFACT_URL_FILE_NAME }}"
|
||||
|
||||
build-and-push:
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
needs:
|
||||
- setup
|
||||
- package-urls
|
||||
|
||||
strategy:
|
||||
fail-fast: false # all jobs will run even if one fails
|
||||
matrix:
|
||||
wazuh_component: ${{ fromJson(needs.setup.outputs.WAZUH_COMPONENTS) }}
|
||||
|
||||
env:
|
||||
IMAGE_REGISTRY: ${{ inputs.dev && vars.IMAGE_REGISTRY_DEV || vars.IMAGE_REGISTRY_PROD }}
|
||||
IMAGE_TAG: ${{ inputs.image_tag }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.docker_reference }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Configure aws credentials
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
||||
aws-region: "${{ secrets.AWS_REGION }}"
|
||||
|
||||
- name: Log in to Amazon ECR
|
||||
if: ${{ inputs.dev == true }}
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
|
||||
- name: Download artifact_urls.yaml (dev)
|
||||
if: ${{ inputs.dev == true }}
|
||||
run: |
|
||||
echo "Downloading presigned URLs artifact..."
|
||||
aws s3 cp "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_build_and_push_images/${{ github.run_id }}/${{ vars.ARTIFACT_URL_FILE_NAME }}" "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}"
|
||||
mv "${{ env.LOCAL_ARTIFACT_URLS_FILEPATH }}" ./build-docker-images/${{ vars.ARTIFACT_URL_FILE_NAME }}
|
||||
|
||||
- name: Compute component reference (dev)
|
||||
if: ${{ inputs.dev == true }}
|
||||
env:
|
||||
COMPONENT: ${{ matrix.wazuh_component }}
|
||||
WAZUH_COMPONENTS: ${{ needs.setup.outputs.WAZUH_COMPONENTS }}
|
||||
COMMIT_LIST: ${{ needs.setup.outputs.COMMIT_LIST }}
|
||||
run: |
|
||||
idx=$(jq -r --arg c "$COMPONENT" 'index($c)' <<<"$WAZUH_COMPONENTS")
|
||||
ref=$(jq -r --argjson i "$idx" '.[ $i ]' <<<"$COMMIT_LIST")
|
||||
|
||||
echo "COMPONENT_REFS_JSON=[\"$ref\"]" >> "$GITHUB_ENV"
|
||||
echo "Using component ref for $COMPONENT: $ref"
|
||||
|
||||
- name: Build Wazuh images
|
||||
env:
|
||||
DEV: ${{ inputs.dev }}
|
||||
WAZUH_COMPONENT: ${{ matrix.wazuh_component }}
|
||||
run: |
|
||||
if [[ "$IMAGE_TAG" == *"-"* ]]; then
|
||||
IFS='-' read -r -a tokens <<< "$IMAGE_TAG"
|
||||
if [ -z "${tokens[1]}" ]; then
|
||||
echo "Invalid image tag: $IMAGE_TAG"
|
||||
exit 1
|
||||
fi
|
||||
DEV_STAGE=${tokens[1]}
|
||||
WAZUH_VER=${tokens[0]}
|
||||
if [ "$DEV" = true ]; then
|
||||
./build-images.sh \
|
||||
-v $WAZUH_VER \
|
||||
-d $DEV_STAGE \
|
||||
-rg $IMAGE_REGISTRY \
|
||||
-m \
|
||||
--dev \
|
||||
-refs "$COMPONENT_REFS_JSON" \
|
||||
-c $WAZUH_COMPONENT
|
||||
else
|
||||
./build-images.sh \
|
||||
-v $WAZUH_VER \
|
||||
-d $DEV_STAGE \
|
||||
-rg $IMAGE_REGISTRY \
|
||||
-m \
|
||||
-c $WAZUH_COMPONENT
|
||||
fi
|
||||
else
|
||||
if [ "$DEV" = true ]; then
|
||||
./build-images.sh \
|
||||
-v $IMAGE_TAG \
|
||||
-rg $IMAGE_REGISTRY \
|
||||
-m \
|
||||
--dev \
|
||||
-refs "$COMPONENT_REFS_JSON" \
|
||||
-c $WAZUH_COMPONENT
|
||||
else
|
||||
./build-images.sh \
|
||||
-v $IMAGE_TAG \
|
||||
-rg $IMAGE_REGISTRY \
|
||||
-m \
|
||||
-c $WAZUH_COMPONENT
|
||||
fi
|
||||
fi
|
||||
# Save .env file (generated by build-images.sh) contents to $GITHUB_ENV
|
||||
ENV_FILE_PATH="../.env"
|
||||
|
||||
if [ -f $ENV_FILE_PATH ]; then
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
echo "$line" >> $GITHUB_ENV
|
||||
done < $ENV_FILE_PATH
|
||||
else
|
||||
echo "The environment file $ENV_FILE_PATH does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
working-directory: ./build-docker-images
|
||||
|
||||
|
||||
notify:
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
needs: [setup, build-and-push]
|
||||
# Only run if NOT dev AND all products were selected
|
||||
if: ${{ inputs.dev == false && needs.setup.outputs.ALL_PRODUCTS_SELECTED == 'true' }}
|
||||
|
||||
steps:
|
||||
- name: Image exists validation
|
||||
id: validation
|
||||
env:
|
||||
IMAGE_TAG: ${{ inputs.image_tag }}
|
||||
IMAGE_REGISTRY: ${{ vars.IMAGE_REGISTRY_PROD }}
|
||||
run: |
|
||||
PURPOSE=""
|
||||
|
||||
if [[ "$IMAGE_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
if docker manifest inspect $IMAGE_REGISTRY/wazuh/wazuh-manager:$IMAGE_TAG > /dev/null 2>&1; then
|
||||
PURPOSE="regeneration"
|
||||
echo "Image wazuh/wazuh-manager:$IMAGE_TAG exists. Setting PURPOSE to 'regeneration'"
|
||||
else
|
||||
PURPOSE="new release"
|
||||
echo "Image wazuh/wazuh-manager:$IMAGE_TAG does NOT exist. Setting PURPOSE to 'new release'"
|
||||
fi
|
||||
echo "✅ Release tag: '$IMAGE_TAG'"
|
||||
elif [[ "$IMAGE_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)[0-9]+$ ]]; then
|
||||
PURPOSE="new stage"
|
||||
echo "✅ Stage tag: '$IMAGE_TAG'. Setting PURPOSE to 'new stage'"
|
||||
else
|
||||
echo "❌ No release or stage tag ('$IMAGE_TAG'), the GH issue will not be created"
|
||||
fi
|
||||
|
||||
echo "purpose=$PURPOSE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: GH issue notification
|
||||
if: ${{ steps.validation.outputs.purpose != '' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.NOTIFICATION_GH_ARTIFACT_TOKEN }}
|
||||
IMAGE_TAG: ${{ inputs.image_tag }}
|
||||
PURPOSE: ${{ steps.validation.outputs.purpose }}
|
||||
run: |
|
||||
|
||||
GH_TITLE=""
|
||||
GH_MESSAGE=""
|
||||
|
||||
## Setting GH issue title
|
||||
GH_TITLE="Artifactory vulnerabilities update \`v$IMAGE_TAG\`"
|
||||
|
||||
## Setting GH issue body
|
||||
GH_MESSAGE=$(cat <<- EOF | tr -d '\r' | sed 's/^[[:space:]]*//'
|
||||
### Description
|
||||
- [ ] Update the [Artifactory vulnerabilities](${{ secrets.NOTIFICATION_SHEET_URL }}) sheet with the \`v$IMAGE_TAG\` vulnerabilities.
|
||||
|
||||
**Purpose**: $PURPOSE
|
||||
>[!NOTE]
|
||||
>To update the \`Tentative Release\` column, follow these steps:
|
||||
https://github.com/wazuh/${{ secrets.NOTIFICATION_REPO }}/issues/2049#issuecomment-2671590268
|
||||
EOF
|
||||
)
|
||||
|
||||
# Print the GH Variables content
|
||||
echo "--- Variable Content ---"
|
||||
echo "$GH_TITLE"
|
||||
echo "------------------------"
|
||||
|
||||
echo "--- Variable Content ---"
|
||||
echo "$GH_MESSAGE"
|
||||
echo "------------------------"
|
||||
|
||||
## GH issue creation
|
||||
ISSUE_URL=$(gh issue create \
|
||||
-R wazuh/${{ secrets.NOTIFICATION_REPO }} \
|
||||
--title "$GH_TITLE" \
|
||||
--body "$GH_MESSAGE" \
|
||||
--label "level/task" \
|
||||
--label "type/maintenance" \
|
||||
--label "request/operational")
|
||||
|
||||
## Adding the issue to the team project
|
||||
PROJECT_ITEM_ID=$(gh project item-add \
|
||||
${{ secrets.NOTIFICATION_PROJECT_NUMBER }} \
|
||||
--url $ISSUE_URL \
|
||||
--owner wazuh \
|
||||
--format json \
|
||||
| jq -r '.id')
|
||||
|
||||
## Setting Objective
|
||||
gh project item-edit --id $PROJECT_ITEM_ID --project-id ${{ secrets.NOTIFICATION_PROJECT_ID }} --field-id ${{ secrets.NOTIFICATION_PROJECT_OBJECTIVE_ID }} --text "Security scans"
|
||||
## Setting Priority
|
||||
gh project item-edit --id $PROJECT_ITEM_ID --project-id ${{ secrets.NOTIFICATION_PROJECT_ID }} --field-id ${{ secrets.NOTIFICATION_PROJECT_PRIORITY_ID }} --single-select-option-id ${{ secrets.NOTIFICATION_PROJECT_PRIORITY_OPTION_ID }}
|
||||
## Setting Size
|
||||
gh project item-edit --id $PROJECT_ITEM_ID --project-id ${{ secrets.NOTIFICATION_PROJECT_ID }} --field-id ${{ secrets.NOTIFICATION_PROJECT_SIZE_ID }} --single-select-option-id ${{ secrets.NOTIFICATION_PROJECT_SIZE_OPTION_ID }}
|
||||
## Setting Subteam
|
||||
gh project item-edit --id $PROJECT_ITEM_ID --project-id ${{ secrets.NOTIFICATION_PROJECT_ID }} --field-id ${{ secrets.NOTIFICATION_PROJECT_SUBTEAM_ID }} --single-select-option-id ${{ secrets.NOTIFICATION_PROJECT_SUBTEAM_OPTION_ID }}
|
||||
@@ -0,0 +1,252 @@
|
||||
name: (5.x) Repository bumper
|
||||
run-name: Bump ${{ github.ref_name }} (${{ inputs.id }})
|
||||
|
||||
on:
|
||||
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
|
||||
set_as_main:
|
||||
description: "Enable main branch mode: bump version values only, keep branch references pointing to main"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
issue-link:
|
||||
description: 'Issue link in format https://github.com/wazuh/<REPO>/issues/<ISSUE-NUMBER>'
|
||||
required: true
|
||||
type: string
|
||||
id:
|
||||
description: 'Optional identifier for the run'
|
||||
required: false
|
||||
type: string
|
||||
revert:
|
||||
description: 'Set to true to revert the bump changes applied for this issue'
|
||||
default: false
|
||||
required: false
|
||||
type: boolean
|
||||
bump-issue-link:
|
||||
description: 'Issue link used in the original bump (required for revert if different from issue-link)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
name: Repository bumper 5.x
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
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: 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:
|
||||
# Using workflow-specific GITHUB_TOKEN because currently CI_WAZUHCI_BUMPER_TOKEN
|
||||
# doesn't have all the necessary permissions
|
||||
token: ${{ env.GH_TOKEN }}
|
||||
|
||||
- name: Determine branch name
|
||||
id: vars
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
STAGE: ${{ inputs.stage }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
script_params=""
|
||||
version=${{ env.VERSION }}
|
||||
stage=${{ env.STAGE }}
|
||||
tag=${{ env.TAG }}
|
||||
set_as_main=${{ inputs.set_as_main }}
|
||||
|
||||
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"
|
||||
elif [[ -z "$version" && -n "$stage" && "$tag" == "true" ]]; then
|
||||
script_params="--stage ${stage} --tag"
|
||||
elif [[ -z "$version" && -z "$stage" && "$tag" == "true" ]]; then
|
||||
script_params="--tag"
|
||||
fi
|
||||
|
||||
if [[ "$set_as_main" == "true" ]]; then
|
||||
if [[ -z "$version" || -z "$stage" ]]; then
|
||||
echo "Error: set_as_main requires both version and stage inputs."
|
||||
exit 1
|
||||
fi
|
||||
script_params="${script_params} --set-as-main"
|
||||
fi
|
||||
|
||||
issue_number=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}')
|
||||
|
||||
if [[ "${{ inputs.revert }}" == "true" ]]; then
|
||||
BRANCH_NAME="enhancement/wqa${issue_number}-revert-bump-${{ github.ref_name }}"
|
||||
echo "pr_title=Revert bump ${{ github.ref_name }} branch" >> $GITHUB_OUTPUT
|
||||
else
|
||||
BRANCH_NAME="enhancement/wqa${issue_number}-bump-${{ github.ref_name }}"
|
||||
echo "pr_title=Bump ${{ github.ref_name }} branch" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
echo "script_params=${script_params}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create and switch to bump branch
|
||||
run: |
|
||||
git checkout -b ${{ steps.vars.outputs.branch_name }}
|
||||
|
||||
- name: Make version bump changes
|
||||
if: inputs.revert != true
|
||||
run: |
|
||||
echo "Running bump script"
|
||||
bash ${{ env.BUMP_SCRIPT_PATH }} ${{ steps.vars.outputs.script_params }}
|
||||
|
||||
- name: Commit changes (Bump)
|
||||
id: bump_commit
|
||||
if: inputs.revert != true
|
||||
run: |
|
||||
git add .
|
||||
if git diff --staged --quiet; then
|
||||
echo "Nothing to bump: the repository is already at the requested version/stage. Skipping commit."
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
git commit -m "feat: bump ${{ github.ref_name }}"
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Fetch full history (Revert)
|
||||
if: inputs.revert == true
|
||||
run: git fetch --unshallow
|
||||
|
||||
- name: Revert references (Revert)
|
||||
id: revert_step
|
||||
if: inputs.revert == true
|
||||
run: |
|
||||
# 1. Get the current issue number (for the new revert branch/PR)
|
||||
ISSUE_NUMBER=$(echo "${{ inputs.issue-link }}" | awk -F'/' '{print $NF}')
|
||||
|
||||
# 2. Get the issue number from the original bump (if provided; otherwise, defaults to the current one)
|
||||
if [ -n "${{ inputs.bump-issue-link }}" ]; then
|
||||
BUMP_ISSUE_NUMBER=$(echo "${{ inputs.bump-issue-link }}" | awk -F'/' '{print $NF}')
|
||||
else
|
||||
BUMP_ISSUE_NUMBER=$ISSUE_NUMBER
|
||||
fi
|
||||
|
||||
# 3. Search for the original bump branch using the obtained BUMP ISSUE number
|
||||
BUMP_BRANCH="enhancement/wqa${BUMP_ISSUE_NUMBER}-bump-${{ github.ref_name }}"
|
||||
|
||||
PR_NUMBER=$(gh pr list --head "$BUMP_BRANCH" --base "${{ github.ref_name }}" --state merged --json number --jq '.[0].number')
|
||||
|
||||
if [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" == "null" ]; then
|
||||
echo "Error: The original PR for the bump was not found"
|
||||
echo "Searching merged PR from: $BUMP_BRANCH to ${{ github.ref_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Original PR found: #$PR_NUMBER"
|
||||
|
||||
MERGE_COMMIT=$(gh pr view $PR_NUMBER --json mergeCommit --jq '.mergeCommit.oid')
|
||||
|
||||
git revert -m 1 $MERGE_COMMIT --no-commit
|
||||
|
||||
# Remove the files to prevent them from being included in the revert commit
|
||||
git checkout HEAD -- VERSION.json 2>/dev/null || true
|
||||
git checkout HEAD -- CHANGELOG.md 2>/dev/null || true
|
||||
# [!] ADD ANY OTHER REPOSITORY-SPECIFIC VERSION FILES HERE [!]
|
||||
|
||||
if git diff --staged --quiet; then
|
||||
echo "No references to revert. Skipping commit."
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
git commit -m "feat: revert ${{ github.ref_name }} references"
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
if: (inputs.revert != true && steps.bump_commit.outputs.has_changes == 'true') || (inputs.revert == true && steps.revert_step.outputs.has_changes == 'true')
|
||||
run: |
|
||||
git push origin ${{ steps.vars.outputs.branch_name }}
|
||||
|
||||
- name: Create pull request
|
||||
id: create_pr
|
||||
if: (inputs.revert != true && steps.bump_commit.outputs.has_changes == 'true') || (inputs.revert == true && steps.revert_step.outputs.has_changes == 'true')
|
||||
run: |
|
||||
gh auth setup-git
|
||||
PR_URL=$(gh pr create \
|
||||
--title "${{ steps.vars.outputs.pr_title }}" \
|
||||
--body "Issue: ${{ inputs.issue-link }}" \
|
||||
--base ${{ github.ref_name }} \
|
||||
--head ${{ steps.vars.outputs.branch_name }})
|
||||
|
||||
echo "Pull request created: ${PR_URL}"
|
||||
echo "pull_request_url=${PR_URL}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Merge pull request
|
||||
if: (inputs.revert != true && steps.bump_commit.outputs.has_changes == 'true') || (inputs.revert == true && steps.revert_step.outputs.has_changes == 'true')
|
||||
run: |
|
||||
# Any checks for the PR are bypassed since the branch is expected to be functional
|
||||
gh pr merge "${{ steps.create_pr.outputs.pull_request_url }}" --merge --admin
|
||||
|
||||
- name: Show logs
|
||||
if: inputs.revert != true
|
||||
run: |
|
||||
if [[ "${{ steps.bump_commit.outputs.has_changes }}" == "true" ]]; then
|
||||
echo "Bump complete."
|
||||
echo "Branch: ${{ steps.vars.outputs.branch_name }}"
|
||||
echo "PR: ${{ steps.create_pr.outputs.pull_request_url }}"
|
||||
else
|
||||
echo "Bump skipped: the repository is already at the requested version/stage."
|
||||
fi
|
||||
echo "Bumper scripts logs:"
|
||||
cat ${BUMP_LOG_PATH}/repository_bumper*log
|
||||
|
||||
- name: Show revert logs
|
||||
if: inputs.revert == true
|
||||
run: |
|
||||
echo "Revert bump complete."
|
||||
echo "Branch: ${{ steps.vars.outputs.branch_name }}"
|
||||
echo "PR: ${{ steps.create_pr.outputs.pull_request_url }}"
|
||||
echo "Revert bumper scripts logs:"
|
||||
cat ${BUMP_LOG_PATH}/repository_bumper*log || true
|
||||
@@ -0,0 +1,62 @@
|
||||
name: 5.x Changelog check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
changelog_check:
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
if: ${{ github.event_name == 'pull_request' && !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'no-changelog') }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Validate CHANGELOG.md changes
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
run: |
|
||||
UPDATED="✅" FORMAT="—" INVALID=""
|
||||
|
||||
ADDED=$(git diff -U0 "origin/${BASE_REF}...HEAD" -- CHANGELOG.md | grep -E '^\+[^+]' | sed 's/^+//' || true)
|
||||
if [ -z "$ADDED" ]; then
|
||||
UPDATED="❌"
|
||||
echo "::error::CHANGELOG.md was not updated with new entries. Add one or add the 'no-changelog' label to skip this check."
|
||||
else
|
||||
FORMAT="✅"
|
||||
|
||||
ENTRY_REGEX='^- .+ \(\[#[0-9]+\]\(https://github\.com/[^)]+/(issues|pull)/[0-9]+\)\)$'
|
||||
INVALID=$(echo "$ADDED" | grep -E '^- ' | grep -vx -- '- None' | grep -vE "$ENTRY_REGEX" || true)
|
||||
if [ -n "$INVALID" ]; then
|
||||
FORMAT="❌"
|
||||
echo "::error::Invalid CHANGELOG.md entries. Expected format: '- Description ([#123](https://github.com/<org>/<repo>/issues/123))'. Offending lines:"
|
||||
echo "$INVALID"
|
||||
fi
|
||||
fi
|
||||
|
||||
{
|
||||
echo "## Changelog check"
|
||||
echo ""
|
||||
echo "| Check | Result |"
|
||||
echo "|---|---|"
|
||||
echo "| CHANGELOG.md has new entries | $UPDATED |"
|
||||
echo "| Entry format | $FORMAT |"
|
||||
if [ -n "$INVALID" ]; then
|
||||
echo ""
|
||||
echo "Offending lines:"
|
||||
echo '```'
|
||||
echo "$INVALID"
|
||||
echo '```'
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
if [ "$UPDATED" != "✅" ] || [ "$FORMAT" != "✅" ]; then
|
||||
exit 1
|
||||
fi
|
||||
echo "CHANGELOG.md update is valid."
|
||||
@@ -0,0 +1,890 @@
|
||||
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: (5.x) 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: '5.0.0'
|
||||
type: string
|
||||
deployment_type:
|
||||
description: 'Deployment type to test'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- single-node
|
||||
- multi-node
|
||||
- both
|
||||
version:
|
||||
description: 'Image version to test (e.g. 5.0.0).'
|
||||
required: false
|
||||
type: string
|
||||
stage:
|
||||
description: 'Image stage suffix (e.g. beta1, beta2-latest, beta2-<commit>). Required when version is set.'
|
||||
required: false
|
||||
type: string
|
||||
registry:
|
||||
description: 'Docker registry. ECR for dev versions, DockerHub for prod versions.'
|
||||
required: false
|
||||
type: choice
|
||||
options:
|
||||
- ECR
|
||||
- DockerHub
|
||||
|
||||
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
|
||||
LOGS_ARTIFACT_ZIP_FILE: "docker_logs_artifacts_${{ github.run_id }}.zip"
|
||||
|
||||
jobs:
|
||||
# -------------------------------------------------------------------------
|
||||
# Job 1: Parse PR info and determine which deployment(s) to test
|
||||
#
|
||||
# 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
|
||||
# -------------------------------------------------------------------------
|
||||
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: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
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
|
||||
env:
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
run: |
|
||||
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: Prepare context (pr_head_ref + deployment matrix) for both triggers.
|
||||
# -------------------------------------------------------------------------
|
||||
prepare:
|
||||
needs: [get_pr_info]
|
||||
if: |
|
||||
always() &&
|
||||
(needs.get_pr_info.result == 'success' || github.event_name == 'workflow_dispatch')
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
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
|
||||
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
|
||||
|
||||
- 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:-<release>}"
|
||||
|
||||
- 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 }}"
|
||||
|
||||
# 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
|
||||
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
|
||||
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"
|
||||
ACTION="PULL (no build)"
|
||||
if [ "$INPUT_REGISTRY" = "ECR" ]; then
|
||||
CASE="b.1 — Version only, ECR → tag = version-latest"
|
||||
EFFECTIVE_TAG="${DOCKER_VERSION}-latest"
|
||||
EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})"
|
||||
else
|
||||
CASE="b.2 — Version only, DockerHub → tag = version"
|
||||
EFFECTIVE_TAG="${DOCKER_VERSION}"
|
||||
EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})"
|
||||
fi
|
||||
else
|
||||
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
|
||||
EFFECTIVE_REGISTRY="ECR (${{ vars.IMAGE_REGISTRY_DEV }})"
|
||||
else
|
||||
EFFECTIVE_REGISTRY="DockerHub (${{ vars.IMAGE_REGISTRY_PROD }})"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 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:-<release>}\` |"
|
||||
echo "| **Input version** | \`${INPUT_VERSION:-<not set>}\` |"
|
||||
echo "| **Input stage** | \`${INPUT_STAGE:-<not set>}\` |"
|
||||
echo "| **Input registry** | \`${INPUT_REGISTRY:-<not set>}\` |"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Job 3: Build Docker images (only for ECR, when no explicit version/stage provided).
|
||||
# Calls 5_build_and_push_images.yml and pushes to the dev registry.
|
||||
# -------------------------------------------------------------------------
|
||||
build_images:
|
||||
name: Build Docker images
|
||||
needs: [prepare]
|
||||
if: |
|
||||
always() &&
|
||||
needs.prepare.result == 'success' &&
|
||||
inputs.version == '' &&
|
||||
inputs.stage == '' &&
|
||||
(inputs.registry == 'ECR' || github.event_name == 'issue_comment')
|
||||
uses: ./.github/workflows/5_build_and_push_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,wazuh-agent"
|
||||
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, build_images]
|
||||
if: |
|
||||
always() &&
|
||||
needs.prepare.result == 'success' &&
|
||||
(needs.build_images.result == 'success' || needs.build_images.result == 'skipped')
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
deployment_type: ${{ fromJSON(needs.prepare.outputs.deployment_matrix) }}
|
||||
|
||||
steps:
|
||||
# -----------------------------------------------------------------------
|
||||
# Setup
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Checkout wazuh-automation
|
||||
uses: actions/checkout@v6
|
||||
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@v6
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.pr_head_ref }}
|
||||
path: wazuh-docker
|
||||
|
||||
- name: Resolve image configuration
|
||||
run: |
|
||||
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 }}" = "ECR" ]; then
|
||||
SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_DEV }}"
|
||||
else
|
||||
SELECTED_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}"
|
||||
fi
|
||||
|
||||
if [ -z "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then
|
||||
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
|
||||
DOCKER_REGISTRY="${{ vars.IMAGE_REGISTRY_PROD }}"
|
||||
DOCKER_TAG="${DOCKER_VERSION}${DOCKER_STAGE:+-${DOCKER_STAGE}}"
|
||||
fi
|
||||
elif [ -n "$INPUT_VERSION" ] && [ -z "$INPUT_STAGE" ]; then
|
||||
DOCKER_VERSION="$INPUT_VERSION"
|
||||
DOCKER_STAGE=""
|
||||
DOCKER_REGISTRY="$SELECTED_REGISTRY"
|
||||
if [ "${{ inputs.registry }}" = "ECR" ]; then
|
||||
DOCKER_TAG="${DOCKER_VERSION}-latest"
|
||||
else
|
||||
DOCKER_TAG="${DOCKER_VERSION}"
|
||||
fi
|
||||
else
|
||||
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 "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
|
||||
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/
|
||||
pip install pyyaml
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.AWS_IAM_DOCKER_ROLE }}
|
||||
role-session-name: docker-test-${{ github.run_id }}-${{ matrix.deployment_type }}
|
||||
aws-region: ${{ env.REGION }}
|
||||
|
||||
- name: Generate presigned cert tool URL
|
||||
run: |
|
||||
python wazuh-automation/tools/sign_urls/generate_presigned_dev_urls.py \
|
||||
--process build_docker \
|
||||
--wazuh-version "${{ env.DOCKER_VERSION }}" \
|
||||
--aws-s3-bucket-dev "${{ vars.AWS_S3_BUCKET_DEV }}"
|
||||
|
||||
python3 -c "
|
||||
import yaml
|
||||
data = yaml.safe_load(open('/tmp/artifact_urls.yaml'))
|
||||
print(f'wazuh_certs_tool={data[\"wazuh_certs_tool\"]}')
|
||||
" >> "$GITHUB_ENV"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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 large \
|
||||
--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
|
||||
"
|
||||
|
||||
- name: Login VM to ECR registry
|
||||
if: inputs.registry == 'ECR' || github.event_name == 'issue_comment'
|
||||
run: |
|
||||
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 }}" \
|
||||
"echo '${ECR_PASS}' | sudo docker login --username AWS --password-stdin ${ECR_REGISTRY}"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Deploy: patch image tags, copy wazuh-docker and start the stack
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Patch image tags
|
||||
run: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
COMPOSE="wazuh-docker/${DEPLOYMENT}/docker-compose.yml"
|
||||
TAG="${{ env.DOCKER_TAG }}"
|
||||
REGISTRY="${{ env.DOCKER_REGISTRY }}"
|
||||
|
||||
if [ "$REGISTRY" = "${{ vars.IMAGE_REGISTRY_PROD }}" ] || [ -z "$REGISTRY" ]; then
|
||||
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}"
|
||||
sed -i -E "s|image: (wazuh/wazuh-[^:]+):[^ ]+|image: ${REGISTRY}/\1:${TAG}|g" "$COMPOSE"
|
||||
fi
|
||||
echo "=== Patched image lines ==="
|
||||
grep 'image:' "$COMPOSE"
|
||||
|
||||
- name: Prepare cert tool and config
|
||||
run: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
|
||||
echo "Cert tool: ${{ env.wazuh_certs_tool }} Docker image: ${{ env.DOCKER_TAG }}"
|
||||
|
||||
curl --output "wazuh-docker/${DEPLOYMENT}/wazuh-certs-tool.sh" "${{ env.wazuh_certs_tool }}"
|
||||
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"
|
||||
|
||||
- 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: 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: Generate SSL certificates
|
||||
run: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" "
|
||||
set -e
|
||||
cd /tmp/wazuh-docker/${DEPLOYMENT}
|
||||
echo '=== Running certificate generation ==='
|
||||
sudo bash /tmp/wazuh-docker/tools/utils/deployment/certificates-conf.sh --cert --copy
|
||||
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
|
||||
run: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" "
|
||||
set -eo pipefail
|
||||
cd /tmp/wazuh-docker/${DEPLOYMENT}
|
||||
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: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" "
|
||||
cd /tmp/wazuh-docker/${DEPLOYMENT}
|
||||
|
||||
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 \
|
||||
| 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/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
|
||||
"
|
||||
|
||||
- name: Cluster warm-up wait
|
||||
run: |
|
||||
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}
|
||||
echo '=== Container status after warm-up ==='
|
||||
sudo docker compose ps
|
||||
"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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 }}" \
|
||||
--version "${{ env.DOCKER_VERSION }}" \
|
||||
--log-level INFO \
|
||||
--output github \
|
||||
--output-file "test-results-docker-${DEPLOYMENT}.github"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" "
|
||||
cd /tmp/wazuh-docker/${DEPLOYMENT}
|
||||
sudo docker compose logs --no-color 2>&1
|
||||
" > docker-logs-${DEPLOYMENT}.txt || true
|
||||
|
||||
- name: Upload Docker logs
|
||||
if: failure() || steps.run_tests.outcome == 'failure'
|
||||
run: |
|
||||
echo "Uploading Docker logs artifact..."
|
||||
zip "${{ env.LOGS_ARTIFACT_ZIP_FILE }}" docker-logs-*.txt
|
||||
aws s3 cp "${{ env.LOGS_ARTIFACT_ZIP_FILE }}" "s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_check_integration_tools/${{ github.run_id }}/${{ env.LOGS_ARTIFACT_ZIP_FILE }}"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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 = `<!-- docker-integration-check-${deployment} -->`;
|
||||
|
||||
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()
|
||||
env:
|
||||
S3_ARTIFACTS_PATH: s3://${{ secrets.CI_DEV_INTERNAL_S3_BUCKET }}/wazuh-docker/5_check_integration_tools/${{ github.run_id }}
|
||||
LOCAL_RESULTS_PATH: test-results-docker-${{ matrix.deployment_type }}.github
|
||||
run: |
|
||||
if [ -f "${LOCAL_RESULTS_PATH}" ]; then
|
||||
echo "Uploading test results to S3..."
|
||||
aws s3 cp "${LOCAL_RESULTS_PATH}" "${S3_ARTIFACTS_PATH}/test-results-docker-${{ matrix.deployment_type }}/"
|
||||
else
|
||||
echo "::warning::No test results file found - skipping upload (an earlier step likely failed before test_runner produced output)."
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Cleanup: always stop stack and deallocate VM
|
||||
# -----------------------------------------------------------------------
|
||||
- name: Stop Docker Compose
|
||||
if: always()
|
||||
run: |
|
||||
DEPLOYMENT="${{ matrix.deployment_type }}"
|
||||
ssh ${{ env.SSH_OPTS }} "${{ env.REMOTE }}" "
|
||||
cd /tmp/wazuh-docker/${DEPLOYMENT} && sudo docker compose 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_DOCKER_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 4: Update the GitHub check run (issue_comment trigger only)
|
||||
# -------------------------------------------------------------------------
|
||||
update_check:
|
||||
needs: [get_pr_info, prepare, build_images, docker_test]
|
||||
if: always() && github.event_name == 'issue_comment' && needs.get_pr_info.result == 'success'
|
||||
runs-on: codebuild-github-actions-codebuild-runner-devops-amd-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
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})`
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user