name: CI on: push: branches: [main] tags: ['v*'] pull_request: # CodeQL runs on main + this weekly cron only (not on PRs) — see the codeql job's `if`. schedule: - cron: '0 3 * * 1' # Mondays 03:00 UTC # Least privilege by default; the CodeQL job widens its own scope locally. permissions: contents: read # A newer push to the same ref cancels the in-flight run. concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: frontend: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: npm - run: npm ci --prefer-offline --no-audit --no-fund - run: npm run lint - run: npm run format:check - run: npm run check:tokens - run: npm test # --localize builds every configured locale (nl + en, angular.json's i18n # block) in one pass; i18nMissingTranslation:"error" (angular.json) fails # this step if messages.en.xlf is missing a unit the source (WP-20) gains. - run: npx ng build --localize # The shipped bundle must stay clean; dev-only advisories are excluded. - run: npm audit --omit=dev storybook-a11y: # Axe runs against every story in the static build; a violation fails the build. runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: npm - run: npm ci --prefer-offline --no-audit --no-fund # Cache the chromium download across runs; `install --with-deps` then only # runs the (fast, idempotent) apt deps check on a hit. - uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} - run: npx playwright install --with-deps chromium - run: npm run build-storybook - run: npm run test-storybook:ci backend: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} restore-keys: nuget-${{ runner.os }}- - run: dotnet format backend/BigRegister.slnx --verify-no-changes - run: dotnet test backend/BigRegister.slnx e2e: # Smoke-level Playwright run against the REAL FE+backend (WP-19) — a fresh # runner checkout per run, so there's no bigregister.db (WP-22, gitignored) # left over from a prior run to leak state in; the backend creates + migrates # an empty one on this boot, same as a fresh clone always has. # Playwright's `webServer` (playwright.config.ts) starts BOTH the backend and # `ng serve`, waits for them, runs the suite, and tears them down — all in the # one `npm run e2e` process. Do NOT background them as separate steps: a `&` # process from one Actions step is dead by the next step, so `wait-on` hung # forever (the 2-hour e2e hang). runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: npm - uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} restore-keys: nuget-${{ runner.os }}- - run: npm ci --prefer-offline --no-audit --no-fund - uses: actions/cache@v4 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} - run: npx playwright install --with-deps chromium - run: npm run e2e codeql: # Static analysis (SAST) for both sides; results appear under the Security tab. # Off the PR path (slow 2-language matrix) — runs on push-to-main + the weekly # cron only, so PR feedback isn't bottlenecked on it. if: github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 20 permissions: security-events: write contents: read actions: read strategy: fail-fast: false matrix: language: [javascript-typescript, csharp] steps: - uses: actions/checkout@v4 - if: matrix.language == 'csharp' uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - if: matrix.language == 'csharp' uses: actions/cache@v4 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} restore-keys: nuget-${{ runner.os }}- - uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - uses: github/codeql-action/autobuild@v3 - uses: github/codeql-action/analyze@v3 api-client-drift: # The committed typed client must match the backend OpenAPI doc. runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 24 cache: npm - uses: actions/setup-dotnet@v4 with: # 8.0 for the bundled NSwag runtime, 10.0 to build/emit the spec. dotnet-version: | 8.0.x 10.0.x - uses: actions/cache@v4 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} restore-keys: nuget-${{ runner.os }}- - run: npm ci --prefer-offline --no-audit --no-fund - run: npm run gen:api - run: git diff --exit-code src/app/shared/infrastructure/api-client.ts backend/swagger.json