From 9a9d320043924f6e8e6ed9933483df15fe3178d8 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 13:58:30 +0000 Subject: [PATCH 1/3] Migrate Jenkins pipeline to GitHub Actions CI/CD workflows Co-Authored-By: Joao Esteves --- .github/workflows/cd.yml | 53 ++++++++++++++ .github/workflows/ci.yml | 145 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 .github/workflows/cd.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 00000000..1bc3cd7e --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,53 @@ +name: CD Pipeline + +on: + workflow_dispatch: + inputs: + docker_tag: + description: "Docker tag of the image built by CI" + required: true + +env: + DOCKER_IMAGE: bankapp + +jobs: + update-manifest-and-deploy: + name: "Update K8s Manifest & Push" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: DevOps + token: ${{ secrets.GH_PAT }} + + - name: Verify Docker image tag + run: | + echo "Docker tag received: ${{ github.event.inputs.docker_tag }}" + + - name: Update Kubernetes deployment manifest + run: | + sed -i "s|${{ vars.DOCKERHUB_USER }}/${DOCKER_IMAGE}:.*|${{ vars.DOCKERHUB_USER }}/${DOCKER_IMAGE}:${{ github.event.inputs.docker_tag }}|g" \ + kubernetes/bankapp-deployment.yaml + + - name: Commit and push changes + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add kubernetes/bankapp-deployment.yaml + git diff --cached --quiet && echo "No changes to commit" && exit 0 + git commit -m "Update K8s deployment image to ${{ vars.DOCKERHUB_USER }}/${DOCKER_IMAGE}:${{ github.event.inputs.docker_tag }}" + git push + + - name: Send deployment notification + if: always() + uses: actions/github-script@v7 + with: + script: | + const status = '${{ job.status }}'; + const emoji = status === 'success' ? ':white_check_mark:' : ':x:'; + const summary = `### ${emoji} BankApp Deployment Update\n` + + `- **Status**: ${status}\n` + + `- **Docker Tag**: ${{ github.event.inputs.docker_tag }}\n` + + `- **Run**: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + core.summary.addRaw(summary).write(); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..2ccae5e8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,145 @@ +name: CI Pipeline + +on: + push: + branches: [main, DevOps] + pull_request: + branches: [main, DevOps] + workflow_dispatch: + inputs: + docker_tag: + description: "Docker image tag" + required: false + default: "latest" + +env: + DOCKER_IMAGE: bankapp + DOCKERHUB_USER: ${{ vars.DOCKERHUB_USER }} + +jobs: + trivy-fs-scan: + name: "Trivy: Filesystem Scan" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run Trivy filesystem scan + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: fs + scan-ref: . + format: table + severity: CRITICAL,HIGH + + owasp-dependency-check: + name: "OWASP: Dependency Check" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run OWASP Dependency-Check + uses: dependency-check/Dependency-Check_Action@main + with: + project: bankapp + path: . + format: XML + args: --failOnCVSS 11 + + - name: Upload OWASP report + if: always() + uses: actions/upload-artifact@v4 + with: + name: owasp-dependency-check-report + path: reports/ + + sonarqube-analysis: + name: "SonarQube: Code Analysis" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: SonarQube Scan + uses: SonarSource/sonarqube-scan-action@v4 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + with: + args: > + -Dsonar.projectKey=bankapp + -Dsonar.projectName=bankapp + + - name: SonarQube Quality Gate + uses: SonarSource/sonarqube-quality-gate-action@v1 + timeout-minutes: 5 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + docker-build-push: + name: "Docker: Build & Push" + runs-on: ubuntu-latest + needs: [trivy-fs-scan, owasp-dependency-check, sonarqube-analysis] + outputs: + docker_tag: ${{ steps.set-tag.outputs.tag }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Determine Docker tag + id: set-tag + run: | + if [ -n "${{ github.event.inputs.docker_tag }}" ]; then + TAG="${{ github.event.inputs.docker_tag }}" + else + TAG="${GITHUB_SHA::7}" + fi + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }} + ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:latest + + - name: Run Trivy image scan + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }} + format: table + severity: CRITICAL,HIGH + + trigger-cd: + name: "Trigger CD Pipeline" + runs-on: ubuntu-latest + needs: docker-build-push + steps: + - name: Trigger CD workflow + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'cd.yml', + ref: context.ref, + inputs: { + docker_tag: '${{ needs.docker-build-push.outputs.docker_tag }}' + } + }); From 5fec830eb842c4eb59ed2f5ea49f41bf5b81f506 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:00:13 +0000 Subject: [PATCH 2/3] Fix Trivy action version and make SonarQube conditional on SONAR_ENABLED Co-Authored-By: Joao Esteves --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ccae5e8..d36cfb44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@v4 - name: Run Trivy filesystem scan - uses: aquasecurity/trivy-action@0.28.0 + uses: aquasecurity/trivy-action@0.35.0 with: scan-type: fs scan-ref: . @@ -57,6 +57,7 @@ jobs: sonarqube-analysis: name: "SonarQube: Code Analysis" runs-on: ubuntu-latest + if: ${{ vars.SONAR_ENABLED == 'true' }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -83,6 +84,7 @@ jobs: name: "Docker: Build & Push" runs-on: ubuntu-latest needs: [trivy-fs-scan, owasp-dependency-check, sonarqube-analysis] + if: ${{ !failure() && !cancelled() }} outputs: docker_tag: ${{ steps.set-tag.outputs.tag }} steps: @@ -118,7 +120,7 @@ jobs: ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:latest - name: Run Trivy image scan - uses: aquasecurity/trivy-action@0.28.0 + uses: aquasecurity/trivy-action@0.35.0 with: image-ref: ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }} format: table From 172a22aec7c4c2506c0dd939ba3d91399cf2e7ce Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 14:02:33 +0000 Subject: [PATCH 3/3] Make Docker login/push conditional on credentials availability Co-Authored-By: Joao Esteves --- .github/workflows/ci.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d36cfb44..5abc9b26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,10 +101,23 @@ jobs: fi echo "tag=$TAG" >> "$GITHUB_OUTPUT" + - name: Check Docker Hub credentials + id: docker-creds + run: | + if [ -n "$DOCKERHUB_USER" ] && [ -n "$DOCKERHUB_TOKEN" ]; then + echo "available=true" >> "$GITHUB_OUTPUT" + else + echo "available=false" >> "$GITHUB_OUTPUT" + echo "::warning::Docker Hub credentials not configured — image will be built locally only" + fi + env: + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub + if: steps.docker-creds.outputs.available == 'true' uses: docker/login-action@v3 with: username: ${{ vars.DOCKERHUB_USER }} @@ -114,12 +127,13 @@ jobs: uses: docker/build-push-action@v6 with: context: . - push: true + push: ${{ steps.docker-creds.outputs.available == 'true' }} tags: | - ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }} - ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:latest + ${{ vars.DOCKERHUB_USER || 'local' }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }} + ${{ vars.DOCKERHUB_USER || 'local' }}/${{ env.DOCKER_IMAGE }}:latest - name: Run Trivy image scan + if: steps.docker-creds.outputs.available == 'true' uses: aquasecurity/trivy-action@0.35.0 with: image-ref: ${{ vars.DOCKERHUB_USER }}/${{ env.DOCKER_IMAGE }}:${{ steps.set-tag.outputs.tag }}