code-foundry 1.10.1 → 1.12.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.
@@ -78,6 +78,7 @@ jobs:
78
78
  sparse-checkout: |
79
79
  .github/actions
80
80
  src/lib
81
+ src/runtime-core.mjs
81
82
  src/runtime.mjs
82
83
  - name: Install runtime
83
84
  run: |
@@ -143,6 +144,7 @@ jobs:
143
144
  sparse-checkout: |
144
145
  .github/actions
145
146
  src/lib
147
+ src/runtime-core.mjs
146
148
  src/runtime.mjs
147
149
  - name: Install runtime
148
150
  run: |
@@ -208,6 +210,7 @@ jobs:
208
210
  sparse-checkout: |
209
211
  .github/actions
210
212
  src/lib
213
+ src/runtime-core.mjs
211
214
  src/runtime.mjs
212
215
  - name: Install runtime
213
216
  run: |
@@ -257,6 +260,7 @@ jobs:
257
260
  sparse-checkout: |
258
261
  .github/actions
259
262
  src/lib
263
+ src/runtime-core.mjs
260
264
  src/runtime.mjs
261
265
  - name: Install runtime
262
266
  run: |
@@ -318,6 +322,7 @@ jobs:
318
322
  sparse-checkout: |
319
323
  .github/actions
320
324
  src/lib
325
+ src/runtime-core.mjs
321
326
  src/runtime.mjs
322
327
  - name: Install runtime
323
328
  run: |
@@ -143,6 +143,7 @@ jobs:
143
143
  path: .github/.code-foundry
144
144
  sparse-checkout: |
145
145
  src/lib
146
+ src/runtime-core.mjs
146
147
  src/runtime.mjs
147
148
  - name: Install runtime
148
149
  run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
@@ -155,6 +155,7 @@ jobs:
155
155
  path: .github/.code-foundry
156
156
  sparse-checkout: |
157
157
  src/lib
158
+ src/runtime-core.mjs
158
159
  src/runtime.mjs
159
160
  - name: Install runtime
160
161
  run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
@@ -45,6 +45,7 @@ jobs:
45
45
  path: .github/.code-foundry
46
46
  sparse-checkout: |
47
47
  src/lib
48
+ src/runtime-core.mjs
48
49
  src/runtime.mjs
49
50
  - name: Install runtime
