Fix url #11
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: Frontend CI/CD Workflow | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'frontend/**' | |
| 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 | |
| needs: start-time-capture | |
| outputs: | |
| cache-hit: ${{ steps.npm-cache-restore.outputs.cache-hit }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Setup Node.js 18 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 18 | |
| # Restore Cache Attempt | |
| - name: Restore npm Cache | |
| id: npm-cache-restore | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: ~/.npm | |
| key: ${{ runner.os }}-node-${{ hashFiles('frontend/package-lock.json') }} | |
| # Install Dependencies (Only runs on a cache miss) | |
| - name: Install Dependencies (Cache Miss Only) | |
| if: steps.npm-cache-restore.outputs.cache-hit != 'true' | |
| run: npm ci | |
| working-directory: ./frontend | |
| - name: Save npm Cache | |
| if: steps.npm-cache-restore.outputs.cache-hit != 'true' | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: ~/.npm | |
| key: ${{ runner.os }}-node-${{ hashFiles('frontend/package-lock.json') }} | |
| - name: Slack Notify | |
| if: failure() | |
| uses: ./.github/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: [prepare-cache, start-time-capture] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Slack Notify | |
| if: failure() | |
| uses: ./.github/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 }} | |
| build-and-test: | |
| name: Build and Run Unit Tests | |
| runs-on: ubuntu-24.04 | |
| needs: [scan-secrets, start-time-capture] | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js 18 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 18 | |
| - name: Restore npm Cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: ~/.npm | |
| key: ${{ runner.os }}-node-${{ hashFiles('frontend/package-lock.json') }} | |
| # (will hit cache from prepare-cache job if available) | |
| - name: Install Dependencies | |
| run: npm ci | |
| working-directory: ./frontend | |
| - name: Build | |
| run: npm run build | |
| working-directory: ./frontend | |
| - name: Run Unit Tests | |
| # Assumes 'test' script is defined in package.json | |
| run: npm test | |
| working-directory: ./frontend | |
| - name: Slack Notify | |
| if: failure() | |
| uses: ./.github/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: [build-and-test, start-time-capture] | |
| container: | |
| image: semgrep/semgrep | |
| if: (github.actor != 'dependabot[bot]') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - run: semgrep ci --subdir frontend/ | |
| env: | |
| SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} | |
| - name: Slack Notify | |
| if: failure() | |
| uses: ./.github/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: [semgrep, start-time-capture] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run Trivy vulnerability scanner on dependencies | |
| uses: aquasecurity/trivy-action@master | |
| continue-on-error: true | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: './frontend' | |
| severity: 'HIGH,CRITICAL' | |
| exit-code: '1' | |
| format: 'table' | |
| - name: Slack Notify | |
| if: failure() | |
| uses: ./.github/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-update-repo: | |
| name: Build, Scan, then SBOM, push and update repo | |
| runs-on: ubuntu-24.04 | |
| needs: [trivy_for_code_dependencies, start-time-capture] | |
| 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: ./frontend | |
| load: true | |
| tags: localbuild/frontend:${{ 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/frontend:${{ env.TAG }} | |
| severity: 'HIGH,CRITICAL' | |
| exit-code: '1' | |
| format: 'table' | |
| - name: Generate SBOM with Syft | |
| uses: anchore/sbom-action@v0 | |
| if: always() | |
| with: | |
| image: localbuild/frontend:${{ 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: always() | |
| with: | |
| name: frontend-sbom | |
| path: sbom.spdx.json | |
| - name: Push Final Image to Registry (Only if all security checks passed) | |
| if: success() | |
| run: | | |
| docker tag localbuild/frontend:${{ env.TAG }} mostafaibrahim24/empl-frontend:${{ env.TAG }} | |
| docker push mostafaibrahim24/empl-frontend:${{ 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-frontend:.*#mostafaibrahim24/empl-frontend:${TAG}#" deployments/frontend-deploy.yaml | |
| git config user.name "ci-bot" | |
| git config user.email "ci@bot.com" | |
| git commit -am "[GH-ACTIONS] Update frontend image" | |
| git push origin main | |
| env: | |
| GITOPS_TOKEN: ${{ secrets.GITOPS_TOKEN }} | |
| GITOPS_REPO: mostafaibrahim24/manifests-gitops | |
| - name: Slack Notify | |
| if: always() | |
| uses: ./.github/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 }} | |