Merge pull request #2083 from valory-xyz/release/v1.8.7 #558
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: | |
| push: | |
| branches: [main, staging] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| backend: | |
| name: Backend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.18" | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Configure Yarn network settings | |
| run: | | |
| yarn config set network-timeout 60000 | |
| yarn config set network-retries 10 | |
| yarn config set network-concurrency 2 | |
| - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: "3.14" | |
| - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 | |
| with: | |
| version: "0.11.15" | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" | |
| - run: yarn install:backend | |
| frontend: | |
| name: Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.18" | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Configure Yarn network settings | |
| run: | | |
| yarn config set network-timeout 60000 | |
| yarn config set network-retries 10 | |
| yarn config set network-concurrency 2 | |
| - name: Ensure root yarn.lock exists and is valid | |
| run: | | |
| if [ ! -f "yarn.lock" ]; then | |
| echo "Error: Missing root yarn.lock." | |
| echo "Run 'yarn install' and commit the generated lockfile." | |
| exit 1 | |
| fi | |
| if [ ! -s "yarn.lock" ]; then | |
| echo "Error: Root yarn.lock exists but is empty." | |
| exit 1 | |
| fi | |
| yarn install --frozen-lockfile | |
| - name: Ensure frontend yarn.lock exists and is valid | |
| run: | | |
| if [ ! -f "frontend/yarn.lock" ]; then | |
| echo "Error: Missing frontend/yarn.lock." | |
| echo "Run 'cd frontend && yarn install' and commit the generated lockfile." | |
| exit 1 | |
| fi | |
| if [ ! -s "frontend/yarn.lock" ]; then | |
| echo "Error: frontend/yarn.lock exists but is empty." | |
| exit 1 | |
| fi | |
| cd frontend | |
| yarn install --frozen-lockfile | |
| - name: Lint & Typecheck | |
| run: yarn quality-check:frontend | |
| - name: Check service templates | |
| run: cd frontend && npx tsx ../scripts/js/check_service_templates.ts | |
| frontend-tests: | |
| name: Frontend Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22.18" | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Install dependencies | |
| run: yarn install:frontend | |
| - name: Run tests | |
| run: yarn test:frontend | |
| gitleaks: | |
| name: Gitleaks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install and run gitleaks | |
| env: | |
| GITLEAKS_VERSION: 8.30.1 | |
| # Verify against the published sha256 on the release page so a swapped | |
| # tarball is rejected. Update both fields together when bumping. | |
| GITLEAKS_LINUX_X64_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb | |
| run: | | |
| set -euo pipefail | |
| TARBALL="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | |
| wget --quiet "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${TARBALL}" | |
| echo "${GITLEAKS_LINUX_X64_SHA256} ${TARBALL}" | sha256sum -c - | |
| tar -xzf "${TARBALL}" | |
| sudo install gitleaks /usr/bin | |
| gitleaks detect --report-format json --report-path leak_report -v | |
| deps-check-pinned: | |
| name: Deps pinned (both trees) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Check root deps are exact-pinned | |
| run: yarn deps:check-pinned | |
| - name: Check frontend deps are exact-pinned | |
| run: cd frontend && yarn deps:check-pinned | |
| audit: | |
| name: yarn audit (both trees) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| # No `yarn install` — `yarn audit` reads yarn.lock directly. Skipping | |
| # install means a compromised `postinstall` script cannot execute inside | |
| # the audit job. Defense in depth at the workflow level. | |
| - name: Audit root tree | |
| run: yarn audit:prod | |
| - name: Audit frontend tree | |
| run: cd frontend && yarn audit:prod | |
| install-hooks-root: | |
| name: install-hooks (root tree) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| # Install with --ignore-scripts so the gate fires before any postinstall | |
| # executes on the runner. The wrapper reads node_modules/*/package.json | |
| # to detect declared hooks; it does NOT need them to have run. | |
| - name: Install root (lifecycle scripts skipped) | |
| run: yarn install --frozen-lockfile --ignore-scripts | |
| - name: Diff install-hook surface against allowlist | |
| run: yarn audit:install-hooks | |
| install-hooks-frontend: | |
| name: install-hooks (frontend tree) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Install frontend (lifecycle scripts skipped) | |
| run: cd frontend && yarn install --frozen-lockfile --ignore-scripts | |
| - name: Diff install-hook surface against allowlist | |
| run: cd frontend && yarn audit:install-hooks | |
| lockfile-lint: | |
| name: lockfile-lint (both trees) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| # Pin lockfile-lint version explicitly so a compromise of the npm-published | |
| # tool can't silently land via `npx @latest`. Bump together with any | |
| # deps-check-pinned coverage updates. | |
| - name: Lint root yarn.lock | |
| run: npx -y lockfile-lint@5.0.0 --path yarn.lock --type yarn --validate-https --allowed-hosts yarn npm --empty-hostname false | |
| - name: Lint frontend yarn.lock | |
| run: npx -y lockfile-lint@5.0.0 --path frontend/yarn.lock --type yarn --validate-https --allowed-hosts yarn npm --empty-hostname false | |
| license-check: | |
| # License allowlist gate, mirroring the backend's tomte [Licenses] | |
| # under liccheck PARANOID. Unlike `audit` (which reads yarn.lock | |
| # directly and skips install for defense-in-depth), this job MUST | |
| # install — license-checker-rseidelsohn walks node_modules and | |
| # reads LICENSE files. We pass --ignore-scripts so postinstall | |
| # hooks still cannot execute during the gate; LICENSE files are | |
| # unpacked from tarballs regardless of script execution. | |
| # | |
| # Rollout: NOT in `all-checks-passed.needs` — this job reports, | |
| # it does not block merges. Flipping to required is a maintainer's | |
| # later action (add to `needs:` here + branch protection). | |
| name: License allowlist gate (both trees) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| - name: Activate pinned Yarn via Corepack | |
| run: | | |
| corepack enable | |
| # Read the full integrity-verified spec from package.json so corepack | |
| # checks the sha512 hash. Plain `corepack prepare yarn@1.22.22 --activate` | |
| # downloads from npm without verifying against the hash. | |
| PM_SPEC=$(node -p "require('./package.json').packageManager") | |
| corepack prepare "$PM_SPEC" --activate | |
| - name: Verify Yarn version | |
| run: | | |
| yarn --version | |
| test "$(yarn --version)" = "1.22.22" || (echo "::error::Yarn version mismatch" && exit 1) | |
| - name: Configure Yarn network settings | |
| run: | | |
| yarn config set network-timeout 60000 | |
| yarn config set network-retries 10 | |
| yarn config set network-concurrency 2 | |
| - name: Install root (lifecycle scripts skipped) | |
| run: yarn install --frozen-lockfile --ignore-scripts | |
| - name: Unit tests for license-check helpers | |
| # Pure-function tests for normalize() / evalExpr() in | |
| # scripts/license-check.lib.mjs. No deps beyond node:test (built-in | |
| # since Node 18). Runs once; the script is shared across both trees | |
| # so testing once is sufficient. | |
| run: yarn test:license-check | |
| - name: License check (root tree) | |
| run: yarn license-check | |
| - name: Install frontend (lifecycle scripts skipped) | |
| run: cd frontend && yarn install --frozen-lockfile --ignore-scripts | |
| - name: License check (frontend tree) | |
| run: cd frontend && yarn license-check | |
| all-checks-passed: | |
| name: All checks passed | |
| needs: [backend, frontend, frontend-tests, gitleaks, deps-check-pinned, lockfile-lint, audit, install-hooks-root, install-hooks-frontend] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify all required checks succeeded | |
| run: | | |
| if [[ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }}" == "true" ]]; then | |
| echo "One or more required checks did not succeed." | |
| echo "Results: ${{ toJson(needs) }}" | |
| exit 1 | |
| fi |