feat: file retry + editable error catalog #186
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
| # workflow bump: force refresh after removing setup-trivy | |
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ───────────────────────── Backend (.NET 10) ───────────────────────── | |
| backend: | |
| name: backend (build + coverage + format) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET 10 | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Restore | |
| run: dotnet restore DocAnalytics.slnx | |
| - name: Build | |
| run: dotnet build DocAnalytics.slnx --no-restore --configuration Release | |
| - name: Format check (dotnet format) | |
| run: dotnet format DocAnalytics.slnx --verify-no-changes | |
| - name: Test + coverage gate (per layer) | |
| shell: bash | |
| run: bash scripts/coverage-gate.sh | |
| # ──────────────────────── Frontend (Angular 22) ──────────────────────── | |
| frontend: | |
| name: frontend (build + test + format) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: docanalytics-web | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node 22 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: npm | |
| cache-dependency-path: docanalytics-web/package-lock.json | |
| - name: Install (clean) | |
| run: npm ci | |
| - name: Prettier format check | |
| run: npm run format:check | |
| - name: Build | |
| run: npm run build | |
| - name: Test (Vitest, single run + coverage thresholds) | |
| run: npx ng test --watch=false | |
| # ──────────────────────── E2E (Playwright) ──────────────────────── | |
| e2e: | |
| name: e2e (Playwright) | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: docanalytics | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET 10 | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: Setup Node 22 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: npm | |
| cache-dependency-path: docanalytics-web/package-lock.json | |
| - name: Trust dev HTTPS cert (API serves https on :7001) | |
| run: dotnet dev-certs https | |
| - name: Restore + build API (so startup is fast) | |
| run: | | |
| dotnet restore DocAnalytics.slnx | |
| dotnet build DocAnalytics.Api -c Release --no-restore | |
| - name: Install web dependencies | |
| working-directory: docanalytics-web | |
| run: npm ci | |
| - name: Install Playwright browsers | |
| working-directory: docanalytics-web | |
| run: npx playwright install --with-deps | |
| - name: Start API and run Playwright E2E | |
| working-directory: docanalytics-web | |
| env: | |
| ASPNETCORE_ENVIRONMENT: Development | |
| ConnectionStrings__Default: "Host=localhost;Port=5432;Database=docanalytics;Username=postgres;Password=postgres" | |
| Jwt__Key: ${{ secrets.E2E_JWT_KEY || 'ci-e2e-dummy-signing-key-not-a-secret-0123456789' }} | |
| CI: 'true' | |
| run: | | |
| set -e | |
| # Start the API in the background WITHIN this step so it stays alive | |
| # while Playwright runs (background procs are killed at step end). | |
| ( cd .. && dotnet run --project DocAnalytics.Api -c Release --no-build > api.log 2>&1 & ) | |
| echo "Waiting for API on https://localhost:7001 ..." | |
| up="" | |
| for i in $(seq 1 90); do | |
| if curl -sk https://localhost:7001/health >/dev/null 2>&1; then up=1; echo "API is up"; break; fi | |
| sleep 2 | |
| done | |
| if [ -z "$up" ]; then echo "API did not start"; cat ../api.log || true; exit 1; fi | |
| npx playwright test | |
| - name: Upload Playwright report | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-report | |
| path: docanalytics-web/playwright-report | |
| retention-days: 7 | |
| # ──────────────────────── DevSecOps (scans) ──────────────────────── | |
| devsecops: | |
| name: devsecops (secrets + deps + image scan) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Gitleaks (working tree only, via Docker) | |
| run: | | |
| docker run --rm \ | |
| -v "${{ github.workspace }}:/repo" \ | |
| ghcr.io/gitleaks/gitleaks:v8.24.3 \ | |
| detect \ | |
| --source=/repo \ | |
| --no-git \ | |
| --redact \ | |
| --config=/repo/.gitleaks.toml \ | |
| --exit-code 1 | |
| # Backend dependency scan (.NET) | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - name: dotnet list package --vulnerable (fail on any) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| dotnet list DocAnalytics.slnx package --vulnerable --include-transitive | tee dotnet-vuln.txt | |
| if grep -qi "has the following vulnerable packages" dotnet-vuln.txt; then | |
| echo "❌ Vulnerable NuGet packages detected" | |
| exit 1 | |
| fi | |
| # Frontend dependency scan (npm) | |
| - name: Setup Node 22 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: npm audit (HIGH+) | |
| working-directory: docanalytics-web | |
| run: | | |
| npm ci | |
| npm audit --audit-level=high | |
| # Container image scan (Trivy) — run via Docker (no setup-trivy dependency) | |
| - name: Build API image | |
| run: docker build -t docanalytics-api:${{ github.sha }} -f DocAnalytics.Api/Dockerfile . | |
| - name: Trivy scan (API image) | |
| run: | | |
| docker run --rm \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| aquasec/trivy:0.54.1 \ | |
| image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 \ | |
| docanalytics-api:${{ github.sha }} | |
| - name: Build Web image | |
| run: docker build -t docanalytics-web:${{ github.sha }} -f docanalytics-web/Dockerfile docanalytics-web | |
| - name: Trivy scan (Web image) | |
| run: | | |
| docker run --rm \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| aquasec/trivy:0.54.1 \ | |
| image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 \ | |
| docanalytics-web:${{ github.sha }} |