code-foundry 1.48.8 → 1.50.0
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 +43 -43
- 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 +50 -4
- 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
|
@@ -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
|
|
@@ -70,6 +75,11 @@ on:
|
|
|
70
75
|
required: false
|
|
71
76
|
type: number
|
|
72
77
|
default: 1
|
|
78
|
+
integration-total-shards:
|
|
79
|
+
description: Integration partitions (1 or 2); sharded scripts must honor INTEGRATION_SHARD_INDEX and INTEGRATION_TOTAL_SHARDS.
|
|
80
|
+
required: false
|
|
81
|
+
type: string
|
|
82
|
+
default: '1'
|
|
73
83
|
e2e-shard-list:
|
|
74
84
|
description: Comma-separated E2E shard indices passed to the test lane's matrix, e.g. "1,2".
|
|
75
85
|
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: true
|
|
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
|
# Type-Check reads the issue-backed requirements ledger with github.token.
|
|
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 }}
|
|
@@ -154,6 +200,11 @@ jobs:
|
|
|
154
200
|
# Release-please pull requests also analyze with CodeQL so repository
|
|
155
201
|
# rulesets requiring code scanning results never deadlock the release.
|
|
156
202
|
if: vars.CI_BILLING_PAUSED != 'true' && (inputs.mode == 'audit' || inputs.mode == 'release')
|
|
203
|
+
permissions:
|
|
204
|
+
actions: read
|
|
205
|
+
contents: read
|
|
206
|
+
packages: read
|
|
207
|
+
security-events: write
|
|
157
208
|
uses: ./.github/workflows/codeql.yml
|
|
158
209
|
with:
|
|
159
210
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -165,10 +216,12 @@ jobs:
|
|
|
165
216
|
|
|
166
217
|
eval:
|
|
167
218
|
name: Eval
|
|
168
|
-
# Behavior evals
|
|
169
|
-
#
|
|
170
|
-
# cleanly when
|
|
219
|
+
# Behavior evals are part of audit qualification. A release-only run may
|
|
220
|
+
# reuse that work only through the exact, unexpired source receipt below.
|
|
221
|
+
# The reusable workflow skips cleanly when there is no eval harness.
|
|
171
222
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
223
|
+
permissions:
|
|
224
|
+
contents: read
|
|
172
225
|
uses: ./.github/workflows/eval.yml
|
|
173
226
|
with:
|
|
174
227
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -178,16 +231,16 @@ jobs:
|
|
|
178
231
|
|
|
179
232
|
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
180
233
|
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
# as a conditional step below, so ordinary pull requests still render no
|
|
186
|
-
# skipped release-policy row.
|
|
234
|
+
# Release Please branches require CI, CodeQL, and the exact generated-diff
|
|
235
|
+
# audit below. The runtime gate also requires unit tests unless the separate
|
|
236
|
+
# qualification job verified a matching source receipt. Ordinary PRs still
|
|
237
|
+
# render no skipped release-policy row.
|
|
187
238
|
gate:
|
|
188
239
|
name: Gate
|
|
189
|
-
needs: [ci, test, security, codeql, eval]
|
|
240
|
+
needs: [ci, test, security, codeql, eval, qualification]
|
|
190
241
|
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
242
|
+
permissions:
|
|
243
|
+
contents: read
|
|
191
244
|
runs-on: ubuntu-slim
|
|
192
245
|
timeout-minutes: 10
|
|
193
246
|
env:
|
|
@@ -197,6 +250,8 @@ jobs:
|
|
|
197
250
|
FOUNDRY_SECURITY: ${{ needs.security.result }}
|
|
198
251
|
FOUNDRY_CODEQL: ${{ needs.codeql.result }}
|
|
199
252
|
FOUNDRY_EVAL: ${{ needs.eval.result }}
|
|
253
|
+
FOUNDRY_SOURCE_QUALIFICATION: ${{ needs.qualification.outputs.reuse }}
|
|
254
|
+
FOUNDRY_QUALIFICATION: ${{ needs.qualification.result }}
|
|
200
255
|
steps:
|
|
201
256
|
- name: Checkout runtime
|
|
202
257
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
@@ -228,3 +283,29 @@ jobs:
|
|
|
228
283
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation release_diff
|
|
229
284
|
- name: Evaluate aggregate gate
|
|
230
285
|
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" validation gate
|
|
286
|
+
|
|
287
|
+
qualification-receipt:
|
|
288
|
+
name: Qualification receipt
|
|
289
|
+
needs: [ci, test, security, codeql, eval, gate]
|
|
290
|
+
if: >-
|
|
291
|
+
vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit' &&
|
|
292
|
+
inputs.release-qualification-receipts == true &&
|
|
293
|
+
github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' &&
|
|
294
|
+
needs.ci.result == 'success' && needs.test.result == 'success' &&
|
|
295
|
+
needs.security.result == 'success' && needs.codeql.result == 'success' &&
|
|
296
|
+
needs.eval.result == 'success' && needs.gate.result == 'success'
|
|
297
|
+
permissions:
|
|
298
|
+
actions: read
|
|
299
|
+
contents: read
|
|
300
|
+
pull-requests: read
|
|
301
|
+
uses: ./.github/workflows/qualification-receipt.yml
|
|
302
|
+
with:
|
|
303
|
+
phase: produce
|
|
304
|
+
mode: ${{ inputs.mode }}
|
|
305
|
+
enabled: ${{ inputs.release-qualification-receipts }}
|
|
306
|
+
codeql-enabled: true
|
|
307
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
308
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
309
|
+
job-results-json: >-
|
|
310
|
+
{"ci":"${{ needs.ci.result }}","test":"${{ needs.test.result }}","security":"${{ needs.security.result }}","codeql":"${{ needs.codeql.result }}","eval":"${{ needs.eval.result }}","gate":"${{ needs.gate.result }}"}
|
|
311
|
+
required-job-names-json: '["Validation / Gate"]'
|
|
@@ -80,15 +80,17 @@ jobs:
|
|
|
80
80
|
contents: read
|
|
81
81
|
issues: read
|
|
82
82
|
packages: read
|
|
83
|
+
pull-requests: read
|
|
83
84
|
security-events: write
|
|
84
85
|
uses: ./.github/workflows/validation.yml
|
|
85
86
|
with:
|
|
86
87
|
mode: ${{ needs.mode.outputs.mode }}
|
|
87
88
|
runtime-repository: 0xPlayerOne/code-foundry
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
runtime-ref:
|
|
89
|
+
# Source PRs validate their proposed runtime commit. A Release Please PR
|
|
90
|
+
# uses its main base, keeping version-only metadata out of the runtime
|
|
91
|
+
# content identity. Scheduled audits use a separate default-branch caller.
|
|
92
|
+
runtime-ref: >-
|
|
93
|
+
${{ startsWith(github.event.pull_request.head.ref, 'release-please--branches--main') && github.event.pull_request.base.sha || github.sha }}
|
|
92
94
|
ci-runner: ubuntu-latest
|
|
93
95
|
test-runner: ubuntu-latest
|
|
94
96
|
unit-runner: ubuntu-slim
|
|
@@ -101,6 +103,7 @@ jobs:
|
|
|
101
103
|
rust-max-parallel: 1
|
|
102
104
|
# The sync renderer rewrites both values from the e2e_shards config key;
|
|
103
105
|
# the defaults keep repositories without that key on one unsharded job.
|
|
106
|
+
integration-total-shards: '1'
|
|
104
107
|
e2e-shard-list: '1'
|
|
105
108
|
e2e-total-shards: '1'
|
|
106
109
|
secrets:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.50.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.3...v1.50.0) (2026-10-29)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **release:** support npm OIDC publishing ([#791](https://github.com/0xPlayerOne/code-foundry/issues/791)) ([74b5155](https://github.com/0xPlayerOne/code-foundry/commit/74b5155157b9f163d70b00b138673c981e19c925))
|
|
9
|
+
|
|
10
|
+
## [1.49.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.2...v1.49.3) (2026-10-29)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### CI
|
|
14
|
+
|
|
15
|
+
* **validation:** require release checks until evidence exists ([#789](https://github.com/0xPlayerOne/code-foundry/issues/789)) ([a5f8be6](https://github.com/0xPlayerOne/code-foundry/commit/a5f8be64b7b28d2248aa71b80e321aa0fe82f30a))
|
|
16
|
+
|
|
17
|
+
## [1.49.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.1...v1.49.2) (2026-10-29)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* safely categorize npm publication failures ([#787](https://github.com/0xPlayerOne/code-foundry/issues/787)) ([a4268af](https://github.com/0xPlayerOne/code-foundry/commit/a4268af5ce7cd0a32407420424419c0cad01dce8))
|
|
23
|
+
|
|
24
|
+
## [1.49.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.0...v1.49.1) (2026-10-28)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* handle empty security audit matrices ([#785](https://github.com/0xPlayerOne/code-foundry/issues/785)) ([02f0565](https://github.com/0xPlayerOne/code-foundry/commit/02f05652e68267a2aa2df5d5af8f13df9ba1e3aa))
|
|
30
|
+
|
|
31
|
+
## [1.49.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.48.9...v1.49.0) (2026-10-27)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* support isolated integration test shards ([#783](https://github.com/0xPlayerOne/code-foundry/issues/783)) ([ad1123f](https://github.com/0xPlayerOne/code-foundry/commit/ad1123ff3bb9654bfbdaef4219490cca3e7e3d20))
|
|
37
|
+
|
|
38
|
+
## [1.48.9](https://github.com/0xPlayerOne/code-foundry/compare/v1.48.8...v1.48.9) (2026-10-26)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* **release:** preserve fallback stdin and paginate existing releases ([#781](https://github.com/0xPlayerOne/code-foundry/issues/781)) ([ede4d2c](https://github.com/0xPlayerOne/code-foundry/commit/ede4d2c7e3bc7d1174580c9a0bc83bdaa160c2da))
|
|
44
|
+
|
|
3
45
|
## [1.48.8](https://github.com/0xPlayerOne/code-foundry/compare/v1.48.7...v1.48.8) (2026-10-24)
|
|
4
46
|
|
|
5
47
|
|
|
@@ -98,51 +140,9 @@
|
|
|
98
140
|
|
|
99
141
|
* **doctor:** pin the machine-hook shadow warning ([#753](https://github.com/0xPlayerOne/code-foundry/issues/753)) ([f634269](https://github.com/0xPlayerOne/code-foundry/commit/f634269424580d8d34323319288747587b6d6ae3))
|
|
100
142
|
|
|
101
|
-
## [1.47.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.6...v1.47.0) (2026-10-08)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
### Features
|
|
105
|
-
|
|
106
|
-
* **release:** configurable dev channel on top of batched releases ([#749](https://github.com/0xPlayerOne/code-foundry/issues/749)) ([8fd8556](https://github.com/0xPlayerOne/code-foundry/commit/8fd85567a1a89735ab0db589649741253fbbeb21)), closes [#699](https://github.com/0xPlayerOne/code-foundry/issues/699)
|
|
107
|
-
|
|
108
|
-
## [1.46.6](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.5...v1.46.6) (2026-10-08)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
### Bug Fixes
|
|
112
|
-
|
|
113
|
-
* **pre-commit:** build before lint and type-check when the gate opts in ([#748](https://github.com/0xPlayerOne/code-foundry/issues/748)) ([f56454f](https://github.com/0xPlayerOne/code-foundry/commit/f56454f313a1a5b802b8a17b09d850902de1ba55)), closes [#691](https://github.com/0xPlayerOne/code-foundry/issues/691)
|
|
114
|
-
|
|
115
|
-
## [1.46.5](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.4...v1.46.5) (2026-10-08)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
### Bug Fixes
|
|
119
|
-
|
|
120
|
-
* **sync:** chain machine-level hooks instead of silencing them ([#747](https://github.com/0xPlayerOne/code-foundry/issues/747)) ([7fcad52](https://github.com/0xPlayerOne/code-foundry/commit/7fcad52d400dbb2aaa9ba46c0c76f14e8d63f660)), closes [#690](https://github.com/0xPlayerOne/code-foundry/issues/690)
|
|
121
|
-
|
|
122
|
-
## [1.46.4](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.3...v1.46.4) (2026-10-08)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
### Bug Fixes
|
|
126
|
-
|
|
127
|
-
* **release:** preserve current-head validation ownership ([#737](https://github.com/0xPlayerOne/code-foundry/issues/737)) ([aa8bfcf](https://github.com/0xPlayerOne/code-foundry/commit/aa8bfcfbfcd3c213d15ba9e1fbfb5c65ab8ddb6b))
|
|
128
|
-
|
|
129
|
-
## [1.46.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.2...v1.46.3) (2026-10-07)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
### Bug Fixes
|
|
133
|
-
|
|
134
|
-
* **billing:** keep lint standalone; join fast-lane receipts in parallel ([#744](https://github.com/0xPlayerOne/code-foundry/issues/744)) ([574690b](https://github.com/0xPlayerOne/code-foundry/commit/574690b707abffe9350ccc67589540afb82323ee))
|
|
135
|
-
|
|
136
|
-
## [1.46.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.46.1...v1.46.2) (2026-10-07)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
### Bug Fixes
|
|
140
|
-
|
|
141
|
-
* **billing:** join fast-lane receipts in a second parallel group ([#742](https://github.com/0xPlayerOne/code-foundry/issues/742)) ([c63a39c](https://github.com/0xPlayerOne/code-foundry/commit/c63a39cf5e236d6747bd85cf10b04bd10f690b11))
|
|
142
|
-
|
|
143
143
|
<!-- code-foundry: packaged changelog -->
|
|
144
144
|
|
|
145
145
|
---
|
|
146
146
|
|
|
147
|
-
This packaged changelog lists the 20 most recent releases;
|
|
147
|
+
This packaged changelog lists the 20 most recent releases; 262 older releases are omitted to keep the package small.
|
|
148
148
|
See the [full changelog](https://github.com/0xPlayerOne/code-foundry/blob/main/CHANGELOG.md) for the complete history.
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -175,6 +175,7 @@ See [Merge queue validation](merge-queues.md) before enabling it.
|
|
|
175
175
|
| `rust_nextest` | `true`, `false` | Install cargo-nextest and prefer `cargo nextest run` over `cargo test` in Rust test lanes. |
|
|
176
176
|
| `e2e_shards` | `1`–`8` | Fan the `Validation / Test / E2E` job into one runner per shard. The repository's `test:e2e`/`e2e` script receives `E2E_SHARD_INDEX` and `E2E_TOTAL_SHARDS` and partitions itself (Playwright takes `--shard=$E2E_SHARD_INDEX/$E2E_TOTAL_SHARDS`); each shard owns a runner-local test database, so shards stay isolated. |
|
|
177
177
|
| `billing_lanes` | `true`, `false` | Route validation through the merged-lane billing orchestrator: format, build, performance, smoke, and eval run as sequential steps of one shared runner, and profile plus dependency audit share one job, so GitHub's whole-minute rounding stops dominating billed minutes on private repositories. Coverage and the `Validation / Gate` check are unchanged; only merge a lane into the shared job when its work stays under the longest separate lane, so CI completion time does not grow. Requires all runner inputs on standard hosted runners. |
|
|
178
|
+
| `release_qualification_receipts` | `true`, `false` (default `false`) | Opt in to seven-day source qualification receipts for eligible version-only Release Please PRs. Defaults to false; see [workflow policy](WORKFLOWS.md#standard-triggers) for requirements and fallback behavior. |
|
|
178
179
|
| `release_batching_schedule` | five-field numeric cron | Batch Release Please into scheduled windows. Ordinary pushes skip the producer; release-PR squashes and manual dispatches still run. Batched releases are created privately as drafts and published with prerelease visibility atomically. Manual dispatches publish stable hotfixes. Absent, releases publish per merge. Requires a single root Release Please package. |
|
|
179
180
|
| `release_batching_prerelease` | `true`, `false` | Defaults to `true` with a schedule. Sync enables `draft` and `force-tag-creation` in Release Please; the producer publishes the draft with the selected visibility. `false` keeps scheduled releases stable-visible. |
|
|
180
181
|
| `release_batching_soak_hours` | `1`–`336` | Generate a daily promoter that promotes the newest prerelease when the oldest candidate since the last stable has soaked this many hours, stitching batch notes. Requires a batching schedule and prerelease publication. Set `STABLE_PROMOTION_HELD=true` in repository Actions variables to hold scheduled and manual promotion; `force` overrides the hold or soak, and `version` selects a plain semantic version. |
|
|
@@ -272,6 +273,7 @@ installed hook predates chaining.
|
|
|
272
273
|
| ------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
273
274
|
| `release_type` | `auto`, `node`, `python`, `rust`, `simple`, `none` | Select a release manifest; `auto` detects one. |
|
|
274
275
|
| `npm_publish` | `true`, `false` | Opt into npm publication. |
|
|
276
|
+
| `npm_publish_auth` | `auto`, `oidc`, `token` | Select trusted OIDC publication or preserve an explicit token workflow. |
|
|
275
277
|
| `license` | `gpl-3.0-or-later`, `agpl-3.0-or-later`, `apache-2.0`, `mit`, `preserve`, `none` | License policy for initialized repositories. |
|
|
276
278
|
| `git_workflow` | `direct`, `staging-release` | Choose the branch topology. |
|
|
277
279
|
| `merge_strategy` | `squash` or `rebase` | Required topology-specific merge method. |
|
|
@@ -300,6 +302,15 @@ described in [Qualified publication](qualified-publication.md). A self-sync of
|
|
|
300
302
|
the Code Foundry source does not advance its own `runtime_ref`; this prevents a
|
|
301
303
|
self-referencing runtime pin from creating a release loop.
|
|
302
304
|
|
|
305
|
+
`npm_publish_auth` defaults to `auto`: a configured `NPM_TOKEN` keeps the
|
|
306
|
+
legacy token publisher, while a missing token uses npm trusted publishing.
|
|
307
|
+
Choose `oidc` to force trusted publishing and prevent `NPM_TOKEN` from reaching
|
|
308
|
+
the reusable release workflow; choose `token` to require `NPM_TOKEN`. The
|
|
309
|
+
separate optional `NPM_READ_TOKEN` is passed only to dependency installation
|
|
310
|
+
when private npm packages need read access. For OIDC, configure npm's trusted
|
|
311
|
+
publisher for the package repository and its generated `.github/workflows/release.yml`
|
|
312
|
+
caller, with `id-token: write` available to both caller and reusable job.
|
|
313
|
+
|
|
303
314
|
## Synchronization and extensions
|
|
304
315
|
|
|
305
316
|
| Key | Values | Purpose |
|
package/docs/PUBLISHING.md
CHANGED
|
@@ -12,8 +12,13 @@ Choose the release path that matches the repository:
|
|
|
12
12
|
## npm publication for consumer repositories
|
|
13
13
|
|
|
14
14
|
Set `npm_publish: true` only when the repository owns an npm package. Configure
|
|
15
|
-
npm trusted publishing for the generated `release.yml` workflow
|
|
16
|
-
|
|
15
|
+
npm trusted publishing for the generated `release.yml` workflow. The
|
|
16
|
+
`npm_publish_auth` setting defaults to `auto`: existing `NPM_TOKEN` users keep
|
|
17
|
+
token publication, and tokenless repositories use OIDC. Set it to `oidc` to
|
|
18
|
+
force trusted publishing and keep `NPM_TOKEN` out of publication and install;
|
|
19
|
+
use `NPM_READ_TOKEN` separately when private dependencies must be installed.
|
|
20
|
+
Set `npm_publish_auth: token` only when a long-lived publishing token is still
|
|
21
|
+
required.
|
|
17
22
|
|
|
18
23
|
Declare the package's intended visibility explicitly:
|
|
19
24
|
|
|
@@ -26,8 +31,11 @@ Declare the package's intended visibility explicitly:
|
|
|
26
31
|
```
|
|
27
32
|
|
|
28
33
|
Publication occurs only from a Release Please tag; ordinary pushes do not
|
|
29
|
-
publish.
|
|
30
|
-
|
|
34
|
+
publish. `token` mode fails clearly unless `NPM_TOKEN` is configured. `auto`
|
|
35
|
+
uses OIDC when the publishing token is absent, and `oidc` always uses the
|
|
36
|
+
workflow's short-lived trusted identity. For private dependency installation,
|
|
37
|
+
the workflow consumes `NPM_READ_TOKEN` first; `NPM_TOKEN` is an install fallback
|
|
38
|
+
only outside explicit OIDC mode.
|
|
31
39
|
|
|
32
40
|
After enabling publication, make one controlled release and verify both the
|
|
33
41
|
registry version and its provenance link before treating the setup as complete.
|
|
@@ -43,7 +51,7 @@ callers:
|
|
|
43
51
|
3. Publish the immutable GitHub Release after verifying the tag, source commit,
|
|
44
52
|
archive digest, immutable-release setting, and qualification reports.
|
|
45
53
|
4. Publish the already-qualified archive through the qualified publisher using npm
|
|
46
|
-
trusted publishing
|
|
54
|
+
trusted publishing.
|
|
47
55
|
|
|
48
56
|
The final publisher does not rebuild or reinstall the package. It publishes only
|
|
49
57
|
the bytes selected from the same workflow run and attempt. See [Consumer
|
package/docs/WORKFLOWS.md
CHANGED
|
@@ -56,15 +56,27 @@ workflow_dispatch:
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
In the `staging-release` topology, pull requests into `staging` run the fast
|
|
59
|
-
tier
|
|
60
|
-
Release Please pull requests into `main`
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
tier and ordinary pull requests into `main` run the full audit tier. Exact
|
|
60
|
+
Release Please pull requests into `main` must pass the release-diff policy and
|
|
61
|
+
configured CodeQL scan. They also run the full CI and unit-test fallback unless
|
|
62
|
+
the workflow verifies a seven-day source qualification receipt. A receipt is
|
|
63
|
+
usable only when a successful full audit tested the exact current `main` tree
|
|
64
|
+
with the same validation workflow, Code Foundry runtime, CodeQL policy, and
|
|
65
|
+
pull-request/run identity. Verification checks the merged source PR, the
|
|
66
|
+
aggregate gate's success in the exact run attempt, the required component
|
|
67
|
+
results, and the artifact's bounded download size and SHA-256 digest. The release-diff preflight must confirm a
|
|
68
|
+
version-only patch. Reuse is currently supported only for a public npm package
|
|
69
|
+
released from the repository root; private roots, workspaces, and unknown
|
|
70
|
+
Release Please layouts use the full CI and test fallback. A root package may
|
|
71
|
+
use `prepublishOnly` only when it exactly invokes the configured package
|
|
72
|
+
manager's `run build` task; other lifecycle hooks and custom prepublish commands
|
|
73
|
+
use the full fallback. With a verified
|
|
74
|
+
receipt, the applicable build is forced even when path filtering would skip it,
|
|
75
|
+
and the versioned root npm package inspection still runs. Only duplicate
|
|
76
|
+
format, lint, type-check, and unit-test work is skipped. The receipt never
|
|
77
|
+
replaces the release-diff audit or configured CodeQL scan.
|
|
78
|
+
The managed branch rulesets require only the aggregate `Validation / Gate`
|
|
79
|
+
check; do not hand-require individual job contexts on release branches.
|
|
68
80
|
In the
|
|
69
81
|
`direct` topology (the default) every pull request targets `main` and runs the
|
|
70
82
|
full audit tier, because there is no integration branch for a fast pass.
|
|
@@ -185,9 +197,10 @@ Use concise job names such as `CI / Format`, `Test / Unit`, and
|
|
|
185
197
|
included) and security audits run through a detection-built matrix, so a
|
|
186
198
|
repository only ever shows checks for languages it actually uses — never
|
|
187
199
|
skipped rows for other languages. The release tier validates the generated
|
|
188
|
-
diff
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
diff inside the gate and requires CodeQL when configured. It reuses prior
|
|
201
|
+
source tests only when the short-lived exact-tree receipt verifies; otherwise
|
|
202
|
+
it runs the full CI and unit-test fallback. Required checks should match the
|
|
203
|
+
jobs actually enabled for the repository profile — in practice, require only the aggregate
|
|
191
204
|
`Validation / Gate`, which fails closed unless every generated check
|
|
192
205
|
succeeds.
|
|
193
206
|
|
|
@@ -29,17 +29,19 @@ package.
|
|
|
29
29
|
The publishing job serializes publication for a tag and has no dependency
|
|
30
30
|
installation/build step. Qualification has no npm credential. This self-only
|
|
31
31
|
publisher has no environment approval gate; publication is automatic after its
|
|
32
|
-
completed gates. npm trusted publishing
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
completed gates and uses OIDC only. Configure npm trusted publishing for the
|
|
33
|
+
actual caller workflow filename, `release_self-ci.yml`, in repository
|
|
34
|
+
`0xPlayerOne/code-foundry`, with direct publish permission and no GitHub
|
|
35
|
+
environment. Both the caller and reusable publisher grant `id-token: write`.
|
|
36
|
+
For generated consumer workflows, the caller filename is `release.yml` and the
|
|
37
|
+
auth mode remains configurable with `npm_publish_auth`.
|
|
35
38
|
Existing version publication is not overwritten: retrying an already-published
|
|
36
39
|
version fails rather than treating a registry conflict or network error as proof
|
|
37
40
|
of identity.
|
|
38
41
|
|
|
39
42
|
The publisher never rebuilds the package, publishes a directory, or treats an
|
|
40
|
-
already-published version conflict as proof of success.
|
|
41
|
-
|
|
42
|
-
fallback for environments that cannot use trusted publishing.
|
|
43
|
+
already-published version conflict as proof of success. It never accepts or
|
|
44
|
+
forwards `NPM_TOKEN`.
|
|
43
45
|
|
|
44
46
|
Qualification and publication are gated on `main` push or an explicitly
|
|
45
47
|
requested `workflow_dispatch`. The shared billing pause blocks normal runs. A
|
|
@@ -89,15 +91,16 @@ jobs:
|
|
|
89
91
|
with:
|
|
90
92
|
tag: ${{ needs.release-producer.outputs.tag }}
|
|
91
93
|
asset: ${{ needs.release-producer.outputs.npm-asset }}
|
|
92
|
-
secrets:
|
|
93
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
For the self repository, `release_self-ci.yml` supplies the release output and
|
|
97
|
-
uses the
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
uses the qualified publisher job without a GitHub environment. The actual
|
|
98
|
+
caller filename must match npm's trusted-publisher configuration; a similarly
|
|
99
|
+
named reusable workflow does not match. A prior publisher entry named
|
|
100
|
+
`release.yml` did not match the self-publish caller; the repository owner reports
|
|
101
|
+
adding the `release_self-ci.yml` entry. A successful OIDC publication still
|
|
102
|
+
needs to verify that identity before any old trust entry or secret is removed.
|
|
103
|
+
This source change does not edit npm trust settings.
|
|
101
104
|
|
|
102
105
|
## Identity and retry rules
|
|
103
106
|
|
|
@@ -131,8 +134,8 @@ administration-read, contents-write, and verification access; it is never expose
|
|
|
131
134
|
to qualification jobs. Preflight and staging reuse the producer's validated
|
|
132
135
|
credential selection, falling back to the workflow token only when the configured
|
|
133
136
|
token is rejected. Configure npm trusted-publisher identity for the actual
|
|
134
|
-
caller
|
|
135
|
-
|
|
137
|
+
caller workflow filename. This self-only publisher does not support a token
|
|
138
|
+
fallback.
|
|
136
139
|
|
|
137
140
|
## Trust boundaries
|
|
138
141
|
|
|
@@ -168,6 +171,11 @@ publisher from the same source-bound workflow after confirming npm has not alrea
|
|
|
168
171
|
accepted that version. Never weaken the SHA guard, move an immutable tag, or treat
|
|
169
172
|
npm's version-conflict response as success.
|
|
170
173
|
|
|
174
|
+
If npm fails, the publisher reports only a fixed diagnostic category for known
|
|
175
|
+
npm error codes. Unknown errors remain generic; stderr, registry URLs, paths, and
|
|
176
|
+
credentials are not logged by this diagnostic. A category is a clue, not proof
|
|
177
|
+
of the cause, and does not change the publication gates.
|
|
178
|
+
|
|
171
179
|
## Validation
|
|
172
180
|
|
|
173
181
|
Run the focused local suites before changing this path:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-foundry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.50.0",
|
|
4
4
|
"description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
|
|
5
5
|
"homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"src",
|
|
19
|
+
"!src/commands/qualification-receipt.mjs",
|
|
20
|
+
"!src/lib/qualification-receipt.mjs",
|
|
21
|
+
"!src/lib/release-package-contract.mjs",
|
|
19
22
|
"docs",
|
|
20
23
|
".github",
|
|
21
24
|
"!.github/actions/**",
|
|
@@ -31,6 +31,29 @@ export const REQUIRED_FIXTURES = [
|
|
|
31
31
|
function ensure(condition, message) {
|
|
32
32
|
if (!condition) throw new Error(message)
|
|
33
33
|
}
|
|
34
|
+
// Extract only fixed categories from npm's code line. Never echo stderr or the
|
|
35
|
+
// captured code: npm output may contain credentials, paths, or registry URLs.
|
|
36
|
+
/** @param {string} stderr */
|
|
37
|
+
export function npmFailureCategory(stderr) {
|
|
38
|
+
const categories = {
|
|
39
|
+
E401: 'authentication',
|
|
40
|
+
E403: 'authorization-or-policy',
|
|
41
|
+
E404: 'registry-or-package',
|
|
42
|
+
E409: 'version-conflict',
|
|
43
|
+
EOTP: 'authentication',
|
|
44
|
+
ENEEDAUTH: 'authentication',
|
|
45
|
+
ECONNRESET: 'network',
|
|
46
|
+
ECONNREFUSED: 'network',
|
|
47
|
+
ENOTFOUND: 'network',
|
|
48
|
+
ETIMEDOUT: 'network',
|
|
49
|
+
}
|
|
50
|
+
for (const line of stderr.split(/\r?\n/)) {
|
|
51
|
+
const code = /^npm (?:ERR!|error) code ([A-Z0-9]+)\s*$/.exec(line)?.[1]
|
|
52
|
+
if (code && Object.hasOwn(categories, code))
|
|
53
|
+
return categories[/** @type {keyof typeof categories} */ (code)]
|
|
54
|
+
}
|
|
55
|
+
return 'unknown'
|
|
56
|
+
}
|
|
34
57
|
/** @type {Run} */
|
|
35
58
|
export function runCommand(command, args, cwd) {
|
|
36
59
|
const result = spawnSync(command, args, {
|
|
@@ -40,6 +63,10 @@ export function runCommand(command, args, cwd) {
|
|
|
40
63
|
maxBuffer: 8 * 1024 * 1024,
|
|
41
64
|
env: { ...process.env, GH_HOST: 'github.com', GH_PROMPT_DISABLED: '1' },
|
|
42
65
|
})
|
|
66
|
+
if (command === 'npm' && (result.error || result.status !== 0)) {
|
|
67
|
+
const category = npmFailureCategory(result.stderr ?? '')
|
|
68
|
+
throw new Error(`npm failed (category: ${category}); publication remains blocked`)
|
|
69
|
+
}
|
|
43
70
|
ensure(
|
|
44
71
|
!result.error && result.status === 0,
|
|
45
72
|
`${command} failed (${result.status ?? result.error?.message}); publication remains blocked`
|