name: 'API: Container Build and Push' on: push: branches: - 'master' paths: - 'api/**' - 'prowler/**' - '.github/workflows/api-container-build-push.yml' release: types: - 'published' workflow_dispatch: inputs: release_tag: description: 'Release tag (e.g., 5.14.0)' required: true type: string permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false env: # Tags LATEST_TAG: latest RELEASE_TAG: ${{ github.event.release.tag_name || inputs.release_tag }} STABLE_TAG: stable WORKING_DIRECTORY: ./api # Container registries PROWLERCLOUD_DOCKERHUB_REPOSITORY: prowlercloud PROWLERCLOUD_DOCKERHUB_IMAGE: prowler-api jobs: setup: if: github.repository == 'prowler-cloud/prowler' runs-on: ubuntu-latest timeout-minutes: 5 outputs: short-sha: ${{ steps.set-short-sha.outputs.short-sha }} steps: - name: Calculate short SHA id: set-short-sha run: echo "short-sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT notify-release-started: if: github.repository == 'prowler-cloud/prowler' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') needs: setup runs-on: ubuntu-latest timeout-minutes: 5 outputs: message-ts: ${{ steps.slack-notification.outputs.ts }} steps: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Notify container push started id: slack-notification uses: ./.github/actions/slack-notification env: SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }} COMPONENT: API RELEASE_TAG: ${{ env.RELEASE_TAG }} GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_RUN_ID: ${{ github.run_id }} with: slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }} payload-file-path: "./.github/scripts/slack-messages/container-release-started.json" container-build-push: needs: [setup, notify-release-started] if: always() && needs.setup.result == 'success' && (needs.notify-release-started.result == 'success' || needs.notify-release-started.result == 'skipped') runs-on: ${{ matrix.runner }} strategy: matrix: include: - platform: linux/amd64 runner: ubuntu-latest arch: amd64 - platform: linux/arm64 runner: ubuntu-24.04-arm arch: arm64 timeout-minutes: 30 permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Login to DockerHub uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build and push API container for ${{ matrix.arch }} id: container-push if: github.event_name == 'push' || github.event_name == 'release' || github.event_name == 'workflow_dispatch' uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: ${{ env.WORKING_DIRECTORY }} push: true platforms: ${{ matrix.platform }} tags: | ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ needs.setup.outputs.short-sha }}-${{ matrix.arch }} cache-from: type=gha,scope=${{ matrix.arch }} cache-to: type=gha,mode=max,scope=${{ matrix.arch }} # Create and push multi-architecture manifest create-manifest: needs: [setup, container-build-push] if: always() && needs.setup.result == 'success' && needs.container-build-push.result == 'success' runs-on: ubuntu-latest steps: - name: Login to DockerHub uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifests for push event if: github.event_name == 'push' run: | docker buildx imagetools create \ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.LATEST_TAG }} \ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA} \ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-amd64 \ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-arm64 env: NEEDS_SETUP_OUTPUTS_SHORT_SHA: ${{ needs.setup.outputs.short-sha }} - name: Create and push manifests for release event if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' run: | docker buildx imagetools create \ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${RELEASE_TAG} \ -t ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${{ env.STABLE_TAG }} \ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-amd64 \ ${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-arm64 env: NEEDS_SETUP_OUTPUTS_SHORT_SHA: ${{ needs.setup.outputs.short-sha }} - name: Install regctl if: always() uses: regclient/actions/regctl-installer@f61d18f46c86af724a9c804cb9ff2a6fec741c7c # main - name: Cleanup intermediate architecture tags if: always() run: | echo "Cleaning up intermediate tags..." regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-amd64" || true regctl tag delete "${{ env.PROWLERCLOUD_DOCKERHUB_REPOSITORY }}/${{ env.PROWLERCLOUD_DOCKERHUB_IMAGE }}:${NEEDS_SETUP_OUTPUTS_SHORT_SHA}-arm64" || true echo "Cleanup completed" env: NEEDS_SETUP_OUTPUTS_SHORT_SHA: ${{ needs.setup.outputs.short-sha }} notify-release-completed: if: always() && needs.notify-release-started.result == 'success' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch') needs: [setup, notify-release-started, container-build-push, create-manifest] runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: persist-credentials: false - name: Determine overall outcome id: outcome run: | if [[ "${NEEDS_CONTAINER_BUILD_PUSH_RESULT}" == "success" && "${NEEDS_CREATE_MANIFEST_RESULT}" == "success" ]]; then echo "outcome=success" >> $GITHUB_OUTPUT else echo "outcome=failure" >> $GITHUB_OUTPUT fi env: NEEDS_CONTAINER_BUILD_PUSH_RESULT: ${{ needs.container-build-push.result }} NEEDS_CREATE_MANIFEST_RESULT: ${{ needs.create-manifest.result }} - name: Notify container push completed uses: ./.github/actions/slack-notification env: SLACK_CHANNEL_ID: ${{ secrets.SLACK_PLATFORM_DEPLOYMENTS }} MESSAGE_TS: ${{ needs.notify-release-started.outputs.message-ts }} COMPONENT: API RELEASE_TAG: ${{ env.RELEASE_TAG }} GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_RUN_ID: ${{ github.run_id }} with: slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }} payload-file-path: "./.github/scripts/slack-messages/container-release-completed.json" step-outcome: ${{ steps.outcome.outputs.outcome }} update-ts: ${{ needs.notify-release-started.outputs.message-ts }} trigger-deployment: needs: [setup, container-build-push] if: always() && github.event_name == 'push' && needs.setup.result == 'success' && needs.container-build-push.result == 'success' runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read steps: - name: Trigger API deployment uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 with: token: ${{ secrets.PROWLER_BOT_ACCESS_TOKEN }} repository: ${{ secrets.CLOUD_DISPATCH }} event-type: api-prowler-deployment client-payload: '{"sha": "${{ github.sha }}", "short_sha": "${{ needs.setup.outputs.short-sha }}"}'