π‘οΈ Sentinel: [security improvement] Dual Rate-Limiting #405
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: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| quality: | |
| name: Quality Gates | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: test | |
| POSTGRES_PASSWORD: test | |
| POSTGRES_DB: amph_v2_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgresql://test:test@localhost:5432/amph_v2_test | |
| JWT_SECRET: test-secret-min-32-characters-long-aaaaaaaa | |
| NODE_ENV: test | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| # gitleaks diffs the PR commit against its parent (`git log <sha>^..<sha>`), | |
| # which needs that parent to exist locally. The default shallow | |
| # (depth-1) checkout omits it, so gitleaks fails with "unknown | |
| # revision" on every PR regardless of what changed. | |
| fetch-depth: 0 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - run: pnpm install --frozen-lockfile | |
| # Prisma 7 removed @prisma/client's install-time auto-generate, so the | |
| # client must be generated before anything typechecks against it. | |
| - name: Generate Prisma client | |
| run: pnpm prisma generate | |
| - name: TypeScript check | |
| run: pnpm typecheck | |
| - name: Lint (includes no-ai-slop) | |
| run: pnpm lint | |
| - name: Secret scan | |
| uses: gitleaks/gitleaks-action@v3 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Prisma schema validation | |
| run: | | |
| pnpm prisma format --check | |
| pnpm prisma validate | |
| - name: Apply migrations | |
| run: pnpm prisma migrate deploy | |
| - name: Unit + integration tests | |
| # Not `pnpm test -- --coverage`: pnpm forwards the literal `--` to | |
| # vitest, which then reads `--coverage` as a filename filter and | |
| # emits no coverage output at all. | |
| run: pnpm test:coverage | |
| - name: Coverage threshold check | |
| run: | | |
| node scripts/check-coverage.js | |
| - name: Build | |
| run: pnpm build | |
| # Sprint 11 / STORY-048 β upload source maps to Sentry | |
| - name: Upload Sentry source maps | |
| if: env.SENTRY_AUTH_TOKEN != '' | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
| SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
| run: pnpm sentry:sourcemaps | |
| e2e: | |
| name: E2E Tests | |
| runs-on: ubuntu-latest | |
| needs: quality | |
| # The Playwright suite drives the real app (signup β sign-in β courses β | |
| # pricing), so it needs a reachable Postgres with migrations + seed data | |
| # and the same runtime env the dev server expects. | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: test | |
| POSTGRES_PASSWORD: test | |
| POSTGRES_DB: amph_v2_e2e | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgresql://test:test@localhost:5432/amph_v2_e2e | |
| JWT_SECRET: test-secret-min-32-characters-long-aaaaaaaa | |
| # The seed fails loudly if these are unset (C5 hardening). CI-only test | |
| # credentials, never used outside this ephemeral Postgres. | |
| ADMIN_EMAIL: admin@ci.local | |
| ADMIN_PASSWORD: ci-test-password-not-secret | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm prisma generate | |
| - run: pnpm prisma migrate deploy | |
| - name: Seed database | |
| run: pnpm exec tsx prisma/seed.ts | |
| - run: pnpm exec playwright install --with-deps chromium | |
| - run: pnpm build | |
| - run: pnpm test:e2e | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: playwright-report | |
| path: playwright-report/ | |
| retention-days: 7 | |
| lighthouse: | |
| name: Lighthouse CI | |
| runs-on: ubuntu-latest | |
| needs: quality | |
| # Lighthouse boots the production server and audits /pricing, which | |
| # queries the database β so it needs the same Postgres + seed as e2e. | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: test | |
| POSTGRES_PASSWORD: test | |
| POSTGRES_DB: amph_v2_lhci | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| DATABASE_URL: postgresql://test:test@localhost:5432/amph_v2_lhci | |
| JWT_SECRET: test-secret-min-32-characters-long-aaaaaaaa | |
| # The seed fails loudly if these are unset (C5 hardening). CI-only test | |
| # credentials, never used outside this ephemeral Postgres. | |
| ADMIN_EMAIL: admin@ci.local | |
| ADMIN_PASSWORD: ci-test-password-not-secret | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm prisma generate | |
| - run: pnpm prisma migrate deploy | |
| - name: Seed database | |
| run: pnpm exec tsx prisma/seed.ts | |
| - run: pnpm build | |
| - name: Run Lighthouse CI | |
| uses: treosh/lighthouse-ci-action@v12 | |
| with: | |
| configPath: .lighthouserc.json | |
| uploadArtifacts: true |