code-foundry 1.20.2 → 1.25.3
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 +5 -2
- package/.github/code-foundry.yml +1 -0
- package/.github/release-please-foundry.json +56 -0
- package/.github/workflows/cloudflare-delivery.yml +9 -0
- package/.github/workflows/cloudflare-deploy.yml +8 -1
- package/.github/workflows/eval.yml +116 -0
- package/.github/workflows/opencode-security_self-ci.yml +1 -1
- package/.github/workflows/qualified-foundry-publish.yml +6 -7
- package/.github/workflows/release.yml +58 -10
- package/.github/workflows/release_self-ci.yml +211 -8
- package/.github/workflows/validation-no-codeql.yml +34 -6
- package/.github/workflows/validation.yml +32 -5
- package/.github/workflows/validation_audit_self-ci.yml +1 -0
- package/.github/workflows/validation_self-ci.yml +1 -0
- package/.gitignore +1 -1
- package/AGENTS.md +5 -1
- package/CHANGELOG.md +95 -0
- package/README.md +23 -17
- package/docs/CONFIGURATION.md +189 -152
- package/docs/EVALS.md +139 -0
- package/docs/EXTENSIONS.md +28 -7
- package/docs/INITIALIZATION.md +13 -9
- package/docs/PERFORMANCE.md +67 -59
- package/docs/PUBLISHING.md +39 -14
- package/docs/README.md +37 -22
- package/docs/RELEASES.md +18 -9
- package/docs/WORKFLOWS.md +23 -4
- package/docs/agent-validation.md +6 -5
- package/docs/cloudflare-delivery.md +20 -8
- package/docs/consumer-qualification.md +11 -9
- package/docs/fleet-release-eligibility.md +14 -15
- package/docs/fleet-rollouts.md +3 -3
- package/docs/merge-queues.md +21 -21
- package/docs/product-quality.md +9 -10
- package/docs/qualified-publication.md +166 -93
- package/docs/release-integrity.md +7 -6
- package/docs/required-capabilities.md +24 -15
- package/package.json +1 -1
- package/src/commands/cloudflare-delivery.mjs +6 -1
- package/src/commands/qualified-publication.mjs +103 -12
- package/src/commands/release-integrity.mjs +46 -14
- package/src/commands/sync.mjs +30 -24
- package/src/lib/eval-envelope.mjs +234 -0
- package/src/lib/merge-queue.mjs +1 -0
- package/src/lib/product-quality.mjs +220 -16
- package/src/lib/task-policy.mjs +7 -0
- package/src/lib/validation-policy.mjs +10 -6
- package/src/runtime-core.mjs +166 -8
- package/src/runtime.mjs +3 -1
- package/src/templates/gitignore +3 -1
|
@@ -12,32 +12,235 @@ on:
|
|
|
12
12
|
default: false
|
|
13
13
|
|
|
14
14
|
permissions:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
# One owner for draft staging and npm publication. Never cancel an active release.
|
|
18
|
+
concurrency:
|
|
19
|
+
group: code-foundry-qualified-release-${{ github.repository }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: false
|
|
20
21
|
|
|
21
22
|
jobs:
|
|
22
23
|
qualification:
|
|
23
24
|
name: Qualify consumers
|
|
24
|
-
if: vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)
|
|
25
|
+
if: github.ref == 'refs/heads/main' && (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true))
|
|
25
26
|
uses: ./.github/workflows/consumer-qualification.yml
|
|
26
27
|
with:
|
|
27
28
|
billing-pause-bypass: ${{ github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true }}
|
|
28
29
|
permissions:
|
|
29
30
|
actions: read
|
|
30
31
|
contents: read
|
|
32
|
+
|
|
33
|
+
preflight:
|
|
34
|
+
name: Verify release prerequisites
|
|
35
|
+
if: github.ref == 'refs/heads/main' && (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true))
|
|
36
|
+
runs-on: ubuntu-24.04
|
|
37
|
+
timeout-minutes: 5
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout trusted verifier
|
|
40
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
41
|
+
with:
|
|
42
|
+
persist-credentials: false
|
|
43
|
+
ref: ${{ github.sha }}
|
|
44
|
+
- name: Setup Node
|
|
45
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
|
46
|
+
with:
|
|
47
|
+
node-version: '24'
|
|
48
|
+
- name: Require activation and verify immutability without changing it
|
|
49
|
+
env:
|
|
50
|
+
REQUIRE_IMMUTABLE_RELEASES: ${{ vars.REQUIRE_IMMUTABLE_RELEASES }}
|
|
51
|
+
CODE_FOUNDRY_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN }}
|
|
52
|
+
GH_TOKEN: ${{ github.token }}
|
|
53
|
+
run: |
|
|
54
|
+
set -euo pipefail
|
|
55
|
+
test "$REQUIRE_IMMUTABLE_RELEASES" = true || { echo 'Enable and review immutable release prerequisites before this cutover.' >&2; exit 1; }
|
|
56
|
+
gh release verify --help >/dev/null
|
|
57
|
+
gh release verify-asset --help >/dev/null
|
|
58
|
+
# Match the reusable producer's credential selection. A rejected
|
|
59
|
+
# configured token must not make the later staging job use it.
|
|
60
|
+
if [ -n "$CODE_FOUNDRY_TOKEN" ] && GH_TOKEN="$CODE_FOUNDRY_TOKEN" gh api "repos/${GITHUB_REPOSITORY}" --jq '.full_name' >/dev/null 2>&1; then
|
|
61
|
+
GH_TOKEN="$CODE_FOUNDRY_TOKEN" node src/commands/release-integrity.mjs settings --repo "$GITHUB_REPOSITORY"
|
|
62
|
+
else
|
|
63
|
+
node src/commands/release-integrity.mjs settings --repo "$GITHUB_REPOSITORY"
|
|
64
|
+
fi
|
|
65
|
+
|
|
31
66
|
release:
|
|
32
67
|
name: Release
|
|
33
|
-
needs: qualification
|
|
34
|
-
if: vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)
|
|
68
|
+
needs: [qualification, preflight]
|
|
69
|
+
if: github.ref == 'refs/heads/main' && (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true))
|
|
35
70
|
uses: ./.github/workflows/release.yml
|
|
36
71
|
with:
|
|
37
72
|
billing-pause-bypass: ${{ github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true }}
|
|
38
73
|
runner: ubuntu-slim
|
|
39
74
|
runtime-repository: 0xPlayerOne/code-foundry
|
|
40
75
|
runtime-ref: ${{ github.sha }}
|
|
76
|
+
config-file: .github/release-please-foundry.json
|
|
77
|
+
defer-publication: true
|
|
78
|
+
permissions:
|
|
79
|
+
actions: write
|
|
80
|
+
contents: write
|
|
81
|
+
issues: write
|
|
82
|
+
pull-requests: write
|
|
83
|
+
# Required by the reusable legacy workflow's declared npm job, which is disabled here.
|
|
84
|
+
id-token: write
|
|
41
85
|
secrets:
|
|
42
86
|
CODE_FOUNDRY_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN }}
|
|
87
|
+
|
|
88
|
+
recovery:
|
|
89
|
+
name: Recover qualified draft identity
|
|
90
|
+
needs: [qualification, release]
|
|
91
|
+
if: (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)) && needs.qualification.result == 'success' && needs.release.result == 'success'
|
|
92
|
+
runs-on: ubuntu-24.04
|
|
93
|
+
timeout-minutes: 5
|
|
94
|
+
permissions:
|
|
95
|
+
contents: read
|
|
96
|
+
outputs:
|
|
97
|
+
found: ${{ steps.recover.outputs.found }}
|
|
98
|
+
tag: ${{ steps.recover.outputs.tag }}
|
|
99
|
+
sha: ${{ steps.recover.outputs.sha }}
|
|
100
|
+
env:
|
|
101
|
+
RELEASE_CREATED: ${{ needs.release.outputs.release_created }}
|
|
102
|
+
SOURCE_SHA: ${{ needs.qualification.outputs.source-sha }}
|
|
103
|
+
steps:
|
|
104
|
+
- name: Checkout trusted recovery runtime
|
|
105
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
106
|
+
with:
|
|
107
|
+
persist-credentials: false
|
|
108
|
+
ref: ${{ github.sha }}
|
|
109
|
+
- name: Setup Node
|
|
110
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
|
111
|
+
with:
|
|
112
|
+
node-version: '24'
|
|
113
|
+
- name: Locate an exact existing draft
|
|
114
|
+
id: recover
|
|
115
|
+
env:
|
|
116
|
+
GH_TOKEN: ${{ github.token }}
|
|
117
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
118
|
+
run: |
|
|
119
|
+
set -euo pipefail
|
|
120
|
+
node --input-type=module <<'NODE'
|
|
121
|
+
import { appendFileSync, readFileSync } from "node:fs"
|
|
122
|
+
import { resolveTagCommit, runGh } from "./src/commands/release-integrity.mjs"
|
|
123
|
+
const output = process.env.GITHUB_OUTPUT
|
|
124
|
+
const write = (found, tag = "", sha = "") => appendFileSync(output, `found=${found}\ntag=${tag}\nsha=${sha}\n`)
|
|
125
|
+
if (process.env.RELEASE_CREATED === "true") {
|
|
126
|
+
write("false")
|
|
127
|
+
process.exit(0)
|
|
128
|
+
}
|
|
129
|
+
const version = JSON.parse(readFileSync("package.json", "utf8")).version
|
|
130
|
+
const tag = `v${version}`
|
|
131
|
+
// GitHub's get-by-tag endpoint does not return draft releases. Use
|
|
132
|
+
// the authenticated release list and inspect every page instead.
|
|
133
|
+
const endpoint = `repos/${process.env.GITHUB_REPOSITORY}/releases?per_page=100`
|
|
134
|
+
const response = runGh(["api", "--paginate", "--slurp", endpoint])
|
|
135
|
+
if (response.status !== 0) throw new Error("Could not inspect the expected draft release; recovery remains blocked")
|
|
136
|
+
let pages
|
|
137
|
+
try {
|
|
138
|
+
pages = JSON.parse(response.stdout)
|
|
139
|
+
} catch {
|
|
140
|
+
throw new Error("GitHub returned an invalid release response; recovery remains blocked")
|
|
141
|
+
}
|
|
142
|
+
if (!Array.isArray(pages) || pages.some((page) => !Array.isArray(page))) {
|
|
143
|
+
throw new Error("GitHub returned an invalid release list; recovery remains blocked")
|
|
144
|
+
}
|
|
145
|
+
const release = pages.flat().find((entry) => entry?.tag_name === tag)
|
|
146
|
+
if (!release || release.draft !== true) {
|
|
147
|
+
write("false")
|
|
148
|
+
process.exit(0)
|
|
149
|
+
}
|
|
150
|
+
if (release.tag_name !== tag) throw new Error("Existing draft tag does not match the expected package version")
|
|
151
|
+
const sourceSha = resolveTagCommit(process.env.GITHUB_REPOSITORY, tag, runGh)
|
|
152
|
+
if (sourceSha.toLowerCase() !== process.env.SOURCE_SHA.toLowerCase()) throw new Error("Existing draft tag does not match the qualified source SHA")
|
|
153
|
+
write("true", tag, sourceSha)
|
|
154
|
+
NODE
|
|
155
|
+
|
|
156
|
+
stage:
|
|
157
|
+
name: Stage qualified release
|
|
158
|
+
needs: [qualification, release, recovery]
|
|
159
|
+
if: (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)) && github.ref == 'refs/heads/main' && (needs.release.outputs.release_created == 'true' || needs.recovery.outputs.found == 'true')
|
|
160
|
+
runs-on: ubuntu-24.04
|
|
161
|
+
timeout-minutes: 15
|
|
162
|
+
permissions:
|
|
163
|
+
actions: read
|
|
164
|
+
attestations: read
|
|
165
|
+
contents: write
|
|
166
|
+
env:
|
|
167
|
+
RELEASE_TAG: ${{ needs.release.outputs.tag_name || needs.recovery.outputs.tag }}
|
|
168
|
+
RELEASE_SHA: ${{ needs.release.outputs.sha || needs.recovery.outputs.sha }}
|
|
169
|
+
SOURCE_SHA: ${{ needs.qualification.outputs.source-sha }}
|
|
170
|
+
PACKAGE: ${{ needs.qualification.outputs.filename }}
|
|
171
|
+
CANDIDATE_SHA256: ${{ needs.qualification.outputs.sha256 }}
|
|
172
|
+
CANDIDATE_ARTIFACT: ${{ needs.qualification.outputs.candidate-artifact }}
|
|
173
|
+
steps:
|
|
174
|
+
- name: Checkout trusted staging runtime
|
|
175
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
176
|
+
with:
|
|
177
|
+
persist-credentials: false
|
|
178
|
+
ref: ${{ github.sha }}
|
|
179
|
+
- name: Setup Node
|
|
180
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
|
|
181
|
+
with:
|
|
182
|
+
node-version: '24'
|
|
183
|
+
- name: Require the release to identify this qualified candidate
|
|
184
|
+
run: |
|
|
185
|
+
node --input-type=module <<'NODE'
|
|
186
|
+
import assert from 'node:assert/strict'
|
|
187
|
+
import { readFileSync } from 'node:fs'
|
|
188
|
+
const env = process.env
|
|
189
|
+
const version = JSON.parse(readFileSync('package.json', 'utf8')).version
|
|
190
|
+
assert.match(env.SOURCE_SHA, /^[a-f0-9]{40}$/)
|
|
191
|
+
assert.equal(env.SOURCE_SHA, env.GITHUB_SHA)
|
|
192
|
+
assert.equal(env.RELEASE_SHA, env.SOURCE_SHA)
|
|
193
|
+
assert.equal(env.RELEASE_TAG, `v${version}`)
|
|
194
|
+
assert.equal(env.PACKAGE, `code-foundry-${version}.tgz`)
|
|
195
|
+
assert.match(env.CANDIDATE_SHA256, /^[a-f0-9]{64}$/)
|
|
196
|
+
assert.equal(env.CANDIDATE_ARTIFACT, `qualification-candidate-${env.GITHUB_RUN_ID}-${env.GITHUB_RUN_ATTEMPT}`)
|
|
197
|
+
NODE
|
|
198
|
+
- name: Retrieve only this attempt's qualified bytes and reports
|
|
199
|
+
env:
|
|
200
|
+
GH_TOKEN: ${{ github.token }}
|
|
201
|
+
run: |
|
|
202
|
+
set -euo pipefail
|
|
203
|
+
gh run download "$GITHUB_RUN_ID" --repo "$GITHUB_REPOSITORY" \
|
|
204
|
+
--name "$CANDIDATE_ARTIFACT" --dir "$RUNNER_TEMP/candidate"
|
|
205
|
+
test "$(sha256sum "$RUNNER_TEMP/candidate/$PACKAGE" | cut -d' ' -f1)" = "$CANDIDATE_SHA256"
|
|
206
|
+
for node in 20 22 24; do
|
|
207
|
+
gh run download "$GITHUB_RUN_ID" --repo "$GITHUB_REPOSITORY" \
|
|
208
|
+
--name "consumer-qualification-$GITHUB_RUN_ATTEMPT-node-$node" \
|
|
209
|
+
--dir "$RUNNER_TEMP/reports/$node"
|
|
210
|
+
done
|
|
211
|
+
- name: Stage identical assets then publish and verify the immutable release
|
|
212
|
+
env:
|
|
213
|
+
GH_TOKEN: ${{ needs.release.outputs.token_source == 'configured' && secrets.CODE_FOUNDRY_TOKEN || github.token }}
|
|
214
|
+
run: |
|
|
215
|
+
set -euo pipefail
|
|
216
|
+
node src/commands/qualified-publication.mjs stage \
|
|
217
|
+
"$GITHUB_REPOSITORY" "$RELEASE_TAG" "$SOURCE_SHA" "$PACKAGE" \
|
|
218
|
+
"$RUNNER_TEMP/candidate" \
|
|
219
|
+
"$RUNNER_TEMP/reports/20/report.json" \
|
|
220
|
+
"$RUNNER_TEMP/reports/22/report.json" \
|
|
221
|
+
"$RUNNER_TEMP/reports/24/report.json" > "$RUNNER_TEMP/staging.json"
|
|
222
|
+
- name: Retain staging identity
|
|
223
|
+
if: always()
|
|
224
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
225
|
+
with:
|
|
226
|
+
name: release-staging-${{ github.run_id }}-${{ github.run_attempt }}
|
|
227
|
+
path: ${{ runner.temp }}/staging.json
|
|
228
|
+
if-no-files-found: warn
|
|
229
|
+
retention-days: 14
|
|
230
|
+
|
|
231
|
+
publish:
|
|
232
|
+
name: Publish verified package
|
|
233
|
+
needs: [qualification, release, recovery, stage]
|
|
234
|
+
if: (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)) && github.ref == 'refs/heads/main' && needs.stage.result == 'success' && (needs.release.outputs.release_created == 'true' || needs.recovery.outputs.found == 'true')
|
|
235
|
+
uses: ./.github/workflows/qualified-foundry-publish.yml
|
|
236
|
+
permissions:
|
|
237
|
+
actions: read
|
|
238
|
+
attestations: read
|
|
239
|
+
contents: read
|
|
240
|
+
id-token: write
|
|
241
|
+
with:
|
|
242
|
+
tag: ${{ needs.release.outputs.tag_name || needs.recovery.outputs.tag }}
|
|
243
|
+
asset: ${{ needs.qualification.outputs.filename }}
|
|
244
|
+
billing-pause-bypass: ${{ github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true }}
|
|
245
|
+
secrets:
|
|
43
246
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -42,6 +42,14 @@ on:
|
|
|
42
42
|
required: false
|
|
43
43
|
type: string
|
|
44
44
|
default: ubuntu-slim
|
|
45
|
+
eval-runner:
|
|
46
|
+
description: >-
|
|
47
|
+
Runner used by the eval harness. Browser evals need a
|
|
48
|
+
Chrome-capable runner such as ubuntu-latest; ubuntu-slim does not
|
|
49
|
+
ship a browser.
|
|
50
|
+
required: false
|
|
51
|
+
type: string
|
|
52
|
+
default: ubuntu-latest
|
|
45
53
|
codeql-runner:
|
|
46
54
|
description: Runner used by CodeQL jobs.
|
|
47
55
|
required: false
|
|
@@ -106,28 +114,47 @@ jobs:
|
|
|
106
114
|
runner: ${{ inputs.test-runner }}
|
|
107
115
|
unit-runner: ${{ inputs.unit-runner }}
|
|
108
116
|
performance-runner: ${{ inputs.performance-runner }}
|
|
109
|
-
|
|
117
|
+
# Release pull requests change version metadata only; their content was
|
|
118
|
+
# audited on the pull requests that merged into main. Integration, E2E,
|
|
119
|
+
# smoke, and performance lanes stay in the audit and scheduled lanes.
|
|
120
|
+
unit-only: ${{ inputs.mode == 'fast' || inputs.mode == 'release' }}
|
|
110
121
|
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
111
122
|
secrets:
|
|
112
123
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
113
124
|
|
|
114
125
|
security:
|
|
115
126
|
name: Security
|
|
116
|
-
if: vars.CI_BILLING_PAUSED != 'true' &&
|
|
127
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
117
128
|
uses: ./.github/workflows/security.yml
|
|
118
129
|
with:
|
|
119
130
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
120
131
|
runtime-ref: ${{ inputs.runtime-ref }}
|
|
121
132
|
runner: ${{ inputs.security-runner }}
|
|
122
133
|
|
|
134
|
+
eval:
|
|
135
|
+
name: Eval
|
|
136
|
+
# Behavior evals cover content changes; the lean release lane skips them
|
|
137
|
+
# because its diff is version metadata only. The reusable workflow skips
|
|
138
|
+
# cleanly when the repository has no eval harness.
|
|
139
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
140
|
+
uses: ./.github/workflows/eval.yml
|
|
141
|
+
with:
|
|
142
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
143
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
144
|
+
runner: ${{ inputs.eval-runner }}
|
|
145
|
+
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
146
|
+
|
|
123
147
|
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
124
148
|
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
125
|
-
# The release tier
|
|
126
|
-
#
|
|
127
|
-
#
|
|
149
|
+
# The release tier requires the available fast suite; its diff is version
|
|
150
|
+
# metadata (validated against the release policy below), its content was
|
|
151
|
+
# audited on the pull requests that merged into main, and the scheduled
|
|
152
|
+
# audit lane re-covers drift. Its generated release diff policy executes
|
|
153
|
+
# as a conditional step below, so no separate release-policy job renders
|
|
154
|
+
# skipped checks on ordinary pull requests.
|
|
128
155
|
gate:
|
|
129
156
|
name: Gate
|
|
130
|
-
needs: [ci, test, security]
|
|
157
|
+
needs: [ci, test, security, eval]
|
|
131
158
|
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
132
159
|
runs-on: ubuntu-slim
|
|
133
160
|
timeout-minutes: 10
|
|
@@ -136,6 +163,7 @@ jobs:
|
|
|
136
163
|
FOUNDRY_CI: ${{ needs.ci.result }}
|
|
137
164
|
FOUNDRY_TEST: ${{ needs.test.result }}
|
|
138
165
|
FOUNDRY_SECURITY: ${{ needs.security.result }}
|
|
166
|
+
FOUNDRY_EVAL: ${{ needs.eval.result }}
|
|
139
167
|
# This workflow is selected only for repositories whose canonical
|
|
140
168
|
# configuration explicitly disables unavailable CodeQL. Treat that
|
|
141
169
|
# policy decision as satisfied without registering a skipped PR check.
|
|
@@ -42,6 +42,14 @@ on:
|
|
|
42
42
|
required: false
|
|
43
43
|
type: string
|
|
44
44
|
default: ubuntu-slim
|
|
45
|
+
eval-runner:
|
|
46
|
+
description: >-
|
|
47
|
+
Runner used by the eval harness. Browser evals need a
|
|
48
|
+
Chrome-capable runner such as ubuntu-latest; ubuntu-slim does not
|
|
49
|
+
ship a browser.
|
|
50
|
+
required: false
|
|
51
|
+
type: string
|
|
52
|
+
default: ubuntu-latest
|
|
45
53
|
codeql-runner:
|
|
46
54
|
description: Runner used by CodeQL jobs.
|
|
47
55
|
required: false
|
|
@@ -106,14 +114,17 @@ jobs:
|
|
|
106
114
|
runner: ${{ inputs.test-runner }}
|
|
107
115
|
unit-runner: ${{ inputs.unit-runner }}
|
|
108
116
|
performance-runner: ${{ inputs.performance-runner }}
|
|
109
|
-
|
|
117
|
+
# Release pull requests change version metadata only; their content was
|
|
118
|
+
# audited on the pull requests that merged into main. Integration, E2E,
|
|
119
|
+
# smoke, and performance lanes stay in the audit and scheduled lanes.
|
|
120
|
+
unit-only: ${{ inputs.mode == 'fast' || inputs.mode == 'release' }}
|
|
110
121
|
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
111
122
|
secrets:
|
|
112
123
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
113
124
|
|
|
114
125
|
security:
|
|
115
126
|
name: Security
|
|
116
|
-
if: vars.CI_BILLING_PAUSED != 'true' &&
|
|
127
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
117
128
|
uses: ./.github/workflows/security.yml
|
|
118
129
|
with:
|
|
119
130
|
runtime-repository: ${{ inputs.runtime-repository }}
|
|
@@ -134,15 +145,30 @@ jobs:
|
|
|
134
145
|
rust-threads: ${{ inputs.rust-threads }}
|
|
135
146
|
rust-max-parallel: ${{ inputs.rust-max-parallel }}
|
|
136
147
|
|
|
148
|
+
eval:
|
|
149
|
+
name: Eval
|
|
150
|
+
# Behavior evals cover content changes; the lean release lane skips them
|
|
151
|
+
# because its diff is version metadata only. The reusable workflow skips
|
|
152
|
+
# cleanly when the repository has no eval harness.
|
|
153
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.mode == 'audit'
|
|
154
|
+
uses: ./.github/workflows/eval.yml
|
|
155
|
+
with:
|
|
156
|
+
runtime-repository: ${{ inputs.runtime-repository }}
|
|
157
|
+
runtime-ref: ${{ inputs.runtime-ref }}
|
|
158
|
+
runner: ${{ inputs.eval-runner }}
|
|
159
|
+
artifact-prefix: ${{ inputs.artifact-prefix }}
|
|
160
|
+
|
|
137
161
|
# Aggregate check: "Validation / Gate" (caller job name + this job name).
|
|
138
162
|
# Always evaluates; only jobs required for the mode must have succeeded.
|
|
139
|
-
# The release tier
|
|
140
|
-
#
|
|
163
|
+
# The release tier requires the fast suite plus CodeQL: its diff is version
|
|
164
|
+
# metadata (validated against the release policy below), its content was
|
|
165
|
+
# audited on the pull requests that merged into main, and the scheduled
|
|
166
|
+
# audit lane re-covers drift. Its generated release diff policy executes
|
|
141
167
|
# as a conditional step below, so ordinary pull requests still render no
|
|
142
168
|
# skipped release-policy row.
|
|
143
169
|
gate:
|
|
144
170
|
name: Gate
|
|
145
|
-
needs: [ci, test, security, codeql]
|
|
171
|
+
needs: [ci, test, security, codeql, eval]
|
|
146
172
|
if: vars.CI_BILLING_PAUSED != 'true' && always()
|
|
147
173
|
runs-on: ubuntu-slim
|
|
148
174
|
timeout-minutes: 10
|
|
@@ -152,6 +178,7 @@ jobs:
|
|
|
152
178
|
FOUNDRY_TEST: ${{ needs.test.result }}
|
|
153
179
|
FOUNDRY_SECURITY: ${{ needs.security.result }}
|
|
154
180
|
FOUNDRY_CODEQL: ${{ needs.codeql.result }}
|
|
181
|
+
FOUNDRY_EVAL: ${{ needs.eval.result }}
|
|
155
182
|
steps:
|
|
156
183
|
- name: Checkout runtime
|
|
157
184
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
package/.gitignore
CHANGED
package/AGENTS.md
CHANGED
|
@@ -106,7 +106,10 @@ This repository uses the `direct` workflow. Topic pull requests target `main`.
|
|
|
106
106
|
- Keep ordinary pull requests in draft while preparing them. The generated
|
|
107
107
|
Draft Guard converts ready ordinary pull requests to draft when they are
|
|
108
108
|
opened or reopened, and runner-heavy validation starts only after an
|
|
109
|
-
explicit `ready_for_review` transition
|
|
109
|
+
explicit `ready_for_review` transition unless `draft_protection: false` is
|
|
110
|
+
configured for generated callers. That opt-out does not disable Draft Guard
|
|
111
|
+
or draft-PR automation. Cloudflare reusable callers use
|
|
112
|
+
`draft-protection: false`.
|
|
110
113
|
- Run local validation and finish review preparation before marking an ordinary
|
|
111
114
|
pull request ready. Ready pull requests stay ready when new commits arrive,
|
|
112
115
|
and validation reruns for the current head; draft updates allocate no
|
|
@@ -146,6 +149,7 @@ node src/runtime.mjs ci unit
|
|
|
146
149
|
node src/runtime.mjs ci integration
|
|
147
150
|
node src/runtime.mjs ci e2e
|
|
148
151
|
node src/runtime.mjs ci smoke
|
|
152
|
+
node src/runtime.mjs ci eval
|
|
149
153
|
node src/runtime.mjs ci performance
|
|
150
154
|
Security and dependency audits run through the GitHub Security workflow.
|
|
151
155
|
```
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,100 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.25.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.25.2...v1.25.3) (2026-09-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **release:** cover the attestation lag in publication retries ([#587](https://github.com/0xPlayerOne/code-foundry/issues/587)) ([7ae5e4b](https://github.com/0xPlayerOne/code-foundry/commit/7ae5e4bb95f68cbf4e2b48778776a0396c877271))
|
|
9
|
+
|
|
10
|
+
## [1.25.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.25.1...v1.25.2) (2026-09-10)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **release:** retry integrity verification through the publication consistency window ([#585](https://github.com/0xPlayerOne/code-foundry/issues/585)) ([5b997dd](https://github.com/0xPlayerOne/code-foundry/commit/5b997dda7e272b59a386eeeda115e60ad284f6ce))
|
|
16
|
+
|
|
17
|
+
## [1.25.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.25.0...v1.25.1) (2026-09-10)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **release:** wait for the release index before verifying a published release ([#583](https://github.com/0xPlayerOne/code-foundry/issues/583)) ([7823c14](https://github.com/0xPlayerOne/code-foundry/commit/7823c1473d8c5e7c17b039dc755ff5c8d1dba39c))
|
|
23
|
+
|
|
24
|
+
## [1.25.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.24.0...v1.25.0) (2026-09-10)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* **eval:** run the eval tier as a managed Validation / Eval lane ([#580](https://github.com/0xPlayerOne/code-foundry/issues/580)) ([9414889](https://github.com/0xPlayerOne/code-foundry/commit/94148894da9a627a6bd7c71c846848c198c1dfec))
|
|
30
|
+
|
|
31
|
+
## [1.24.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.23.0...v1.24.0) (2026-09-10)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* **validation:** run a lean release lane for Release Please pull requests ([#579](https://github.com/0xPlayerOne/code-foundry/issues/579)) ([a38ca75](https://github.com/0xPlayerOne/code-foundry/commit/a38ca75c7da577af8368467b8b026d0ec563fc41))
|
|
37
|
+
|
|
38
|
+
## [1.23.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.22.1...v1.23.0) (2026-09-09)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Features
|
|
42
|
+
|
|
43
|
+
* add ci eval tier with shared report contract and budget gate ([#576](https://github.com/0xPlayerOne/code-foundry/issues/576)) ([7d881dd](https://github.com/0xPlayerOne/code-foundry/commit/7d881dd1bc6ace8e48dffff45b1a22a12bdae1c9))
|
|
44
|
+
|
|
45
|
+
## [1.22.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.22.0...v1.22.1) (2026-09-09)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### Bug Fixes
|
|
49
|
+
|
|
50
|
+
* **release:** use shell-safe recovery script ([#574](https://github.com/0xPlayerOne/code-foundry/issues/574)) ([264036f](https://github.com/0xPlayerOne/code-foundry/commit/264036f34afa4d7bc405285918395f2ce075bde3))
|
|
51
|
+
|
|
52
|
+
## [1.22.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.21.3...v1.22.0) (2026-09-09)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### Features
|
|
56
|
+
|
|
57
|
+
* **workflows:** protect draft pull requests by default ([#572](https://github.com/0xPlayerOne/code-foundry/issues/572)) ([6fa4ce1](https://github.com/0xPlayerOne/code-foundry/commit/6fa4ce1b2dde5eddff361b819722912fed7a9815))
|
|
58
|
+
|
|
59
|
+
## [1.21.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.21.2...v1.21.3) (2026-09-09)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### Bug Fixes
|
|
63
|
+
|
|
64
|
+
* **release:** unblock draft publication and PR deployment links ([#570](https://github.com/0xPlayerOne/code-foundry/issues/570)) ([35ab90f](https://github.com/0xPlayerOne/code-foundry/commit/35ab90f185483b0cd6a9c622b9793e46c90dd60c))
|
|
65
|
+
|
|
66
|
+
## [1.21.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.21.1...v1.21.2) (2026-09-09)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### Documentation
|
|
70
|
+
|
|
71
|
+
* refresh documentation for current workflows ([#568](https://github.com/0xPlayerOne/code-foundry/issues/568)) ([d0028e0](https://github.com/0xPlayerOne/code-foundry/commit/d0028e096371e1019c466f72f8744bdf832e067c))
|
|
72
|
+
|
|
73
|
+
## [1.21.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.21.0...v1.21.1) (2026-09-09)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Bug Fixes
|
|
77
|
+
|
|
78
|
+
* release-hook-and-performance-safety ([#565](https://github.com/0xPlayerOne/code-foundry/issues/565)) ([0d410c6](https://github.com/0xPlayerOne/code-foundry/commit/0d410c68abfbc0d9fdd03b7aa81676489e459c19))
|
|
79
|
+
* **release:** automate self publication after CI ([91b2655](https://github.com/0xPlayerOne/code-foundry/commit/91b265585aa03e742e5bfc8a839b2794bf234491))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
### Performance
|
|
83
|
+
|
|
84
|
+
* **ci:** batch native Rust test targets by category ([#564](https://github.com/0xPlayerOne/code-foundry/issues/564)) ([6def882](https://github.com/0xPlayerOne/code-foundry/commit/6def8826e90b23d021a4f4587fa843dbb37df0e7))
|
|
85
|
+
|
|
86
|
+
## [1.21.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.20.2...v1.21.0) (2026-09-09)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### Features
|
|
90
|
+
|
|
91
|
+
* **release:** wire qualified draft staging and immutable publication ([#558](https://github.com/0xPlayerOne/code-foundry/issues/558)) ([19aea32](https://github.com/0xPlayerOne/code-foundry/commit/19aea32f50c747cdc5642d1752a9f02008c157f6))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
### Bug Fixes
|
|
95
|
+
|
|
96
|
+
* **quality:** harden HTML filtering ([#562](https://github.com/0xPlayerOne/code-foundry/issues/562)) ([ea45590](https://github.com/0xPlayerOne/code-foundry/commit/ea45590db24dc05ef12db57e80c7405fa217514f))
|
|
97
|
+
|
|
3
98
|
## [1.20.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.20.1...v1.20.2) (2026-09-09)
|
|
4
99
|
|
|
5
100
|
|
package/README.md
CHANGED
|
@@ -39,6 +39,9 @@ contract. For normal updates, edit that file and run `npx code-foundry sync`.
|
|
|
39
39
|
audits, Draft Guard, Draft PR, Release PR, and Release.
|
|
40
40
|
- A deterministic performance lane with ordered command support, stable result
|
|
41
41
|
artifacts, and an optional shared Node package budget profile.
|
|
42
|
+
- A deterministic eval tier (`ci eval`) that runs a repository's behavior-eval
|
|
43
|
+
harness against a shared report contract with optional budgets, keeping task
|
|
44
|
+
outcomes comparable across revisions and executors.
|
|
42
45
|
- An opt-in product-quality runner for static sites, web apps, Workers, and
|
|
43
46
|
published packages.
|
|
44
47
|
- A small `.githooks/pre-commit` launcher with language-aware formatting and
|
|
@@ -58,7 +61,7 @@ preserved and can coexist with the standard baseline.
|
|
|
58
61
|
The generated configuration is the one place to control the baseline. See
|
|
59
62
|
[Configuration reference](docs/CONFIGURATION.md) for the visual configuration
|
|
60
63
|
guide and [Initialization and synchronization](docs/INITIALIZATION.md) for
|
|
61
|
-
the
|
|
64
|
+
the init, sync, and doctor workflow.
|
|
62
65
|
|
|
63
66
|
New repositories default to GPL-3.0-or-later. Existing projects preserve an
|
|
64
67
|
authored license unless a replacement is explicitly selected. Our maintained
|
|
@@ -82,9 +85,11 @@ PRs: it converts them to drafts without checking out PR code. It verifies the
|
|
|
82
85
|
event head and update timestamp before changing state, and excludes Release
|
|
83
86
|
Please version PRs whose release workflow owns readiness. Pull-request
|
|
84
87
|
validation runs on the ready-for-review transition and on new commits while a
|
|
85
|
-
PR remains ready; draft updates allocate no validation runner
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
PR remains ready; draft updates allocate no validation runner by default. Set
|
|
89
|
+
`draft_protection: false` in generated consumer configuration, or pass
|
|
90
|
+
`draft-protection: false` to a Cloudflare reusable workflow, to run those gates
|
|
91
|
+
for drafts. Converting a PR to draft runs only the lightweight cancellation
|
|
92
|
+
control. Scheduled and manually dispatched audits are unaffected.
|
|
88
93
|
|
|
89
94
|
Jobs are language-aware and skip irrelevant setup inside the applicable
|
|
90
95
|
aggregate checks. TypeScript uses Oxlint, Oxfmt, and Bun's native
|
|
@@ -125,9 +130,16 @@ workflow runs.
|
|
|
125
130
|
In the default `direct` flow, changes reach `main` through feature pull
|
|
126
131
|
requests and Release Please opens a versioned release PR against `main`. In
|
|
127
132
|
the `staging-release` flow, a promotion PR promotes `staging` into `main`
|
|
128
|
-
first.
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
first. Generated consumer callers create a GitHub release after the version PR
|
|
134
|
+
is merged; npm publication is opt-in through `npm_publish: true` and supports
|
|
135
|
+
npm trusted publishing or an `NPM_TOKEN` fallback.
|
|
136
|
+
|
|
137
|
+
Code Foundry's own release caller is stricter: it qualifies the package across
|
|
138
|
+
Node 20, 22, and 24, stages the exact qualified archive, publishes the
|
|
139
|
+
immutable GitHub Release, and publishes that archive through the verified
|
|
140
|
+
publisher. See
|
|
141
|
+
[Consumer qualification](docs/consumer-qualification.md) and [Qualified
|
|
142
|
+
publication](docs/qualified-publication.md).
|
|
131
143
|
|
|
132
144
|
Read [Release management](docs/RELEASES.md),
|
|
133
145
|
[Release integrity and build provenance](docs/release-integrity.md), and
|
|
@@ -137,16 +149,10 @@ copied into other repositories.
|
|
|
137
149
|
|
|
138
150
|
## Documentation and extensions
|
|
139
151
|
|
|
140
|
-
The `docs/` directory contains generalized operational guides.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
- [Documentation index](docs/README.md)
|
|
145
|
-
- [Initialization and synchronization](docs/INITIALIZATION.md)
|
|
146
|
-
- [Workflow and CI conventions](docs/WORKFLOWS.md)
|
|
147
|
-
- [Release management](docs/RELEASES.md)
|
|
148
|
-
- [Publishing packages](docs/PUBLISHING.md)
|
|
149
|
-
- [Caching and remote caching](docs/CACHING.md)
|
|
152
|
+
The `docs/` directory contains generalized operational guides. Start with the
|
|
153
|
+
[documentation index](docs/README.md), which groups every guide by task. Add
|
|
154
|
+
repository-specific documentation there as well; synchronization preserves
|
|
155
|
+
files in `docs/`.
|
|
150
156
|
|
|
151
157
|
## License
|
|
152
158
|
|