Repository navigation
Conversation
🦋 Changeset detectedLatest commit: 2a23e1a The changes in this PR will be included in the next version bump. This PR includes changesets to release 17 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🧪 E2E Test Results❌ Some tests failed ❌ Failed E2E Tests▲ Vercel Production (668 failed)astro-node (24 failed):
astro-quickjs (23 failed):
example-node (28 failed):
example-quickjs (26 failed):
express-node (24 failed):
express-quickjs (26 failed):
fastify-node (19 failed):
fastify-quickjs (25 failed):
hono-node (19 failed):
hono-quickjs (25 failed):
nest-node (26 failed):
nest-quickjs (27 failed):
nextjs-turbopack-node (32 failed):
nextjs-turbopack-quickjs (16 failed):
nextjs-webpack-node (33 failed):
nextjs-webpack-quickjs (29 failed):
nitro-node (19 failed):
nitro-quickjs (22 failed):
nuxt-node (32 failed):
nuxt-quickjs (29 failed):
sveltekit-node (28 failed):
sveltekit-quickjs (29 failed):
tanstack-start-node (28 failed):
tanstack-start-quickjs (25 failed):
vite-node (27 failed):
vite-quickjs (27 failed):
vercel-http-transport (176 failed)example (29 failed):
express (28 failed):
hono (31 failed):
nextjs-turbopack (28 failed):
nitro (29 failed):
vite (31 failed):
vercel-multi-region (1 failed)nextjs-turbopack (1 failed):
vercel-ws-transport (115 failed)example (28 failed):
express (28 failed):
nextjs-turbopack (28 failed):
vite (31 failed):
|
| Passed | Failed | Skipped | Total | |
|---|---|---|---|---|
| ❌ ▲ Vercel Production | 3314 | 668 | 878 | 4860 |
| ✅ 💻 Local Development | 4669 | 0 | 551 | 5220 |
| ✅ 📦 Local Production | 4669 | 0 | 551 | 5220 |
| ✅ 🐘 Local Postgres | 4669 | 0 | 551 | 5220 |
| ✅ 🪟 Windows | 348 | 0 | 12 | 360 |
| ✅ 🌐 Cross-language Conformance | 68 | 0 | 87 | 155 |
| ✅ dynamic-runs | 0 | 0 | 0 | 0 |
| ❌ vercel-http-transport | 721 | 176 | 183 | 1080 |
| ❌ vercel-multi-region | 26 | 1 | 0 | 27 |
| ❌ vercel-ws-transport | 492 | 115 | 113 | 720 |
| Total | 18976 | 960 | 2926 | 22862 |
Details by Category
❌ ▲ Vercel Production
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ❌ astro-node | 121 | 24 | 35 |
| ❌ astro-quickjs | 122 | 23 | 35 |
| ❌ example-node | 117 | 28 | 35 |
| ❌ example-quickjs | 119 | 26 | 35 |
| ❌ express-node | 121 | 24 | 35 |
| ❌ express-quickjs | 119 | 26 | 35 |
| ❌ fastify-node | 126 | 19 | 35 |
| ❌ fastify-quickjs | 120 | 25 | 35 |
| ❌ hono-node | 126 | 19 | 35 |
| ❌ hono-quickjs | 120 | 25 | 35 |
| ❌ nest-node | 119 | 26 | 35 |
| ❌ nest-quickjs | 118 | 27 | 35 |
| ❌ nextjs-turbopack-node | 140 | 32 | 8 |
| ❌ nextjs-turbopack-quickjs | 156 | 16 | 8 |
| ❌ nextjs-webpack-node | 139 | 33 | 8 |
| ❌ nextjs-webpack-quickjs | 143 | 29 | 8 |
| ❌ nitro-node | 126 | 19 | 35 |
| ❌ nitro-quickjs | 123 | 22 | 35 |
| ❌ nuxt-node | 113 | 32 | 35 |
| ❌ nuxt-quickjs | 116 | 29 | 35 |
| ✅ python-node | 66 | 0 | 114 |
| ❌ sveltekit-node | 136 | 28 | 16 |
| ❌ sveltekit-quickjs | 135 | 29 | 16 |
| ❌ tanstack-start-node | 117 | 28 | 35 |
| ❌ tanstack-start-quickjs | 120 | 25 | 35 |
| ❌ vite-node | 118 | 27 | 35 |
| ❌ vite-quickjs | 118 | 27 | 35 |
✅ 💻 Local Development
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ astro-stable-node | 151 | 0 | 29 |
| ✅ astro-stable-quickjs | 151 | 0 | 29 |
| ✅ express-stable-node | 151 | 0 | 29 |
| ✅ express-stable-quickjs | 151 | 0 | 29 |
| ✅ fastify-stable-node | 151 | 0 | 29 |
| ✅ fastify-stable-quickjs | 151 | 0 | 29 |
| ✅ hono-stable-node | 151 | 0 | 29 |
| ✅ hono-stable-quickjs | 151 | 0 | 29 |
| ✅ nest-stable-node | 151 | 0 | 29 |
| ✅ nest-stable-quickjs | 151 | 0 | 29 |
| ✅ nextjs-turbopack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-turbopack-quickjs-snapshot | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-quickjs | 179 | 0 | 1 |
| ✅ nitro-stable-node | 151 | 0 | 29 |
| ✅ nitro-stable-quickjs | 151 | 0 | 29 |
| ✅ nuxt-stable-node | 151 | 0 | 29 |
| ✅ nuxt-stable-quickjs | 151 | 0 | 29 |
| ✅ sveltekit-stable-node | 170 | 0 | 10 |
| ✅ sveltekit-stable-quickjs | 170 | 0 | 10 |
| ✅ tanstack-start-node | 151 | 0 | 29 |
| ✅ tanstack-start-quickjs | 151 | 0 | 29 |
| ✅ vite-stable-node | 151 | 0 | 29 |
| ✅ vite-stable-quickjs | 151 | 0 | 29 |
✅ 📦 Local Production
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ astro-stable-node | 151 | 0 | 29 |
| ✅ astro-stable-quickjs | 151 | 0 | 29 |
| ✅ express-stable-node | 151 | 0 | 29 |
| ✅ express-stable-quickjs | 151 | 0 | 29 |
| ✅ fastify-stable-node | 151 | 0 | 29 |
| ✅ fastify-stable-quickjs | 151 | 0 | 29 |
| ✅ hono-stable-node | 151 | 0 | 29 |
| ✅ hono-stable-quickjs | 151 | 0 | 29 |
| ✅ nest-stable-node | 151 | 0 | 29 |
| ✅ nest-stable-quickjs | 151 | 0 | 29 |
| ✅ nextjs-turbopack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-turbopack-quickjs-snapshot | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-quickjs | 179 | 0 | 1 |
| ✅ nitro-stable-node | 151 | 0 | 29 |
| ✅ nitro-stable-quickjs | 151 | 0 | 29 |
| ✅ nuxt-stable-node | 151 | 0 | 29 |
| ✅ nuxt-stable-quickjs | 151 | 0 | 29 |
| ✅ sveltekit-stable-node | 170 | 0 | 10 |
| ✅ sveltekit-stable-quickjs | 170 | 0 | 10 |
| ✅ tanstack-start-node | 151 | 0 | 29 |
| ✅ tanstack-start-quickjs | 151 | 0 | 29 |
| ✅ vite-stable-node | 151 | 0 | 29 |
| ✅ vite-stable-quickjs | 151 | 0 | 29 |
✅ 🐘 Local Postgres
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ astro-stable-node | 151 | 0 | 29 |
| ✅ astro-stable-quickjs | 151 | 0 | 29 |
| ✅ express-stable-node | 151 | 0 | 29 |
| ✅ express-stable-quickjs | 151 | 0 | 29 |
| ✅ fastify-stable-node | 151 | 0 | 29 |
| ✅ fastify-stable-quickjs | 151 | 0 | 29 |
| ✅ hono-stable-node | 151 | 0 | 29 |
| ✅ hono-stable-quickjs | 151 | 0 | 29 |
| ✅ nest-stable-node | 151 | 0 | 29 |
| ✅ nest-stable-quickjs | 151 | 0 | 29 |
| ✅ nextjs-turbopack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-turbopack-quickjs-snapshot | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-turbopack-stable-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-canary-quickjs | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-node | 179 | 0 | 1 |
| ✅ nextjs-webpack-stable-quickjs | 179 | 0 | 1 |
| ✅ nitro-stable-node | 151 | 0 | 29 |
| ✅ nitro-stable-quickjs | 151 | 0 | 29 |
| ✅ nuxt-stable-node | 151 | 0 | 29 |
| ✅ nuxt-stable-quickjs | 151 | 0 | 29 |
| ✅ sveltekit-stable-node | 170 | 0 | 10 |
| ✅ sveltekit-stable-quickjs | 170 | 0 | 10 |
| ✅ tanstack-start-node | 151 | 0 | 29 |
| ✅ tanstack-start-quickjs | 151 | 0 | 29 |
| ✅ vite-stable-node | 151 | 0 | 29 |
| ✅ vite-stable-quickjs | 151 | 0 | 29 |
✅ 🪟 Windows
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ nextjs-turbopack-node | 174 | 0 | 6 |
| ✅ nextjs-turbopack-quickjs | 174 | 0 | 6 |
✅ 🌐 Cross-language Conformance
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ python | 68 | 0 | 87 |
✅ dynamic-runs
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ✅ astro-vercel | 0 | 0 | 0 |
| ✅ example-vercel | 0 | 0 | 0 |
| ✅ express-vercel | 0 | 0 | 0 |
| ✅ fastify-vercel | 0 | 0 | 0 |
| ✅ hono-vercel | 0 | 0 | 0 |
| ✅ nest-vercel | 0 | 0 | 0 |
| ✅ nextjs-turbopack-vercel | 0 | 0 | 0 |
| ✅ nextjs-webpack-vercel | 0 | 0 | 0 |
| ✅ nitro-vercel | 0 | 0 | 0 |
| ✅ nuxt-vercel | 0 | 0 | 0 |
| ✅ sveltekit-vercel | 0 | 0 | 0 |
| ✅ tanstack-start-vercel | 0 | 0 | 0 |
| ✅ vite-vercel | 0 | 0 | 0 |
❌ vercel-http-transport
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ❌ example | 116 | 29 | 35 |
| ❌ express | 117 | 28 | 35 |
| ❌ hono | 114 | 31 | 35 |
| ❌ nextjs-turbopack | 144 | 28 | 8 |
| ❌ nitro | 116 | 29 | 35 |
| ❌ vite | 114 | 31 | 35 |
❌ vercel-multi-region
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ❌ nextjs-turbopack | 26 | 1 | 0 |
❌ vercel-ws-transport
| App | Passed | Failed | Skipped |
|---|---|---|---|
| ❌ example | 117 | 28 | 35 |
| ❌ express | 117 | 28 | 35 |
| ❌ nextjs-turbopack | 144 | 28 | 8 |
| ❌ vite | 114 | 31 | 35 |
📊 Workflow Benchmarkscommit Backend:
📈 STSO distribution vs main (inline / queue-hop histograms)1020 steps (inline) Cumulative STSO time: main 113193ms → this run 95689ms (Δ -17504ms, -15%) 📜 Previous results (3)af4207fTue, 06 Oct 2026 20:51:44 GMT · run logs
60588dfFri, 25 Sep 2026 19:30:08 GMT · run logs
fed6c9fWed, 23 Sep 2026 21:35:26 GMT · run logs
ℹ️ Metric definitions & methodologyThe collapsed STSO distribution section above buckets every step gap, split inline (same warm process — pure framework overhead) vs queue-hop (fresh process — dispatch, reinit, replay). Best/P75/P90/P99 deltas compare against the most recent benchmark run on Metrics — TTFS: time to first step body (in-deployment start() → first step body) · Fan-out TTFS: fan-out time to first step (in-deployment start() → first of the parallel step bodies to complete) · Fan-out TTLS: fan-out time to last step (in-deployment start() → last of the parallel step bodies to complete, i.e. when the Promise.all resolves) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · Promise.all(100 steps): 100 trivial no-op steps started together in a single Promise.all; Fan-out TTFS is the first of them to complete and Fan-out TTLS the last, both from the in-deployment clientStart, so their gap is the spread the runtime adds across the fan-out 🔴 marks a percentile over its target (within target is left unmarked). Targets (p75/p90/p99, ms) — TTFS 200/300/600 All timestamps are deployment-side; runs are triggered in-deployment, so the CI runner and api.vercel.com sit outside every measured window. TTFS = Cold starts stay in the numbers (real bursty-workload latency, inflates P75+); Best is the warm floor. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Sim WorldSimulated world deterministic testing for races. Traces 🟢 world-sim scenario book — 0 fail of 42 total
Full trace: |
About these numbersSizes are gzip; parentheses show the change against
|
Same change as on main (#4335). The plain bump to nanoid 5.1.16 broke the hook-sleep-interaction replay fixtures, because nanoid 5.1.16 draws a different number of random bytes per id. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
@workflow/core pinned nanoid 5.1.6, which is affected by GHSA-28wg-ghj8-5hjv. Bumping to 5.1.16 is not replay-safe: its customRandom draws 21 bytes per id instead of 34, which changes default hook tokens and every seeded value drawn after them for the same run. Inline nanoid 5.1.6's customRandom(urlAlphabet, 21) with a golden test and remove the dependency. Closes #3842. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
fed6c9f to
60588df
Compare
|
Rebased onto latest CI notes: the red Vercel Prod / HTTP / WS e2e lanes all fail on one test, |
|
This PR looks fine, thought we're also not affected by the issue (no attacker-passed values for ID generation), ignoring for now |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
|
Merged latest CI on this push:
These need a rerun of the failed jobs, which I can't trigger from here. 🤖 Generated with Claude Code |
# Conflicts: # workbench/nextjs-turbopack/package.json # workbench/nextjs-webpack/package.json
VaguelySerious
left a comment
There was a problem hiding this comment.
AI review: no blocking issues
| "@workflow/core": patch | ||
| --- | ||
|
|
||
| Security: remove the `nanoid` dependency (pinned at 5.1.6, affected by [GHSA-28wg-ghj8-5hjv](https://github.com/advisories/GHSA-28wg-ghj8-5hjv)). Default hook tokens now come from a built-in copy of the same generator, so tokens and seeded random values stay identical for runs recorded on earlier versions. Upgrading `nanoid` itself would have changed them, because `nanoid@5.1.16` draws a different number of random bytes per id. |
There was a problem hiding this comment.
AI Review: Nit
The changeset is used verbatim in the changelog, and the repo convention is one terse line with no implementation detail. Something like: Security: remove the nanoid dependency (GHSA-28wg-ghj8-5hjv). Hook tokens are unchanged for existing runs. The rationale for not bumping fits better in the PR description, where it already is.
| const BYTES_PER_ID = 34; | ||
|
|
||
| export function createSeededNanoid(random: () => number): () => string { | ||
| return () => { |
There was a problem hiding this comment.
AI Review: Note
Checked this against the real nanoid@5.1.6 locally: 5,000 random seeds, 5 tokens each, with 0-3 extra PRNG draws between tokens to mimic Math.random() calls in workflow code. All 25,000 tokens matched and the PRNG ended at the same position every time. The returned function also takes no size argument, which is fine: all callers (hook.ts and both QuickJS __generateNanoid bindings) call it with no arguments.
Closes #3842.
What
@workflow/corepinsnanoidexactly at5.1.6, which is in the vulnerable range of GHSA-28wg-ghj8-5hjv (high,>=4.0.0 <5.1.16). Because the pin is exact, apps can only move off it with anoverrides/resolutionsentry.This PR removes the dependency instead of bumping it.
Why not just bump nanoid?
Core uses nanoid only to build the seeded generator for default hook tokens:
customRandom(urlAlphabet, 21, bytes from the run-seeded PRNG). In 5.1.16,customRandomrequests 21 bytes per id instead of 34. For the same seed, that changes both the hook token and every seeded value drawn after it (Math.random()inside the workflow, later tokens):wrun_test:seedMath.random()pVjvQyygUGbIid9mUBIhpmgNKWnMBr9yywfW_syBGT0.3399…d9mUBIhphoZLwZ1T1ma-kjdT3d6rupVjvQyygUGbIi0.1769…A run recorded before the upgrade and replayed after it would diverge. On
stable, a plain bump failed thehook-sleep-interactionreplay tests withReplayDivergenceError(see #4336's history). The same applies to users who add ananoidoverride today.Changes
packages/core/src/seeded-nanoid.tsreproduces nanoid 5.1.6'scustomRandom(urlAlphabet, 21, ...)exactly: 34 draws per id, read from the end of the batch.seeded-nanoid.test.tspins the recorded 5.1.6 output and PRNG position, so any change to the draw pattern fails a test.workflow.ts), the QuickJS engine (runtime/quickjs-runtime.ts) and the test helpers all use it.nanoidis removed from@workflow/core's dependencies.@workflow/core, worded as a security fix so the backport check picks it up.Verification
pnpm --filter @workflow/core testpasses (3070 tests on currentmain), andtypecheckpasses.npm audit --omit=devreports 0 vulnerabilities, with nonanoidin the tree.Related
stable(4.x), plus the undici 7.29.0 backport from chore(deps): upgrade undici to 7.29.0 #3315.🤖 Generated with Claude Code