Hotfix/socai custom header (#2101) #517
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "v11 - Build & Deploy Pipeline" | |
| on: | |
| push: | |
| branches: | |
| - 'release/v11**' | |
| - 'v11' | |
| release: | |
| types: [ released ] | |
| jobs: | |
| setup_deployment: | |
| name: Setup Deployment | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| tag: ${{ steps.set-env.outputs.tag }} | |
| environment: ${{ steps.set-env.outputs.environment }} | |
| cm_url: ${{ steps.set-env.outputs.cm_url }} | |
| event_processor_tag: ${{ steps.set-env.outputs.event_processor_tag }} | |
| steps: | |
| - name: Determine Build Environment | |
| id: set-env | |
| run: | | |
| # ===================================================================== | |
| # DEV — push to release/v11** | |
| # Version = <branch-base>-dev.N, auto-incremented via CM. | |
| # ===================================================================== | |
| if ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release/v11') }}; then | |
| ENVIRONMENT="dev" | |
| CM_URL="https://cm.dev.utmstack.com" | |
| echo "Environment: $ENVIRONMENT" | |
| echo "CM URL: $CM_URL" | |
| # Extract version from branch name (e.g. release/v11.2.1 → v11.2.1) | |
| BRANCH_VERSION=$(echo "${{ github.ref }}" | sed 's|refs/heads/release/||') | |
| echo "Branch version: $BRANCH_VERSION" | |
| RESPONSE=$(curl -s "${CM_URL}/api/v1/versions/latest") | |
| LATEST_VERSION=$(echo "$RESPONSE" | jq -r '.version // empty') | |
| echo "Latest version from CM: $LATEST_VERSION" | |
| if [ -n "$LATEST_VERSION" ]; then | |
| LATEST_BASE=$(echo "$LATEST_VERSION" | sed 's/-dev\.[0-9]*$//') | |
| if [ "$BRANCH_VERSION" = "$LATEST_BASE" ]; then | |
| DEV_NUM=$(echo "$LATEST_VERSION" | grep -oP '(?<=-dev\.)\d+') | |
| NEW_DEV_NUM=$((DEV_NUM + 1)) | |
| TAG="${BRANCH_VERSION}-dev.${NEW_DEV_NUM}" | |
| echo "Versions match, incrementing: $TAG" | |
| else | |
| TAG="${BRANCH_VERSION}-dev.1" | |
| echo "Versions don't match, starting fresh: $TAG" | |
| fi | |
| else | |
| TAG="${BRANCH_VERSION}-dev.1" | |
| echo "No previous version found, starting fresh: $TAG" | |
| fi | |
| echo "tag=$TAG" >> $GITHUB_OUTPUT | |
| echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT | |
| echo "cm_url=$CM_URL" >> $GITHUB_OUTPUT | |
| echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_DEV }}" >> $GITHUB_OUTPUT | |
| # ===================================================================== | |
| # RC — push to v11 | |
| # | |
| # Tag derivation walks two CMs to handle both the normal flow and | |
| # the hotfix flow without divergent code paths: | |
| # | |
| # 1. CM DEV gives us the candidate BASE (strip `-dev.N`). | |
| # 2. CM PROD gives us the latest version already in production. | |
| # 3. If BASE > PROD → use BASE. Normal flow. | |
| # If BASE <= PROD → BASE is already released (hotfix scenario) | |
| # so bump the patch of PROD instead. Avoids overwriting an | |
| # already-shipped tag and matches the roll-forward policy. | |
| # ===================================================================== | |
| elif ${{ github.event_name == 'push' && github.ref == 'refs/heads/v11' }}; then | |
| ENVIRONMENT="rc" | |
| CM_URL="https://cm.utmstack.com" | |
| CM_DEV_URL="https://cm.dev.utmstack.com" | |
| echo "Environment: $ENVIRONMENT" | |
| echo "CM URL (target): $CM_URL" | |
| echo "CM URL (source for base): $CM_DEV_URL" | |
| DEV_RESPONSE=$(curl -s "${CM_DEV_URL}/api/v1/versions/latest") | |
| LATEST_DEV_VERSION=$(echo "$DEV_RESPONSE" | jq -r '.version // empty') | |
| echo "Latest dev version from CM DEV: $LATEST_DEV_VERSION" | |
| if [ -z "$LATEST_DEV_VERSION" ]; then | |
| echo "❌ No dev version found in CM DEV — cannot derive RC base. Push a release/v11.x.x branch first." | |
| exit 1 | |
| fi | |
| BASE=$(echo "$LATEST_DEV_VERSION" | sed -E 's/-dev\.[0-9]+$//') | |
| echo "BASE derived from CM DEV: $BASE" | |
| if [[ ! "$BASE" =~ ^v11\. ]]; then | |
| echo "❌ Derived BASE '$BASE' is not a v11 release." | |
| exit 1 | |
| fi | |
| # Double-check against production to detect the hotfix scenario. | |
| PROD_RESPONSE=$(curl -s "${CM_URL}/api/v1/versions/latest") | |
| PROD_LATEST=$(echo "$PROD_RESPONSE" | jq -r '.version // empty') | |
| echo "Latest production version from CM PROD: ${PROD_LATEST:-<none>}" | |
| if [ -n "$PROD_LATEST" ]; then | |
| # sort -V puts the higher semver last. | |
| HIGHER=$(printf '%s\n%s\n' "$BASE" "$PROD_LATEST" | sort -V | tail -1) | |
| if [ "$HIGHER" = "$BASE" ] && [ "$BASE" != "$PROD_LATEST" ]; then | |
| # BASE is strictly newer than PROD — use it as-is. | |
| TAG="$BASE" | |
| echo "BASE ($BASE) > PROD ($PROD_LATEST) — using BASE as RC tag." | |
| else | |
| # PROD is >= BASE → BASE was already released (hotfix case). | |
| # Bump the patch of PROD. | |
| MAJOR_MINOR=$(echo "$PROD_LATEST" | sed -E 's/^(v[0-9]+\.[0-9]+)\.[0-9]+.*$/\1/') | |
| PATCH=$(echo "$PROD_LATEST" | sed -E 's/^v[0-9]+\.[0-9]+\.([0-9]+).*$/\1/') | |
| NEW_PATCH=$((PATCH + 1)) | |
| TAG="${MAJOR_MINOR}.${NEW_PATCH}" | |
| echo "BASE ($BASE) <= PROD ($PROD_LATEST) — hotfix scenario. Bumping patch: $TAG" | |
| fi | |
| else | |
| # CM PROD has no versions yet — use BASE. | |
| TAG="$BASE" | |
| echo "CM PROD is empty — using BASE as RC tag." | |
| fi | |
| echo "RC tag: $TAG" | |
| echo "tag=$TAG" >> $GITHUB_OUTPUT | |
| echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT | |
| echo "cm_url=$CM_URL" >> $GITHUB_OUTPUT | |
| echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_PROD }}" >> $GITHUB_OUTPUT | |
| # ===================================================================== | |
| # PRODUCTION — release.released (non-prerelease publish) | |
| # | |
| # Production does NOT rebuild anything. The images, installer, and | |
| # changelog are all artifacts of the RC run. The production trigger | |
| # only needs to tell CM "this version is now available to community | |
| # instances" via a promote endpoint (TODO: define and wire up). | |
| # ===================================================================== | |
| elif ${{ github.event_name == 'release' && github.event.action == 'released' }}; then | |
| ENVIRONMENT="production" | |
| CM_URL="https://cm.utmstack.com" | |
| echo "Environment: $ENVIRONMENT" | |
| echo "CM URL: $CM_URL" | |
| TAG="${{ github.event.release.tag_name }}" | |
| echo "Tag from release: $TAG" | |
| if [[ ! "$TAG" =~ ^v11\. ]]; then | |
| echo "⏭️ Skipping: tag '$TAG' is not a v11 release." | |
| exit 0 | |
| fi | |
| echo "tag=$TAG" >> $GITHUB_OUTPUT | |
| echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT | |
| echo "cm_url=$CM_URL" >> $GITHUB_OUTPUT | |
| echo "event_processor_tag=${{ vars.TW_EVENT_PROCESSOR_VERSION_PROD }}" >> $GITHUB_OUTPUT | |
| fi | |
| build_agent: | |
| name: Build Agent Binaries | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out code into the right branch | |
| uses: actions/checkout@v4 | |
| - name: Build Linux Binaries (amd64) | |
| env: | |
| GOOS: linux | |
| GOARCH: amd64 | |
| CGO_ENABLED: 0 | |
| run: | | |
| cd ${{ github.workspace }}/agent | |
| go build -o utmstack_agent_service_linux_amd64 -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/agent/updater | |
| go build -o utmstack_updater_service_linux_amd64 . | |
| - name: Build Linux Binaries (arm64) | |
| env: | |
| GOOS: linux | |
| GOARCH: arm64 | |
| CGO_ENABLED: 0 | |
| run: | | |
| cd ${{ github.workspace }}/agent | |
| go build -o utmstack_agent_service_linux_arm64 -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/agent/updater | |
| go build -o utmstack_updater_service_linux_arm64 . | |
| - name: Build Windows Binaries (amd64) | |
| env: | |
| GOOS: windows | |
| GOARCH: amd64 | |
| CGO_ENABLED: 0 | |
| run: | | |
| cd ${{ github.workspace }}/agent | |
| go build -o utmstack_agent_service_windows_amd64.exe -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/agent/updater | |
| go build -o utmstack_updater_service_windows_amd64.exe . | |
| - name: Build Windows Binaries (arm64) | |
| env: | |
| GOOS: windows | |
| GOARCH: arm64 | |
| CGO_ENABLED: 0 | |
| run: | | |
| cd ${{ github.workspace }}/agent | |
| go build -o utmstack_agent_service_windows_arm64.exe -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/agent/updater | |
| go build -o utmstack_updater_service_windows_arm64.exe . | |
| - name: Build macOS Binaries (arm64) | |
| env: | |
| GOOS: darwin | |
| GOARCH: arm64 | |
| CGO_ENABLED: 0 | |
| run: | | |
| cd ${{ github.workspace }}/agent | |
| go build -o utmstack_agent_service_darwin_arm64 -v -ldflags "-X 'github.com/utmstack/UTMStack/agent/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/agent/updater | |
| go build -o utmstack_updater_service_darwin_arm64 . | |
| - name: Upload Linux binaries as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: agents-linux | |
| path: | | |
| agent/utmstack_agent_service_linux_amd64 | |
| agent/utmstack_agent_service_linux_arm64 | |
| agent/updater/utmstack_updater_service_linux_amd64 | |
| agent/updater/utmstack_updater_service_linux_arm64 | |
| retention-days: 1 | |
| - name: Upload unsigned Windows binaries as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: agents-windows-unsigned | |
| path: | | |
| agent/utmstack_agent_service_windows_amd64.exe | |
| agent/utmstack_agent_service_windows_arm64.exe | |
| agent/updater/utmstack_updater_service_windows_amd64.exe | |
| agent/updater/utmstack_updater_service_windows_arm64.exe | |
| retention-days: 1 | |
| - name: Upload unsigned macOS binaries as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: agents-darwin-unsigned | |
| path: | | |
| agent/utmstack_agent_service_darwin_arm64 | |
| agent/updater/utmstack_updater_service_darwin_arm64 | |
| retention-days: 1 | |
| sign_agent_windows: | |
| name: Sign Windows Agent Binaries | |
| needs: [build_agent, setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-sign-agent.yml | |
| with: | |
| os: windows | |
| artifact_name: agents-windows-unsigned | |
| signed_artifact_name: agents-windows-signed | |
| gcp_project_id: ${{ vars.GCP_PROJECT_PROD }} | |
| kms_location: ${{ vars.KMS_KEYRING_LOCATION }} | |
| kms_keyring: ${{ vars.KMS_KEYRING_NAME }} | |
| kms_key: ${{ vars.KMS_KEY_NAME }} | |
| binaries: | | |
| utmstack_agent_service_windows_amd64.exe | |
| utmstack_agent_service_windows_arm64.exe | |
| updater/utmstack_updater_service_windows_amd64.exe | |
| updater/utmstack_updater_service_windows_arm64.exe | |
| secrets: inherit | |
| sign_agent_macos: | |
| name: Sign macOS Agent Binaries | |
| needs: [build_agent, setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-sign-agent.yml | |
| with: | |
| os: macos | |
| artifact_name: agents-darwin-unsigned | |
| signed_artifact_name: agents-darwin-signed | |
| binaries: | | |
| utmstack_agent_service_darwin_arm64 | |
| updater/utmstack_updater_service_darwin_arm64 | |
| secrets: inherit | |
| build_utmstack_collector: | |
| name: Build UTMStack Collector | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out code into the right branch | |
| uses: actions/checkout@v4 | |
| - name: Build UTMStack Collectors | |
| run: | | |
| echo "Building UTMStack Collector..." | |
| cd ${{ github.workspace }}/utmstack-collector | |
| GOOS=linux GOARCH=amd64 go build -o utmstack_collector -v -ldflags "-X 'github.com/utmstack/UTMStack/utmstack-collector/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| echo "Building UTMStack AS400 Collector..." | |
| cd ${{ github.workspace }}/as400 | |
| GOOS=linux GOARCH=amd64 go build -o utmstack_as400_collector_service -v -ldflags "-X 'github.com/utmstack/UTMStack/as400/config.REPLACE_KEY=${{ secrets.AGENT_SECRET_PREFIX }}'" . | |
| cd ${{ github.workspace }}/as400/updater | |
| GOOS=linux GOARCH=amd64 go build -o utmstack_as400_updater_service -v . | |
| - name: Upload collector binary as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: utmstack-collectors | |
| path: | | |
| ${{ github.workspace }}/utmstack-collector/utmstack_collector | |
| ${{ github.workspace }}/as400/utmstack_as400_collector_service | |
| ${{ github.workspace }}/as400/updater/utmstack_as400_updater_service | |
| retention-days: 1 | |
| build_agent_manager: | |
| name: Build Agent Manager Microservice | |
| needs: [sign_agent_windows, sign_agent_macos, build_utmstack_collector, setup_deployment] | |
| if: ${{ always() && needs.sign_agent_windows.result == 'success' && needs.sign_agent_macos.result == 'success' && needs.build_utmstack_collector.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out code into the right branch | |
| uses: actions/checkout@v4 | |
| - name: Download Linux agents from artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agents-linux | |
| path: ${{ github.workspace }}/agent | |
| - name: Download signed Windows agents from artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agents-windows-signed | |
| path: ${{ github.workspace }}/agent | |
| - name: Download UTMStack Collectors from artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: utmstack-collectors | |
| path: ${{ github.workspace }}/utmstack-collector | |
| - name: Download signed macOS agents from artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: agents-darwin-signed | |
| path: ${{ github.workspace }}/agent-darwin | |
| - name: Prepare dependencies for Agent Manager Image | |
| run: | | |
| cd ${{ github.workspace }}/agent-manager | |
| GOOS=linux GOARCH=amd64 go build -o agent-manager -v . | |
| mkdir -p ./dependencies/collector | |
| cp "${{ github.workspace }}/utmstack-collector/utmstack-collector/utmstack_collector" ./dependencies/collector/ | |
| cp "${{ github.workspace }}/utmstack-collector/version.json" ./dependencies/collector/ | |
| mkdir -p ./dependencies/collector/as400 | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/collector/as400-collector.jar" -o ./dependencies/collector/as400/as400-collector.jar | |
| cp "${{ github.workspace }}/as400/version.json" ./dependencies/collector/as400/ | |
| cp "${{ github.workspace }}/utmstack-collector/as400/utmstack_as400_collector_service" ./dependencies/collector/as400/ | |
| cp "${{ github.workspace }}/utmstack-collector/as400/updater/utmstack_as400_updater_service" ./dependencies/collector/as400/ | |
| mkdir -p ./dependencies/agent/ | |
| # Linux agents | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_linux_amd64" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_linux_arm64" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_linux_amd64" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_linux_arm64" ./dependencies/agent/ | |
| # Windows agents | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_windows_amd64.exe" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_windows_arm64.exe" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_windows_amd64.exe" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_windows_arm64.exe" ./dependencies/agent/ | |
| # macOS agents (signed and notarized) | |
| cp "${{ github.workspace }}/agent-darwin/utmstack_agent_service_darwin_arm64" ./dependencies/agent/ | |
| cp "${{ github.workspace }}/agent-darwin/updater/utmstack_updater_service_darwin_arm64" ./dependencies/agent/ | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/agent_updates/release/macos-agent/latest/utmstack-collector-mac" -o ./dependencies/agent/utmstack-collector-mac | |
| # TODO: Remove legacy binary names after all agents have migrated to new naming convention | |
| # Legacy names for backwards compatibility with existing agents | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_linux_amd64" ./dependencies/agent/utmstack_agent_service | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_linux_amd64" ./dependencies/agent/utmstack_updater_service | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_windows_amd64.exe" ./dependencies/agent/utmstack_agent_service.exe | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_windows_amd64.exe" ./dependencies/agent/utmstack_updater_service.exe | |
| cp "${{ github.workspace }}/agent/utmstack_agent_service_windows_arm64.exe" ./dependencies/agent/utmstack_agent_service_arm64.exe | |
| cp "${{ github.workspace }}/agent/updater/utmstack_updater_service_windows_arm64.exe" ./dependencies/agent/utmstack_updater_service_arm64.exe | |
| cp "${{ github.workspace }}/agent/version.json" ./dependencies/agent/ | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: utmstack | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and Push the Agent Manager Image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./agent-manager | |
| push: true | |
| provenance: false | |
| tags: ghcr.io/utmstack/utmstack/agent-manager:${{ needs.setup_deployment.outputs.tag }} | |
| build_event_processor: | |
| name: Build Event Processor Microservice | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out code into the right branch | |
| uses: actions/checkout@v4 | |
| - name: Build Plugins | |
| env: | |
| GOOS: linux | |
| GOARCH: amd64 | |
| run: | | |
| cd ${{ github.workspace }}/plugins/alerts; go build -o com.utmstack.alerts.plugin -v . | |
| cd ${{ github.workspace }}/plugins/aws; go build -o com.utmstack.aws.plugin -v . | |
| cd ${{ github.workspace }}/plugins/azure; go build -o com.utmstack.azure.plugin -v . | |
| cd ${{ github.workspace }}/plugins/bitdefender; go build -o com.utmstack.bitdefender.plugin -v . | |
| cd ${{ github.workspace }}/plugins/config; go build -o com.utmstack.config.plugin -v . | |
| cd ${{ github.workspace }}/plugins/events; go build -o com.utmstack.events.plugin -v . | |
| cd ${{ github.workspace }}/plugins/gcp; go build -o com.utmstack.gcp.plugin -v . | |
| cd ${{ github.workspace }}/plugins/geolocation; go build -o com.utmstack.geolocation.plugin -v . | |
| cd ${{ github.workspace }}/plugins/inputs; go build -o com.utmstack.inputs.plugin -v . | |
| cd ${{ github.workspace }}/plugins/o365; go build -o com.utmstack.o365.plugin -v . | |
| cd ${{ github.workspace }}/plugins/sophos; go build -o com.utmstack.sophos.plugin -v . | |
| cd ${{ github.workspace }}/plugins/stats; go build -o com.utmstack.stats.plugin -v . | |
| cd ${{ github.workspace }}/plugins/soc-ai; go build -o com.utmstack.soc-ai.plugin -v . | |
| cd ${{ github.workspace }}/plugins/modules-config; go build -o com.utmstack.modules-config.plugin -v . | |
| cd ${{ github.workspace }}/plugins/crowdstrike; go build -o com.utmstack.crowdstrike.plugin -v . | |
| cd ${{ github.workspace }}/plugins/feeds; go build -o com.utmstack.feeds.plugin -v . | |
| - name: Prepare Dependencies for Event Processor Image | |
| run: | | |
| mkdir -p ./geolocation | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/geolocation/asn-blocks-v4.csv" -o ./geolocation/asn-blocks-v4.csv | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/geolocation/asn-blocks-v6.csv" -o ./geolocation/asn-blocks-v6.csv | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/geolocation/blocks-v4.csv" -o ./geolocation/blocks-v4.csv | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/geolocation/blocks-v6.csv" -o ./geolocation/blocks-v6.csv | |
| curl -sSL "https://storage.googleapis.com/utmstack-updates/dependencies/geolocation/locations-en.csv" -o ./geolocation/locations-en.csv | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: utmstack | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and Push the Event Processor Image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ./event_processor.Dockerfile | |
| push: true | |
| provenance: false | |
| tags: ghcr.io/utmstack/utmstack/eventprocessor:${{ needs.setup_deployment.outputs.tag }} | |
| build-args: | | |
| BASE_IMAGE=ghcr.io/threatwinds/eventprocessor/base:${{ needs.setup_deployment.outputs.event_processor_tag }} | |
| build_backend: | |
| name: Build Backend Microservice | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-java.yml | |
| with: | |
| image_name: backend | |
| tag: ${{ needs.setup_deployment.outputs.tag }} | |
| java_version: '17' | |
| use_tag_as_version: true | |
| maven_profile: 'prod' | |
| maven_goals: 'clean package' | |
| copy_filters_and_rules: true | |
| build_frontend: | |
| name: Build Frontend Microservice | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-node.yml | |
| with: | |
| image_name: frontend | |
| tag: ${{ needs.setup_deployment.outputs.tag }} | |
| build_user_auditor: | |
| name: Build User-Auditor Microservice | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-java.yml | |
| with: | |
| image_name: user-auditor | |
| tag: ${{ needs.setup_deployment.outputs.tag }} | |
| java_version: '11' | |
| use_version_file: false | |
| maven_goals: 'clean install -U' | |
| build_web_pdf: | |
| name: Build Web-PDF Microservice | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| uses: ./.github/workflows/reusable-java.yml | |
| with: | |
| image_name: web-pdf | |
| tag: ${{ needs.setup_deployment.outputs.tag }} | |
| java_version: '11' | |
| use_version_file: false | |
| maven_goals: 'clean install -U' | |
| all_builds_complete: | |
| name: All Builds Complete | |
| needs: [ | |
| build_agent_manager, | |
| build_event_processor, | |
| build_backend, | |
| build_frontend, | |
| build_user_auditor, | |
| build_web_pdf | |
| ] | |
| if: ${{ always() && needs.build_agent_manager.result == 'success' && needs.build_event_processor.result == 'success' && needs.build_backend.result == 'success' && needs.build_frontend.result == 'success' && needs.build_user_auditor.result == 'success' && needs.build_web_pdf.result == 'success' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - run: echo "✅ All builds completed successfully." | |
| # AI changelog runs only on RC. Production reuses the same release notes | |
| # because the GitHub Release was already created during RC. | |
| generate_changelog: | |
| name: Generate Changelog | |
| needs: [all_builds_complete, setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'rc' }} | |
| uses: ./.github/workflows/generate-changelog.yml | |
| with: | |
| current_tag: ${{ needs.setup_deployment.outputs.tag }} | |
| secrets: | |
| THREATWINDS_API_KEY: ${{ secrets.THREATWINDS_API_KEY }} | |
| THREATWINDS_API_SECRET: ${{ secrets.THREATWINDS_API_SECRET }} | |
| # Installer build runs only on RC. The resulting binary is uploaded to the | |
| # GitHub Release as a prerelease asset. When the release is later promoted | |
| # to non-prerelease (which triggers production), the installer is already | |
| # there — no rebuild needed. | |
| build_installer_release: | |
| name: Build & Upload Installer | |
| needs: [generate_changelog, setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'rc' }} | |
| uses: ./.github/workflows/installer-release.yml | |
| with: | |
| version: ${{ needs.setup_deployment.outputs.tag }} | |
| version_major: v11 | |
| environment: rc | |
| prerelease: true | |
| changelog: ${{ needs.generate_changelog.outputs.changelog }} | |
| secrets: | |
| API_SECRET: ${{ secrets.API_SECRET }} | |
| CM_ENCRYPT_SALT: ${{ secrets.CM_ENCRYPT_SALT }} | |
| CM_SIGN_PUBLIC_KEY: ${{ secrets.CM_SIGN_PUBLIC_KEY }} | |
| deploy_installer_dev: | |
| name: Deploy Installer (Dev) | |
| needs: [all_builds_complete, setup_deployment] | |
| if: ${{ always() && needs.all_builds_complete.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'dev' }} | |
| uses: ./.github/workflows/installer-release.yml | |
| with: | |
| version: ${{ needs.setup_deployment.outputs.tag }} | |
| version_major: v11 | |
| environment: dev | |
| secrets: | |
| API_SECRET: ${{ secrets.API_SECRET }} | |
| CM_ENCRYPT_SALT: ${{ secrets.CM_ENCRYPT_SALT }} | |
| CM_SIGN_PUBLIC_KEY: ${{ secrets.CM_SIGN_PUBLIC_KEY }} | |
| # Publish a new version to CM. Runs for dev and rc — production does NOT | |
| # re-publish because the rc run already registered v11.x.x in CM PROD. | |
| publish_new_version: | |
| name: Publish New Version to Customer Manager | |
| needs: [all_builds_complete, generate_changelog, setup_deployment] | |
| if: ${{ always() && needs.all_builds_complete.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@v4 | |
| - name: Publish version | |
| env: | |
| CHANGELOG_CONTENT: ${{ needs.generate_changelog.outputs.changelog }} | |
| ENVIRONMENT: ${{ needs.setup_deployment.outputs.environment }} | |
| TAG: ${{ needs.setup_deployment.outputs.tag }} | |
| CM_URL: ${{ needs.setup_deployment.outputs.cm_url }} | |
| run: | | |
| # Use AI changelog for rc / production, generic for dev. | |
| if [ "$ENVIRONMENT" != "dev" ] && [ -n "$CHANGELOG_CONTENT" ]; then | |
| changelog="$CHANGELOG_CONTENT" | |
| else | |
| changelog="Development build $TAG - Internal testing release" | |
| fi | |
| echo "Environment: $ENVIRONMENT" | |
| echo "CM URL: $CM_URL" | |
| echo "Tag: $TAG" | |
| # Select CM_SERVICE_ACCOUNT based on environment | |
| if [ "$ENVIRONMENT" = "dev" ]; then | |
| cmAuth=$(echo '${{ secrets.CM_SERVICE_ACCOUNT_DEV }}' | jq -r '.') | |
| else | |
| cmAuth=$(echo '${{ secrets.CM_SERVICE_ACCOUNT_PROD }}' | jq -r '.') | |
| fi | |
| id=$(echo "$cmAuth" | jq -r '.id') | |
| key=$(echo "$cmAuth" | jq -r '.key') | |
| body=$(jq -n \ | |
| --arg version "$TAG" \ | |
| --arg changelog "$changelog" \ | |
| '{version: $version, changelog: $changelog}' | |
| ) | |
| response=$(curl -s -X POST "${CM_URL}/api/v1/versions/register" \ | |
| -H "Content-Type: application/json" \ | |
| -H "id: $id" \ | |
| -H "key: $key" \ | |
| -d "$body") | |
| echo "Response: $response" | |
| # Schedule the freshly-published version. For dev, this targets the dev | |
| # instance list; for rc, the RC instance list. Production does NOT use this | |
| # job — promotion to community lives in `promote_to_community` below. | |
| schedule: | |
| name: Schedule release to our instances | |
| needs: [publish_new_version, setup_deployment] | |
| if: ${{ always() && needs.publish_new_version.result == 'success' && needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment != 'production' }} | |
| runs-on: ubuntu-24.04 | |
| env: | |
| ENVIRONMENT: ${{ needs.setup_deployment.outputs.environment }} | |
| TAG: ${{ needs.setup_deployment.outputs.tag }} | |
| CM_URL: ${{ needs.setup_deployment.outputs.cm_url }} | |
| steps: | |
| - name: Schedule updates | |
| run: | | |
| echo "🔍 Environment: $ENVIRONMENT" | |
| echo "🔍 Version: $TAG" | |
| echo "🔍 CM URL: $CM_URL" | |
| # Select instance IDs and auth based on environment | |
| if [ "$ENVIRONMENT" = "dev" ]; then | |
| instance_ids="${{ vars.SCHEDULE_INSTANCES_DEV }}" | |
| auth_json='${{ secrets.CM_SERVICE_ACCOUNT_DEV }}' | |
| else | |
| # rc uses prod variables | |
| instance_ids="${{ vars.SCHEDULE_INSTANCES_PROD }}" | |
| auth_json='${{ secrets.CM_SERVICE_ACCOUNT_PROD }}' | |
| fi | |
| # Extract id and key from auth JSON | |
| auth_id=$(echo "$auth_json" | jq -r '.id') | |
| auth_key=$(echo "$auth_json" | jq -r '.key') | |
| # Parse IDs (handle single ID or comma-separated IDs) | |
| IFS=',' read -ra ID_ARRAY <<< "$instance_ids" | |
| # Iterate over each instance ID | |
| for instance_id in "${ID_ARRAY[@]}"; do | |
| instance_id=$(echo "$instance_id" | xargs) | |
| echo "📅 Scheduling release for instance: $instance_id" | |
| response=$(curl -s -w "\n%{http_code}" -X POST "${CM_URL}/api/v1/updates" \ | |
| -H "Content-Type: application/json" \ | |
| -H "id: $auth_id" \ | |
| -H "key: $auth_key" \ | |
| -d "{\"instances_ids\": [\"$instance_id\"], \"version\": \"$TAG\"}") | |
| http_code=$(echo "$response" | tail -n1) | |
| body=$(echo "$response" | sed '$d') | |
| if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then | |
| echo "✅ Successfully scheduled for instance: $instance_id" | |
| else | |
| echo "❌ Failed to schedule for instance: $instance_id (HTTP $http_code)" | |
| echo "Response: $body" | |
| exit 1 | |
| fi | |
| done | |
| echo "✅ Scheduled release for all instances with version $TAG" | |
| promote_to_community: | |
| name: Promote to Community | |
| needs: [setup_deployment] | |
| if: ${{ needs.setup_deployment.outputs.tag != '' && needs.setup_deployment.outputs.environment == 'production' }} | |
| runs-on: ubuntu-24.04 | |
| env: | |
| TAG: ${{ needs.setup_deployment.outputs.tag }} | |
| CM_URL: ${{ needs.setup_deployment.outputs.cm_url }} | |
| steps: | |
| - name: Schedule update for all community instances | |
| run: | | |
| echo "🚀 Promoting $TAG to community" | |
| echo " CM URL: $CM_URL" | |
| cmAuth=$(echo '${{ secrets.CM_SERVICE_ACCOUNT_PROD }}' | jq -r '.') | |
| auth_id=$(echo "$cmAuth" | jq -r '.id') | |
| auth_key=$(echo "$cmAuth" | jq -r '.key') | |
| body=$(jq -n \ | |
| --arg version "$TAG" \ | |
| '{version: $version, edition: "community"}') | |
| response=$(curl -sS -w "\n%{http_code}" -X POST "${CM_URL}/api/v1/updates" \ | |
| -H "Content-Type: application/json" \ | |
| -H "id: $auth_id" \ | |
| -H "key: $auth_key" \ | |
| -d "$body") | |
| http_code=$(echo "$response" | tail -n1) | |
| payload=$(echo "$response" | sed '$d') | |
| echo "HTTP $http_code" | |
| echo "Response: $payload" | |
| if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then | |
| echo "✅ Community broadcast scheduled for $TAG" | |
| else | |
| echo "❌ Community broadcast failed (HTTP $http_code)" | |
| exit 1 | |
| fi | |