diff --git a/.github/workflows/build-preview-environment.yml b/.github/workflows/build-preview-environment.yml new file mode 100644 index 0000000000..b419b3d335 --- /dev/null +++ b/.github/workflows/build-preview-environment.yml @@ -0,0 +1,121 @@ +# Deploys a temporary environment for testing a version of the code when a pull request is created / updated with a 'deploy-pr' label +name: Deploy PR Environment +concurrency: + group: "deploy-${{ github.event.pull_request.head.ref }}" + cancel-in-progress: false + +on: + workflow_dispatch: + pull_request: + types: [ labeled, synchronize ] + +permissions: + id-token: write + contents: read + pull-requests: read + +env: + REF: ${{ github.event_name == 'workflow_dispatch' && github.ref_name || github.event_name == 'pull_request' && github.event.pull_request.head.ref }} + +jobs: + deploy-dev-pr-environment: + if: contains(github.event.pull_request.labels.*.name, 'deploy-pr') + runs-on: ubuntu-latest + outputs: + env_name: ${{ steps.env-name.outputs.PR_ENV_NAME }} + ref: ${{ steps.clean-ref.outputs.ref }} + steps: + - name: Clean Ref + id: clean-ref + shell: bash + run: | + BRANCH_NAME=${{ env.REF }} + CLEAN_BRANCH_NAME=${BRANCH_NAME#refs/heads/} + echo "ref=$CLEAN_BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Checkout the Tool and actions + uses: actions/checkout@v4 + with: + ref: ${{ steps.clean-ref.outputs.ref }} + fetch-depth: 1 + + - name: "Sanitize ENV name" + id: sanitize_env + shell: bash + run: | + SANITIZED_BRANCH_NAME=$(echo -n "${{ steps.clean-ref.outputs.ref }}" | tr "/" "-") + echo "Sanitized branch name: $SANITIZED_BRANCH_NAME" + TRIMMED_BRANCH_NAME=$(echo -n "$SANITIZED_BRANCH_NAME" | cut -c 1-8) + echo "sanitized_env_name=$SANITIZED_BRANCH_NAME" >> $GITHUB_OUTPUT; + echo "trimmed_env_name=$TRIMMED_BRANCH_NAME" >> $GITHUB_OUTPUT; + + - name: Environment deployment + id: env-name + run: | + echo "deploying environment" + echo "PR_ENV_NAME=${{ steps.sanitize_env.outputs.trimmed_env_name }}" >> $GITHUB_ENV + echo "PR_ENV_NAME=${{ steps.sanitize_env.outputs.trimmed_env_name }}" >> $GITHUB_OUTPUT + + build-wf-service: + needs: deploy-dev-pr-environment + uses: ./.github/workflows/build-push-docker-images.yml + with: + registry: ghcr.io/${{ github.repository_owner }} + context: services/workflows-service + image_name: workflows-service + ref: ${{ needs.deploy-dev-pr-environment.outputs.ref }} + tag: ${{ needs.deploy-dev-pr-environment.outputs.env_name }} + + build-backoffice: + needs: deploy-dev-pr-environment + uses: ./.github/workflows/build-push-docker-images.yml + with: + registry: ghcr.io/${{ github.repository_owner }} + context: apps/backoffice-v2 + image_name: backoffice + ref: ${{ needs.deploy-dev-pr-environment.outputs.ref }} + tag: ${{ needs.deploy-dev-pr-environment.outputs.env_name }} + + build-kyb: + needs: deploy-dev-pr-environment + uses: ./.github/workflows/build-push-docker-images.yml + with: + registry: ghcr.io/${{ github.repository_owner }} + context: apps/kyb-app + image_name: kyb-app + ref: ${{ needs.deploy-dev-pr-environment.outputs.ref }} + tag: ${{ needs.deploy-dev-pr-environment.outputs.env_name }} + + build-dashboard: + needs: deploy-dev-pr-environment + uses: ./.github/workflows/build-push-docker-images.yml + with: + registry: ghcr.io/${{ github.repository_owner }} + context: apps/workflows-dashboard + image_name: workflows-dashboard + ref: ${{ needs.deploy-dev-pr-environment.outputs.ref }} + tag: ${{ needs.deploy-dev-pr-environment.outputs.env_name }} + + deploy-preview: + needs: [deploy-dev-pr-environment,build-wf-service,build-backoffice,build-kyb,build-dashboard] + runs-on: ubuntu-latest + steps: + - name: Trigger workflow in another repo + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GIT_TOKEN }} + script: | + try { + await github.rest.repos.createDispatchEvent({ + owner: 'ballerine-io', + repo: 'cloud-infra-config', + event_type: 'deploy-preview', + client_payload: { + 'ref': '${{ needs.deploy-dev-pr-environment.outputs.env_name }}' + } + }); + console.log('Successfully triggered deploy-preview event'); + } catch (error) { + console.error('Failed to trigger deploy-preview event:', error); + throw error; + } \ No newline at end of file diff --git a/.github/workflows/build-push-docker-images.yml b/.github/workflows/build-push-docker-images.yml new file mode 100644 index 0000000000..12e75b06d0 --- /dev/null +++ b/.github/workflows/build-push-docker-images.yml @@ -0,0 +1,134 @@ +name: Build and Push Docker Images + +on: + workflow_call: + inputs: + registry: + required: true + description: "The Docker registry URL" + type: string + context: + required: true + description: "The build context path for the Docker image" + type: string + image_name: + required: true + description: "The name of the Docker image" + type: string + ref: + required: true + description: "Branch name of the Preview" + type: string + tag: + required: true + description: "Tag name of the Preview Image" + type: string + +permissions: + id-token: write + contents: write + pull-requests: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + fetch-depth: 1 + persist-credentials: false + sparse-checkout: | + ${{ inputs.context }} + sparse-checkout-cone-mode: true + + - name: Get tags + run: git fetch --tags origin + + - name: Get version + if: ${{ inputs.image_name }} == 'workflows-service' + id: version + run: | + TAG=$(git tag -l "$(echo ${{ inputs.image_name }}@)*" | sort -V -r | head -n 1) + echo "tag=$TAG" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "TAG=$TAG" >> "$GITHUB_ENV" + SHORT_SHA=$(git rev-parse --short HEAD) + echo "sha_short=$SHORT_SHA" >> "$GITHUB_OUTPUT" + echo "SHORT_SHA=$SHORT_SHA" >> "$GITHUB_ENV" + + - name: Bump version + id: bump-version + if: ${{ inputs.image_name }} == 'workflows-service' + uses: ./.github/actions/bump-version + with: + tag: ${{ steps.version.outputs.tag }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: 'arm64,arm' + + - name: Cache Docker layers + id: cache + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }} + restore-keys: | + ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile') }} + ${{ runner.os }}-docker- + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ inputs.registry }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker images + id: docker_meta + uses: docker/metadata-action@v4 + with: + images: ${{ inputs.registry }}/${{ inputs.image_name }} + tags: | + type=raw,value=${{ inputs.tag }} + type=sha,format=short + + - name: Print docker version outputs + run: | + echo "Metadata: ${{ steps.docker_meta.outputs.tags }}" + if [[ "${{ inputs.image_name }}" == "workflows-service" ]]; then + echo "sha_short: ${{ steps.version.outputs.sha_short }}" + echo "bump-version-version: ${{ steps.bump-version.outputs.version }}" + echo "bump-version-tag: ${{ steps.bump-version.outputs.tag }}" + fi + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ${{ inputs.context }} + platforms: linux/amd64 + push: true + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + tags: ${{ steps.docker_meta.outputs.tags }} + build-args: | + ${{ inputs.image_name == 'workflows-service' && format('"RELEASE={0}"\n"SHORT_SHA={1}"', steps.version.outputs.tag, steps.version.outputs.sha_short) || '' }} + + - name: Scan Docker Image + uses: aquasecurity/trivy-action@master + continue-on-error: true + with: + image-ref: ${{ steps.docker_meta.outputs.tags }} + format: 'table' + ignore-unfixed: true + exit-code: 1 + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + timeout: '5m' diff --git a/.github/workflows/destroy-preview-environment.yml b/.github/workflows/destroy-preview-environment.yml new file mode 100644 index 0000000000..ee4896cf50 --- /dev/null +++ b/.github/workflows/destroy-preview-environment.yml @@ -0,0 +1,83 @@ +# Destroys a temporary environment that was created forwhen a pull request is created / updated with a 'deploy-pr' label or triggerred manually +name: Destroy PR Environment +concurrency: + group: "deploy-${{ github.event.pull_request.head.ref }}" + cancel-in-progress: false + +on: + workflow_dispatch: + pull_request: + types: [ closed, unlabeled ] + +permissions: + id-token: write + contents: write + +env: + REF: ${{ github.event_name == 'workflow_dispatch' && github.ref || github.event_name == 'pull_request' && github.event.pull_request.head.ref }} + +jobs: + deploy-dev-pr-environment: + if: contains(github.event.pull_request.labels.*.name, 'deploy-pr') + runs-on: ubuntu-latest + outputs: + env_name: ${{ steps.env-name.outputs.PR_ENV_NAME }} + steps: + - name: Clean Ref + id: clean-ref + shell: bash + run: | + BRANCH_NAME=${{ env.REF }} + CLEAN_BRANCH_NAME=${BRANCH_NAME#refs/heads/} + echo "ref=$CLEAN_BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Checkout the Tool and actions + uses: actions/checkout@v4 + with: + ref: ${{ steps.clean-ref.outputs.ref }} + fetch-depth: 1 + + - name: "Sanitize ENV name" + id: sanitize_env + shell: bash + run: | + SANITIZED_BRANCH_NAME=$(echo -n ${{ steps.clean-ref.outputs.ref }} | tr "/" "-") + echo "Sanitized branch name: $SANITIZED_BRANCH_NAME" + TRIMMED_BRANCH_NAME=$(echo -n "$SANITIZED_BRANCH_NAME" | cut -c 1-8) + echo "sanitized_env_name=$SANITIZED_BRANCH_NAME" >> $GITHUB_OUTPUT; + echo "trimmed_env_name=$TRIMMED_BRANCH_NAME" >> $GITHUB_OUTPUT; + + - name: Environment deployment + id: env-name + run: | + echo "deploying environment" + echo "PR_ENV_NAME=${{ steps.sanitize_env.outputs.trimmed_env_name }}" >> $GITHUB_ENV + echo "PR_ENV_NAME=${{ steps.sanitize_env.outputs.trimmed_env_name }}" >> $GITHUB_OUTPUT + + destroy-preview: + needs: deploy-dev-pr-environment + if: | + (github.event_name == 'pull_request' && github.event.action == 'unlabeled' && github.event.label.name == 'deploy-pr') + || + (github.event_name == 'pull_request' && github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'deploy-pr')) + runs-on: ubuntu-latest + steps: + - name: Trigger workflow in another repo + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GIT_TOKEN }} + script: | + try { + await github.rest.repos.createDispatchEvent({ + owner: 'ballerine-io', + repo: 'cloud-infra-config', + event_type: 'destroy-preview', + client_payload: { + 'ref': '${{ needs.deploy-dev-pr-environment.outputs.env_name }}' + } + }); + console.log('Successfully triggered deploy-preview event'); + } catch (error) { + console.error('Failed to trigger deploy-preview event:', error); + throw error; + } \ No newline at end of file