Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/jsc/RuntimeTranspilerCache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ bun_core::declare_scope!(cache, visible);
/// path reinstates the bug for any previously-cached TLA module (#30887).
/// Version 23: `jsx.runtime`/`jsx.development` participate in the features hash,
/// and tsconfig `"jsx": "react-jsx"` now emits the production runtime (#4227).
const EXPECTED_VERSION: u32 = 23;
/// Version 24: Worker threads no longer inline `process.env.X` dot-reads.
/// Entries written by a pre-fix worker carry the writing process's env values
/// as string literals; a cache hit reinstates the bug (#34210).
Comment thread
robobun marked this conversation as resolved.
const EXPECTED_VERSION: u32 = 24;

/// Source files smaller than this are not written to / read from the on-disk
/// transpiler cache. Originally 50 KiB, which excluded almost every file in a
Expand Down
3 changes: 3 additions & 0 deletions src/jsc/web_worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,9 @@ impl WebWorker {
unsafe {
let b = &mut (*vm).transpiler;
b.resolver.env_loader = NonNull::new(b.env);
// Match run_command.rs: no `process.env.X` dot-read inlining at runtime.
b.options.env.behavior =
bun_options_types::schema::api::DotEnvBehavior::LoadAllWithoutInlining;
Comment thread
claude[bot] marked this conversation as resolved.

if let Some(graph) = parent.standalone_module_graph {
(hooks.apply_standalone_runtime_flags)(b, graph);
Expand Down
17 changes: 17 additions & 0 deletions test/cli/run/transpiler-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,23 @@ describe("transpiler cache", () => {
expect(b.stdout == "production 5");
expect(newCacheCount()).toBe(0);
});
test("does not inline process.env in Worker threads", () => {
// https://github.com/oven-sh/bun/issues/34210
writeFileSync(
join(temp_dir, "big-env.js"),
dummyFile((50 * 1024 * 1.5) | 0, "1", { code: "process.env.TRANSPILER_CACHE_TEST_ID" }),
);
writeFileSync(join(temp_dir, "worker-entry.js"), `await import("./big-env.js");`);
writeFileSync(join(temp_dir, "worker-main.js"), `new Worker(new URL("./worker-entry.js", import.meta.url));`);

const a = bunRun(join(temp_dir, "worker-main.js"), { ...env, TRANSPILER_CACHE_TEST_ID: "first" });
expect(a.stdout).toBe("first");
expect(newCacheCount()).toBe(1);

const b = bunRun(join(temp_dir, "worker-main.js"), { ...env, TRANSPILER_CACHE_TEST_ID: "second" });
expect(b.stdout).toBe("second");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
expect(newCacheCount()).toBe(0);
});
test("--feature flag invalidates cache", () => {
// feature() can only appear in an if/ternary, so wrap it
const code = `import { feature } from "bun:bundle";\nif (feature("SUPER_SECRET")) console.log("enabled"); else console.log("disabled");`;
Expand Down
33 changes: 33 additions & 0 deletions test/js/node/worker_threads/worker_threads.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,39 @@ test("*Internal introspection methods are DontEnum on Worker.prototype", () => {
expect(enumerable).not.toContain("cpuUsageInternal");
});

test("env: {} scrubs the launch environment from the worker's process.env", async () => {
// https://github.com/oven-sh/bun/issues/34210
await using proc = Bun.spawn({
cmd: [
bunExe(),
"-e",
`const { Worker } = require("node:worker_threads");
const src = \`const { parentPort } = require("node:worker_threads");
parentPort.postMessage({
keys: Object.keys(process.env),
secret: process.env.LAUNCH_SECRET ?? null,
only: process.env.ONLY ?? null,
inSecret: "LAUNCH_SECRET" in process.env,
node_env: process.env.NODE_ENV ?? null,
});\`;
const w = new Worker(src, { eval: true, env: { ONLY: "1" } });
w.once("message", m => { console.log(JSON.stringify(m)); w.terminate(); });`,
],
env: { ...bunEnv, LAUNCH_SECRET: "s3cr3t", NODE_ENV: "production" },
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect(stderr).toBe("");
expect(JSON.parse(stdout.trim())).toEqual({
keys: ["ONLY"],
secret: null,
only: "1",
inSecret: false,
node_env: null,
});
expect(exitCode).toBe(0);
});

describe("env: SHARE_ENV shares the spawning thread's env, not a process-wide one", () => {
async function run(mode: string) {
const proc = Bun.spawn({
Expand Down
Loading