Local semgrep run found 25 findings (not the WP's remembered 27 — already-stale by the time this ran): dependabot cooldown, npm min-release-age, every GitHub Action pinned to a full commit SHA (dependabot's existing github-actions ecosystem entry keeps these current), and 2 detect-non-literal-regexp findings in e2e/create-ssp.mjs suppressed as false positives (non-attacker-controlled input: a test's own captured version number, a local generator's CLI arg). `semgrep scan` now runs with `--error`, a real blocking gate instead of report-only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
181 lines
8.7 KiB
YAML
181 lines
8.7 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
pull_request:
|
|
|
|
# Least privilege by default.
|
|
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@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
- run: npm ci --prefer-offline --no-audit --no-fund
|
|
- run: npm run lint
|
|
# Bounded-context + atomic-layer boundaries (WP-38, dependency-cruiser).
|
|
- run: npm run dep:check
|
|
# Showcase snippets must match their real source regions (WP-39, no drift).
|
|
- run: npm run gen:snippets && git diff --exit-code src/app/showcase/snippets.generated.ts
|
|
- run: npm run format:check
|
|
- run: npm run check:tokens
|
|
# Runs the full suite AND reports coverage (WP-46, report-only — no thresholds, so
|
|
# it can't fail on coverage; it still fails on a failing test, like `npm test` did).
|
|
- run: npm run test:coverage
|
|
# --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
|
|
# Hard resource ceiling so a runaway test-storybook (one headless Chromium per Jest
|
|
# worker) can't OOM the runner host — it fails its own container instead. The real cap
|
|
# is `--maxWorkers=2` in test-storybook:ci; this is the belt-and-suspenders guardrail.
|
|
# 4g is enough: verified by running this job's exact steps (npm ci, playwright install,
|
|
# build-storybook, test-storybook:ci) in `docker run --cpus=2 --memory=4g
|
|
# --memory-swap=4g node:24-bookworm` locally — completes clean, no OOM. (An earlier
|
|
# unconstrained local RSS measurement of build-storybook alone suggested ~5.8GB was
|
|
# needed, but that number reflects what Node/V8 is willing to use when memory is
|
|
# plentiful, not what the job actually needs under a real cgroup cap.)
|
|
# NB: requires the Gitea act_runner to allow container jobs (docker mode). If the runner
|
|
# is host-only, drop this `container:` block and rely on the worker cap alone.
|
|
container:
|
|
image: node:24-bookworm
|
|
options: --cpus=2 --memory=4g --memory-swap=4g
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
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@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
|
with:
|
|
dotnet-version: 10.0.x
|
|
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: ~/.nuget/packages
|
|
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}
|
|
restore-keys: nuget-${{ runner.os }}-
|
|
- run: dotnet format backend/BigRegister.slnx --verify-no-changes
|
|
# Category=Integration (WP-54, OpenZaakIntegrationTests) needs a live OpenZaak — opt-in,
|
|
# run manually against backend/openzaak/ (see its README), never in CI.
|
|
- run: dotnet test backend/BigRegister.slnx --filter "Category!=Integration"
|
|
|
|
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@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
|
with:
|
|
dotnet-version: 10.0.x
|
|
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
- run: npx playwright install --with-deps chromium
|
|
- run: npm run e2e
|
|
|
|
semgrep:
|
|
# SAST for both sides — replaces CodeQL, which is GitHub-only (its analyze step uploads
|
|
# SARIF to GitHub's code-scanning API) and can't run on this Gitea instance. Semgrep OSS
|
|
# is a plain CLI: no account, no external platform API. Findings print in the job log.
|
|
# Installed via the runner's preinstalled python3/pip — NOT `setup-python` (its Python
|
|
# download failed on this runner) and NOT a job `container:` (this act_runner times out
|
|
# pulling the base runner image for container jobs). `--break-system-packages` survives
|
|
# PEP-668; pip drops `semgrep` on PATH. `--ignore-installed` is required because some of
|
|
# semgrep's deps (e.g. PyJWT) are already present as apt-managed packages, which pip cannot
|
|
# uninstall ("RECORD file not found") — this flag installs fresh without uninstalling, so it
|
|
# never touches the Debian copies. Don't drop it.
|
|
# WP-30: initial findings triaged (dependabot cooldown, npm min-release-age, GH Actions
|
|
# pinned to SHA, 2 nosemgrep'd ReDoS false positives on non-attacker-controlled input) —
|
|
# `--error` below makes this a real blocking gate, not report-only.
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- run: python3 -m pip install --break-system-packages --ignore-installed semgrep
|
|
# p/default = curated cross-language security (covers JS/TS); p/csharp = the backend.
|
|
# Anonymous registry fetch; --metrics=off disables telemetry (not `auto`, which uploads
|
|
# project metadata).
|
|
- run: semgrep scan --config p/default --config p/csharp --metrics=off --error
|
|
|
|
api-client-drift:
|
|
# The committed typed client must match the backend OpenAPI doc.
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
- uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1
|
|
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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
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
|