diff --git a/.changeset/cli-common-runcheck-stdio-ignore.md b/.changeset/cli-common-runcheck-stdio-ignore.md new file mode 100644 index 0000000000..1d2986eaf0 --- /dev/null +++ b/.changeset/cli-common-runcheck-stdio-ignore.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-common': patch +--- + +Fixed `runCheck` to ignore stdio of the spawned process, preventing unwanted output from leaking to the terminal. diff --git a/packages/cli-common/src/run.test.ts b/packages/cli-common/src/run.test.ts index 01c6c915d6..f38c1659ba 100644 --- a/packages/cli-common/src/run.test.ts +++ b/packages/cli-common/src/run.test.ts @@ -338,5 +338,26 @@ describe('run', () => { const result = await runCheck(['nonexistent-command-12345']); expect(result).toBe(false); }); + + it('should not leak stdout or stderr from the child process', async () => { + const stdoutSpy = jest.spyOn(process.stdout, 'write'); + const stderrSpy = jest.spyOn(process.stderr, 'write'); + const stdoutBefore = stdoutSpy.mock.calls.length; + const stderrBefore = stderrSpy.mock.calls.length; + + await runCheck([ + 'node', + '--eval', + 'console.log("leaked stdout"); console.error("leaked stderr")', + ]); + + const stdoutCalls = stdoutSpy.mock.calls.slice(stdoutBefore); + const stderrCalls = stderrSpy.mock.calls.slice(stderrBefore); + const stdout = stdoutCalls.map(c => String(c[0])).join(''); + const stderr = stderrCalls.map(c => String(c[0])).join(''); + + expect(stdout).not.toContain('leaked stdout'); + expect(stderr).not.toContain('leaked stderr'); + }); }); }); diff --git a/packages/cli-common/src/run.ts b/packages/cli-common/src/run.ts index 23e71460e4..0e95bd517b 100644 --- a/packages/cli-common/src/run.ts +++ b/packages/cli-common/src/run.ts @@ -211,7 +211,7 @@ export async function runOutput( */ export async function runCheck(args: string[]): Promise { try { - await run(args).waitForExit(); + await run(args, { stdio: 'ignore' }).waitForExit(); return true; } catch { return false;