Protect stdout and stderr so JavaScript code can't accidentally write to stdout corrupting ink rendering (#13247)

Bypassing rules as link checker failure is spurious.
This commit is contained in:
Jacob Richman
2025-11-20 10:44:02 -08:00
committed by GitHub
parent e20d282088
commit d1e35f8660
82 changed files with 1523 additions and 868 deletions
@@ -13,6 +13,7 @@ import {
afterEach,
type Mock,
} from 'vitest';
import { format } from 'node:util';
import { type CommandModule, type Argv } from 'yargs';
import { handleUpdate, updateCommand } from './update.js';
import { ExtensionManager } from '../../config/extension-manager.js';
@@ -22,22 +23,33 @@ import * as github from '../../config/extensions/github.js';
import { ExtensionUpdateState } from '../../ui/state/extensions.js';
// Mock dependencies
vi.mock('../../config/extension-manager.js');
vi.mock('../../config/settings.js');
vi.mock('../../utils/errors.js');
vi.mock('../../config/extensions/update.js');
vi.mock('../../config/extensions/github.js');
const emitConsoleLog = vi.hoisted(() => vi.fn());
const debugLogger = vi.hoisted(() => ({
log: vi.fn((message, ...args) => {
emitConsoleLog('log', format(message, ...args));
}),
error: vi.fn((message, ...args) => {
emitConsoleLog('error', format(message, ...args));
}),
}));
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const actual =
await importOriginal<typeof import('@google/gemini-cli-core')>();
return {
...actual,
debugLogger: {
log: vi.fn(),
error: vi.fn(),
coreEvents: {
emitConsoleLog,
},
debugLogger,
};
});
vi.mock('../../config/extension-manager.js');
vi.mock('../../config/settings.js');
vi.mock('../../utils/errors.js');
vi.mock('../../config/extensions/update.js');
vi.mock('../../config/extensions/github.js');
vi.mock('../../config/extensions/consent.js', () => ({
requestConsentNonInteractive: vi.fn(),
}));
@@ -57,16 +69,8 @@ describe('extensions update command', () => {
update.updateAllUpdatableExtensions,
);
interface MockDebugLogger {
log: Mock;
error: Mock;
}
let mockDebugLogger: MockDebugLogger;
beforeEach(async () => {
vi.clearAllMocks();
mockDebugLogger = (await import('@google/gemini-cli-core'))
.debugLogger as unknown as MockDebugLogger;
mockLoadSettings.mockReturnValue({
merged: { experimental: { extensionReloading: true } },
} as unknown as LoadedSettings);
@@ -106,7 +110,7 @@ describe('extensions update command', () => {
await handleUpdate({ name: 'my-extension' });
expect(mockDebugLogger.log).toHaveBeenCalledWith(expectedLog);
expect(emitConsoleLog).toHaveBeenCalledWith('log', expectedLog);
if (shouldCallUpdateExtension) {
expect(mockUpdateExtension).toHaveBeenCalled();
} else {
@@ -141,7 +145,7 @@ describe('extensions update command', () => {
await handleUpdate({ all: true });
expect(mockDebugLogger.log).toHaveBeenCalledWith(expectedLog);
expect(emitConsoleLog).toHaveBeenCalledWith('log', expectedLog);
mockCwd.mockRestore();
},
);