code-foundry 1.48.8 → 1.50.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.
- package/.github/CONTRIBUTING.md +8 -8
- package/.github/code-foundry.schema.json +10 -0
- package/.github/code-foundry.yml +2 -0
- package/.github/workflows/ci.yml +41 -5
- package/.github/workflows/draft-enforcement_self-ci.yml +12 -8
- package/.github/workflows/qualification-receipt.yml +201 -0
- package/.github/workflows/qualified-foundry-publish.yml +0 -12
- package/.github/workflows/release.yml +58 -20
- package/.github/workflows/release_self-ci.yml +0 -2
- package/.github/workflows/security.yml +3 -1
- package/.github/workflows/test.yml +90 -1
- package/.github/workflows/validation-billing.yml +159 -23
- package/.github/workflows/validation-no-codeql.yml +91 -15
- package/.github/workflows/validation.yml +96 -15
- package/.github/workflows/validation_self-ci.yml +7 -4
- package/CHANGELOG.md +50 -50
- package/docs/CONFIGURATION.md +11 -0
- package/docs/PUBLISHING.md +13 -5
- package/docs/WORKFLOWS.md +25 -12
- package/docs/qualified-publication.md +22 -14
- package/package.json +4 -1
- package/src/commands/qualified-publication.mjs +27 -0
- package/src/commands/sync.mjs +76 -9
- package/src/lib/github-doctor.mjs +23 -2
- package/src/lib/node-package-performance.mjs +21 -1
- package/src/lib/validation-policy.mjs +11 -11
- package/src/runtime-core.mjs +2 -0
|
@@ -38,6 +38,11 @@ on:
|
|
|
38
38
|
required: false
|
|
39
39
|
type: string
|
|
40
40
|
default: task-result
|
|
41
|
+
integration-total-shards:
|
|
42
|
+
description: Integration partitions (1 or 2); sharded scripts must honor INTEGRATION_SHARD_INDEX and INTEGRATION_TOTAL_SHARDS.
|
|
43
|
+
required: false
|
|
44
|
+
type: string
|
|
45
|
+
default: '1'
|
|
41
46
|
e2e-shard-list:
|
|
42
47
|
description: Comma-separated E2E shard indices, for example "1,2". A single index runs one unsharded job.
|
|
43
48
|
required: false
|
|
@@ -255,10 +260,14 @@ jobs:
|
|
|
255
260
|
|
|
256
261
|
integration:
|
|
257
262
|
name: Integration
|
|
258
|
-
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true
|
|
263
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true && inputs.integration-total-shards != '2'
|
|
259
264
|
runs-on: ${{ inputs.runner }}
|
|
260
265
|
timeout-minutes: 30
|
|
261
266
|
steps:
|
|
267
|
+
- name: Validate integration shard count
|
|
268
|
+
env:
|
|
269
|
+
SHARDS: ${{ inputs.integration-total-shards }}
|
|
270
|
+
run: test "$SHARDS" = 1
|
|
262
271
|
- name: Checkout
|
|
263
272
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
264
273
|
with:
|
|
@@ -326,6 +335,86 @@ jobs:
|
|
|
326
335
|
- name: Save Vite+ task cache
|
|
327
336
|
uses: ./.github/actions/vite-plus-cache-save
|
|
328
337
|
|
|
338
|
+
integration-sharded:
|
|
339
|
+
name: Integration shard
|
|
340
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true && inputs.integration-total-shards == '2'
|
|
341
|
+
runs-on: ${{ inputs.runner }}
|
|
342
|
+
timeout-minutes: 30
|
|
343
|
+
strategy:
|
|
344
|
+
fail-fast: false
|
|
345
|
+
matrix:
|
|
346
|
+
shard: [1, 2]
|
|
347
|
+
steps:
|
|
348
|
+
- name: Checkout
|
|
349
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
350
|
+
with:
|
|
351
|
+
persist-credentials: false
|
|
352
|
+
fetch-depth: 2
|
|
353
|
+
- name: Runtime
|
|
354
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
355
|
+
with:
|
|
356
|
+
persist-credentials: false
|
|
357
|
+
repository: ${{ inputs.runtime-repository }}
|
|
358
|
+
ref: ${{ inputs.runtime-ref }}
|
|
359
|
+
path: .github/.code-foundry
|
|
360
|
+
sparse-checkout: |
|
|
361
|
+
.github/actions
|
|
362
|
+
src/lib
|
|
363
|
+
src/runtime-core.mjs
|
|
364
|
+
src/runtime.mjs
|
|
365
|
+
- name: Install runtime
|
|
366
|
+
run: |
|
|
367
|
+
mkdir -p .github/actions
|
|
368
|
+
mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
|
|
369
|
+
cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
|
|
370
|
+
- name: Detect
|
|
371
|
+
id: applicability
|
|
372
|
+
env:
|
|
373
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
374
|
+
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
375
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
376
|
+
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
377
|
+
BEFORE_SHA: ${{ github.event.before }}
|
|
378
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile integration >> "$GITHUB_OUTPUT"
|
|
379
|
+
- name: Setup
|
|
380
|
+
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
|
|
381
|
+
uses: ./.github/actions/setup
|
|
382
|
+
with:
|
|
383
|
+
install: true
|
|
384
|
+
install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
|
|
385
|
+
install-python: ${{ steps.applicability.outputs.python == 'true' }}
|
|
386
|
+
install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
|
|
387
|
+
cache-build: ${{ steps.applicability.outputs.rust == 'true' }}
|
|
388
|
+
cache-environment: false
|
|
389
|
+
cache-save: ${{ github.event_name == 'push' }}
|
|
390
|
+
task: integration
|
|
391
|
+
task-javascript: ${{ steps.applicability.outputs.javascript }}
|
|
392
|
+
task-python: ${{ steps.applicability.outputs.python }}
|
|
393
|
+
task-rust: ${{ steps.applicability.outputs.rust }}
|
|
394
|
+
- name: Integration
|
|
395
|
+
id: execute
|
|
396
|
+
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
|
|
397
|
+
env:
|
|
398
|
+
INTEGRATION_SHARD_INDEX: ${{ matrix.shard }}
|
|
399
|
+
INTEGRATION_TOTAL_SHARDS: ${{ inputs.integration-total-shards }}
|
|
400
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci integration
|
|
401
|
+
- name: Retain task receipt
|
|
402
|
+
if: >-
|
|
403
|
+
always() &&
|
|
404
|
+
(steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
|
|
405
|
+
steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
|
|
406
|
+
hashFiles('.code-foundry/results/integration.json') != ''
|
|
407
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
408
|
+
with:
|
|
409
|
+
name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-integration-s${{ matrix.shard }}
|
|
410
|
+
path: .code-foundry/results/integration.json
|
|
411
|
+
include-hidden-files: true
|
|
412
|
+
if-no-files-found: error
|
|
413
|
+
retention-days: 14
|
|
414
|
+
|
|
415
|
+
- name: Save Vite+ task cache
|
|
416
|
+
uses: ./.github/actions/vite-plus-cache-save
|
|
417
|
+
|
|
329
418
|
e2e:
|
|
330
419
|
name: E2E
|
|
331
420
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true
|
|
@@ -25,6 +25,11 @@ on:
|
|
|
25
25
|
description: Validation tier (fast, audit, or release).
|
|
26
26
|
required: true
|
|
27
27
|
type: string
|
|
28
|
+
release-qualification-receipts:
|
|
29
|
+
description: Reuse a recent exact-tree audit receipt for Release Please PRs.
|
|
30
|
+
required: false
|
|
31
|
+
type: boolean
|
|
32
|
+
default: false
|
|
28
33
|
codeql:
|
|
29
34
|
description: Run the CodeQL lane (the consumer's canonical codeql config).
|
|
30
35
|
required: false
|
|
@@ -95,6 +100,11 @@ on:
|
|
|
95
100
|
required: false
|
|
96
101
|
type: string
|
|
97
102
|
default: task-result
|
|
103
|
+
integration-total-shards:
|
|
104
|
+
description: Integration partitions (1 or 2); sharded scripts must honor INTEGRATION_SHARD_INDEX and INTEGRATION_TOTAL_SHARDS.
|
|
105
|
+
required: false
|
|
106
|
+
type: string
|
|
107
|
+
default: '1'
|
|
98
108
|
e2e-shard-list:
|
|
99
109
|
description: Comma-separated E2E shard indices passed to the test lane's matrix, e.g. "1,2".
|
|
100
110
|
required: false
|
|
@@ -118,6 +128,7 @@ permissions:
|
|
|
118
128
|
actions: read
|
|
119
129
|
contents: read
|
|
120
130
|
packages: read
|
|
131
|
+
pull-requests: read
|
|
121
132
|
security-events: write
|
|
122
133
|
|
|
123
134
|
env:
|
|
@@ -141,16 +152,41 @@ concurrency:
|
|
|
141
152
|
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
142
153
|
|
|
143
154
|
jobs:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
qualification:
|
|
156
|
+
name: Qualification
|
|
157
|
+
if: >-
|
|
158
|
+
vars.CI_BILLING_PAUSED != 'true' &&
|
|
159
|
+
inputs.release-qualification-receipts == true && inputs.mode == 'release'
|
|
160
|
+
permissions:
|
|
161
|
+
actions: read
|
|
162
|
+
contents: read
|
|
163
|
+
pull-requests: read
|
|
164
|
+
uses: ./.github/workflows/qualification-receipt.yml
|
|
165
|
+
with:
|
|
166
|
+
phase: verify
|
|
167
|
+
mode: ${{ inputs.mode }}
|
|
168
|
+
enabled: ${{ inputs.release-qualification-receipts }}
|
|
169
|
+
codeql-enabled: ${{ inputs.codeql }}
|
|
170
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
171
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
172
|
+
required-job-names-json: '["Validation / Gate"]'
|
|
173
|
+
|
|
148
174
|
fast-lanes:
|
|
149
175
|
name: Fast lanes
|
|
150
|
-
|
|
176
|
+
needs: qualification
|
|
177
|
+
if: >-
|
|
178
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true'
|
|
179
|
+
permissions:
|
|
180
|
+
actions: read
|
|
181
|
+
contents: read
|
|
182
|
+
packages: read
|
|
151
183
|
runs-on: ${{ inputs.ci-runner }}
|
|
152
184
|
timeout-minutes: 45
|
|
153
185
|
steps:
|
|
186
|
+
- name: Validate integration shard count
|
|
187
|
+
env:
|
|
188
|
+
SHARDS: ${{ inputs.integration-total-shards }}
|
|
189
|
+
run: test "$SHARDS" = 1
|
|
154
190
|
- name: Checkout
|
|
155
191
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
156
192
|
with:
|
|
@@ -165,6 +201,7 @@ jobs:
|
|
|
165
201
|
path: .github/.code-foundry
|
|
166
202
|
sparse-checkout: |
|
|
167
203
|
.github/actions
|
|
204
|
+
src/commands/qualification-receipt.mjs
|
|
168
205
|
src/lib
|
|
169
206
|
src/runtime-core.mjs
|
|
170
207
|
src/runtime.mjs
|
|
@@ -173,9 +210,15 @@ jobs:
|
|
|
173
210
|
mkdir -p .github/actions
|
|
174
211
|
mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
|
|
175
212
|
cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
|
|
213
|
+
- name: Set up Node.js 24.18.0 for package inspection
|
|
214
|
+
if: ${{ inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' }}
|
|
215
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
216
|
+
with:
|
|
217
|
+
node-version: 24.18.0
|
|
176
218
|
# --- Format lane (mirror of ci.yml format) ---
|
|
177
219
|
- name: Detect format
|
|
178
220
|
id: format_applicability
|
|
221
|
+
if: ${{ !(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true') }}
|
|
179
222
|
env:
|
|
180
223
|
EVENT_NAME: ${{ github.event_name }}
|
|
181
224
|
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
@@ -194,6 +237,11 @@ jobs:
|
|
|
194
237
|
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
195
238
|
BEFORE_SHA: ${{ github.event.before }}
|
|
196
239
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci should_run build >> "$GITHUB_OUTPUT"
|
|
240
|
+
- name: Verify versioned package build contract
|
|
241
|
+
if: ${{ inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' }}
|
|
242
|
+
env:
|
|
243
|
+
FOUNDRY_BUILD_TASK_APPLICABLE: ${{ steps.build_applicability.outputs.applicable }}
|
|
244
|
+
run: node "$RUNNER_TEMP/code-foundry/src/commands/qualification-receipt.mjs" package-contract
|
|
197
245
|
# --- Performance lane (mirror of test.yml performance; audit tier only) ---
|
|
198
246
|
- name: Detect performance
|
|
199
247
|
id: performance_applicability
|
|
@@ -239,7 +287,10 @@ jobs:
|
|
|
239
287
|
BEFORE_SHA: ${{ github.event.before }}
|
|
240
288
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile integration >> "$GITHUB_OUTPUT"
|
|
241
289
|
- name: Setup format
|
|
242
|
-
if:
|
|
290
|
+
if: >-
|
|
291
|
+
${{ !(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true') &&
|
|
292
|
+
steps.format_applicability.outputs.applicable == 'true' &&
|
|
293
|
+
steps.format_applicability.outputs.affected != 'false' }}
|
|
243
294
|
uses: ./.github/actions/setup
|
|
244
295
|
with:
|
|
245
296
|
# Repository format scripts normally call a project-local formatter
|
|
@@ -251,7 +302,10 @@ jobs:
|
|
|
251
302
|
cache-build: 'false'
|
|
252
303
|
task: format
|
|
253
304
|
- name: Setup build
|
|
254
|
-
if:
|
|
305
|
+
if: >-
|
|
306
|
+
${{ !cancelled() && steps.build_applicability.outputs.applicable == 'true' &&
|
|
307
|
+
((inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true') ||
|
|
308
|
+
steps.build_applicability.outputs.affected != 'false') }}
|
|
255
309
|
uses: ./.github/actions/setup
|
|
256
310
|
with:
|
|
257
311
|
install: 'true'
|
|
@@ -323,12 +377,18 @@ jobs:
|
|
|
323
377
|
# --- Format execute ---
|
|
324
378
|
- name: Format
|
|
325
379
|
id: format_execute
|
|
326
|
-
if:
|
|
380
|
+
if: >-
|
|
381
|
+
${{ !(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true') &&
|
|
382
|
+
steps.format_applicability.outputs.applicable == 'true' &&
|
|
383
|
+
steps.format_applicability.outputs.affected != 'false' }}
|
|
327
384
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci format
|
|
328
385
|
# --- Build execute ---
|
|
329
386
|
- name: Build
|
|
330
387
|
id: build_execute
|
|
331
|
-
if:
|
|
388
|
+
if: >-
|
|
389
|
+
${{ !cancelled() && steps.build_applicability.outputs.applicable == 'true' &&
|
|
390
|
+
((inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true') ||
|
|
391
|
+
steps.build_applicability.outputs.affected != 'false') }}
|
|
332
392
|
env:
|
|
333
393
|
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET || 'code-foundry-ci-placeholder-0123456789' }}
|
|
334
394
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci build
|
|
@@ -352,6 +412,21 @@ jobs:
|
|
|
352
412
|
id: integration_execute
|
|
353
413
|
if: ${{ !cancelled() && inputs.mode == 'audit' && steps.integration_applicability.outputs.applicable == 'true' && steps.integration_applicability.outputs.affected != 'false' }}
|
|
354
414
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci integration
|
|
415
|
+
- name: Inspect versioned npm package contents
|
|
416
|
+
if: ${{ inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' && hashFiles('package.json') != '' }}
|
|
417
|
+
run: |
|
|
418
|
+
npm pack --dry-run --ignore-scripts --json > "$RUNNER_TEMP/foundry-package-inspection.json"
|
|
419
|
+
node --input-type=module -e '
|
|
420
|
+
import { readFileSync } from "node:fs";
|
|
421
|
+
import { join } from "node:path";
|
|
422
|
+
import { pathToFileURL } from "node:url";
|
|
423
|
+
|
|
424
|
+
const runtime = join(process.env.RUNNER_TEMP, "code-foundry", "src/lib/node-package-performance.mjs");
|
|
425
|
+
const { verifyNpmPackPackage } = await import(pathToFileURL(runtime).href);
|
|
426
|
+
const manifest = JSON.parse(readFileSync("package.json", "utf8"));
|
|
427
|
+
const report = JSON.parse(readFileSync(process.argv[1], "utf8"));
|
|
428
|
+
verifyNpmPackPackage(report, manifest);
|
|
429
|
+
' "$RUNNER_TEMP/foundry-package-inspection.json"
|
|
355
430
|
# Upload only after execution joins, and keep uploads sequential: the
|
|
356
431
|
# runner rewrites GITHUB_EVENT_PATH for each action, racing the event
|
|
357
432
|
# JSON read in upload-artifact's context initialization (runner#4641).
|
|
@@ -473,7 +548,14 @@ jobs:
|
|
|
473
548
|
|
|
474
549
|
lint:
|
|
475
550
|
name: Lint
|
|
476
|
-
|
|
551
|
+
needs: qualification
|
|
552
|
+
if: >-
|
|
553
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true' &&
|
|
554
|
+
!(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true')
|
|
555
|
+
permissions:
|
|
556
|
+
actions: read
|
|
557
|
+
contents: read
|
|
558
|
+
packages: read
|
|
477
559
|
runs-on: ${{ inputs.ci-runner }}
|
|
478
560
|
timeout-minutes: 30
|
|
479
561
|
steps:
|
|
@@ -537,7 +619,10 @@ jobs:
|
|
|
537
619
|
|
|
538
620
|
type-check:
|
|
539
621
|
name: Type-Check
|
|
540
|
-
|
|
622
|
+
needs: qualification
|
|
623
|
+
if: >-
|
|
624
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true' &&
|
|
625
|
+
!(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true')
|
|
541
626
|
permissions:
|
|
542
627
|
contents: read
|
|
543
628
|
issues: read
|
|
@@ -606,7 +691,14 @@ jobs:
|
|
|
606
691
|
|
|
607
692
|
unit:
|
|
608
693
|
name: Unit
|
|
609
|
-
|
|
694
|
+
needs: qualification
|
|
695
|
+
if: >-
|
|
696
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true' &&
|
|
697
|
+
!(inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true')
|
|
698
|
+
permissions:
|
|
699
|
+
actions: read
|
|
700
|
+
contents: read
|
|
701
|
+
packages: read
|
|
610
702
|
runs-on: ${{ inputs.unit-runner }}
|
|
611
703
|
timeout-minutes: 30
|
|
612
704
|
steps:
|
|
@@ -696,6 +788,10 @@ jobs:
|
|
|
696
788
|
e2e:
|
|
697
789
|
name: E2E
|
|
698
790
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
791
|
+
permissions:
|
|
792
|
+
actions: read
|
|
793
|
+
contents: read
|
|
794
|
+
packages: read
|
|
699
795
|
runs-on: ${{ inputs.test-runner }}
|
|
700
796
|
timeout-minutes: 45
|
|
701
797
|
# Shards duplicate the whole job, but each shard owns a runner-local test
|
|
@@ -798,6 +894,10 @@ jobs:
|
|
|
798
894
|
audit:
|
|
799
895
|
name: Audit
|
|
800
896
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
897
|
+
permissions:
|
|
898
|
+
actions: read
|
|
899
|
+
contents: read
|
|
900
|
+
packages: read
|
|
801
901
|
runs-on: ${{ inputs.security-runner }}
|
|
802
902
|
timeout-minutes: 30
|
|
803
903
|
steps:
|
|
@@ -1103,6 +1203,11 @@ jobs:
|
|
|
1103
1203
|
# Release-please pull requests also analyze with CodeQL so repository
|
|
1104
1204
|
# rulesets requiring code scanning results never deadlock the release.
|
|
1105
1205
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.codeql == true && (inputs.mode == 'audit' || inputs.mode == 'release')
|
|
1206
|
+
permissions:
|
|
1207
|
+
actions: read
|
|
1208
|
+
contents: read
|
|
1209
|
+
packages: read
|
|
1210
|
+
security-events: write
|
|
1106
1211
|
uses: ./.github/workflows/codeql.yml
|
|
1107
1212
|
with:
|
|
1108
1213
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -1115,24 +1220,25 @@ jobs:
|
|
|
1115
1220
|
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
1116
1221
|
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
1117
1222
|
# Category results fold the merged job's lanes back into the same FOUNDRY_*
|
|
1118
|
-
# vocabulary the split orchestrators feed the runtime gate
|
|
1119
|
-
#
|
|
1223
|
+
# vocabulary the split orchestrators feed the runtime gate. Exact source
|
|
1224
|
+
# receipts can replace repeat lint/type/unit work; Build, package inspection,
|
|
1225
|
+
# CodeQL when configured, and the receipt gate remain required.
|
|
1120
1226
|
gate:
|
|
1121
1227
|
name: Gate
|
|
1122
|
-
needs: [fast-lanes, lint, type-check, unit, e2e, audit, codeql]
|
|
1228
|
+
needs: [fast-lanes, lint, type-check, unit, e2e, audit, codeql, qualification]
|
|
1123
1229
|
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
1230
|
+
permissions:
|
|
1231
|
+
contents: read
|
|
1124
1232
|
runs-on: ubuntu-slim
|
|
1125
1233
|
timeout-minutes: 10
|
|
1126
1234
|
env:
|
|
1127
1235
|
FOUNDRY_MODE: ${{ inputs.mode }}
|
|
1128
|
-
# CI category:
|
|
1129
|
-
#
|
|
1130
|
-
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' }}
|
|
1131
|
-
# Test category:
|
|
1132
|
-
#
|
|
1133
|
-
|
|
1134
|
-
# eval-mode lanes, so its result joins the category too.
|
|
1135
|
-
FOUNDRY_TEST: ${{ needs.unit.result == 'success' && needs.fast-lanes.result == 'success' && (needs.e2e.result == 'success' || needs.e2e.result == 'skipped') && 'success' || ((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') }}
|
|
1236
|
+
# CI category: normal and fallback runs include lint/type-check. A
|
|
1237
|
+
# verified source receipt retains the build/package lane here.
|
|
1238
|
+
FOUNDRY_CI: ${{ (inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' && needs.fast-lanes.result == 'success' && 'success') || ((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') }}
|
|
1239
|
+
# Test category: a verified receipt replaces duplicate unit-test work;
|
|
1240
|
+
# otherwise unit plus applicable integration/E2E lanes must succeed.
|
|
1241
|
+
FOUNDRY_TEST: ${{ (inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' && needs.fast-lanes.result == 'success' && 'success') || (needs.unit.result == 'success' && needs.fast-lanes.result == 'success' && (needs.e2e.result == 'success' || needs.e2e.result == 'skipped') && 'success') || ((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') }}
|
|
1136
1242
|
FOUNDRY_SECURITY: ${{ needs.audit.result }}
|
|
1137
1243
|
# This orchestrator runs CodeQL only when the consumer's canonical
|
|
1138
1244
|
# configuration enables it; otherwise the unavailability decision is
|
|
@@ -1142,6 +1248,8 @@ jobs:
|
|
|
1142
1248
|
# fast-lanes failure on that tier marks the eval category failed even if
|
|
1143
1249
|
# another merged lane caused it, which fails closed.
|
|
1144
1250
|
FOUNDRY_EVAL: ${{ needs.fast-lanes.result }}
|
|
1251
|
+
FOUNDRY_SOURCE_QUALIFICATION: ${{ needs.qualification.outputs.reuse }}
|
|
1252
|
+
FOUNDRY_QUALIFICATION: ${{ needs.qualification.result }}
|
|
1145
1253
|
steps:
|
|
1146
1254
|
- name: Checkout runtime
|
|
1147
1255
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
@@ -1173,3 +1281,31 @@ jobs:
|
|
|
1173
1281
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
|
|
1174
1282
|
- name: Evaluate aggregate gate
|
|
1175
1283
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate
|
|
1284
|
+
|
|
1285
|
+
qualification-receipt:
|
|
1286
|
+
name: Qualification receipt
|
|
1287
|
+
needs: [fast-lanes, lint, type-check, unit, e2e, audit, codeql, gate]
|
|
1288
|
+
if: >-
|
|
1289
|
+
vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit' &&
|
|
1290
|
+
inputs.release-qualification-receipts == true &&
|
|
1291
|
+
github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' &&
|
|
1292
|
+
needs.fast-lanes.result == 'success' && needs.lint.result == 'success' &&
|
|
1293
|
+
needs.type-check.result == 'success' && needs.unit.result == 'success' &&
|
|
1294
|
+
needs.e2e.result == 'success' && needs.audit.result == 'success' &&
|
|
1295
|
+
(inputs.codeql != true || needs.codeql.result == 'success') &&
|
|
1296
|
+
needs.gate.result == 'success'
|
|
1297
|
+
permissions:
|
|
1298
|
+
actions: read
|
|
1299
|
+
contents: read
|
|
1300
|
+
pull-requests: read
|
|
1301
|
+
uses: ./.github/workflows/qualification-receipt.yml
|
|
1302
|
+
with:
|
|
1303
|
+
phase: produce
|
|
1304
|
+
mode: ${{ inputs.mode }}
|
|
1305
|
+
enabled: ${{ inputs.release-qualification-receipts }}
|
|
1306
|
+
codeql-enabled: ${{ inputs.codeql }}
|
|
1307
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
1308
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
1309
|
+
job-results-json: >-
|
|
1310
|
+
{"ci":"${{ needs.lint.result == 'success' && needs.type-check.result == 'success' && needs.fast-lanes.result == 'success' && 'success' || 'failure' }}","test":"${{ needs.unit.result == 'success' && needs.fast-lanes.result == 'success' && needs.e2e.result == 'success' && 'success' || 'failure' }}","security":"${{ needs.audit.result }}","codeql":"${{ inputs.codeql == true && needs.codeql.result || 'not-configured' }}","eval":"${{ needs.fast-lanes.result }}","gate":"${{ needs.gate.result }}"}
|
|
1311
|
+
required-job-names-json: '["Validation / Gate"]'
|
|
@@ -7,6 +7,11 @@ on:
|
|
|
7
7
|
description: Validation tier (fast, audit, or release).
|
|
8
8
|
required: true
|
|
9
9
|
type: string
|
|
10
|
+
release-qualification-receipts:
|
|
11
|
+
description: Reuse a recent exact-tree audit receipt for Release Please PRs.
|
|
12
|
+
required: false
|
|
13
|
+
type: boolean
|
|
14
|
+
default: false
|
|
10
15
|
runtime-repository:
|
|
11
16
|
description: Repository containing the Code Foundry runtime.
|
|
12
17
|
required: false
|
|
@@ -75,6 +80,11 @@ on:
|
|
|
75
80
|
required: false
|
|
76
81
|
type: string
|
|
77
82
|
default: task-result
|
|
83
|
+
integration-total-shards:
|
|
84
|
+
description: Integration partitions (1 or 2); sharded scripts must honor INTEGRATION_SHARD_INDEX and INTEGRATION_TOTAL_SHARDS.
|
|
85
|
+
required: false
|
|
86
|
+
type: string
|
|
87
|
+
default: '1'
|
|
78
88
|
e2e-shard-list:
|
|
79
89
|
description: Comma-separated E2E shard indices passed to the test lane's matrix, e.g. "1,2".
|
|
80
90
|
required: false
|
|
@@ -98,12 +108,35 @@ permissions:
|
|
|
98
108
|
actions: read
|
|
99
109
|
contents: read
|
|
100
110
|
packages: read
|
|
111
|
+
pull-requests: read
|
|
101
112
|
security-events: write
|
|
102
113
|
|
|
103
114
|
jobs:
|
|
115
|
+
qualification:
|
|
116
|
+
name: Qualification
|
|
117
|
+
if: >-
|
|
118
|
+
vars.CI_BILLING_PAUSED != 'true' &&
|
|
119
|
+
inputs.release-qualification-receipts == true && inputs.mode == 'release'
|
|
120
|
+
permissions:
|
|
121
|
+
actions: read
|
|
122
|
+
contents: read
|
|
123
|
+
pull-requests: read
|
|
124
|
+
uses: ./.github/workflows/qualification-receipt.yml
|
|
125
|
+
with:
|
|
126
|
+
phase: verify
|
|
127
|
+
mode: ${{ inputs.mode }}
|
|
128
|
+
enabled: ${{ inputs.release-qualification-receipts }}
|
|
129
|
+
codeql-enabled: false
|
|
130
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
131
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
132
|
+
required-job-names-json: '["Validation / Gate"]'
|
|
133
|
+
|
|
104
134
|
ci:
|
|
105
135
|
name: CI
|
|
106
|
-
|
|
136
|
+
needs: qualification
|
|
137
|
+
if: >-
|
|
138
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true' &&
|
|
139
|
+
(inputs.mode == 'fast' || inputs.mode == 'audit' || inputs.mode == 'release')
|
|
107
140
|
# Forward issue-read only to the CI workflow that runs Type-Check.
|
|
108
141
|
permissions:
|
|
109
142
|
actions: read
|
|
@@ -116,13 +149,23 @@ jobs:
|
|
|
116
149
|
runtime-ref: ${{ inputs.runtime-ref }}
|
|
117
150
|
runner: ${{ inputs.ci-runner }}
|
|
118
151
|
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
152
|
+
release-build-only: ${{ inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' }}
|
|
153
|
+
release-package-check: ${{ inputs.mode == 'release' && needs.qualification.outputs.reuse == 'true' }}
|
|
119
154
|
secrets:
|
|
120
155
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
121
156
|
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
|
|
122
157
|
|
|
123
158
|
test:
|
|
124
159
|
name: Test
|
|
125
|
-
|
|
160
|
+
needs: qualification
|
|
161
|
+
if: >-
|
|
162
|
+
!cancelled() && vars.CI_BILLING_PAUSED != 'true' &&
|
|
163
|
+
(inputs.mode == 'fast' || inputs.mode == 'audit' ||
|
|
164
|
+
(inputs.mode == 'release' && needs.qualification.outputs.reuse != 'true'))
|
|
165
|
+
permissions:
|
|
166
|
+
actions: read
|
|
167
|
+
contents: read
|
|
168
|
+
packages: read
|
|
126
169
|
uses: ./.github/workflows/test.yml
|
|
127
170
|
with:
|
|
128
171
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -130,11 +173,12 @@ jobs:
|
|
|
130
173
|
runner: ${{ inputs.test-runner }}
|
|
131
174
|
unit-runner: ${{ inputs.unit-runner }}
|
|
132
175
|
performance-runner: ${{ inputs.performance-runner }}
|
|
133
|
-
# Release pull requests
|
|
134
|
-
#
|
|
135
|
-
#
|
|
176
|
+
# Fast and Release Please pull requests run unit tests only. Until a
|
|
177
|
+
# successful full qualification is verifiable for the exact main tree,
|
|
178
|
+
# release mode keeps its CI and unit-test fallback.
|
|
136
179
|
unit-only: ${{ inputs.mode == 'fast' || inputs.mode == 'release' }}
|
|
137
180
|
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
181
|
+
integration-total-shards: ${{ inputs.integration-total-shards }}
|
|
138
182
|
e2e-shard-list: ${{ inputs.e2e-shard-list }}
|
|
139
183
|
e2e-total-shards: ${{ inputs.e2e-total-shards }}
|
|
140
184
|
secrets:
|
|
@@ -143,6 +187,8 @@ jobs:
|
|
|
143
187
|
security:
|
|
144
188
|
name: Security
|
|
145
189
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
190
|
+
permissions:
|
|
191
|
+
contents: read
|
|
146
192
|
uses: ./.github/workflows/security.yml
|
|
147
193
|
with:
|
|
148
194
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -151,10 +197,12 @@ jobs:
|
|
|
151
197
|
|
|
152
198
|
eval:
|
|
153
199
|
name: Eval
|
|
154
|
-
# Behavior evals
|
|
155
|
-
#
|
|
156
|
-
# cleanly when
|
|
200
|
+
# Behavior evals are part of audit qualification. A release-only run may
|
|
201
|
+
# reuse that work only through the exact, unexpired source receipt below.
|
|
202
|
+
# The reusable workflow skips cleanly when there is no eval harness.
|
|
157
203
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
204
|
+
permissions:
|
|
205
|
+
contents: read
|
|
158
206
|
uses: ./.github/workflows/eval.yml
|
|
159
207
|
with:
|
|
160
208
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -164,16 +212,16 @@ jobs:
|
|
|
164
212
|
|
|
165
213
|
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
166
214
|
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
# as a conditional step below, so no separate release-policy job renders
|
|
172
|
-
# skipped checks on ordinary pull requests.
|
|
215
|
+
# Release Please branches require CI and the exact generated-diff audit
|
|
216
|
+
# below. The runtime gate also requires unit tests unless the separate
|
|
217
|
+
# qualification job verified a matching source receipt. Ordinary PRs still
|
|
218
|
+
# render no skipped release-policy row.
|
|
173
219
|
gate:
|
|
174
220
|
name: Gate
|
|
175
|
-
needs: [ci, test, security, eval]
|
|
221
|
+
needs: [ci, test, security, eval, qualification]
|
|
176
222
|
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
223
|
+
permissions:
|
|
224
|
+
contents: read
|
|
177
225
|
runs-on: ubuntu-slim
|
|
178
226
|
timeout-minutes: 10
|
|
179
227
|
env:
|
|
@@ -182,6 +230,8 @@ jobs:
|
|
|
182
230
|
FOUNDRY_TEST: ${{ needs.test.result }}
|
|
183
231
|
FOUNDRY_SECURITY: ${{ needs.security.result }}
|
|
184
232
|
FOUNDRY_EVAL: ${{ needs.eval.result }}
|
|
233
|
+
FOUNDRY_SOURCE_QUALIFICATION: ${{ needs.qualification.outputs.reuse }}
|
|
234
|
+
FOUNDRY_QUALIFICATION: ${{ needs.qualification.result }}
|
|
185
235
|
# This workflow is selected only for repositories whose canonical
|
|
186
236
|
# configuration explicitly disables unavailable CodeQL. Treat that
|
|
187
237
|
# policy decision as satisfied without registering a skipped PR check.
|
|
@@ -217,3 +267,29 @@ jobs:
|
|
|
217
267
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
|
|
218
268
|
- name: Evaluate aggregate gate
|
|
219
269
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate
|
|
270
|
+
|
|
271
|
+
qualification-receipt:
|
|
272
|
+
name: Qualification receipt
|
|
273
|
+
needs: [ci, test, security, eval, gate]
|
|
274
|
+
if: >-
|
|
275
|
+
vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit' &&
|
|
276
|
+
inputs.release-qualification-receipts == true &&
|
|
277
|
+
github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' &&
|
|
278
|
+
needs.ci.result == 'success' && needs.test.result == 'success' &&
|
|
279
|
+
needs.security.result == 'success' && needs.eval.result == 'success' &&
|
|
280
|
+
needs.gate.result == 'success'
|
|
281
|
+
permissions:
|
|
282
|
+
actions: read
|
|
283
|
+
contents: read
|
|
284
|
+
pull-requests: read
|
|
285
|
+
uses: ./.github/workflows/qualification-receipt.yml
|
|
286
|
+
with:
|
|
287
|
+
phase: produce
|
|
288
|
+
mode: ${{ inputs.mode }}
|
|
289
|
+
enabled: ${{ inputs.release-qualification-receipts }}
|
|
290
|
+
codeql-enabled: false
|
|
291
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
292
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
293
|
+
job-results-json: >-
|
|
294
|
+
{"ci":"${{ needs.ci.result }}","test":"${{ needs.test.result }}","security":"${{ needs.security.result }}","codeql":"not-configured","eval":"${{ needs.eval.result }}","gate":"${{ needs.gate.result }}"}
|
|
295
|
+
required-job-names-json: '["Validation / Gate"]'
|