code-foundry 1.44.11 → 1.45.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1169 @@
1
+ name: Code Foundry Validation (Billing)
2
+
3
+ # Billing-lane orchestrator for repositories whose Actions minutes are billed:
4
+ # identical coverage to the split orchestrators, but lanes that measure under a
5
+ # minute in practice share one runner so GitHub's whole-minute rounding stops
6
+ # dominating the invoice. Wall-clock neutrality rule enforced by review: a lane
7
+ # may only join the merged job when its work plus the shared checkout/setup
8
+ # overhead stays under the longest separate lane (type-check, unit, or build),
9
+ # so the merged job never becomes the critical path. Repositories that adopt
10
+ # this orchestrator must keep every runner input on standard hosted runners.
11
+ #
12
+ # Differences from the split orchestrators, by design:
13
+ # - Format, build, performance, smoke, and eval run as sequential steps of one
14
+ # job ("Fast lanes"). Each lane keeps its own detect, setup, execution, and
15
+ # task-receipt steps, so receipts and skip semantics are unchanged.
16
+ # - Profile and dependency audit run in one job; the audit matrix is replaced
17
+ # by language blocks driven directly by the profile step's outputs.
18
+ # - One file serves both CodeQL-enabled and CodeQL-unavailable consumers via
19
+ # the `codeql` input, instead of two orchestrator variants.
20
+
21
+ on:
22
+ workflow_call:
23
+ inputs:
24
+ mode:
25
+ description: Validation tier (fast, audit, or release).
26
+ required: true
27
+ type: string
28
+ codeql:
29
+ description: Run the CodeQL lane (the consumer's canonical codeql config).
30
+ required: false
31
+ type: boolean
32
+ default: false
33
+ runtime-repository:
34
+ description: Repository containing the Code Foundry runtime.
35
+ required: false
36
+ type: string
37
+ default: 0xPlayerOne/code-foundry
38
+ runtime-ref:
39
+ description: Code Foundry runtime tag or ref.
40
+ required: false
41
+ type: string
42
+ default: v1.0.5
43
+ ci-runner:
44
+ description: Runner used by CI jobs and the merged fast-lanes job.
45
+ required: false
46
+ type: string
47
+ default: ubuntu-latest
48
+ test-runner:
49
+ description: Runner used by non-unit test jobs.
50
+ required: false
51
+ type: string
52
+ default: ubuntu-latest
53
+ unit-runner:
54
+ description: Runner used by unit tests.
55
+ required: false
56
+ type: string
57
+ default: ubuntu-slim
58
+ performance-runner:
59
+ description: Accepted for caller parity; the merged fast-lanes job runs performance on ci-runner.
60
+ required: false
61
+ type: string
62
+ default: ubuntu-latest
63
+ security-runner:
64
+ description: Runner used by the merged audit job.
65
+ required: false
66
+ type: string
67
+ default: ubuntu-slim
68
+ eval-runner:
69
+ description: Accepted for caller parity; the merged fast-lanes job runs eval on ci-runner.
70
+ required: false
71
+ type: string
72
+ default: ubuntu-latest
73
+ codeql-runner:
74
+ description: Runner used by CodeQL jobs.
75
+ required: false
76
+ type: string
77
+ default: ubuntu-latest
78
+ rust-shards:
79
+ description: JSON array of Rust scope sharding values. Use ["all"] for single-pass behavior.
80
+ required: false
81
+ type: string
82
+ default: '["all"]'
83
+ rust-threads:
84
+ description: Threads used for Rust extraction and analysis. Values above 1 opt into local parallelism.
85
+ required: false
86
+ type: string
87
+ default: '1'
88
+ rust-max-parallel:
89
+ description: Maximum Rust shard jobs allowed to run concurrently.
90
+ required: false
91
+ type: number
92
+ default: 1
93
+ artifact-prefix:
94
+ description: Prefix for task receipts; use a unique value when calling this workflow more than once.
95
+ required: false
96
+ type: string
97
+ default: task-result
98
+ e2e-shard-list:
99
+ description: Comma-separated E2E shard indices passed to the test lane's matrix, e.g. "1,2".
100
+ required: false
101
+ type: string
102
+ default: '1'
103
+ e2e-total-shards:
104
+ description: Total E2E shard count passed to the repository script as E2E_TOTAL_SHARDS.
105
+ required: false
106
+ type: string
107
+ default: '1'
108
+ secrets:
109
+ TURBO_TOKEN:
110
+ required: false
111
+ NEXTAUTH_SECRET:
112
+ required: false
113
+
114
+ # The orchestrator keeps the union of permissions needed by the chain it calls
115
+ # (CodeQL uploads require security-events: write). Nested reusable workflows
116
+ # can only maintain or reduce permissions, never elevate them.
117
+ permissions:
118
+ actions: read
119
+ contents: read
120
+ packages: read
121
+ security-events: write
122
+
123
+ env:
124
+ TURBO_API: ${{ vars.TURBO_API }}
125
+ TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
126
+ TURBO_TEAM: ${{ vars.TURBO_TEAM }}
127
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
128
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
129
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
130
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
131
+ REPO_FOUNDRY_RUNNER: ${{ vars.REPO_FOUNDRY_RUNNER }}
132
+ REPO_FOUNDRY_CACHE_PACKAGES: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
133
+ REPO_FOUNDRY_CACHE_BUILD: ${{ vars.REPO_FOUNDRY_CACHE_BUILD || 'auto' }}
134
+ REPO_FOUNDRY_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before || '' }}
135
+
136
+ concurrency:
137
+ group: code-foundry-validation-billing-${{ github.event_name }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
138
+ # Superseded pull-request runs are cancelled so the newest head owns the
139
+ # group; push and scheduled runs queue instead, because cancelling a main
140
+ # push can drop default-branch analysis or release-adjacent work.
141
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
142
+
143
+ jobs:
144
+ # Merged low-cost lanes. Each block below is a step-for-step mirror of the
145
+ # corresponding lane job in ci.yml, test.yml, or eval.yml; only the step ids
146
+ # are prefixed and subsequent lanes add !cancelled() so one lane's failure
147
+ # never hides another lane's result.
148
+ fast-lanes:
149
+ name: Fast lanes
150
+ if: vars.CI_BILLING_PAUSED != 'true'
151
+ runs-on: ${{ inputs.ci-runner }}
152
+ timeout-minutes: 45
153
+ steps:
154
+ - name: Checkout
155
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
156
+ with:
157
+ persist-credentials: false
158
+ fetch-depth: 2
159
+ - name: Runtime
160
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
161
+ with:
162
+ persist-credentials: false
163
+ repository: ${{ inputs.runtime-repository }}
164
+ ref: ${{ inputs.runtime-ref }}
165
+ path: .github/.code-foundry
166
+ sparse-checkout: |
167
+ .github/actions
168
+ src/lib
169
+ src/runtime-core.mjs
170
+ src/runtime.mjs
171
+ - name: Install runtime
172
+ run: |
173
+ mkdir -p .github/actions
174
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
175
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
176
+ # --- Format lane (mirror of ci.yml format) ---
177
+ - name: Detect format
178
+ id: format_applicability
179
+ env:
180
+ EVENT_NAME: ${{ github.event_name }}
181
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
182
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
183
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
184
+ BEFORE_SHA: ${{ github.event.before }}
185
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run format >> "$GITHUB_OUTPUT"
186
+ - name: Setup format
187
+ if: steps.format_applicability.outputs.applicable == 'true' && steps.format_applicability.outputs.affected != 'false'
188
+ uses: ./.github/actions/setup
189
+ with:
190
+ # Repository format scripts normally call a project-local formatter
191
+ # (for example, Oxfmt). Install dependencies before running them;
192
+ # otherwise a clean runner cannot resolve the declared tool.
193
+ install: 'true'
194
+ cache-format: 'true'
195
+ cache-lint: 'false'
196
+ cache-build: 'false'
197
+ task: format
198
+ - name: Format
199
+ id: format_execute
200
+ if: steps.format_applicability.outputs.applicable == 'true' && steps.format_applicability.outputs.affected != 'false'
201
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci format
202
+ - name: Retain format task receipt
203
+ if: >-
204
+ always() &&
205
+ (steps.format_execute.outcome == 'success' || steps.format_execute.outcome == 'failure' ||
206
+ steps.format_applicability.outputs.applicable == 'false' || steps.format_applicability.outputs.affected == 'false') &&
207
+ hashFiles('.code-foundry/results/format.json') != ''
208
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
209
+ with:
210
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-format
211
+ path: .code-foundry/results/format.json
212
+ include-hidden-files: true
213
+ if-no-files-found: error
214
+ retention-days: 14
215
+ # --- Build lane (mirror of ci.yml build) ---
216
+ - name: Detect build
217
+ id: build_applicability
218
+ if: ${{ !cancelled() }}
219
+ env:
220
+ EVENT_NAME: ${{ github.event_name }}
221
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
222
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
223
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
224
+ BEFORE_SHA: ${{ github.event.before }}
225
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run build >> "$GITHUB_OUTPUT"
226
+ - name: Setup build
227
+ if: ${{ !cancelled() && steps.build_applicability.outputs.applicable == 'true' && steps.build_applicability.outputs.affected != 'false' }}
228
+ uses: ./.github/actions/setup
229
+ with:
230
+ install: 'true'
231
+ cache-build: 'true'
232
+ task: build
233
+ env:
234
+ # Framework builds may validate server-side configuration at build
235
+ # time. Consumers can provide the real value; the fallback is
236
+ # intentionally CI-only and must never be used at runtime.
237
+ NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET || 'code-foundry-ci-placeholder-0123456789' }}
238
+ - name: Build
239
+ id: build_execute
240
+ if: ${{ !cancelled() && steps.build_applicability.outputs.applicable == 'true' && steps.build_applicability.outputs.affected != 'false' }}
241
+ env:
242
+ NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET || 'code-foundry-ci-placeholder-0123456789' }}
243
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci build
244
+ - name: Retain build task receipt
245
+ if: >-
246
+ always() &&
247
+ (steps.build_execute.outcome == 'success' || steps.build_execute.outcome == 'failure' ||
248
+ steps.build_applicability.outputs.applicable == 'false' || steps.build_applicability.outputs.affected == 'false') &&
249
+ hashFiles('.code-foundry/results/build.json') != ''
250
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
251
+ with:
252
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-build
253
+ path: .code-foundry/results/build.json
254
+ include-hidden-files: true
255
+ if-no-files-found: error
256
+ retention-days: 14
257
+ # --- Performance lane (mirror of test.yml performance; audit tier only) ---
258
+ - name: Detect performance
259
+ id: performance_applicability
260
+ if: ${{ !cancelled() && inputs.mode == 'audit' }}
261
+ env:
262
+ EVENT_NAME: ${{ github.event_name }}
263
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
264
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
265
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
266
+ BEFORE_SHA: ${{ github.event.before }}
267
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile performance >> "$GITHUB_OUTPUT"
268
+ - name: Setup performance
269
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.performance_applicability.outputs.applicable == 'true' && steps.performance_applicability.outputs.affected != 'false' }}
270
+ uses: ./.github/actions/setup
271
+ with:
272
+ install: true
273
+ install-javascript: ${{ steps.performance_applicability.outputs.javascript == 'true' }}
274
+ install-python: ${{ steps.performance_applicability.outputs.python == 'true' }}
275
+ install-rust: ${{ steps.performance_applicability.outputs.rust == 'true' }}
276
+ cache-build: false
277
+ cache-environment: false
278
+ cache-save: false
279
+ cache-packages: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
280
+ task: performance
281
+ task-javascript: ${{ steps.performance_applicability.outputs.javascript }}
282
+ task-python: ${{ steps.performance_applicability.outputs.python }}
283
+ task-rust: ${{ steps.performance_applicability.outputs.rust }}
284
+ - name: Performance
285
+ id: performance_execute
286
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.performance_applicability.outputs.applicable == 'true' && steps.performance_applicability.outputs.affected != 'false' }}
287
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci performance
288
+ - name: Retain performance task receipt
289
+ if: >-
290
+ always() &&
291
+ inputs.mode == 'audit' &&
292
+ (steps.performance_execute.outcome == 'success' || steps.performance_execute.outcome == 'failure' ||
293
+ steps.performance_applicability.outputs.applicable == 'false' || steps.performance_applicability.outputs.affected == 'false') &&
294
+ hashFiles('.code-foundry/results/performance.json') != ''
295
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
296
+ with:
297
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-performance
298
+ path: .code-foundry/results/performance.json
299
+ include-hidden-files: true
300
+ if-no-files-found: error
301
+ retention-days: 14
302
+ - name: Upload performance results
303
+ if: >-
304
+ always() &&
305
+ inputs.mode == 'audit' &&
306
+ steps.performance_applicability.outputs.applicable == 'true' &&
307
+ hashFiles('artifacts/performance/**', 'performance-results.json', 'performance-results/**') != ''
308
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
309
+ with:
310
+ name: performance-${{ github.run_id }}
311
+ path: |
312
+ artifacts/performance/**
313
+ performance-results.json
314
+ performance-results/**
315
+ compression-level: 1
316
+ if-no-files-found: ignore
317
+ retention-days: 14
318
+ # --- Smoke lane (mirror of test.yml smoke; audit tier only) ---
319
+ - name: Detect smoke
320
+ id: smoke_applicability
321
+ if: ${{ !cancelled() && inputs.mode == 'audit' }}
322
+ env:
323
+ EVENT_NAME: ${{ github.event_name }}
324
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
325
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
326
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
327
+ BEFORE_SHA: ${{ github.event.before }}
328
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile smoke >> "$GITHUB_OUTPUT"
329
+ - name: Setup smoke
330
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.smoke_applicability.outputs.applicable == 'true' && steps.smoke_applicability.outputs.affected != 'false' }}
331
+ uses: ./.github/actions/setup
332
+ with:
333
+ install: true
334
+ install-javascript: ${{ steps.smoke_applicability.outputs.javascript == 'true' }}
335
+ install-python: ${{ steps.smoke_applicability.outputs.python == 'true' }}
336
+ install-rust: ${{ steps.smoke_applicability.outputs.rust == 'true' }}
337
+ cache-build: false
338
+ cache-environment: false
339
+ cache-save: ${{ github.event_name == 'push' }}
340
+ cache-packages: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
341
+ task: smoke
342
+ task-javascript: ${{ steps.smoke_applicability.outputs.javascript }}
343
+ task-python: ${{ steps.smoke_applicability.outputs.python }}
344
+ task-rust: ${{ steps.smoke_applicability.outputs.rust }}
345
+ - name: Smoke
346
+ id: smoke_execute
347
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.smoke_applicability.outputs.applicable == 'true' && steps.smoke_applicability.outputs.affected != 'false' }}
348
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci smoke
349
+ - name: Retain smoke task receipt
350
+ if: >-
351
+ always() &&
352
+ inputs.mode == 'audit' &&
353
+ (steps.smoke_execute.outcome == 'success' || steps.smoke_execute.outcome == 'failure' ||
354
+ steps.smoke_applicability.outputs.applicable == 'false' || steps.smoke_applicability.outputs.affected == 'false') &&
355
+ hashFiles('.code-foundry/results/smoke.json') != ''
356
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
357
+ with:
358
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-smoke
359
+ path: .code-foundry/results/smoke.json
360
+ include-hidden-files: true
361
+ if-no-files-found: error
362
+ retention-days: 14
363
+ # --- Eval lane (mirror of eval.yml; audit tier only) ---
364
+ - name: Detect eval
365
+ id: eval_applicability
366
+ if: ${{ !cancelled() && inputs.mode == 'audit' }}
367
+ env:
368
+ EVENT_NAME: ${{ github.event_name }}
369
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
370
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
371
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
372
+ BEFORE_SHA: ${{ github.event.before }}
373
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run eval >> "$GITHUB_OUTPUT"
374
+ - name: Setup eval
375
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.eval_applicability.outputs.applicable == 'true' && steps.eval_applicability.outputs.affected != 'false' }}
376
+ uses: ./.github/actions/setup
377
+ with:
378
+ # Eval harnesses run through the repository's own package scripts and
379
+ # need their dependencies installed before the task executes.
380
+ install: 'true'
381
+ cache-build: 'true'
382
+ task: eval
383
+ - name: Eval
384
+ id: eval_execute
385
+ if: ${{ !cancelled() && inputs.mode == 'audit' && steps.eval_applicability.outputs.applicable == 'true' && steps.eval_applicability.outputs.affected != 'false' }}
386
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci eval
387
+ - name: Retain eval task receipt
388
+ if: >-
389
+ always() &&
390
+ inputs.mode == 'audit' &&
391
+ (steps.eval_execute.outcome == 'success' || steps.eval_execute.outcome == 'failure' ||
392
+ steps.eval_applicability.outputs.applicable == 'false' || steps.eval_applicability.outputs.affected == 'false') &&
393
+ hashFiles('.code-foundry/results/eval.json') != ''
394
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
395
+ with:
396
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-eval
397
+ path: .code-foundry/results/eval.json
398
+ include-hidden-files: true
399
+ if-no-files-found: error
400
+ retention-days: 14
401
+ - name: Retain eval report
402
+ if: >-
403
+ always() &&
404
+ inputs.mode == 'audit' &&
405
+ steps.eval_execute.outcome == 'failure' &&
406
+ hashFiles('eval-results/result.json') != ''
407
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
408
+ with:
409
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-eval-report
410
+ path: |
411
+ eval-results/result.json
412
+ eval-results/summary.json
413
+ if-no-files-found: error
414
+ retention-days: 14
415
+
416
+ lint:
417
+ name: Lint
418
+ if: vars.CI_BILLING_PAUSED != 'true'
419
+ runs-on: ${{ inputs.ci-runner }}
420
+ timeout-minutes: 30
421
+ steps:
422
+ - name: Checkout
423
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
424
+ with:
425
+ persist-credentials: false
426
+ - name: Runtime
427
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
428
+ with:
429
+ persist-credentials: false
430
+ repository: ${{ inputs.runtime-repository }}
431
+ ref: ${{ inputs.runtime-ref }}
432
+ path: .github/.code-foundry
433
+ sparse-checkout: |
434
+ .github/actions
435
+ src/lib
436
+ src/runtime-core.mjs
437
+ src/runtime.mjs
438
+ - name: Install runtime
439
+ run: |
440
+ mkdir -p .github/actions
441
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
442
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
443
+ - name: Detect
444
+ id: applicability
445
+ env:
446
+ EVENT_NAME: ${{ github.event_name }}
447
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
448
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
449
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
450
+ BEFORE_SHA: ${{ github.event.before }}
451
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run lint >> "$GITHUB_OUTPUT"
452
+ - name: Setup
453
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
454
+ uses: ./.github/actions/setup
455
+ with:
456
+ install: 'true'
457
+ cache-lint: 'true'
458
+ task: lint
459
+ - name: Lint
460
+ id: execute
461
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
462
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci lint
463
+ - name: Retain task receipt
464
+ if: >-
465
+ always() &&
466
+ (steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
467
+ steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
468
+ hashFiles('.code-foundry/results/lint.json') != ''
469
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
470
+ with:
471
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-lint
472
+ path: .code-foundry/results/lint.json
473
+ include-hidden-files: true
474
+ if-no-files-found: error
475
+ retention-days: 14
476
+
477
+ type-check:
478
+ name: Type-Check
479
+ if: vars.CI_BILLING_PAUSED != 'true'
480
+ runs-on: ${{ inputs.ci-runner }}
481
+ timeout-minutes: 30
482
+ steps:
483
+ - name: Checkout
484
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
485
+ with:
486
+ persist-credentials: false
487
+ - name: Runtime
488
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
489
+ with:
490
+ persist-credentials: false
491
+ repository: ${{ inputs.runtime-repository }}
492
+ ref: ${{ inputs.runtime-ref }}
493
+ path: .github/.code-foundry
494
+ sparse-checkout: |
495
+ .github/actions
496
+ src/lib
497
+ src/runtime-core.mjs
498
+ src/runtime.mjs
499
+ - name: Install runtime
500
+ run: |
501
+ mkdir -p .github/actions
502
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
503
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
504
+ - name: Detect
505
+ id: applicability
506
+ env:
507
+ EVENT_NAME: ${{ github.event_name }}
508
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
509
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
510
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
511
+ BEFORE_SHA: ${{ github.event.before }}
512
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run type_check >> "$GITHUB_OUTPUT"
513
+ - name: Setup
514
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
515
+ uses: ./.github/actions/setup
516
+ with:
517
+ install: 'true'
518
+ cache-build: 'true'
519
+ task: type_check
520
+ - name: Type-Check
521
+ id: execute
522
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
523
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci type_check
524
+ - name: Retain task receipt
525
+ if: >-
526
+ always() &&
527
+ (steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
528
+ steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
529
+ hashFiles('.code-foundry/results/type_check.json') != ''
530
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
531
+ with:
532
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-type_check
533
+ path: .code-foundry/results/type_check.json
534
+ include-hidden-files: true
535
+ if-no-files-found: error
536
+ retention-days: 14
537
+
538
+ unit:
539
+ name: Unit
540
+ if: vars.CI_BILLING_PAUSED != 'true'
541
+ runs-on: ${{ inputs.unit-runner }}
542
+ timeout-minutes: 30
543
+ steps:
544
+ - name: Checkout
545
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
546
+ with:
547
+ persist-credentials: false
548
+ fetch-depth: 2
549
+ - name: Runtime
550
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
551
+ with:
552
+ persist-credentials: false
553
+ repository: ${{ inputs.runtime-repository }}
554
+ ref: ${{ inputs.runtime-ref }}
555
+ path: .github/.code-foundry
556
+ sparse-checkout: |
557
+ .github/actions
558
+ src/lib
559
+ src/runtime-core.mjs
560
+ src/runtime.mjs
561
+ - name: Install runtime
562
+ run: |
563
+ mkdir -p .github/actions
564
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
565
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
566
+ - name: Detect
567
+ id: applicability
568
+ env:
569
+ EVENT_NAME: ${{ github.event_name }}
570
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
571
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
572
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
573
+ BEFORE_SHA: ${{ github.event.before }}
574
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile unit >> "$GITHUB_OUTPUT"
575
+ - name: Setup
576
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
577
+ uses: ./.github/actions/setup
578
+ with:
579
+ install: true
580
+ install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
581
+ install-python: ${{ steps.applicability.outputs.python == 'true' }}
582
+ install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
583
+ cache-build: false
584
+ cache-environment: false
585
+ cache-packages: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
586
+ task: unit
587
+ task-javascript: ${{ steps.applicability.outputs.javascript }}
588
+ task-python: ${{ steps.applicability.outputs.python }}
589
+ task-rust: ${{ steps.applicability.outputs.rust }}
590
+ - name: Unit
591
+ id: execute
592
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
593
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci unit
594
+ - name: Retain task receipt
595
+ if: >-
596
+ always() &&
597
+ (steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
598
+ steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
599
+ hashFiles('.code-foundry/results/unit.json') != ''
600
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
601
+ with:
602
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-unit
603
+ path: .code-foundry/results/unit.json
604
+ include-hidden-files: true
605
+ if-no-files-found: error
606
+ retention-days: 14
607
+ - name: Upload coverage
608
+ if: >-
609
+ always() &&
610
+ steps.applicability.outputs.applicable == 'true' &&
611
+ hashFiles('coverage/**', 'htmlcov/**', '.coverage*', 'target/llvm-cov/**') != ''
612
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
613
+ with:
614
+ name: coverage-unit-${{ github.run_id }}
615
+ path: |
616
+ coverage/**
617
+ htmlcov/**
618
+ .coverage*
619
+ target/llvm-cov/**
620
+ compression-level: 1
621
+ if-no-files-found: ignore
622
+ retention-days: 14
623
+
624
+ integration:
625
+ name: Integration
626
+ if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
627
+ runs-on: ${{ inputs.test-runner }}
628
+ timeout-minutes: 30
629
+ steps:
630
+ - name: Checkout
631
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
632
+ with:
633
+ persist-credentials: false
634
+ fetch-depth: 2
635
+ - name: Runtime
636
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
637
+ with:
638
+ persist-credentials: false
639
+ repository: ${{ inputs.runtime-repository }}
640
+ ref: ${{ inputs.runtime-ref }}
641
+ path: .github/.code-foundry
642
+ sparse-checkout: |
643
+ .github/actions
644
+ src/lib
645
+ src/runtime-core.mjs
646
+ src/runtime.mjs
647
+ - name: Install runtime
648
+ run: |
649
+ mkdir -p .github/actions
650
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
651
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
652
+ - name: Detect
653
+ id: applicability
654
+ env:
655
+ EVENT_NAME: ${{ github.event_name }}
656
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
657
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
658
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
659
+ BEFORE_SHA: ${{ github.event.before }}
660
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile integration >> "$GITHUB_OUTPUT"
661
+ - name: Setup
662
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
663
+ uses: ./.github/actions/setup
664
+ with:
665
+ install: true
666
+ install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
667
+ install-python: ${{ steps.applicability.outputs.python == 'true' }}
668
+ install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
669
+ cache-build: ${{ steps.applicability.outputs.rust == 'true' }}
670
+ cache-environment: false
671
+ cache-save: ${{ github.event_name == 'push' }}
672
+ task: integration
673
+ task-javascript: ${{ steps.applicability.outputs.javascript }}
674
+ task-python: ${{ steps.applicability.outputs.python }}
675
+ task-rust: ${{ steps.applicability.outputs.rust }}
676
+ - name: Integration
677
+ id: execute
678
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
679
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci integration
680
+ - name: Retain task receipt
681
+ if: >-
682
+ always() &&
683
+ (steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
684
+ steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
685
+ hashFiles('.code-foundry/results/integration.json') != ''
686
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
687
+ with:
688
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-integration
689
+ path: .code-foundry/results/integration.json
690
+ include-hidden-files: true
691
+ if-no-files-found: error
692
+ retention-days: 14
693
+
694
+ e2e:
695
+ name: E2E
696
+ if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
697
+ runs-on: ${{ inputs.test-runner }}
698
+ timeout-minutes: 45
699
+ # Shards duplicate the whole job, but each shard owns a runner-local test
700
+ # database (repositories without DATABASE_URL fall back to their own local
701
+ # compose services), so shards stay isolated. A single-entry matrix keeps
702
+ # the unsharded default byte-compatible with the pre-matrix job.
703
+ strategy:
704
+ fail-fast: false
705
+ matrix:
706
+ shard: ${{ fromJson(format('[{0}]', inputs.e2e-shard-list)) }}
707
+ steps:
708
+ - name: Checkout
709
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
710
+ with:
711
+ persist-credentials: false
712
+ fetch-depth: 2
713
+ - name: Runtime
714
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
715
+ with:
716
+ persist-credentials: false
717
+ repository: ${{ inputs.runtime-repository }}
718
+ ref: ${{ inputs.runtime-ref }}
719
+ path: .github/.code-foundry
720
+ sparse-checkout: |
721
+ .github/actions
722
+ src/lib
723
+ src/runtime-core.mjs
724
+ src/runtime.mjs
725
+ - name: Install runtime
726
+ run: |
727
+ mkdir -p .github/actions
728
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
729
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
730
+ - name: Detect
731
+ id: applicability
732
+ env:
733
+ EVENT_NAME: ${{ github.event_name }}
734
+ BASE_REF: ${{ github.event.pull_request.base.ref }}
735
+ BASE_SHA: ${{ github.event.pull_request.base.sha }}
736
+ HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
737
+ BEFORE_SHA: ${{ github.event.before }}
738
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile e2e >> "$GITHUB_OUTPUT"
739
+ - name: Cache browser binaries
740
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false' && steps.applicability.outputs.browser == 'true'
741
+ uses: ./.github/actions/cache
742
+ with:
743
+ save: ${{ github.event_name == 'push' }}
744
+ path: |
745
+ ~/.cache/ms-playwright
746
+ ~/.cache/Cypress
747
+ ~/.cache/puppeteer
748
+ key: ${{ runner.os }}-e2e-browsers-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/playwright.config.*', '**/cypress.config.*') }}
749
+ restore-keys: |
750
+ ${{ runner.os }}-e2e-browsers-
751
+ - name: Setup
752
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
753
+ uses: ./.github/actions/setup
754
+ with:
755
+ install: true
756
+ install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
757
+ install-python: ${{ steps.applicability.outputs.python == 'true' }}
758
+ install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
759
+ cache-build: false
760
+ cache-environment: false
761
+ cache-save: ${{ github.event_name == 'push' }}
762
+ task: e2e
763
+ task-javascript: ${{ steps.applicability.outputs.javascript }}
764
+ task-python: ${{ steps.applicability.outputs.python }}
765
+ task-rust: ${{ steps.applicability.outputs.rust }}
766
+ - name: E2E
767
+ id: execute
768
+ if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
769
+ env:
770
+ E2E_SHARD_INDEX: ${{ matrix.shard }}
771
+ E2E_TOTAL_SHARDS: ${{ inputs.e2e-total-shards }}
772
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci e2e
773
+ - name: Retain task receipt
774
+ if: >-
775
+ always() &&
776
+ (steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
777
+ steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
778
+ hashFiles('.code-foundry/results/e2e.json') != ''
779
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
780
+ with:
781
+ name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-e2e${{ inputs.e2e-total-shards != '1' && format('-s{0}', matrix.shard) || '' }}
782
+ path: .code-foundry/results/e2e.json
783
+ include-hidden-files: true
784
+ if-no-files-found: error
785
+ retention-days: 14
786
+
787
+ # Profile and dependency audit merged into one job. The split orchestrators
788
+ # run a profile job that feeds an audit matrix; here the language blocks run
789
+ # sequentially, driven directly by the profile step's outputs, so the second
790
+ # runner spin-up disappears. Python requirements run in one loop inside the
791
+ # audit step because a matrix cannot follow preceding steps in the same job.
792
+ audit:
793
+ name: Audit
794
+ if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
795
+ runs-on: ${{ inputs.security-runner }}
796
+ timeout-minutes: 30
797
+ steps:
798
+ - name: Checkout
799
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
800
+ with:
801
+ persist-credentials: false
802
+ fetch-depth: 2
803
+ filter: blob:none
804
+ sparse-checkout: |
805
+ .github
806
+ .mise.toml
807
+ mise.lock
808
+ .npmrc
809
+ .pnpmfile.cjs
810
+ .yarnrc*
811
+ **/package.json
812
+ **/bun.lock
813
+ **/bun.lockb
814
+ **/pnpm-lock.yaml
815
+ **/yarn.lock
816
+ **/package-lock.json
817
+ **/Cargo.toml
818
+ **/Cargo.lock
819
+ **/.cargo/**
820
+ **/pyproject.toml
821
+ **/requirements*.txt
822
+ **/setup.py
823
+ **/setup.cfg
824
+ **/Pipfile
825
+ **/Pipfile.lock
826
+ **/poetry.lock
827
+ **/uv.lock
828
+ sparse-checkout-cone-mode: false
829
+ - name: Runtime
830
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
831
+ with:
832
+ persist-credentials: false
833
+ repository: ${{ inputs.runtime-repository }}
834
+ ref: ${{ inputs.runtime-ref }}
835
+ path: .github/.code-foundry
836
+ sparse-checkout: |
837
+ .github/actions
838
+ src/lib
839
+ src/runtime-core.mjs
840
+ src/runtime.mjs
841
+ - name: Install runtime
842
+ run: |
843
+ mkdir -p .github/actions
844
+ mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
845
+ cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
846
+ - name: Detect
847
+ id: profile
848
+ env:
849
+ REPO_FOUNDRY_PRIVATE: ${{ github.event.repository.private }}
850
+ REPO_FOUNDRY_VISIBILITY: ${{ github.event.repository.visibility }}
851
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security profile >> "$GITHUB_OUTPUT"
852
+ - name: Dependency Review
853
+ if: ${{ github.event_name == 'pull_request' && steps.profile.outputs.dependency_review == 'true' }}
854
+ uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
855
+ with:
856
+ fail-on-severity: high
857
+ license-check: true
858
+ - name: Detect audit toolchain
859
+ id: audit-toolchain
860
+ if: steps.profile.outputs.javascript == 'true' || steps.profile.outputs.rust == 'true' || steps.profile.outputs.python == 'true'
861
+ shell: bash
862
+ env:
863
+ REPO_FOUNDRY_LANGUAGE: ${{ steps.profile.outputs.javascript == 'true' && 'javascript' || (steps.profile.outputs.rust == 'true' && 'rust' || 'python') }}
864
+ run: |
865
+ toolchain=auto
866
+ configured_toolchain=''
867
+ configured_package_manager=''
868
+ if [ -f .github/code-foundry.yml ]; then
869
+ configured_toolchain="$(awk -F': ' '/^toolchain:/ {print $2; exit}' .github/code-foundry.yml)"
870
+ configured_package_manager="$(awk -F': ' '/^package_manager:/ {print $2; exit}' .github/code-foundry.yml)"
871
+ fi
872
+ [ -n "$configured_toolchain" ] && toolchain="$configured_toolchain"
873
+ if [ "$toolchain" = auto ] && [ -f .mise.toml ]; then toolchain=mise; fi
874
+
875
+ package_manager=none
876
+ case "$configured_package_manager" in
877
+ bun|pnpm|yarn|npm|none) package_manager="$configured_package_manager" ;;
878
+ *)
879
+ if [ -f bun.lock ] || [ -f bun.lockb ]; then package_manager=bun
880
+ elif [ -f pnpm-lock.yaml ]; then package_manager=pnpm
881
+ elif [ -f yarn.lock ]; then package_manager=yarn
882
+ elif [ -f package-lock.json ]; then package_manager=npm
883
+ elif [ -f package.json ]; then package_manager=bun
884
+ fi
885
+ ;;
886
+ esac
887
+
888
+ mise_tools=''
889
+ configured_tool() {
890
+ [ -f .mise.toml ] && grep -Eq "^$1[[:space:]]*=" .mise.toml
891
+ }
892
+ add_mise_tool() {
893
+ configured_tool "$1" || return 0
894
+ if [ -n "$mise_tools" ]; then mise_tools="$mise_tools $1"; else mise_tools="$1"; fi
895
+ }
896
+ if [ "$toolchain" = mise ] && [ -f .mise.toml ]; then
897
+ case "$REPO_FOUNDRY_LANGUAGE" in
898
+ javascript)
899
+ add_mise_tool node
900
+ [ "$package_manager" = bun ] && add_mise_tool bun
901
+ ;;
902
+ python)
903
+ add_mise_tool python
904
+ add_mise_tool uv
905
+ add_mise_tool ruff
906
+ ;;
907
+ rust) add_mise_tool rust ;;
908
+ esac
909
+ fi
910
+
911
+ {
912
+ printf 'toolchain_mode=%s\n' "$toolchain"
913
+ printf 'package_manager=%s\n' "$package_manager"
914
+ printf 'mise_tools=%s\n' "$mise_tools"
915
+ } >> "$GITHUB_OUTPUT"
916
+ - name: Setup mise toolchain
917
+ if: steps.audit-toolchain.outputs.mise_tools != ''
918
+ uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4
919
+ with:
920
+ version: 2026.9.2
921
+ cache: false
922
+ install_args: ${{ steps.audit-toolchain.outputs.mise_tools }}
923
+ # --- JavaScript audit block ---
924
+ - name: Detect JavaScript
925
+ id: applicability-javascript
926
+ if: steps.profile.outputs.javascript == 'true'
927
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security should_run javascript >> "$GITHUB_OUTPUT"
928
+ - name: Setup Node
929
+ if: >-
930
+ steps.profile.outputs.javascript == 'true' &&
931
+ steps.applicability-javascript.outputs.applicable == 'true' &&
932
+ steps.audit-toolchain.outputs.toolchain_mode != 'mise' &&
933
+ steps.audit-toolchain.outputs.package_manager != 'bun' &&
934
+ steps.audit-toolchain.outputs.package_manager != 'none'
935
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
936
+ with:
937
+ node-version: 24
938
+ - name: Setup Bun
939
+ if: >-
940
+ steps.profile.outputs.javascript == 'true' &&
941
+ steps.applicability-javascript.outputs.applicable == 'true' &&
942
+ steps.audit-toolchain.outputs.toolchain_mode != 'mise' &&
943
+ steps.audit-toolchain.outputs.package_manager == 'bun'
944
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
945
+ with:
946
+ bun-version: 1.4.0
947
+ - name: Enable Corepack
948
+ if: >-
949
+ steps.profile.outputs.javascript == 'true' &&
950
+ steps.applicability-javascript.outputs.applicable == 'true' &&
951
+ (steps.audit-toolchain.outputs.package_manager == 'pnpm' ||
952
+ steps.audit-toolchain.outputs.package_manager == 'yarn')
953
+ shell: bash
954
+ run: corepack enable
955
+ - name: Audit JavaScript dependencies
956
+ if: >-
957
+ steps.profile.outputs.javascript == 'true' &&
958
+ steps.applicability-javascript.outputs.applicable == 'true'
959
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security audit javascript
960
+ # --- Rust audit block ---
961
+ - name: Checkout Rust
962
+ if: steps.profile.outputs.rust == 'true'
963
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
964
+ with:
965
+ persist-credentials: false
966
+ filter: blob:none
967
+ path: .audit-worktree
968
+ sparse-checkout: |
969
+ .github
970
+ .mise.toml
971
+ mise.lock
972
+ **/Cargo.toml
973
+ **/Cargo.lock
974
+ **/.cargo/**
975
+ sparse-checkout-cone-mode: false
976
+ - name: Detect Rust
977
+ id: applicability-rust
978
+ if: steps.profile.outputs.rust == 'true'
979
+ working-directory: .audit-worktree
980
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security should_run rust >> "$GITHUB_OUTPUT"
981
+ - name: Check Rust
982
+ id: system-rust
983
+ if: >-
984
+ steps.profile.outputs.rust == 'true' &&
985
+ steps.applicability-rust.outputs.applicable == 'true'
986
+ shell: bash
987
+ run: |
988
+ if command -v cargo >/dev/null 2>&1 && command -v rustc >/dev/null 2>&1; then
989
+ cargo --version
990
+ rustc --version
991
+ echo 'available=true' >> "$GITHUB_OUTPUT"
992
+ else
993
+ echo 'available=false' >> "$GITHUB_OUTPUT"
994
+ fi
995
+ - name: Setup Rust
996
+ if: >-
997
+ steps.profile.outputs.rust == 'true' &&
998
+ steps.applicability-rust.outputs.applicable == 'true' &&
999
+ steps.audit-toolchain.outputs.toolchain_mode != 'mise' &&
1000
+ steps.system-rust.outputs.available != 'true'
1001
+ uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable
1002
+ - name: Install cargo-audit
1003
+ if: >-
1004
+ steps.profile.outputs.rust == 'true' &&
1005
+ steps.applicability-rust.outputs.applicable == 'true'
1006
+ uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
1007
+ with:
1008
+ tool: cargo-audit
1009
+ - name: Audit Rust dependencies
1010
+ if: >-
1011
+ steps.profile.outputs.rust == 'true' &&
1012
+ steps.applicability-rust.outputs.applicable == 'true'
1013
+ working-directory: .audit-worktree
1014
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security audit rust
1015
+ # --- Python audit block ---
1016
+ - name: Checkout Python
1017
+ if: steps.profile.outputs.python == 'true'
1018
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
1019
+ with:
1020
+ persist-credentials: false
1021
+ filter: blob:none
1022
+ path: .audit-worktree
1023
+ sparse-checkout: |
1024
+ .github
1025
+ .mise.toml
1026
+ mise.lock
1027
+ **/pyproject.toml
1028
+ **/requirements*.txt
1029
+ **/setup.py
1030
+ **/setup.cfg
1031
+ **/Pipfile
1032
+ **/Pipfile.lock
1033
+ **/poetry.lock
1034
+ **/uv.lock
1035
+ sparse-checkout-cone-mode: false
1036
+ - name: Detect Python
1037
+ id: applicability-python
1038
+ if: steps.profile.outputs.python == 'true'
1039
+ working-directory: .audit-worktree
1040
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security should_run python >> "$GITHUB_OUTPUT"
1041
+ - name: Setup Python
1042
+ if: >-
1043
+ steps.profile.outputs.python == 'true' &&
1044
+ steps.applicability-python.outputs.applicable == 'true' &&
1045
+ steps.audit-toolchain.outputs.toolchain_mode != 'mise'
1046
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
1047
+ with:
1048
+ python-version: '3.13'
1049
+ - name: Check uv
1050
+ id: uv
1051
+ if: steps.profile.outputs.python == 'true' && steps.applicability-python.outputs.applicable == 'true'
1052
+ shell: bash
1053
+ run: |
1054
+ if command -v uv >/dev/null 2>&1; then
1055
+ echo 'available=true' >> "$GITHUB_OUTPUT"
1056
+ else
1057
+ echo 'available=false' >> "$GITHUB_OUTPUT"
1058
+ fi
1059
+ - name: Setup uv
1060
+ if: >-
1061
+ steps.profile.outputs.python == 'true' &&
1062
+ steps.applicability-python.outputs.applicable == 'true' &&
1063
+ steps.uv.outputs.available != 'true'
1064
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
1065
+ with:
1066
+ version: 0.11.32
1067
+ enable-cache: false
1068
+ - name: Audit Python dependencies
1069
+ if: steps.profile.outputs.python == 'true' && steps.applicability-python.outputs.applicable == 'true'
1070
+ working-directory: .audit-worktree
1071
+ shell: bash
1072
+ env:
1073
+ REQUIREMENTS_JSON: ${{ steps.profile.outputs.python_requirements }}
1074
+ run: |
1075
+ # The split orchestrator fans one matrix job out per Python
1076
+ # requirement; a single merged job loops over them instead.
1077
+ requirements=''
1078
+ if [ -n "$REQUIREMENTS_JSON" ] && [ "$REQUIREMENTS_JSON" != '[]' ]; then
1079
+ requirements="$(node -e '
1080
+ const parsed = JSON.parse(process.argv[1] || "[]");
1081
+ console.log(parsed.filter((item) => item && item !== "none").join("\n"));
1082
+ ' "$REQUIREMENTS_JSON")"
1083
+ fi
1084
+ if [ -z "$requirements" ]; then
1085
+ node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security audit python
1086
+ else
1087
+ while IFS= read -r requirement; do
1088
+ [ -n "$requirement" ] || continue
1089
+ echo "Auditing Python requirements set: $requirement"
1090
+ REPO_FOUNDRY_PYTHON_REQUIREMENT="$requirement" \
1091
+ node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" security audit python
1092
+ done <<< "$requirements"
1093
+ fi
1094
+
1095
+ codeql:
1096
+ name: CodeQL
1097
+ # Release-please pull requests also analyze with CodeQL so repository
1098
+ # rulesets requiring code scanning results never deadlock the release.
1099
+ if: vars.CI_BILLING_PAUSED != 'true' && inputs.codeql == true && (inputs.mode == 'audit' || inputs.mode == 'release')
1100
+ uses: ./.github/workflows/codeql.yml
1101
+ with:
1102
+ runtime-repository: ${{ inputs.runtime-repository }}
1103
+ runtime-ref: ${{ inputs.runtime-ref }}
1104
+ runner: ${{ inputs.codeql-runner }}
1105
+ rust-shards: ${{ inputs.rust-shards }}
1106
+ rust-threads: ${{ inputs.rust-threads }}
1107
+ rust-max-parallel: ${{ inputs.rust-max-parallel }}
1108
+
1109
+ # Aggregate check: "Validation / Gate" (caller job name + this job name).
1110
+ # Always evaluates; only jobs required for the mode must have succeeded.
1111
+ # Category results fold the merged job's lanes back into the same FOUNDRY_*
1112
+ # vocabulary the split orchestrators feed the runtime gate, so
1113
+ # evaluateValidationGate's mode truth table is reused unchanged.
1114
+ gate:
1115
+ name: Gate
1116
+ needs: [fast-lanes, lint, type-check, unit, integration, e2e, audit, codeql]
1117
+ if: vars.CI_BILLING_PAUSED != 'true' && always()
1118
+ runs-on: ubuntu-slim
1119
+ timeout-minutes: 10
1120
+ env:
1121
+ FOUNDRY_MODE: ${{ inputs.mode }}
1122
+ # CI category: lint and type-check always run; the merged fast-lanes job
1123
+ # carries the format and build lanes.
1124
+ FOUNDRY_CI: ${{ (needs.lint.result != 'success' && needs.lint.result) || (needs.type-check.result != 'success' && needs.type-check.result) || (needs.fast-lanes.result != 'success' && needs.fast-lanes.result) || 'success' }}
1125
+ # Test category: unit always runs and must succeed; integration and e2e
1126
+ # are audit-tier jobs whose expected skip on fast/release is not a
1127
+ # failure; the merged fast-lanes job carries performance, smoke, and
1128
+ # eval-mode lanes, so its result joins the category too.
1129
+ FOUNDRY_TEST: ${{ needs.unit.result == 'success' && needs.fast-lanes.result == 'success' && (needs.integration.result == 'success' || needs.integration.result == 'skipped') && (needs.e2e.result == 'success' || needs.e2e.result == 'skipped') && 'success' || ((needs.integration.result != 'success' && needs.integration.result != 'skipped' && needs.integration.result) || (needs.e2e.result != 'success' && needs.e2e.result != 'skipped' && needs.e2e.result) || (needs.unit.result != 'success' && needs.unit.result) || (needs.fast-lanes.result != 'success' && needs.fast-lanes.result) || 'failure') }}
1130
+ FOUNDRY_SECURITY: ${{ needs.audit.result }}
1131
+ # This orchestrator runs CodeQL only when the consumer's canonical
1132
+ # configuration enables it; otherwise the unavailability decision is
1133
+ # treated as satisfied without registering a skipped PR check.
1134
+ FOUNDRY_CODEQL: ${{ inputs.codeql == true && needs.codeql.result || 'success' }}
1135
+ # Eval runs inside the merged fast-lanes job on the audit tier; a
1136
+ # fast-lanes failure on that tier marks the eval category failed even if
1137
+ # another merged lane caused it, which fails closed.
1138
+ FOUNDRY_EVAL: ${{ needs.fast-lanes.result }}
1139
+ steps:
1140
+ - name: Checkout runtime
1141
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
1142
+ with:
1143
+ persist-credentials: false
1144
+ repository: ${{ inputs.runtime-repository }}
1145
+ ref: ${{ inputs.runtime-ref }}
1146
+ path: .github/.code-foundry
1147
+ sparse-checkout: |
1148
+ src/lib
1149
+ src/runtime-core.mjs
1150
+ src/runtime.mjs
1151
+ - name: Install runtime
1152
+ run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
1153
+ - name: Checkout consumer repository
1154
+ if: ${{ inputs.mode == 'release' }}
1155
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
1156
+ with:
1157
+ persist-credentials: false
1158
+ fetch-depth: 0
1159
+ filter: blob:none
1160
+ - name: Validate generated release diff
1161
+ if: ${{ inputs.mode == 'release' }}
1162
+ env:
1163
+ FOUNDRY_BASE_SHA: ${{ github.event.pull_request.base.sha }}
1164
+ FOUNDRY_HEAD_REF: ${{ github.event.pull_request.head.ref }}
1165
+ FOUNDRY_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
1166
+ FOUNDRY_REPOSITORY: ${{ github.repository }}
1167
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
1168
+ - name: Evaluate aggregate gate
1169
+ run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate