From 0fb9a68a2e8ea2bb46e033786ccfd7f2417f90a7 Mon Sep 17 00:00:00 2001 From: Khanh Le Date: Mon, 15 Jun 2026 13:12:46 -0500 Subject: [PATCH 1/3] fix(worker): reject process global in workflow bundle --- .../src/mocks/workflows-with-process-global.ts | 3 +++ packages/test/src/test-bundler.ts | 12 ++++++++++++ packages/worker/src/workflow/bundler.ts | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 packages/test/src/mocks/workflows-with-process-global.ts diff --git a/packages/test/src/mocks/workflows-with-process-global.ts b/packages/test/src/mocks/workflows-with-process-global.ts new file mode 100644 index 0000000000..e0f288fec8 --- /dev/null +++ b/packages/test/src/mocks/workflows-with-process-global.ts @@ -0,0 +1,3 @@ +export async function processGlobalWorkflow(): Promise { + return process.pid; +} diff --git a/packages/test/src/test-bundler.ts b/packages/test/src/test-bundler.ts index 70bc5bb13f..cbd5fdb663 100644 --- a/packages/test/src/test-bundler.ts +++ b/packages/test/src/test-bundler.ts @@ -23,6 +23,18 @@ test('moduleMatches works', (t) => { t.false(moduleMatches('fs', ['foo'])); }); +test('An error is thrown when workflow references the process global', async (t) => { + await t.throwsAsync( + bundleWorkflowCode({ + workflowsPath: require.resolve('./mocks/workflows-with-process-global'), + }), + { + instanceOf: Error, + message: /is importing the following disallowed modules.*process/s, + } + ); +}); + async function runPreloadSharedCounter( t: ExecutionContext, workerOptions: Pick diff --git a/packages/worker/src/workflow/bundler.ts b/packages/worker/src/workflow/bundler.ts index 85d1f2444a..e828822c9e 100644 --- a/packages/worker/src/workflow/bundler.ts +++ b/packages/worker/src/workflow/bundler.ts @@ -238,6 +238,22 @@ exports.importInterceptors = function importInterceptors() { }, }, plugins: [ + { + apply: (compiler) => { + compiler.hooks.normalModuleFactory.tap('WorkflowCodeBundler', (normalModuleFactory) => { + for (const moduleType of ['javascript/auto', 'javascript/dynamic', 'javascript/esm']) { + normalModuleFactory.hooks.parser.for(moduleType).tap('WorkflowCodeBundler', (parser) => { + const javascriptParser = parser as any; + javascriptParser.hooks.expression.for('process').tap('WorkflowCodeBundler', () => { + if (!javascriptParser.isVariableDefined('process')) { + this.foundProblematicModules.add('process'); + } + }); + }); + } + }); + }, + }, // `@temporalio/interceptors-opentelemetry` only requires `@temporalio/workflow` for interceptors that run in workflow context. // In order to keep `@temporalio/workflow` as an optional peer dependency for `@temporalio/interceptors-opentelemetry` // we use `workflow-imports` to reexport all required imports from `@temporalio/workflow`. From 5bba954ba8a1fb1ab6829c3f7ca6f8238992e091 Mon Sep 17 00:00:00 2001 From: Khanh Le <58643031+nkgotcode@users.noreply.github.com> Date: Tue, 23 Jun 2026 19:23:27 -0400 Subject: [PATCH 2/3] fix(worker): type workflow parser without any cast --- packages/worker/src/workflow/bundler.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/worker/src/workflow/bundler.ts b/packages/worker/src/workflow/bundler.ts index e828822c9e..7183bc68e2 100644 --- a/packages/worker/src/workflow/bundler.ts +++ b/packages/worker/src/workflow/bundler.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import util from 'node:util'; import * as unionfs from 'unionfs'; import * as memfs from 'memfs'; -import type { Configuration } from 'webpack'; +import type { Configuration, javascript } from 'webpack'; import { webpack, NormalModuleReplacementPlugin } from 'webpack'; import type { Logger } from '../logger'; import { DefaultLogger, hasColorSupport } from '../logger'; @@ -241,15 +241,16 @@ exports.importInterceptors = function importInterceptors() { { apply: (compiler) => { compiler.hooks.normalModuleFactory.tap('WorkflowCodeBundler', (normalModuleFactory) => { - for (const moduleType of ['javascript/auto', 'javascript/dynamic', 'javascript/esm']) { - normalModuleFactory.hooks.parser.for(moduleType).tap('WorkflowCodeBundler', (parser) => { - const javascriptParser = parser as any; - javascriptParser.hooks.expression.for('process').tap('WorkflowCodeBundler', () => { - if (!javascriptParser.isVariableDefined('process')) { - this.foundProblematicModules.add('process'); - } + for (const moduleType of ['javascript/auto', 'javascript/dynamic', 'javascript/esm'] as const) { + normalModuleFactory.hooks.parser + .for(moduleType) + .tap('WorkflowCodeBundler', (javascriptParser: javascript.JavascriptParser) => { + javascriptParser.hooks.expression.for('process').tap('WorkflowCodeBundler', () => { + if (!javascriptParser.isVariableDefined('process')) { + this.foundProblematicModules.add('process'); + } + }); }); - }); } }); }, From 557a05aa2d80f35f44c9e94a1695b718b0dd261b Mon Sep 17 00:00:00 2001 From: Khanh Le <58643031+nkgotcode@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:30:29 -0400 Subject: [PATCH 3/3] fix(worker): let process global check respect ignoreModules --- packages/test-helpers/src/bundler.ts | 1 + packages/test/src/test-bundler.ts | 10 ++++++++++ packages/worker/src/workflow/bundler.ts | 8 ++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/test-helpers/src/bundler.ts b/packages/test-helpers/src/bundler.ts index 928b696d15..b31c7b0265 100644 --- a/packages/test-helpers/src/bundler.ts +++ b/packages/test-helpers/src/bundler.ts @@ -14,6 +14,7 @@ export const baseBundlerIgnoreModules = [ '@temporalio/nexus', '@temporalio/worker', 'ava', + 'process', 'crypto', 'module', 'path', diff --git a/packages/test/src/test-bundler.ts b/packages/test/src/test-bundler.ts index 901ef7ea54..18524d5093 100644 --- a/packages/test/src/test-bundler.ts +++ b/packages/test/src/test-bundler.ts @@ -9,6 +9,7 @@ import { randomUUID } from 'crypto'; import type { ExecutionContext } from 'ava'; import test from 'ava'; import { moduleMatches } from '@temporalio/worker/lib/workflow/bundler'; +import { baseBundlerIgnoreModules } from '@temporalio/test-helpers'; import type { LogEntry, WorkerOptions } from '@temporalio/worker'; import { bundleWorkflowCode, DefaultLogger } from '@temporalio/worker'; import { WorkflowClient } from '@temporalio/client'; @@ -35,6 +36,15 @@ test('An error is thrown when workflow references the process global', async (t) ); }); +test('Workflow bundle can be created from code using process global with test helper ignoreModules', async (t) => { + await t.notThrowsAsync( + bundleWorkflowCode({ + workflowsPath: require.resolve('./mocks/workflows-with-process-global'), + ignoreModules: baseBundlerIgnoreModules, + }) + ); +}); + async function runPreloadSharedCounter( t: ExecutionContext, workerOptions: Pick diff --git a/packages/worker/src/workflow/bundler.ts b/packages/worker/src/workflow/bundler.ts index be2e4deff7..8997f888ad 100644 --- a/packages/worker/src/workflow/bundler.ts +++ b/packages/worker/src/workflow/bundler.ts @@ -58,6 +58,10 @@ export class WorkflowCodeBundler { protected readonly webpackConfigHook: (config: Configuration) => Configuration; protected readonly plugins: BundlerPlugin[]; + protected isIgnoredModule(module: string): boolean { + return moduleMatches(module, this.ignoreModules); + } + constructor(options: BundleOptions) { this.plugins = options.plugins ?? []; for (const plugin of this.plugins) { @@ -218,7 +222,7 @@ exports.importInterceptors = function importInterceptors() { ? data.request.slice('node:'.length) : data.request ?? ''; - if (moduleMatches(module, disallowedModules) && !moduleMatches(module, this.ignoreModules)) { + if (moduleMatches(module, disallowedModules) && !this.isIgnoredModule(module)) { this.foundProblematicModules.add(module); } @@ -246,7 +250,7 @@ exports.importInterceptors = function importInterceptors() { .for(moduleType) .tap('WorkflowCodeBundler', (javascriptParser: javascript.JavascriptParser) => { javascriptParser.hooks.expression.for('process').tap('WorkflowCodeBundler', () => { - if (!javascriptParser.isVariableDefined('process')) { + if (!javascriptParser.isVariableDefined('process') && !this.isIgnoredModule('process')) { this.foundProblematicModules.add('process'); } });