From 4c2b36e527093f5b32e8df59b88393acc4c4fb0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Nov 2026 14:16:33 +0000 Subject: [PATCH 1/3] build(deps): bump minimatch and just-bash Removes [minimatch](https://github.com/isaacs/minimatch). It's no longer used after updating ancestor dependency [just-bash](https://github.com/vercel-labs/just-bash). These dependencies need to be updated together. Removes `minimatch` Updates `just-bash` from 3.2.0 to 3.6.0 - [Release notes](https://github.com/vercel-labs/just-bash/releases) - [Commits](https://github.com/vercel-labs/just-bash/compare/just-bash@3.2.0...just-bash@3.6.0) --- updated-dependencies: - dependency-name: just-bash dependency-version: 3.6.0 dependency-type: direct:production - dependency-name: minimatch dependency-version: dependency-type: indirect ... Signed-off-by: dependabot[bot] --- examples/artifacts/package.json | 2 +- examples/egress/package.json | 2 +- examples/mcp/package.json | 2 +- examples/pi-ai/package.json | 2 +- examples/tanstack-ai/package.json | 2 +- examples/think-compare-runtimes/package.json | 2 +- examples/think/package.json | 2 +- examples/vite-bundle/package.json | 2 +- examples/worker-shell/package.json | 2 +- package-lock.json | 221 +++++++------------ packages/computer/package.json | 4 +- 11 files changed, 96 insertions(+), 147 deletions(-) diff --git a/examples/artifacts/package.json b/examples/artifacts/package.json index 6c4c6a8f6..458aa2d0b 100644 --- a/examples/artifacts/package.json +++ b/examples/artifacts/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", diff --git a/examples/egress/package.json b/examples/egress/package.json index 08e73ab24..e3cf6192f 100644 --- a/examples/egress/package.json +++ b/examples/egress/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", diff --git a/examples/mcp/package.json b/examples/mcp/package.json index afc44bb20..ea7fd0331 100644 --- a/examples/mcp/package.json +++ b/examples/mcp/package.json @@ -18,7 +18,7 @@ "@modelcontextprotocol/sdk": "1.32.1", "@platformatic/vfs": "^0.4.0", "ai": "^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/examples/pi-ai/package.json b/examples/pi-ai/package.json index 984614495..533998a7f 100644 --- a/examples/pi-ai/package.json +++ b/examples/pi-ai/package.json @@ -14,7 +14,7 @@ "dependencies": { "@cloudflare/computer": "*", "@earendil-works/pi-ai": "^0.99.2", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/examples/tanstack-ai/package.json b/examples/tanstack-ai/package.json index bceac9d92..35ea3292e 100644 --- a/examples/tanstack-ai/package.json +++ b/examples/tanstack-ai/package.json @@ -15,7 +15,7 @@ "@cloudflare/computer": "*", "@tanstack/ai": "^0.63.0", "@tanstack/ai-cloudflare": "^0.2.1", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/examples/think-compare-runtimes/package.json b/examples/think-compare-runtimes/package.json index 389f1d3c3..509f2aef4 100644 --- a/examples/think-compare-runtimes/package.json +++ b/examples/think-compare-runtimes/package.json @@ -29,7 +29,7 @@ "@shikijs/themes": "^4.2.0", "agents": "^0.29.0", "ai": "^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "partyserver": "^0.5.6", "partysocket": "^1.1.19", "react": "^19.2.7", diff --git a/examples/think/package.json b/examples/think/package.json index abe4d6900..d9cf4c7c0 100644 --- a/examples/think/package.json +++ b/examples/think/package.json @@ -26,7 +26,7 @@ "agents": "^0.29.0", "ai": "^7.0.0", "isomorphic-git": "^1.38.3", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "workers-ai-provider": "^4.0.0", "zod": "^4.4.3" }, diff --git a/examples/vite-bundle/package.json b/examples/vite-bundle/package.json index bba6f9c75..22260b964 100644 --- a/examples/vite-bundle/package.json +++ b/examples/vite-bundle/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "@cloudflare/vite-plugin": "^1.68.0", diff --git a/examples/worker-shell/package.json b/examples/worker-shell/package.json index afef852a5..aa282f9d4 100644 --- a/examples/worker-shell/package.json +++ b/examples/worker-shell/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", diff --git a/package-lock.json b/package-lock.json index 15d03773a..63af92295 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "version": "0.0.0", "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", @@ -279,7 +279,7 @@ "version": "0.0.0", "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", @@ -297,7 +297,7 @@ "@modelcontextprotocol/sdk": "1.32.1", "@platformatic/vfs": "^0.4.0", "ai": "^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { @@ -313,7 +313,7 @@ "dependencies": { "@cloudflare/computer": "*", "@earendil-works/pi-ai": "^0.99.2", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { @@ -537,7 +537,7 @@ "@cloudflare/computer": "*", "@tanstack/ai": "^0.63.0", "@tanstack/ai-cloudflare": "^0.2.1", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "zod": "^4.4.3" }, "devDependencies": { @@ -561,7 +561,7 @@ "agents": "^0.29.0", "ai": "^7.0.0", "isomorphic-git": "^1.38.3", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "workers-ai-provider": "^4.0.0", "zod": "^4.4.3" }, @@ -590,7 +590,7 @@ "@shikijs/themes": "^4.2.0", "agents": "^0.29.0", "ai": "^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "partyserver": "^0.5.6", "partysocket": "^1.1.19", "react": "^19.2.7", @@ -1204,7 +1204,7 @@ "version": "0.0.0", "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "@cloudflare/vite-plugin": "^1.68.0", @@ -1218,7 +1218,7 @@ "version": "0.0.0", "dependencies": { "@cloudflare/computer": "*", - "just-bash": "^3.0.1" + "just-bash": "^3.6.0" }, "devDependencies": { "typescript": "^6.0.3", @@ -4920,48 +4920,6 @@ "node": ">=18.0.0" } }, - "node_modules/@jitl/quickjs-ffi-types": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-ffi-types/-/quickjs-ffi-types-0.32.0.tgz", - "integrity": "sha512-v9T+GQpmk43VDJ7d72sf0Nexhk+ArvtUihW27dy7lqAl0zBObFKtSBBIm5RBjwIhE8VwsPPm9PNuvPvNqLWUEg==", - "license": "MIT" - }, - "node_modules/@jitl/quickjs-wasmfile-debug-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-asyncify/-/quickjs-wasmfile-debug-asyncify-0.32.0.tgz", - "integrity": "sha512-EX8zbXwGqCgAE764M+qvkHtyXDi/FUoMBea0JnES7vCM3P7a2+EOZOjGv85wtZ2sJhI1oJ+nekmqpOODFDY+hw==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-debug-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-sync/-/quickjs-wasmfile-debug-sync-0.32.0.tgz", - "integrity": "sha512-LeYWrPGC1uNCTBWvibo3ZLJj0CSVNYUXvJpXMCmuQ5Sap2cCACc3uvGvYV4homHHBAzfw5akoTqMMS4YFRtw+Q==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-asyncify": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-asyncify/-/quickjs-wasmfile-release-asyncify-0.32.0.tgz", - "integrity": "sha512-3oSwPfja12ICz4aIblB58cuY8JlEq5Txt8Cut4VLo+LH47QN+mzCnSgnbB03hWzg1LBcc+VyyI9UOag7a1NF+Q==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, - "node_modules/@jitl/quickjs-wasmfile-release-sync": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-sync/-/quickjs-wasmfile-release-sync-0.32.0.tgz", - "integrity": "sha512-BKNDI/TPBfGlLNGYpLrhcDGXmIk4xHm4MRAisOBnOzpXVn9HZWsfmMAc9WMBrAHjvvds6HOikKeaOBKdPdpVrg==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -8811,15 +8769,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -8987,18 +8936,6 @@ "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", "license": "MIT" }, - "node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -11175,6 +11112,28 @@ "dev": true, "license": "ISC" }, + "node_modules/guarded-fetch": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/guarded-fetch/-/guarded-fetch-0.1.3.tgz", + "integrity": "sha512-PSaNyJk8VJlUVEhMHPXT/Z/WgNrLBh43WaYQJiu1qvyCuPQA+kgFMNmAOxI3GU3uXrCkO/xRW11XjcswrksYOA==", + "license": "Apache-2.0", + "dependencies": { + "ipaddr.js": "2.2.0", + "undici": "7.29.0" + }, + "engines": { + "node": ">=20.19" + } + }, + "node_modules/guarded-fetch/node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -12324,38 +12283,38 @@ } }, "node_modules/just-bash": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/just-bash/-/just-bash-3.2.0.tgz", - "integrity": "sha512-hRTLLWBXCKuosjaNFJR7uPYBza+T2vjG3NdPBz4wxlctlnxwrbLjtLQf6RtSKmy/jzNJ6/URCtvxrXjy6yFGeQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/just-bash/-/just-bash-3.6.0.tgz", + "integrity": "sha512-2COjEgcHdqKXeQSiNfPAHmpwQx4S8wATaIwog83g2t645U5tom6FED4CBBdr3M+0ioX4xZ26eODw3/nD6RQ6xw==", "license": "Apache-2.0", "dependencies": { - "diff": "^8.0.2", - "fast-xml-parser": "^5.7.3", - "file-type": "^21.2.0", + "diff": "^8.0.4", + "fast-xml-parser": "^5.10.1", + "file-type": "^21.3.4", + "guarded-fetch": "0.1.3", "ini": "^6.0.0", - "minimatch": "^10.1.1", - "modern-tar": "^0.7.3", - "papaparse": "^5.5.3", - "quickjs-emscripten": "^0.32.0", - "re2js": "^1.2.1", + "modern-tar": "^0.7.7", + "papaparse": "^5.6.0", + "re2js": "^1.3.3", + "run": "2.1.3", "seek-bzip": "^2.0.0", - "smol-toml": "^1.6.0", + "smol-toml": "^1.9.0", "sprintf-js": "^1.1.3", - "sql.js": "^1.13.0", - "turndown": "^7.2.2", - "undici": "^7.25.0", - "yaml": "^2.8.2" + "sql.js": "^1.14.1", + "turndown": "^7.2.4", + "typescript": "^5.9.3", + "yaml": "^2.9.0" }, "bin": { "just-bash": "dist/bin/just-bash.js", "just-bash-shell": "dist/bin/shell/shell.js" }, "engines": { - "node": ">=20.18.1" + "node": ">=20.19" }, "optionalDependencies": { "@mongodb-js/zstd": "^7.0.0", - "node-liblzma": "^2.0.3" + "node-liblzma": "^2.2.0" } }, "node_modules/just-bash/node_modules/diff": { @@ -12367,6 +12326,19 @@ "node": ">=0.3.1" } }, + "node_modules/just-bash/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", @@ -14437,21 +14409,6 @@ } } }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -15258,9 +15215,9 @@ "license": "(MIT AND Zlib)" }, "node_modules/papaparse": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.4.tgz", - "integrity": "sha512-SwzWD9gl/ElwYLCI0nUja1mFJzjq2D8ziShfNBa7zCHzkOozeOGDwHWQ+tvCzEZcewecWZ5U7kUopDnG+DFYEQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.7.0.tgz", + "integrity": "sha512-qBGxg/7Q3Kl9Wfhrz2Z74UnvnHTXLNG6jmKJFeBvP2+y4lV7So+7SR62+Zd47JvdrCkX+nDcnr0ObPzek/+6RA==", "license": "MIT" }, "node_modules/parse-entities": { @@ -15796,31 +15753,6 @@ ], "license": "MIT" }, - "node_modules/quickjs-emscripten": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten/-/quickjs-emscripten-0.32.0.tgz", - "integrity": "sha512-So0Sqw869y/S2oE3Nuc0uT3Dhqgvsj8FSrwBdsuTosVsG8ME5/OcudU1GxsrIFdFABgy17GHnTVO9TYV/bLQcA==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-wasmfile-debug-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-debug-sync": "0.32.0", - "@jitl/quickjs-wasmfile-release-asyncify": "0.32.0", - "@jitl/quickjs-wasmfile-release-sync": "0.32.0", - "quickjs-emscripten-core": "0.32.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/quickjs-emscripten-core": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/quickjs-emscripten-core/-/quickjs-emscripten-core-0.32.0.tgz", - "integrity": "sha512-QFnPfjFey8EqknSrSxe1hZrf1/8z7/6s1QzGOmKo6++02r7QRRX7ZoyNaZh7JuVjWsVW87KnQrbZqnHkOAzUyg==", - "license": "MIT", - "dependencies": { - "@jitl/quickjs-ffi-types": "0.32.0" - } - }, "node_modules/range-parser": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", @@ -16314,6 +16246,23 @@ "node": ">= 18" } }, + "node_modules/run": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/run/-/run-2.1.3.tgz", + "integrity": "sha512-KUurW05zgjtZ2su0cBURC1q2RG/Uq0uzV3qURDsXqiKh03p9IXABQK4Qem56cFMqjT8TdQ2iTWsePrMprQWIRA==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "typescript": ">=5.1.6 <7" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -18208,7 +18157,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -20743,7 +20692,7 @@ "esbuild": "^0.28.1", "ignore": "^7.0.14", "isomorphic-git": "^1.38.3", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "memfs": "^4.57.6", "picomatch": "^4.0.7", "tsdown": "^0.23.1", @@ -20757,7 +20706,7 @@ "@cloudflare/workers-types": "^4.20260616.1 || ^5.20260921.1", "@platformatic/vfs": "*", "ai": "^6.0.196 || ^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "zod": "^4.4.3" }, diff --git a/packages/computer/package.json b/packages/computer/package.json index e0f596e81..6d9db2df5 100644 --- a/packages/computer/package.json +++ b/packages/computer/package.json @@ -180,7 +180,7 @@ "@cloudflare/workers-types": "^4.20260616.1 || ^5.20260921.1", "@platformatic/vfs": "*", "ai": "^6.0.196 || ^7.0.0", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "zod": "^4.4.3" }, @@ -221,7 +221,7 @@ "esbuild": "^0.28.1", "ignore": "^7.0.14", "isomorphic-git": "^1.38.3", - "just-bash": "^3.0.1", + "just-bash": "^3.6.0", "memfs": "^4.57.6", "picomatch": "^4.0.7", "tsdown": "^0.23.1", From ace57a58ddf5c16f61fc258b668024ed2c9538d8 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Wed, 11 Nov 2026 14:58:39 +0000 Subject: [PATCH 2/3] computer: Keep guarded-fetch out of the Worker shell bundle just-bash 3.6 imports guarded-fetch when it loads and sends curl's requests through it. guarded-fetch imports Headers and buildConnector from undici, which the shell bundle replaces with a stub that has neither, so the bundle no longer built. guarded-fetch adds DNS pinning and private-range checks. The Worker backend runs with denyPrivateRanges off and leaves egress to the Dynamic Worker's globalOutbound, so those checks change nothing for it: requests to localhost, private addresses and public hosts reach the outbound the same way with and without it. Bundled, it would add about 42 KB to core, which every shell loads whether it has curl or not. The bundle now turns just-bash's import("guarded-fetch") into Promise.resolve(null), which is the path just-bash takes in a browser: plain fetch, through the SecureFetch the entrypoint passes. The build fails if just-bash stops having that import. The worker-backend tests gain a shell with an outbound gateway that echoes each request, and run curl against it, so a request through the whole path is covered rather than curl's argument check alone. The bundle test now checks that neither the real undici nor guarded-fetch is in core or any command group. --- .../worker-shell/script/build-bundle.mjs | 39 ++++++++++++++++++- .../worker-shell/shell-modules.test.ts | 32 +++++++++++---- .../computer/tests/worker-backend-worker.ts | 30 +++++++++++++- .../computer/tests/worker-backend.test.ts | 17 ++++++++ 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/packages/computer/src/backends/worker-shell/script/build-bundle.mjs b/packages/computer/src/backends/worker-shell/script/build-bundle.mjs index 90503eac0..e31106cfc 100644 --- a/packages/computer/src/backends/worker-shell/script/build-bundle.mjs +++ b/packages/computer/src/backends/worker-shell/script/build-bundle.mjs @@ -34,14 +34,15 @@ // (script/undici-stub.mjs) because the Worker backend runs curl on // the plain-fetch path, never the undici DNS-pinning path — so a // consumer that imports the curl group gets a working curl without -// undici's bytes. +// undici's bytes. just-bash's guarded-fetch, which does that pinning +// through undici, is kept out the same way (see exclude-guarded-fetch). // // The generated/ output is gitignored. It's regenerated by the // computer package's prepare / pretest / pretypecheck scripts // so any install from this repo or downstream consumer sees a // fresh bundle matching the source. -import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { basename, dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; @@ -147,6 +148,40 @@ try { "seek-bzip", ], plugins: [ + // just-bash (3.6 and later) starts `import("guarded-fetch")` when + // it loads and sends every curl request through it once it + // resolves. guarded-fetch adds DNS pinning and private-range + // checks, through undici and node:dns. The Worker backend runs + // with denyPrivateRanges off and leaves egress to the Dynamic + // Worker's globalOutbound, so guarded-fetch changes nothing for + // it, yet it would add about 42 KB to core, which every shell + // loads, curl or not. With the import resolving to null, just-bash + // takes its plain fetch path, as it does in a browser, through the + // SecureFetch entrypoint.ts passes. The import is in a minified + // file, so a just-bash without it fails the build here rather + // than quietly bundling guarded-fetch. + { + name: "exclude-guarded-fetch", + setup(pluginBuild) { + let replaced = 0; + pluginBuild.onLoad({ filter: /[/\\]just-bash[/\\]dist[/\\].*\.js$/ }, async (args) => { + const source = await readFile(args.path, "utf8"); + if (!source.includes('import("guarded-fetch")')) return undefined; + replaced += 1; + return { + contents: source.replaceAll('import("guarded-fetch")', "Promise.resolve(null)"), + loader: "js", + }; + }); + pluginBuild.onEnd((result) => { + if (result.errors.length === 0 && replaced === 0) { + throw new Error( + 'build-bundle: just-bash no longer has import("guarded-fetch"); check how curl reaches the network before updating exclude-guarded-fetch', + ); + } + }); + }, + }, // curl reaches undici only through just-bash's DNS-pinning // connection owner, which the Worker backend never activates: // ShellWorker registers curl on the plain-`fetch` path diff --git a/packages/computer/src/backends/worker-shell/shell-modules.test.ts b/packages/computer/src/backends/worker-shell/shell-modules.test.ts index 8b61c2d8a..42829830a 100644 --- a/packages/computer/src/backends/worker-shell/shell-modules.test.ts +++ b/packages/computer/src/backends/worker-shell/shell-modules.test.ts @@ -89,14 +89,30 @@ describe("SHELL_CORE_MODULES", () => { } }); - it("excludes the real undici dependency, leaving only the stub", () => { - // undici is redirected to a throwing stub at bundle time, so - // even when curl is included it runs on the fetch path and the - // ~620 KB real dependency never ships. The stub marker lives in - // core (the secure-fetch seam), so it is present by default. - const marker = "undici is excluded from the Worker shell bundle"; - const stubPresent = Object.values(SHELL_CORE_MODULES).some((mod) => mod.js.includes(marker)); - expect(stubPresent).toBe(true); + it("leaves out guarded-fetch and the real undici, in core and every group", () => { + // curl runs on the plain fetch path, so neither guarded-fetch's DNS + // pinning nor the ~620 KB undici it pins through ships. Each marker is + // a string literal of the real library's: undici's error code, and the + // message guarded-fetch blocks a URL with. + const groups = [ + SHELL_CORE_MODULES, + curlModules, + fileModules, + htmlToMarkdownModules, + jqModules, + jsExecModules, + pythonModules, + sqliteModules, + xanModules, + yqModules, + ]; + for (const marker of ["UND_ERR_CONNECT_TIMEOUT", "guarded-fetch blocked URL"]) { + for (const group of groups) { + for (const [name, mod] of Object.entries(group)) { + expect(mod.js.includes(marker), `${marker} in ${name}`).toBe(false); + } + } + } }); }); diff --git a/packages/computer/tests/worker-backend-worker.ts b/packages/computer/tests/worker-backend-worker.ts index 08b68873d..7d8411d52 100644 --- a/packages/computer/tests/worker-backend-worker.ts +++ b/packages/computer/tests/worker-backend-worker.ts @@ -25,6 +25,15 @@ import { Workspace } from "../src/index"; export { WorkspaceServiceProxy } from "../src/proxy"; +/** The gateway the networked shell's requests go to: it answers with what it was sent. */ +export class EchoGateway extends WorkerEntrypoint { + override async fetch(request: Request): Promise { + return new Response(`${request.method} ${request.url} ${await request.text()}`, { + headers: { "x-echo": "yes" }, + }); + } +} + export interface Env { HOST: DurableObjectNamespace; LOADER: WorkerLoader; @@ -47,6 +56,19 @@ export class HostDO extends DurableObject { // fetch-path curl integration test exercises the wiring. commands: [curlModules], }), + // The same shell with a network: its requests go to EchoGateway, so curl's whole path, + // through just-bash's fetch and the Dynamic Worker's outbound, runs without real egress. + new WorkerShellBackend({ + id: "worker-shell-net", + loader: env.LOADER, + workspace: { binding: "HOST", id: ctx.id.toString() }, + ctx, + commands: [curlModules], + egress: { + mode: "http-gateway", + gateway: (ctx as unknown as { exports: { EchoGateway: Fetcher } }).exports.EchoGateway, + }, + }), ], }); } @@ -81,7 +103,10 @@ export class HostDO extends DurableObject { return this.#workspace.fs.readFile(path, "utf8"); } - async exec(command: string): Promise<{ + async exec( + command: string, + backend?: string, + ): Promise<{ exitCode: number; stdout: string; stderr: string; @@ -90,6 +115,7 @@ export class HostDO extends DurableObject { await this.#seed(); const handle = await this.#workspace.runtime.exec(command, { encoding: "utf8", + ...(backend === undefined ? {} : { backend }), }); const result = await handle.result(); return { @@ -130,7 +156,7 @@ export default class extends WorkerEntrypoint { if (url.pathname === "/exec") { const command = url.searchParams.get("command") ?? "true"; - const result = await stub.exec(command); + const result = await stub.exec(command, url.searchParams.get("backend") ?? undefined); return Response.json(result); } diff --git a/packages/computer/tests/worker-backend.test.ts b/packages/computer/tests/worker-backend.test.ts index a0cc49e7c..2f8384f89 100644 --- a/packages/computer/tests/worker-backend.test.ts +++ b/packages/computer/tests/worker-backend.test.ts @@ -69,6 +69,7 @@ async function read(id: string, path: string): Promise { async function exec( id: string, command: string, + backend?: string, ): Promise<{ exitCode: number; stdout: string; @@ -78,6 +79,7 @@ async function exec( const url = new URL("http://test/exec"); url.searchParams.set("id", id); url.searchParams.set("command", command); + if (backend !== undefined) url.searchParams.set("backend", backend); const res = await SELF.fetch(url); if (!res.ok) throw new Error(`exec failed: ${res.status} ${await res.text()}`); return res.json(); @@ -165,6 +167,21 @@ describe("WorkerShellBackend end-to-end", () => { expect(result.stdout).not.toMatch(/command not found/); }); + it("fetches with curl through the Dynamic Worker's outbound", async () => { + // The networked shell sends its requests to EchoGateway, which answers with what it got, so + // this covers curl's whole path: just-bash's fetch, then the Dynamic Worker's outbound. + const id = freshId(); + const result = await exec( + id, + "curl -s -i -X POST -d hello https://api.example.test/things", + "worker-shell-net", + ); + expect(result.exitCode).toBe(0); + expect(result.stdout).toMatch(/^HTTP\/1\.1 200/); + expect(result.stdout.toLowerCase()).toContain("x-echo: yes"); + expect(result.stdout).toContain("POST https://api.example.test/things hello"); + }); + it("isolates state between separate workspace ids", async () => { // Two host-DO names → two distinct workspaces, two distinct // Dynamic Worker isolates (the loader caches by From 9f051e6f199e23732a4527c838df78b163c0da9e Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Wed, 11 Nov 2026 14:59:16 +0000 Subject: [PATCH 3/3] computer: Add a changeset for just-bash 3.6 --- .changeset/just-bash-3-6.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/just-bash-3-6.md diff --git a/.changeset/just-bash-3-6.md b/.changeset/just-bash-3-6.md new file mode 100644 index 000000000..b9c85e4e7 --- /dev/null +++ b/.changeset/just-bash-3-6.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/computer": patch +--- + +Update `just-bash` to 3.6. The Worker shell keeps running `curl` on plain `fetch`, without `guarded-fetch`. See [Worker backend](https://github.com/cloudflare/computer/blob/main/docs/12_worker_backend.md).