50
51
  run: mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.12.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.11.0...v1.12.0) (2026-09-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * **cloudflare:** verify candidates before protected version promotion ([#535](https://github.com/0xPlayerOne/code-foundry/issues/535)) ([5dd9afa](https://github.com/0xPlayerOne/code-foundry/commit/5dd9afa8418718823844875b0aedce926b887184))
9
+
10
+ ## [1.11.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.10.1...v1.11.0) (2026-09-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * **validation:** enforce required capabilities, coverage, and task evidence ([#534](https://github.com/0xPlayerOne/code-foundry/issues/534)) ([2e341d9](https://github.com/0xPlayerOne/code-foundry/commit/2e341d94381599f1d78ec1394d42883157b30ea6))
16
+
3
17
  ## [1.10.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.10.0...v1.10.1) (2026-09-09)
4
18
 
5
19
 
@@ -36,10 +36,15 @@ repository manifests and source
36
36
  | `package_manager` | `bun`, `pnpm`, `yarn`, `npm`, `none` | JavaScript setup |
37
37
  | `toolchain` | `auto`, `native`, `mise` | Environment setup policy; defaults to `auto` |
38
38
  | `staging_validation_mode` | `fast`, `audit` | Staging-release-only validation tier; omitted from direct repositories |
39
- | `performance` | `auto`, `true`, `false` | Run a deterministic performance task when a supported entrypoint exists; defaults to `auto` |
39
+ | `performance` | `auto`, `true`, `false` | `auto` discovers an optional task; `true` requires a supported performance entrypoint; `false` disables discovery |
40
40
  | `performance_command` | JSON argv array or array of argv arrays | One or more ordered commands for non-package harnesses; package scripts take precedence |
41
41
  | `performance_profile` | empty, `node-package` | Optional shared package import, memory, archive, and dependency budget harness |
42
42
  | `performance_budget_file` | repository path | Budget policy for the shared package harness; defaults to `performance-package-budgets.json` |
43
+ | `required_capabilities` | comma-separated task names | Fail closed when a required task or `coverage` evidence is unavailable; defaults to none |
44
+ | `coverage_enforcement` | `auto`, `required`, `off` | Shared coverage report policy; `auto` accepts explicit skips, `required` rejects missing reports, `off` skips it |
45
+ | `coverage_minimum` | percentage from `0` to `100` | Minimum measured coverage; defaults to `80` |
46
+ | `coverage_metrics` | `lines`, `functions`, `branches`, `statements` | Metrics checked by the shared coverage gate; defaults to `lines` |
47
+ | `coverage_report` | comma-separated repository paths | Istanbul summary or LCOV evidence files; defaults to standard coverage paths |
43
48
  | `features` | `all` or a list | Standard workflow callers |
44
49
  | `codeql` | `auto`, `true`, `false` | CodeQL policy; public repositories default to enabled, non-public repositories default to disabled |
45
50
  | `codeql_rust_shards` | JSON array of paths | Rust scan scopes; `["all"]` keeps the safe single full scan |
@@ -174,15 +179,23 @@ shards. Do not split a single crate by arbitrary non-Rust directories: use
174
179
  ## Cloudflare Workers deployments
175
180
 
176
181
  Repositories that deploy to Cloudflare Workers can opt into GitHub-native
177
- deployments (Preview/Production environments with deployment statuses, like
178
- Vercel's integration) by adding a small caller for the runtime's reusable
179
- `cloudflare-deploy.yml` workflow. The workflow runs `wrangler versions upload`
180
- for pull-request previews and `wrangler deploy` for production, records a
181
- GitHub deployment plus status with the workers.dev URL, and respects
182
- `CI_BILLING_PAUSED`. It requires the `CLOUDFLARE_API_TOKEN` and
183
- `CLOUDFLARE_ACCOUNT_ID` secrets in the consumer repository. Bun consumers may
184
- also pass `build-script`, `install-working-directory`, and `bun-version`; the
185
- runtime installs the frozen lockfile and builds the Worker before invoking
182
+ verified delivery (fixed `Preview`/`Production` environments, candidate
183
+ verification, and version-identity promotion) by adding a caller for the
184
+ runtime's reusable `cloudflare-delivery.yml` workflow. Use the same immutable
185
+ 40-character Code Foundry commit SHA for both the reusable workflow ref and
186
+ `runtime-ref`; configure required reviewers and branch restrictions on the
187
+ `Production` environment. The workflow requires the
188
+ `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` secrets in the consumer
189
+ repository. See [Verified Cloudflare delivery](./cloudflare-delivery.md) for
190
+ binding policy, canary, rollback, and evidence requirements.
191
+
192
+ The legacy `cloudflare-deploy.yml` workflow remains available for direct
193
+ (unverified) deployments. It runs `wrangler versions upload` for previews and
194
+ `wrangler deploy` for production, records a GitHub deployment plus status, and
195
+ respects `CI_BILLING_PAUSED`. Its legacy-compatible Wrangler default is `latest`;
196
+ callers should prefer `local` or provide an exact `wrangler-version` for
197
+ reproducibility. Bun consumers may pass `build-script`, `install-working-directory`, and `bun-version`;
198
+ the runtime installs the frozen lockfile and builds the Worker before invoking
186
199
  Wrangler. Bun-backed callers invoke Wrangler through `bunx` so OpenNext's
187
200
  production delegation resolves the workspace-local `opennextjs-cloudflare`
188
201
  binary; callers without `build-script` retain the npm/npx path.
package/docs/README.md CHANGED
@@ -13,6 +13,7 @@ its own names, environments, and deployment details.
13
13
  - [Publishing packages](PUBLISHING.md)
14
14
  - [Caching and remote caching](CACHING.md)
15
15
  - [Performance budgets and baselines](PERFORMANCE.md)
16
+ - [Required capabilities and task evidence](required-capabilities.md)
16
17
 
17
18
  ## Repository-specific documentation
18
19
 
@@ -0,0 +1,188 @@
1
+ # Verified Cloudflare delivery
2
+
3
+ The opt-in `cloudflare-delivery.yml` workflow builds and uploads a candidate,
4
+ validates its actual version bindings, runs an HTTP smoke probe and the required
5
+ repository-owned verification command, then promotes **that version ID** after
6
+ GitHub environment approval. Production promotion uses the Cloudflare deployment
7
+ API and never rebuilds the application. The existing `cloudflare-deploy.yml`
8
+ remains available for direct deployments and initial provisioning.
9
+
10
+ ## Adoption
11
+
12
+ Call the new reusable workflow using an immutable, reviewed 40-character Code
13
+ Foundry commit SHA and pass the same `runtime-ref`. Required inputs are
14
+ `worker-name`, `artifact-path`, and `verify-command`.
15
+
16
+ ```yaml
17
+ jobs:
18
+ delivery:
19
+ # Replace REVIEWED_SHA with the same reviewed 40-character SHA in both places.
20
+ uses: 0xPlayerOne/code-foundry/.github/workflows/cloudflare-delivery.yml@REVIEWED_SHA
21
+ permissions:
22
+ contents: read
23
+ deployments: write
24
+ with:
25
+ runtime-ref: REVIEWED_SHA
26
+ mode: production
27
+ worker-name: company-site
28
+ artifact-path: dist
29
+ verify-command: '["bun", "run", "test:deployed"]'
30
+ production-url: https://example.com
31
+ smoke-path: /health
32
+ canary-percentage: 10
33
+ canary-verify-command: '["bun", "run", "test:canary"]'
34
+ secrets:
35
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
36
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
37
+ ```
38
+
39
+ `artifact-path` is relative to `working-directory`; `install-working-directory`
40
+ selects the lockfile root. The selected output tree is hashed before and after
41
+ upload; changes during upload fail. Include all built code/assets in that tree
42
+ and disable duplicate custom build steps. This digest identifies the declared
43
+ local build tree, not a Cloudflare-signed digest of every uploaded configuration
44
+ field. The Worker version ID is the authoritative identity for promotion.
45
+
46
+ Wrangler defaults to the installed, lockfile-resolved version. Explicit overrides
47
+ must be exact versions, never `latest`, floating majors, or semver ranges. Pin a
48
+ Wrangler version supporting `WRANGLER_OUTPUT_FILE_PATH` and version-1
49
+ `version-upload` records. Missing preview URLs and output-schema mismatches fail.
50
+ Bun remains the installation path, consistent with the existing deploy workflow.
51
+
52
+ The repository verification command receives `BASE_URL` and
53
+ `FOUNDRY_DEPLOYMENT_PHASE` (`candidate`, `canary`, or `production`). It must check
54
+ critical journeys, redirects, assets, and application-specific behavior. The
55
+ built-in smoke probe requires a successful 2xx response and does not follow
56
+ redirects. Deploy credentials are not supplied to verification steps and are
57
+ removed from the verification child environment as defense in depth. Install any
58
+ browser binaries required by your verification command explicitly.
59
+
60
+ When `canary-percentage` is below 100, `canary-verify-command` is required and
61
+ must prove that the live request served the candidate rather than the baseline.
62
+ It receives `FOUNDRY_EXPECTED_VERSION_ID`, `FOUNDRY_DEPLOYMENT_ID`, and
63
+ `FOUNDRY_CANARY_PERCENTAGE`; use a version-aware response/header or an equivalent
64
+ application check. A command that only observes a successful production URL is
65
+ not sufficient.
66
+
67
+ ## Approvals, ordering, and evidence
68
+
69
+ Create and protect the fixed `Preview` and `Production` GitHub environments
70
+ before adoption. The workflow references them at the **job** level; naming an
71
+ environment does not itself configure reviewers or branch restrictions. Configure
72
+ required reviewers and branch restrictions on `Production` separately. Production
73
+ execution requires the current default-branch commit and
74
+ rechecks freshness after approval and before final promotion. Fork PRs and
75
+ `pull_request_target` execution are excluded.
76
+
77
+ Per-repository/Worker/mode concurrency never cancels a running promotion. GitHub
78
+ concurrency is not a FIFO queue; stale-source rejection is still necessary.
79
+ Other deployment systems and dashboard edits are outside this lock. The helper
80
+ also checks that its deployment has not been replaced before a subsequent
81
+ promotion or rollback, but the Cloudflare API check/write is not an atomic CAS.
82
+ Migrate one application to one deployment owner; do not leave competing legacy
83
+ and new production workflows active.
84
+
85
+ Outputs include preview URL, exact version ID, source SHA, declared build-tree
86
+ SHA-256 digest, Cloudflare deployment ID, and GitHub application deployment ID.
87
+ Explicit application deployment records receive in-progress and success/failure
88
+ statuses, in addition to GitHub's environment-job records. Sanitized candidate and
89
+ production JSON evidence is uploaded even on failure. Binding values, API bodies,
90
+ and credentials are not copied into those reports. Forced runner termination may
91
+ prevent final status steps; the GitHub job still reflects cancellation/failure.
92
+
93
+ ## Stateful resources and isolation
94
+
95
+ Without a policy file, non-resource bindings (for example strings, secrets, and
96
+ static assets) are allowed; resource/service bindings fail closed. The uploaded
97
+ version's actual bindings are inspected through the Cloudflare API. Durable
98
+ Object bindings or exports are rejected: use a repository-specific migration and
99
+ preview workflow instead of pretending version preview supports that topology.
100
+
101
+ A reviewed read-only policy can allow smoke testing a candidate that shares
102
+ production resources:
103
+
104
+ ```json
105
+ {
106
+ "schemaVersion": 1,
107
+ "readOnlyBindings": [{ "name": "DB", "type": "d1" }],
108
+ "rollbackSafe": false
109
+ }
110
+ ```
111
+
112
+ Pass its relative path as `binding-policy-file`. This declaration is **not a
113
+ sandbox**: the repository owner must ensure its test routes cannot mutate shared
114
+ data. A version preview does not automatically create isolated KV, R2, D1, or
115
+ service resources, and a GET route can still have side effects.
116
+
117
+ For separately provisioned preview Workers, `isolatedBindings` entries can compare
118
+ the actual binding's resource identifiers with expected preview identifiers and
119
+ assert that they differ from declared production identifiers:
120
+
121
+ ```json
122
+ {
123
+ "schemaVersion": 1,
124
+ "isolatedBindings": [
125
+ {
126
+ "name": "DB",
127
+ "type": "d1",
128
+ "expected": { "id": "preview-database-id" },
129
+ "production": { "id": "production-database-id" }
130
+ }
131
+ ]
132
+ }
133
+ ```
134
+
135
+ Use the field names returned for that binding type by the Version API. Resource
136
+ provisioning and the correctness of production-identifier declarations remain
137
+ repository-owned. Isolated preview bindings are rejected in production mode to
138
+ prevent accidentally promoting staging resources. A version from a different
139
+ Worker cannot be promoted across Workers; production mode uploads and tests its
140
+ own candidate on the production Worker with reviewed read-only tests.
141
+
142
+ ## Canary and rollback policy
143
+
144
+ A percentage below 100 first routes that share to the candidate, verifies it,
145
+ and then promotes the same version to 100 and verifies again. A canary requires
146
+ one prior baseline serving 100% and the explicit `canary-verify-command` above.
147
+ A single load-balanced HTTP request may hit the old version; the command must
148
+ observe the expected version ID. Set `canary-percentage: 100` when that
149
+ version-aware observability is not configured.
150
+
151
+ Automatic rollback is off. Enabling `auto-rollback` also requires an explicit
152
+ `rollbackSafe: true` policy and both current and prior versions to be free of
153
+ stateful bindings/DO exports. The policy must additionally account for external
154
+ side effects that binding inspection cannot detect. Rollback restores the exact
155
+ previous traffic split only when this run's deployment is still current. Failure
156
+ remains a failed deployment even after rollback. Resource data, migrations,
157
+ external API side effects, routes, and non-versioned settings are never rewound.
158
+ The evidence file records prior versions for manual recovery when automation is
159
+ unsafe or unavailable. Recovery itself must be verified operationally.
160
+
161
+ This workflow targets already-provisioned Workers with version previews enabled.
162
+ Manage initial Worker/route/trigger setup and non-versioned settings separately;
163
+ the deployment API intentionally changes version routing only.
164
+
165
+ ## Legacy workflow hardening
166
+
167
+ `cloudflare-deploy.yml` now uses real job environments, non-cancelling concurrency,
168
+ structured Wrangler output, exact/local Wrangler selection, reusable outputs, and
169
+ in-progress/failure deployment records. Its legacy-compatible default remains
170
+ `latest`; callers should prefer `local` or an exact version for reproducibility. A
171
+ production URL can be supplied with `deployment-url` when API output contains only
172
+ route patterns. It is still a **direct, unverified deployment**; adopt
173
+ `cloudflare-delivery.yml` for candidate verification and guarded promotion.
174
+
175
+ ## References and testing
176
+
177
+ The implementation follows Cloudflare's structured Wrangler output and version
178
+ routing APIs:
179
+
180
+ - https://developers.cloudflare.com/workers/wrangler/system-environment-variables/
181
+ - https://developers.cloudflare.com/workers/versions-and-deployments/
182
+ - https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/versions/methods/get/
183
+ - https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/deployments/methods/create/
184
+
185
+ Run `node --test test/cloudflare-delivery.test.mjs`. Tests use deterministic API
186
+ responses and never deploy a Worker. Before production rollout, run the new
187
+ workflow against a disposable Worker and protected test environments, including
188
+ smoke failure and rollback scenarios.
@@ -0,0 +1,82 @@
1
+ # Required capabilities and task evidence
2
+
3
+ Declared requirements fail closed when discovery cannot find an executable task.
4
+ Existing optional task discovery remains available. Configure scalar values in
5
+ `.github/code-foundry.yml`:
6
+
7
+ ```yaml
8
+ required_capabilities: type_check,unit,e2e,performance,coverage
9
+ performance: true
10
+ coverage_enforcement: required
11
+ coverage_minimum: 80
12
+ coverage_metrics: lines,branches
13
+ coverage_report: coverage/coverage-summary.json
14
+ ```
15
+
16
+ Supported task capabilities are `format`, `lint`, `type_check`, `build`, `unit`,
17
+ `integration`, `e2e`, `smoke`, and `performance`. `coverage` additionally requires
18
+ unit tests. Unknown names, contradictory requirements, and invalid thresholds
19
+ are errors. `performance: true` now means required, not merely enabled when a
20
+ script happens to exist. Use `performance: auto` to retain optional discovery.
21
+
22
+ The public `src/runtime.mjs` entrypoint delegates ecosystem execution to the
23
+ unchanged private `src/runtime-core.mjs`. Keep both files and `src/lib` when
24
+ vendoring the runtime. Published packages and the reusable workflows' existing
25
+ cone-mode sparse checkout include both files. Do not call the private executor
26
+ from consumer CI: it intentionally does not enforce the public policy contract.
27
+
28
+ ## Coverage migration
29
+
30
+ `coverage_enforcement` accepts:
31
+
32
+ - `auto` (default): missing reports are explicitly reported as skipped; present
33
+ reports must be fresh, valid, and meet the threshold.
34
+ - `required`: missing reports also fail, as does required capability `coverage`.
35
+ - `off`: skip the shared report gate. This does not disable a test runner's own
36
+ coverage threshold, and cannot be combined with required coverage.
37
+
38
+ The default report candidates are `coverage/coverage-summary.json` (Istanbul
39
+ summary) and `coverage/lcov.info`. `coverage_report` accepts a comma-separated
40
+ list of repository-relative files. When multiple reports exist, every report
41
+ must meet the selected metrics. Percentages are recomputed from measured counts,
42
+ not trusted from reported `pct` fields. Empty reports, unmeasured selected
43
+ metrics, stale files, traversal, and escaping symlinks fail. LCOV supports lines,
44
+ functions, and branches; use JSON summaries for statement coverage.
45
+
46
+ Configure the repository-owned unit-test command to generate the report on each
47
+ run before enabling required mode. The runtime does not inject coverage tooling,
48
+ install a new runner, delete old reports, or lower thresholds. Auto mode preserves
49
+ repos that declare a threshold but have not yet configured report generation;
50
+ a passing unit task with `coverage.status: skipped` is **not** coverage evidence.
51
+
52
+ ## Results and validation tiers
53
+
54
+ Each executed CI task writes `.code-foundry/results/<task>.json`, including its
55
+ status (`passed`, `failed`, or `skipped`), discovery reason, delegated command and
56
+ exit status, source SHA when available, timestamps, and evidence paths. Coverage
57
+ has its own nested status. Discovery also records optional skips. Task reports
58
+ appear in the GitHub job summary when `GITHUB_STEP_SUMMARY` is available.
59
+
60
+ The recorded command is the delegated executor invocation, not a transcript of
61
+ all nested package scripts. No environment variables or captured command output
62
+ are copied into the report. Repository scripts remain responsible for sanitizing
63
+ their own logs. Upload `.code-foundry/results/*.json` with `if: always()` and
64
+ `include-hidden-files: true` to retain downloadable reports; only upload this
65
+ specific directory, not arbitrary hidden files or the entire checkout.
66
+
67
+ `node src/runtime.mjs ci plan` prints a JSON discovery plan without executing
68
+ checks. Discovery validates every required task before reusable workflows select
69
+ jobs. A fast/unit-only tier is still a subset: discovery proves that E2E exists,
70
+ not that E2E ran. Require the existing audit validation gate before merging.
71
+
72
+ Native task detection rejects known no-ops such as a JavaScript project with no
73
+ build script or a Python project with no supported type-check command. Add a
74
+ repository-owned script for unsupported layouts or toolchains. Do not infer that
75
+ an installed package manager or discovered project proves task execution.
76
+
77
+ ## Verification
78
+
79
+ `node --test test/task-policy.test.mjs` exercises policy parsing, discovery,
80
+ coverage parsing/thresholds/freshness/path safety, exit propagation, and reports
81
+ with a deterministic executor fixture. The unchanged ecosystem executor remains
82
+ covered by `test/runtime.test.mjs` in the full suite.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.10.1",
3
+ "version": "1.12.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": {