From 0a1328a4eaf17150c2002c99b6dca0ffccc355f9 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Tue, 10 Feb 2026 01:22:38 -0500 Subject: [PATCH] fix: resolve Node 24+ spawn deprecation warning (DEP0190) When using spawn with shell: true, passing args as a separate array causes a deprecation warning in Node 24+: 'Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.' This commit fixes the issue by joining the command and args into a single command string before passing to spawn, which is the recommended pattern for shell: true usage. Fixes #1102 --- .../src/app/services/pass-through.service.spec.ts | 15 +++++---------- .../src/app/services/pass-through.service.ts | 5 ++++- .../src/app/services/version-manager.service.ts | 6 ++++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/generator-cli/src/app/services/pass-through.service.spec.ts b/apps/generator-cli/src/app/services/pass-through.service.spec.ts index 09f01ade7fe..36780b86340 100644 --- a/apps/generator-cli/src/app/services/pass-through.service.spec.ts +++ b/apps/generator-cli/src/app/services/pass-through.service.spec.ts @@ -178,8 +178,7 @@ describe('PassThroughService', () => { await program.parseAsync([name, ...argv], { from: 'user' }); expect(childProcess.spawn).toHaveBeenNthCalledWith( 1, - 'docker run --rm -v "/foo/bar:/local" openapitools/openapi-generator-cli:v4.2.1', - [name, ...argv], + `docker run --rm -v "/foo/bar:/local" openapitools/openapi-generator-cli:v4.2.1 ${name} ${argv.join(' ')}`, { stdio: 'inherit', shell: true, @@ -192,8 +191,7 @@ describe('PassThroughService', () => { await program.parseAsync([name, ...argv], { from: 'user' }); expect(childProcess.spawn).toHaveBeenNthCalledWith( 1, - 'java -jar "/some/path/to/4.2.1.jar"', - [name, ...argv], + `java -jar "/some/path/to/4.2.1.jar" ${name} ${argv.join(' ')}`, { stdio: 'inherit', shell: true, @@ -206,8 +204,7 @@ describe('PassThroughService', () => { await program.parseAsync([name, ...argv], { from: 'user' }); expect(childProcess.spawn).toHaveBeenNthCalledWith( 1, - 'java java-opt-1=1 -jar "/some/path/to/4.2.1.jar"', - [name, ...argv], + `java java-opt-1=1 -jar "/some/path/to/4.2.1.jar" ${name} ${argv.join(' ')}`, { stdio: 'inherit', shell: true, @@ -227,8 +224,7 @@ describe('PassThroughService', () => { `java -cp "${[ '/some/path/to/4.2.1.jar', '../some/custom.jar', - ].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator`, - [name, ...argv], + ].join(cpDelimiter)}" org.openapitools.codegen.OpenAPIGenerator ${name} ${argv.join(' ')}`, { stdio: 'inherit', shell: true, @@ -303,8 +299,7 @@ describe('PassThroughService', () => { it('spawns the correct process', () => { expect(childProcess.spawn).toHaveBeenNthCalledWith( 1, - 'java -jar "/some/path/to/4.2.1.jar"', - cmd.split(' '), + `java -jar "/some/path/to/4.2.1.jar" ${cmd}`, { stdio: 'inherit', shell: true } ); }); diff --git a/apps/generator-cli/src/app/services/pass-through.service.ts b/apps/generator-cli/src/app/services/pass-through.service.ts index 920d629ac34..75a462c5f3f 100644 --- a/apps/generator-cli/src/app/services/pass-through.service.ts +++ b/apps/generator-cli/src/app/services/pass-through.service.ts @@ -85,8 +85,11 @@ export class PassThroughService { public passThrough = (cmd: Command) => { const args = [cmd.name(), ...cmd.args]; + // Join command and args into a single string to avoid Node 24+ deprecation warning + // DEP0190: passing args to spawn with shell: true concatenates without escaping + const fullCommand = [this.cmd(), ...args].join(' '); - spawn(this.cmd(), args, { + spawn(fullCommand, { stdio: 'inherit', shell: true, }).on('exit', process.exit); diff --git a/apps/generator-cli/src/app/services/version-manager.service.ts b/apps/generator-cli/src/app/services/version-manager.service.ts index 80d0af6e73f..0a40ca127aa 100644 --- a/apps/generator-cli/src/app/services/version-manager.service.ts +++ b/apps/generator-cli/src/app/services/version-manager.service.ts @@ -134,7 +134,8 @@ export class VersionManagerService { async remove(versionName: string) { if (this.configService.useDocker) { await new Promise((resolve) => { - spawn('docker', ['rmi', this.getDockerImageName(versionName)], { + // Use single command string to avoid Node 24+ deprecation warning (DEP0190) + spawn(`docker rmi ${this.getDockerImageName(versionName)}`, { stdio: 'inherit', shell: true, }).on('exit', () => resolve()); @@ -151,7 +152,8 @@ export class VersionManagerService { if (this.configService.useDocker) { await new Promise((resolve) => { - spawn('docker', ['pull', this.getDockerImageName(versionName)], { + // Use single command string to avoid Node 24+ deprecation warning (DEP0190) + spawn(`docker pull ${this.getDockerImageName(versionName)}`, { stdio: 'inherit', shell: true, }).on('exit', () => resolve());