Fix bugs in ci pipeline and IaC vulnerability scan #980
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: ci | |
| on: | |
| pull_request: | |
| types: [ opened, synchronize, reopened, ready_for_review ] | |
| # Ensures CI workflow has minimal permissions for security | |
| permissions: | |
| contents: read # Read-only access to repo contents for safer workflows | |
| pull-requests: write # Allow workflow to comment on, label, and update pull request as part of automation | |
| id-token: write # Allow OIDC tokens for secure cloud authentication | |
| jobs: | |
| lint: | |
| if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 | |
| - name: Setup Python | |
| uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c | |
| with: | |
| python-version: '3.11' | |
| - name: Setup Node.js | |
| uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 | |
| with: | |
| node-version: '22.13.1' | |
| cache: 'npm' | |
| - name: Install pipenv | |
| run: pip install pipenv | |
| - name: Install Python dependencies | |
| run: pipenv install --dev --deploy | |
| - name: Install Node dependencies | |
| run: npm ci | |
| - name: Run linting | |
| run: npm run lint | |
| sonarqube: | |
| if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get github-ci version | |
| id: ci_version | |
| run: | | |
| # Extract version from cd.yml workflow | |
| workflow_yaml=$(cat .github/workflows/cd.yml) | |
| uses_data=$(echo "$workflow_yaml" | grep 'jalantechnologies/github-ci') | |
| tag=$(echo $uses_data | sed -n 's/.*@\(.*\)/\1/p') | |
| echo "version=$(echo $tag)" >> $GITHUB_OUTPUT | |
| - name: Checkout github-ci | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 | |
| with: | |
| repository: jalantechnologies/github-ci | |
| path: platform | |
| ref: ${{ steps.ci_version.outputs.version }} | |
| - name: Run SonarQube analysis | |
| uses: ./platform/.github/actions/analyze | |
| with: | |
| sonar_host_url: ${{ vars.SONAR_HOST_URL }} | |
| sonar_token: ${{ secrets.SONAR_TOKEN }} | |
| branch: ${{ github.head_ref }} | |
| branch_base: main | |
| pull_request_number: ${{ github.event.number }} | |
| review: | |
| if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Placeholder for code review | |
| run: | | |
| echo "Code review placeholder" | |
| echo "Future implementation: AI-powered review for architecture, security, and best practices" | |
| scan: | |
| if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract branch name | |
| id: extract_branch | |
| run: | | |
| BRANCH_NAME=$(echo ${{ github.event.pull_request.head.ref }} | sed -e 's/^refs\/heads\///g') | |
| BRANCH_HASH=$(sha1sum < <(printf '%s' $BRANCH_NAME) | cut -c -15) | |
| echo "branch_hash=$(echo $BRANCH_HASH)" >> $GITHUB_OUTPUT | |
| - name: Get changes | |
| id: changes | |
| run: | | |
| git fetch origin ${{ github.event.pull_request.base.ref }} --depth=1 | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD) | |
| for file in $CHANGED_FILES; do | |
| if [[ -f "$file" ]]; then | |
| mkdir -p "changed_files/$(dirname "$file")" | |
| cp "$file" "changed_files/$file" | |
| fi | |
| done | |
| echo $CHANGED_FILES | |
| ls changed_files/ | |
| echo "changed_files=$(echo $CHANGED_FILES)" >> $GITHUB_OUTPUT | |
| - name: Run Trivy scan on changed files | |
| id: trivy | |
| if: steps.changes.outputs.changed_files != '' | |
| uses: aquasecurity/[email protected] | |
| continue-on-error: true | |
| with: | |
| scan-type: 'filesystem' | |
| scan-ref: './changed_files' | |
| format: 'template' | |
| template: '@fs-markdown.tpl' | |
| output: 'trivy-report.md' | |
| severity: 'HIGH,CRITICAL' | |
| ignore-unfixed: true | |
| trivyignores: ".trivyignore" | |
| exit-code: 1 | |
| - name: Comment PR with audit results | |
| uses: peter-evans/create-or-update-comment@v4 | |
| if: steps.trivy.outcome == 'failure' | |
| with: | |
| token: ${{ secrets.TRIVY_SCAN_TOKEN }} | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body-path: trivy-report.md | |
| - name: Get changes in k8s folder and subfolders | |
| id: iac_changes | |
| run: | | |
| # Fetch base branch | |
| git fetch origin ${{ github.event.pull_request.base.ref }} --depth=1 | |
| # Get all changed files | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} HEAD) | |
| # Initialize filtered variable | |
| FILTERED_FILES="" | |
| mkdir -p iac_changed_files/ | |
| # Loop and copy only files in k8s/ or subdirectories | |
| for file in $CHANGED_FILES; do | |
| if [[ -f "$file" && "$file" == lib/kube/* ]]; then | |
| mkdir -p "iac_changed_files/$(dirname "$file")" | |
| cp "$file" "iac_changed_files/$file" | |
| FILTERED_FILES="$FILTERED_FILES $file" | |
| fi | |
| done | |
| echo "FILTERED_FILES=$FILTERED_FILES" >> $GITHUB_OUTPUT | |
| - name: Run Trivy scan on IaC | |
| if: ${{ steps.iac_changes.outputs.FILTERED_FILES != '' }} | |
| id: trivy_iac | |
| uses: aquasecurity/[email protected] | |
| continue-on-error: true | |
| with: | |
| scan-type: 'config' | |
| scan-ref: 'iac_changed_files' | |
| format: 'template' | |
| template: '@iac-markdown.tpl' | |
| output: 'trivy-iac-report.md' | |
| severity: 'HIGH,CRITICAL' | |
| ignore-unfixed: true | |
| trivyignores: ".trivyignore" | |
| exit-code: 1 | |
| - name: Comment PR with audit results | |
| uses: peter-evans/create-or-update-comment@v4 | |
| if: ${{ steps.iac_changes.outputs.FILTERED_FILES != '' && steps.trivy_iac.outcome == 'failure' }} | |
| with: | |
| token: ${{ secrets.TRIVY_SCAN_TOKEN }} | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body-path: trivy-iac-report.md | |
| - name: Run Checkov action | |
| id: checkov | |
| if: ${{ steps.iac_changes.outputs.FILTERED_FILES != '' }} | |
| uses: bridgecrewio/checkov-action@v12 | |
| continue-on-error: true | |
| with: | |
| directory: iac_changed_files/ | |
| output_format: 'github_failed_only' | |
| output_file_path: checkov_result | |
| quiet: 'true' | |
| - name: Comment PR with audit results | |
| uses: peter-evans/create-or-update-comment@v4 | |
| if: ${{ steps.checkov.outcome == 'failure' }} | |
| with: | |
| token: ${{ secrets.TRIVY_SCAN_TOKEN }} | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body-path: checkov_result/results_github_failed_only.md | |
| - name: Build Docker image for scanning | |
| run: | | |
| docker build -t flask-react-app:${{ steps.extract_branch.outputs.branch_hash }} . | |
| - name: Run Trivy scan on docker images | |
| id: trivy_docker | |
| uses: aquasecurity/[email protected] | |
| continue-on-error: true | |
| with: | |
| scan-type: 'image' | |
| image-ref: 'flask-react-app:${{ steps.extract_branch.outputs.branch_hash }}' | |
| format: 'template' | |
| template: '@docker-markdown.tpl' | |
| output: 'trivy-docker-report.md' | |
| severity: 'HIGH,CRITICAL' | |
| ignore-unfixed: true | |
| trivyignores: ".trivyignore" | |
| exit-code: 1 | |
| - name: Comment PR with audit results | |
| uses: peter-evans/create-or-update-comment@v4 | |
| if: steps.trivy_docker.outcome == 'failure' | |
| with: | |
| token: ${{ secrets.TRIVY_SCAN_TOKEN }} | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body-path: trivy-docker-report.md | |
| - name: Fail job if Trivy found issues | |
| if: steps.trivy.outcome == 'failure' || steps.trivy_docker.outcome == 'failure' || steps.checkov.outcome == 'failure' | |
| run: | | |
| echo "❌ Trivy found vulnerabilities — failing the job." | |
| exit 1 | |
| test: | |
| if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 | |
| - name: Run integration tests | |
| run: docker compose -f docker-compose.test.yml up --exit-code-from app | |
| - name: Coverage report | |
| continue-on-error: true | |
| uses: irongut/CodeCoverageSummary@51cc3a756ddcd398d447c044c02cb6aa83fdae95 | |
| with: | |
| filename: output/coverage.xml | |
| badge: true | |
| fail_below_min: true | |
| format: markdown | |
| hide_branch_rate: false | |
| hide_complexity: true | |
| indicators: true | |
| output: both | |
| thresholds: '60 80' | |
| - name: Add coverage PR comment | |
| continue-on-error: true | |
| uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 | |
| with: | |
| recreate: true | |
| path: code-coverage-results.md |