Skip to content

Backend CI/CD Workflow #45

Backend CI/CD Workflow

Backend CI/CD Workflow #45

Workflow file for this run

name: Backend CI/CD Workflow
on:
workflow_dispatch:
push:
branches:
- main
paths:
- 'backend/**'
jobs:
start-time-capture:
runs-on: ubuntu-24.04
outputs:
workflow_start_time: ${{ steps.start.outputs.start_time_unix }}
steps:
- name: Capture Workflow Start Time
id: start
run: echo "start_time_unix=$(date +%s)" >> $GITHUB_OUTPUT
prepare-cache:
runs-on: ubuntu-24.04
outputs:
cache-hit: ${{ steps.cache-restore.outputs.cache-hit }}
needs: [start-time-capture]
steps:
- uses: actions/checkout@v5
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 21
# Restore Cache Attempt
- name: Restore Maven Cache
id: cache-restore
uses: actions/cache/restore@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
# Download Dependencies (Only runs on a cache miss)
- name: Download Dependencies (Cache Miss Only)
if: steps.cache-restore.outputs.cache-hit != 'true'
run: |
mvn dependency:go-offline -B
mvn dependency:resolve-plugins -B
working-directory: ./backend
- name: Save Maven Cache
if: steps.cache-restore.outputs.cache-hit != 'true'
# saves the new/updated ~/.m2/repository.
uses: actions/cache/save@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
- name: Slack Notify
if: failure()
uses: ./actions/slack-notify
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
job-status: ${{ job.status }}
last: 'no'
start-time: ${{ needs.start-time-capture.outputs.workflow_start_time }}
scan-secrets:
name: Gitleaks Scan
runs-on: ubuntu-24.04
needs: [start-time-capture, prepare-cache]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
compile-and-test:
name: Compile and Unit test
runs-on: ubuntu-24.04
needs: [start-time-capture,scan-secrets]
steps:
- name: Checkout Code
uses: actions/checkout@v5
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 21
- name: Restore Maven Cache
uses: actions/cache/restore@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
- name: Run Unit test
run: mvn -B test
working-directory: ./backend
- name: Slack Notify
if: failure()
uses: ./actions/slack-notify
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
job-status: ${{ job.status }}
last: 'no'
start-time: ${{ needs.start-time-capture.outputs.workflow_start_time }}
semgrep:
name: semgrep SAST scan
runs-on: ubuntu-24.04
needs: [start-time-capture, compile-and-test]
container:
image: semgrep/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- uses: actions/checkout@v4
- run: semgrep ci --subdir backend/src/main/java
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Slack Notify
if: failure()
uses: ./actions/slack-notify
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
job-status: ${{ job.status }}
last: 'no'
start-time: ${{ needs.start-time-capture.outputs.workflow_start_time }}
trivy_for_code_dependencies:
runs-on: ubuntu-24.04
name: Trivy for Code dependencies
needs: [start-time-capture,semgrep]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner on Java dependencies
uses: aquasecurity/trivy-action@master
# continue-on-error: true
with:
scan-type: 'fs'
scan-ref: './backend'
severity: 'HIGH,CRITICAL'
exit-code: '1'
format: 'table'
- name: Slack Notify
if: failure()
uses: ./actions/slack-notify
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
job-status: ${{ job.status }}
last: 'no'
start-time: ${{ needs.start-time-capture.outputs.workflow_start_time }}
image-build-scan-sbom-push:
name: Build, Scan, then SBOM and push
runs-on: ubuntu-24.04
needs: [start-time-capture,trivy_for_code_dependencies]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub (for push)
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set Image Tag
id: vars
run: echo "TAG=$(echo ${GITHUB_SHA} | cut -c1-7)" >> $GITHUB_ENV
- name: Build Image
uses: docker/build-push-action@v6
with:
context: ./backend
load: true
tags: localbuild/backend:${{ env.TAG }}
upload-artifact: false
- name: Run Trivy vulnerability scanner for the entire image artifact
uses: aquasecurity/trivy-action@master
#continue-on-error: true
with:
image-ref: localbuild/backend:${{ env.TAG }}
severity: 'HIGH,CRITICAL'
exit-code: '1'
format: 'table'
- name: Generate SBOM with Syft
uses: anchore/sbom-action@v0
if: failure()
with:
image: localbuild/backend:${{ env.TAG }} # Scan the local image
output-file: 'sbom.spdx.json' # Save the SBOM file
upload-artifact: false
- name: Upload SBOM Artifact
uses: actions/upload-artifact@v4
if: failure()
with:
name: backend-sbom
path: sbom.spdx.json
- name: Push Final Image to Registry (Only if all security checks passed)
if: success()
run: |
docker tag localbuild/backend:${{ env.TAG }} mostafaibrahim24/empl-backend:${{ env.TAG }}
docker push mostafaibrahim24/empl-backend:${{ env.TAG }}
- name: Update GitOps manifest with new image tag
if: success()
run: |
git clone https://x-access-token:${GITOPS_TOKEN}@github.com/${GITOPS_REPO}.git
cd manifests-gitops
sed -i "s#mostafaibrahim24/empl-backend:.*#mostafaibrahim24/empl-backend:${TAG}#" deployments/backend-deploy.yaml
git config user.name "ci-bot"
git config user.email "ci@bot.com"
git commit -am "[GH-ACTIONS] Update backend image"
git push origin main
env:
GITOPS_TOKEN: ${{ secrets.GITOPS_TOKEN }}
GITOPS_REPO: mostafaibrahim24/manifests-gitops
- name: Slack Notify
if: always()
uses: ./actions/slack-notify
with:
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
job-status: ${{ job.status }}
last: 'yes'
start-time: ${{ needs.start-time-capture.outputs.workflow_start_time }}