@google/gemini-cli 0.19.0-nightly.20251124.e177314a4 → 0.19.0-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +0 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/package.json +3 -3
  6. package/dist/src/commands/extensions/examples/mcp-server/package.json +1 -1
  7. package/dist/src/commands/extensions.test.d.ts +6 -0
  8. package/dist/src/commands/extensions.test.js +67 -0
  9. package/dist/src/commands/extensions.test.js.map +1 -0
  10. package/dist/src/commands/utils.test.d.ts +6 -0
  11. package/dist/src/commands/utils.test.js +35 -0
  12. package/dist/src/commands/utils.test.js.map +1 -0
  13. package/dist/src/config/config.js +1 -3
  14. package/dist/src/config/config.js.map +1 -1
  15. package/dist/src/config/config.test.js +3 -16
  16. package/dist/src/config/config.test.js.map +1 -1
  17. package/dist/src/config/extensions/github.js +20 -4
  18. package/dist/src/config/extensions/github.js.map +1 -1
  19. package/dist/src/config/extensions/github.test.js +6 -2
  20. package/dist/src/config/extensions/github.test.js.map +1 -1
  21. package/dist/src/config/settingsSchema.d.ts +9 -0
  22. package/dist/src/config/settingsSchema.js +9 -0
  23. package/dist/src/config/settingsSchema.js.map +1 -1
  24. package/dist/src/config/settingsSchema.test.js +11 -0
  25. package/dist/src/config/settingsSchema.test.js.map +1 -1
  26. package/dist/src/core/auth.test.d.ts +6 -0
  27. package/dist/src/core/auth.test.js +43 -0
  28. package/dist/src/core/auth.test.js.map +1 -0
  29. package/dist/src/core/initializer.test.d.ts +6 -0
  30. package/dist/src/core/initializer.test.js +101 -0
  31. package/dist/src/core/initializer.test.js.map +1 -0
  32. package/dist/src/core/theme.test.d.ts +6 -0
  33. package/dist/src/core/theme.test.js +46 -0
  34. package/dist/src/core/theme.test.js.map +1 -0
  35. package/dist/src/gemini.d.ts +1 -0
  36. package/dist/src/gemini.js +7 -2
  37. package/dist/src/gemini.js.map +1 -1
  38. package/dist/src/gemini.test.js +621 -1
  39. package/dist/src/gemini.test.js.map +1 -1
  40. package/dist/src/gemini_cleanup.test.d.ts +6 -0
  41. package/dist/src/gemini_cleanup.test.js +201 -0
  42. package/dist/src/gemini_cleanup.test.js.map +1 -0
  43. package/dist/src/generated/git-commit.d.ts +2 -2
  44. package/dist/src/generated/git-commit.js +2 -2
  45. package/dist/src/generated/git-commit.js.map +1 -1
  46. package/dist/src/nonInteractiveCli.test.js +336 -0
  47. package/dist/src/nonInteractiveCli.test.js.map +1 -1
  48. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  49. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  50. package/dist/src/services/BuiltinCommandLoader.test.js +1 -0
  51. package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
  52. package/dist/src/test-utils/render.js +4 -0
  53. package/dist/src/test-utils/render.js.map +1 -1
  54. package/dist/src/ui/App.test.js +28 -14
  55. package/dist/src/ui/App.test.js.map +1 -1
  56. package/dist/src/ui/AppContainer.js +21 -2
  57. package/dist/src/ui/AppContainer.js.map +1 -1
  58. package/dist/src/ui/IdeIntegrationNudge.test.d.ts +6 -0
  59. package/dist/src/ui/IdeIntegrationNudge.test.js +147 -0
  60. package/dist/src/ui/IdeIntegrationNudge.test.js.map +1 -0
  61. package/dist/src/ui/auth/ApiAuthDialog.test.js +12 -17
  62. package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
  63. package/dist/src/ui/auth/AuthDialog.test.js +120 -74
  64. package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
  65. package/dist/src/ui/auth/AuthInProgress.test.d.ts +6 -0
  66. package/dist/src/ui/auth/AuthInProgress.test.js +71 -0
  67. package/dist/src/ui/auth/AuthInProgress.test.js.map +1 -0
  68. package/dist/src/ui/auth/useAuth.test.d.ts +6 -0
  69. package/dist/src/ui/auth/useAuth.test.js +178 -0
  70. package/dist/src/ui/auth/useAuth.test.js.map +1 -0
  71. package/dist/src/ui/commands/extensionsCommand.js +28 -6
  72. package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
  73. package/dist/src/ui/commands/extensionsCommand.test.js +32 -0
  74. package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
  75. package/dist/src/ui/commands/resumeCommand.d.ts +7 -0
  76. package/dist/src/ui/commands/resumeCommand.js +16 -0
  77. package/dist/src/ui/commands/resumeCommand.js.map +1 -0
  78. package/dist/src/ui/commands/statsCommand.js +27 -16
  79. package/dist/src/ui/commands/statsCommand.js.map +1 -1
  80. package/dist/src/ui/commands/types.d.ts +1 -1
  81. package/dist/src/ui/commands/types.js.map +1 -1
  82. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +62 -11
  83. package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +1 -1
  84. package/dist/src/ui/components/AnsiOutput.test.js +18 -23
  85. package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
  86. package/dist/src/ui/components/DialogManager.js +4 -0
  87. package/dist/src/ui/components/DialogManager.js.map +1 -1
  88. package/dist/src/ui/components/InputPrompt.test.js +6 -0
  89. package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
  90. package/dist/src/ui/components/ProQuotaDialog.js +2 -2
  91. package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
  92. package/dist/src/ui/components/SessionBrowser.d.ts +2 -2
  93. package/dist/src/ui/components/SessionBrowser.js +11 -11
  94. package/dist/src/ui/components/SessionBrowser.js.map +1 -1
  95. package/dist/src/ui/components/SessionBrowser.test.js +15 -7
  96. package/dist/src/ui/components/SessionBrowser.test.js.map +1 -1
  97. package/dist/src/ui/contexts/UIActionsContext.d.ts +5 -0
  98. package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
  99. package/dist/src/ui/contexts/UIStateContext.d.ts +1 -0
  100. package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
  101. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -0
  102. package/dist/src/ui/hooks/slashCommandProcessor.js +3 -0
  103. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  104. package/dist/src/ui/hooks/slashCommandProcessor.test.js +1 -0
  105. package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
  106. package/dist/src/ui/hooks/useQuotaAndFallback.js +9 -3
  107. package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
  108. package/dist/src/ui/hooks/useQuotaAndFallback.test.js +25 -3
  109. package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
  110. package/dist/src/ui/hooks/useSessionBrowser.js +5 -1
  111. package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -1
  112. package/dist/src/ui/hooks/useSlashCompletion.test.js +4 -4
  113. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  114. package/dist/src/ui/hooks/useToolScheduler.test.js +5 -1
  115. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  116. package/dist/src/ui/state/extensions.test.js +208 -51
  117. package/dist/src/ui/state/extensions.test.js.map +1 -1
  118. package/dist/src/ui/utils/kittyProtocolDetector.test.d.ts +6 -0
  119. package/dist/src/ui/utils/kittyProtocolDetector.test.js +113 -0
  120. package/dist/src/ui/utils/kittyProtocolDetector.test.js.map +1 -0
  121. package/dist/src/ui/utils/terminalSetup.js +39 -38
  122. package/dist/src/ui/utils/terminalSetup.js.map +1 -1
  123. package/dist/src/ui/utils/terminalSetup.test.d.ts +6 -0
  124. package/dist/src/ui/utils/terminalSetup.test.js +131 -0
  125. package/dist/src/ui/utils/terminalSetup.test.js.map +1 -0
  126. package/dist/src/ui/utils/ui-sizing.test.d.ts +6 -0
  127. package/dist/src/ui/utils/ui-sizing.test.js +56 -0
  128. package/dist/src/ui/utils/ui-sizing.test.js.map +1 -0
  129. package/dist/src/utils/checks.test.d.ts +6 -0
  130. package/dist/src/utils/checks.test.js +29 -0
  131. package/dist/src/utils/checks.test.js.map +1 -0
  132. package/dist/src/utils/cleanup.test.js +69 -16
  133. package/dist/src/utils/cleanup.test.js.map +1 -1
  134. package/dist/src/utils/dialogScopeUtils.test.d.ts +6 -0
  135. package/dist/src/utils/dialogScopeUtils.test.js +81 -0
  136. package/dist/src/utils/dialogScopeUtils.test.js.map +1 -0
  137. package/dist/src/utils/errors.test.js +62 -0
  138. package/dist/src/utils/errors.test.js.map +1 -1
  139. package/dist/src/utils/events.test.d.ts +6 -0
  140. package/dist/src/utils/events.test.js +24 -0
  141. package/dist/src/utils/events.test.js.map +1 -0
  142. package/dist/src/utils/handleAutoUpdate.test.js +103 -24
  143. package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
  144. package/dist/src/utils/math.test.d.ts +6 -0
  145. package/dist/src/utils/math.test.js +23 -0
  146. package/dist/src/utils/math.test.js.map +1 -0
  147. package/dist/src/utils/persistentState.test.d.ts +6 -0
  148. package/dist/src/utils/persistentState.test.js +68 -0
  149. package/dist/src/utils/persistentState.test.js.map +1 -0
  150. package/dist/src/utils/readStdin.js +1 -0
  151. package/dist/src/utils/readStdin.js.map +1 -1
  152. package/dist/src/utils/readStdin.test.js +25 -0
  153. package/dist/src/utils/readStdin.test.js.map +1 -1
  154. package/dist/src/utils/resolvePath.test.d.ts +6 -0
  155. package/dist/src/utils/resolvePath.test.js +31 -0
  156. package/dist/src/utils/resolvePath.test.js.map +1 -0
  157. package/dist/src/utils/sandbox.js +6 -137
  158. package/dist/src/utils/sandbox.js.map +1 -1
  159. package/dist/src/utils/sandbox.test.d.ts +6 -0
  160. package/dist/src/utils/sandbox.test.js +302 -0
  161. package/dist/src/utils/sandbox.test.js.map +1 -0
  162. package/dist/src/utils/sandboxUtils.d.ts +14 -0
  163. package/dist/src/utils/sandboxUtils.js +120 -0
  164. package/dist/src/utils/sandboxUtils.js.map +1 -0
  165. package/dist/src/utils/sandboxUtils.test.d.ts +6 -0
  166. package/dist/src/utils/sandboxUtils.test.js +119 -0
  167. package/dist/src/utils/sandboxUtils.test.js.map +1 -0
  168. package/dist/src/utils/updateEventEmitter.test.d.ts +6 -0
  169. package/dist/src/utils/updateEventEmitter.test.js +18 -0
  170. package/dist/src/utils/updateEventEmitter.test.js.map +1 -0
  171. package/dist/src/utils/version.test.d.ts +6 -0
  172. package/dist/src/utils/version.test.js +39 -0
  173. package/dist/src/utils/version.test.js.map +1 -0
  174. package/dist/tsconfig.tsbuildinfo +1 -1
  175. package/package.json +4 -4
  176. package/dist/google-gemini-cli-0.19.0-nightly.20251123.dadd606c0.tgz +0 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { spawn, exec, execSync } from 'node:child_process';
8
+ import os from 'node:os';
9
+ import fs from 'node:fs';
10
+ import { start_sandbox } from './sandbox.js';
11
+ import { FatalSandboxError } from '@google/gemini-cli-core';
12
+ import { EventEmitter } from 'node:events';
13
+ vi.mock('../config/settings.js', () => ({
14
+ USER_SETTINGS_DIR: '/home/user/.gemini',
15
+ }));
16
+ vi.mock('node:child_process');
17
+ vi.mock('node:os');
18
+ vi.mock('node:fs');
19
+ vi.mock('node:util', async (importOriginal) => {
20
+ const actual = await importOriginal();
21
+ return {
22
+ ...actual,
23
+ promisify: (fn) => {
24
+ if (fn === exec) {
25
+ return async (cmd) => {
26
+ if (cmd === 'id -u' || cmd === 'id -g') {
27
+ return { stdout: '1000', stderr: '' };
28
+ }
29
+ if (cmd.includes('curl')) {
30
+ return { stdout: '', stderr: '' };
31
+ }
32
+ if (cmd.includes('getconf DARWIN_USER_CACHE_DIR')) {
33
+ return { stdout: '/tmp/cache', stderr: '' };
34
+ }
35
+ if (cmd.includes('ps -a --format')) {
36
+ return { stdout: 'existing-container', stderr: '' };
37
+ }
38
+ return { stdout: '', stderr: '' };
39
+ };
40
+ }
41
+ return actual.promisify(fn);
42
+ },
43
+ };
44
+ });
45
+ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
46
+ const actual = await importOriginal();
47
+ return {
48
+ ...actual,
49
+ debugLogger: {
50
+ log: vi.fn(),
51
+ debug: vi.fn(),
52
+ warn: vi.fn(),
53
+ },
54
+ coreEvents: {
55
+ emitFeedback: vi.fn(),
56
+ },
57
+ FatalSandboxError: class extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'FatalSandboxError';
61
+ }
62
+ },
63
+ GEMINI_DIR: '.gemini',
64
+ USER_SETTINGS_DIR: '/home/user/.gemini',
65
+ };
66
+ });
67
+ describe('sandbox', () => {
68
+ const originalEnv = process.env;
69
+ const originalArgv = process.argv;
70
+ let mockProcessIn;
71
+ beforeEach(() => {
72
+ vi.clearAllMocks();
73
+ process.env = { ...originalEnv };
74
+ process.argv = [...originalArgv];
75
+ mockProcessIn = {
76
+ pause: vi.fn(),
77
+ resume: vi.fn(),
78
+ isTTY: true,
79
+ };
80
+ Object.defineProperty(process, 'stdin', {
81
+ value: mockProcessIn,
82
+ writable: true,
83
+ });
84
+ vi.mocked(os.platform).mockReturnValue('linux');
85
+ vi.mocked(os.homedir).mockReturnValue('/home/user');
86
+ vi.mocked(os.tmpdir).mockReturnValue('/tmp');
87
+ vi.mocked(fs.existsSync).mockReturnValue(true);
88
+ vi.mocked(fs.realpathSync).mockImplementation((p) => p);
89
+ vi.mocked(execSync).mockReturnValue(Buffer.from(''));
90
+ });
91
+ afterEach(() => {
92
+ process.env = originalEnv;
93
+ process.argv = originalArgv;
94
+ });
95
+ describe('start_sandbox', () => {
96
+ it('should handle macOS seatbelt (sandbox-exec)', async () => {
97
+ vi.mocked(os.platform).mockReturnValue('darwin');
98
+ const config = {
99
+ command: 'sandbox-exec',
100
+ image: 'some-image',
101
+ };
102
+ const mockSpawnProcess = new EventEmitter();
103
+ mockSpawnProcess.stdout = new EventEmitter();
104
+ mockSpawnProcess.stderr = new EventEmitter();
105
+ vi.mocked(spawn).mockReturnValue(mockSpawnProcess);
106
+ const promise = start_sandbox(config, [], undefined, ['arg1']);
107
+ setTimeout(() => {
108
+ mockSpawnProcess.emit('close', 0);
109
+ }, 10);
110
+ await expect(promise).resolves.toBe(0);
111
+ expect(spawn).toHaveBeenCalledWith('sandbox-exec', expect.arrayContaining([
112
+ '-f',
113
+ expect.stringContaining('sandbox-macos-permissive-open.sb'),
114
+ ]), expect.objectContaining({ stdio: 'inherit' }));
115
+ });
116
+ it('should throw FatalSandboxError if seatbelt profile is missing', async () => {
117
+ vi.mocked(os.platform).mockReturnValue('darwin');
118
+ vi.mocked(fs.existsSync).mockReturnValue(false);
119
+ const config = {
120
+ command: 'sandbox-exec',
121
+ image: 'some-image',
122
+ };
123
+ await expect(start_sandbox(config)).rejects.toThrow(FatalSandboxError);
124
+ });
125
+ it('should handle Docker execution', async () => {
126
+ const config = {
127
+ command: 'docker',
128
+ image: 'gemini-cli-sandbox',
129
+ };
130
+ const mockImageCheckProcess = new EventEmitter();
131
+ mockImageCheckProcess.stdout = new EventEmitter();
132
+ vi.mocked(spawn).mockImplementationOnce((_cmd, args) => {
133
+ if (args && args[0] === 'images') {
134
+ setTimeout(() => {
135
+ mockImageCheckProcess.stdout.emit('data', Buffer.from('image-id'));
136
+ mockImageCheckProcess.emit('close', 0);
137
+ }, 1);
138
+ return mockImageCheckProcess;
139
+ }
140
+ return new EventEmitter(); // fallback
141
+ });
142
+ const mockSpawnProcess = new EventEmitter();
143
+ mockSpawnProcess.on = vi.fn().mockImplementation((event, cb) => {
144
+ if (event === 'close') {
145
+ setTimeout(() => cb(0), 10);
146
+ }
147
+ return mockSpawnProcess;
148
+ });
149
+ vi.mocked(spawn).mockImplementationOnce((cmd, args) => {
150
+ if (cmd === 'docker' && args && args[0] === 'run') {
151
+ return mockSpawnProcess;
152
+ }
153
+ return new EventEmitter();
154
+ });
155
+ const promise = start_sandbox(config, [], undefined, ['arg1']);
156
+ await expect(promise).resolves.toBe(0);
157
+ expect(spawn).toHaveBeenCalledWith('docker', expect.arrayContaining(['run', '-i', '--rm', '--init']), expect.objectContaining({ stdio: 'inherit' }));
158
+ });
159
+ it('should pull image if missing', async () => {
160
+ const config = {
161
+ command: 'docker',
162
+ image: 'missing-image',
163
+ };
164
+ const mockImageCheckProcess1 = new EventEmitter();
165
+ mockImageCheckProcess1.stdout = new EventEmitter();
166
+ vi.mocked(spawn).mockImplementationOnce(() => {
167
+ setTimeout(() => {
168
+ mockImageCheckProcess1.emit('close', 0);
169
+ }, 1);
170
+ return mockImageCheckProcess1;
171
+ });
172
+ const mockPullProcess = new EventEmitter();
173
+ mockPullProcess.stdout = new EventEmitter();
174
+ mockPullProcess.stderr = new EventEmitter();
175
+ vi.mocked(spawn).mockImplementationOnce(() => {
176
+ setTimeout(() => {
177
+ mockPullProcess.emit('close', 0);
178
+ }, 1);
179
+ return mockPullProcess;
180
+ });
181
+ // 3. Image check succeeds
182
+ const mockImageCheckProcess2 = new EventEmitter();
183
+ mockImageCheckProcess2.stdout = new EventEmitter();
184
+ vi.mocked(spawn).mockImplementationOnce(() => {
185
+ setTimeout(() => {
186
+ mockImageCheckProcess2.stdout.emit('data', Buffer.from('image-id'));
187
+ mockImageCheckProcess2.emit('close', 0);
188
+ }, 1);
189
+ return mockImageCheckProcess2;
190
+ });
191
+ // 4. Docker run
192
+ const mockSpawnProcess = new EventEmitter();
193
+ mockSpawnProcess.on = vi.fn().mockImplementation((event, cb) => {
194
+ if (event === 'close') {
195
+ setTimeout(() => cb(0), 10);
196
+ }
197
+ return mockSpawnProcess;
198
+ });
199
+ vi.mocked(spawn).mockImplementationOnce(() => mockSpawnProcess);
200
+ const promise = start_sandbox(config, [], undefined, ['arg1']);
201
+ await expect(promise).resolves.toBe(0);
202
+ expect(spawn).toHaveBeenCalledWith('docker', expect.arrayContaining(['pull', 'missing-image']), expect.any(Object));
203
+ });
204
+ it('should throw if image pull fails', async () => {
205
+ const config = {
206
+ command: 'docker',
207
+ image: 'missing-image',
208
+ };
209
+ const mockImageCheckProcess1 = new EventEmitter();
210
+ mockImageCheckProcess1.stdout = new EventEmitter();
211
+ vi.mocked(spawn).mockImplementationOnce(() => {
212
+ setTimeout(() => {
213
+ mockImageCheckProcess1.emit('close', 0);
214
+ }, 1);
215
+ return mockImageCheckProcess1;
216
+ });
217
+ const mockPullProcess = new EventEmitter();
218
+ mockPullProcess.stdout = new EventEmitter();
219
+ mockPullProcess.stderr = new EventEmitter();
220
+ vi.mocked(spawn).mockImplementationOnce(() => {
221
+ setTimeout(() => {
222
+ mockPullProcess.emit('close', 1);
223
+ }, 1);
224
+ return mockPullProcess;
225
+ });
226
+ await expect(start_sandbox(config)).rejects.toThrow(FatalSandboxError);
227
+ });
228
+ it('should mount volumes correctly', async () => {
229
+ const config = {
230
+ command: 'docker',
231
+ image: 'gemini-cli-sandbox',
232
+ };
233
+ process.env['SANDBOX_MOUNTS'] = '/host/path:/container/path:ro';
234
+ vi.mocked(fs.existsSync).mockReturnValue(true); // For mount path check
235
+ const mockImageCheckProcess = new EventEmitter();
236
+ mockImageCheckProcess.stdout = new EventEmitter();
237
+ vi.mocked(spawn).mockImplementationOnce(() => {
238
+ setTimeout(() => {
239
+ mockImageCheckProcess.stdout.emit('data', Buffer.from('image-id'));
240
+ mockImageCheckProcess.emit('close', 0);
241
+ }, 1);
242
+ return mockImageCheckProcess;
243
+ });
244
+ const mockSpawnProcess = new EventEmitter();
245
+ mockSpawnProcess.on = vi.fn().mockImplementation((event, cb) => {
246
+ if (event === 'close') {
247
+ setTimeout(() => cb(0), 10);
248
+ }
249
+ return mockSpawnProcess;
250
+ });
251
+ vi.mocked(spawn).mockImplementationOnce(() => mockSpawnProcess);
252
+ await start_sandbox(config);
253
+ expect(spawn).toHaveBeenCalledWith('docker', expect.arrayContaining([
254
+ '--volume',
255
+ '/host/path:/container/path:ro',
256
+ '--volume',
257
+ expect.stringContaining('/home/user/.gemini'),
258
+ ]), expect.any(Object));
259
+ });
260
+ it('should handle user creation on Linux if needed', async () => {
261
+ const config = {
262
+ command: 'docker',
263
+ image: 'gemini-cli-sandbox',
264
+ };
265
+ process.env['SANDBOX_SET_UID_GID'] = 'true';
266
+ vi.mocked(os.platform).mockReturnValue('linux');
267
+ vi.mocked(execSync).mockImplementation((cmd) => {
268
+ if (cmd === 'id -u')
269
+ return Buffer.from('1000');
270
+ if (cmd === 'id -g')
271
+ return Buffer.from('1000');
272
+ return Buffer.from('');
273
+ });
274
+ const mockImageCheckProcess = new EventEmitter();
275
+ mockImageCheckProcess.stdout = new EventEmitter();
276
+ vi.mocked(spawn).mockImplementationOnce(() => {
277
+ setTimeout(() => {
278
+ mockImageCheckProcess.stdout.emit('data', Buffer.from('image-id'));
279
+ mockImageCheckProcess.emit('close', 0);
280
+ }, 1);
281
+ return mockImageCheckProcess;
282
+ });
283
+ const mockSpawnProcess = new EventEmitter();
284
+ mockSpawnProcess.on = vi.fn().mockImplementation((event, cb) => {
285
+ if (event === 'close') {
286
+ setTimeout(() => cb(0), 10);
287
+ }
288
+ return mockSpawnProcess;
289
+ });
290
+ vi.mocked(spawn).mockImplementationOnce(() => mockSpawnProcess);
291
+ await start_sandbox(config);
292
+ expect(spawn).toHaveBeenCalledWith('docker', expect.arrayContaining(['--user', 'root', '--env', 'HOME=/home/user']), expect.any(Object));
293
+ // Check that the entrypoint command includes useradd/groupadd
294
+ const args = vi.mocked(spawn).mock.calls[1][1];
295
+ const entrypointCmd = args[args.length - 1];
296
+ expect(entrypointCmd).toContain('groupadd');
297
+ expect(entrypointCmd).toContain('useradd');
298
+ expect(entrypointCmd).toContain('su -p gemini');
299
+ });
300
+ });
301
+ });
302
+ //# sourceMappingURL=sandbox.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.test.js","sourceRoot":"","sources":["../../../src/utils/sandbox.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export declare const LOCAL_DEV_SANDBOX_IMAGE_NAME = "gemini-cli-sandbox";
7
+ export declare const SANDBOX_NETWORK_NAME = "gemini-cli-sandbox";
8
+ export declare const SANDBOX_PROXY_NAME = "gemini-cli-sandbox-proxy";
9
+ export declare const BUILTIN_SEATBELT_PROFILES: string[];
10
+ export declare function getContainerPath(hostPath: string): string;
11
+ export declare function shouldUseCurrentUserInSandbox(): Promise<boolean>;
12
+ export declare function parseImageName(image: string): string;
13
+ export declare function ports(): string[];
14
+ export declare function entrypoint(workdir: string, cliArgs: string[]): string[];
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import os from 'node:os';
7
+ import fs from 'node:fs';
8
+ import { readFile } from 'node:fs/promises';
9
+ import { quote } from 'shell-quote';
10
+ import { debugLogger, GEMINI_DIR } from '@google/gemini-cli-core';
11
+ export const LOCAL_DEV_SANDBOX_IMAGE_NAME = 'gemini-cli-sandbox';
12
+ export const SANDBOX_NETWORK_NAME = 'gemini-cli-sandbox';
13
+ export const SANDBOX_PROXY_NAME = 'gemini-cli-sandbox-proxy';
14
+ export const BUILTIN_SEATBELT_PROFILES = [
15
+ 'permissive-open',
16
+ 'permissive-closed',
17
+ 'permissive-proxied',
18
+ 'restrictive-open',
19
+ 'restrictive-closed',
20
+ 'restrictive-proxied',
21
+ ];
22
+ export function getContainerPath(hostPath) {
23
+ if (os.platform() !== 'win32') {
24
+ return hostPath;
25
+ }
26
+ const withForwardSlashes = hostPath.replace(/\\/g, '/');
27
+ const match = withForwardSlashes.match(/^([A-Z]):\/(.*)/i);
28
+ if (match) {
29
+ return `/${match[1].toLowerCase()}/${match[2]}`;
30
+ }
31
+ return withForwardSlashes;
32
+ }
33
+ export async function shouldUseCurrentUserInSandbox() {
34
+ const envVar = process.env['SANDBOX_SET_UID_GID']?.toLowerCase().trim();
35
+ if (envVar === '1' || envVar === 'true') {
36
+ return true;
37
+ }
38
+ if (envVar === '0' || envVar === 'false') {
39
+ return false;
40
+ }
41
+ // If environment variable is not explicitly set, check for Debian/Ubuntu Linux
42
+ if (os.platform() === 'linux') {
43
+ try {
44
+ const osReleaseContent = await readFile('/etc/os-release', 'utf8');
45
+ if (osReleaseContent.includes('ID=debian') ||
46
+ osReleaseContent.includes('ID=ubuntu') ||
47
+ osReleaseContent.match(/^ID_LIKE=.*debian.*/m) || // Covers derivatives
48
+ osReleaseContent.match(/^ID_LIKE=.*ubuntu.*/m) // Covers derivatives
49
+ ) {
50
+ debugLogger.log('Defaulting to use current user UID/GID for Debian/Ubuntu-based Linux.');
51
+ return true;
52
+ }
53
+ }
54
+ catch (_err) {
55
+ // Silently ignore if /etc/os-release is not found or unreadable.
56
+ // The default (false) will be applied in this case.
57
+ debugLogger.warn('Warning: Could not read /etc/os-release to auto-detect Debian/Ubuntu for UID/GID default.');
58
+ }
59
+ }
60
+ return false; // Default to false if no other condition is met
61
+ }
62
+ export function parseImageName(image) {
63
+ const [fullName, tag] = image.split(':');
64
+ const name = fullName.split('/').at(-1) ?? 'unknown-image';
65
+ return tag ? `${name}-${tag}` : name;
66
+ }
67
+ export function ports() {
68
+ return (process.env['SANDBOX_PORTS'] ?? '')
69
+ .split(',')
70
+ .filter((p) => p.trim())
71
+ .map((p) => p.trim());
72
+ }
73
+ export function entrypoint(workdir, cliArgs) {
74
+ const isWindows = os.platform() === 'win32';
75
+ const containerWorkdir = getContainerPath(workdir);
76
+ const shellCmds = [];
77
+ const pathSeparator = isWindows ? ';' : ':';
78
+ let pathSuffix = '';
79
+ if (process.env['PATH']) {
80
+ const paths = process.env['PATH'].split(pathSeparator);
81
+ for (const p of paths) {
82
+ const containerPath = getContainerPath(p);
83
+ if (containerPath.toLowerCase().startsWith(containerWorkdir.toLowerCase())) {
84
+ pathSuffix += `:${containerPath}`;
85
+ }
86
+ }
87
+ }
88
+ if (pathSuffix) {
89
+ shellCmds.push(`export PATH="$PATH${pathSuffix}";`);
90
+ }
91
+ let pythonPathSuffix = '';
92
+ if (process.env['PYTHONPATH']) {
93
+ const paths = process.env['PYTHONPATH'].split(pathSeparator);
94
+ for (const p of paths) {
95
+ const containerPath = getContainerPath(p);
96
+ if (containerPath.toLowerCase().startsWith(containerWorkdir.toLowerCase())) {
97
+ pythonPathSuffix += `:${containerPath}`;
98
+ }
99
+ }
100
+ }
101
+ if (pythonPathSuffix) {
102
+ shellCmds.push(`export PYTHONPATH="$PYTHONPATH${pythonPathSuffix}";`);
103
+ }
104
+ const projectSandboxBashrc = `${GEMINI_DIR}/sandbox.bashrc`;
105
+ if (fs.existsSync(projectSandboxBashrc)) {
106
+ shellCmds.push(`source ${getContainerPath(projectSandboxBashrc)};`);
107
+ }
108
+ ports().forEach((p) => shellCmds.push(`socat TCP4-LISTEN:${p},bind=$(hostname -i),fork,reuseaddr TCP4:127.0.0.1:${p} 2> /dev/null &`));
109
+ const quotedCliArgs = cliArgs.slice(2).map((arg) => quote([arg]));
110
+ const cliCmd = process.env['NODE_ENV'] === 'development'
111
+ ? process.env['DEBUG']
112
+ ? 'npm run debug --'
113
+ : 'npm rebuild && npm run start --'
114
+ : process.env['DEBUG']
115
+ ? `node --inspect-brk=0.0.0.0:${process.env['DEBUG_PORT'] || '9229'} $(which gemini)`
116
+ : 'gemini';
117
+ const args = [...shellCmds, cliCmd, ...quotedCliArgs];
118
+ return ['bash', '-c', args.join(' ')];
119
+ }
120
+ //# sourceMappingURL=sandboxUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxUtils.js","sourceRoot":"","sources":["../../../src/utils/sandboxUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import os from 'node:os';
8
+ import fs from 'node:fs';
9
+ import { readFile } from 'node:fs/promises';
10
+ import { getContainerPath, parseImageName, ports, entrypoint, shouldUseCurrentUserInSandbox, } from './sandboxUtils.js';
11
+ vi.mock('node:os');
12
+ vi.mock('node:fs');
13
+ vi.mock('node:fs/promises');
14
+ vi.mock('@google/gemini-cli-core', () => ({
15
+ debugLogger: {
16
+ log: vi.fn(),
17
+ warn: vi.fn(),
18
+ },
19
+ GEMINI_DIR: '.gemini',
20
+ }));
21
+ describe('sandboxUtils', () => {
22
+ const originalEnv = process.env;
23
+ beforeEach(() => {
24
+ vi.clearAllMocks();
25
+ process.env = { ...originalEnv };
26
+ });
27
+ afterEach(() => {
28
+ process.env = originalEnv;
29
+ });
30
+ describe('getContainerPath', () => {
31
+ it('should return same path on non-Windows', () => {
32
+ vi.mocked(os.platform).mockReturnValue('linux');
33
+ expect(getContainerPath('/home/user')).toBe('/home/user');
34
+ });
35
+ it('should convert Windows path to container path', () => {
36
+ vi.mocked(os.platform).mockReturnValue('win32');
37
+ expect(getContainerPath('C:\\Users\\user')).toBe('/c/Users/user');
38
+ });
39
+ it('should handle Windows path without drive letter', () => {
40
+ vi.mocked(os.platform).mockReturnValue('win32');
41
+ expect(getContainerPath('\\Users\\user')).toBe('/Users/user');
42
+ });
43
+ });
44
+ describe('parseImageName', () => {
45
+ it('should parse image name with tag', () => {
46
+ expect(parseImageName('my-image:latest')).toBe('my-image-latest');
47
+ });
48
+ it('should parse image name without tag', () => {
49
+ expect(parseImageName('my-image')).toBe('my-image');
50
+ });
51
+ it('should handle registry path', () => {
52
+ expect(parseImageName('gcr.io/my-project/my-image:v1')).toBe('my-image-v1');
53
+ });
54
+ });
55
+ describe('ports', () => {
56
+ it('should return empty array if SANDBOX_PORTS is not set', () => {
57
+ delete process.env['SANDBOX_PORTS'];
58
+ expect(ports()).toEqual([]);
59
+ });
60
+ it('should parse comma-separated ports', () => {
61
+ process.env['SANDBOX_PORTS'] = '8080, 3000 , 9000';
62
+ expect(ports()).toEqual(['8080', '3000', '9000']);
63
+ });
64
+ });
65
+ describe('entrypoint', () => {
66
+ beforeEach(() => {
67
+ vi.mocked(os.platform).mockReturnValue('linux');
68
+ vi.mocked(fs.existsSync).mockReturnValue(false);
69
+ });
70
+ it('should generate default entrypoint', () => {
71
+ const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
72
+ expect(args).toEqual(['bash', '-c', 'gemini arg1']);
73
+ });
74
+ it('should include PATH and PYTHONPATH if set', () => {
75
+ process.env['PATH'] = '/work/bin:/usr/bin';
76
+ process.env['PYTHONPATH'] = '/work/lib';
77
+ const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
78
+ expect(args[2]).toContain('export PATH="$PATH:/work/bin"');
79
+ expect(args[2]).toContain('export PYTHONPATH="$PYTHONPATH:/work/lib"');
80
+ });
81
+ it('should source sandbox.bashrc if exists', () => {
82
+ vi.mocked(fs.existsSync).mockReturnValue(true);
83
+ const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
84
+ expect(args[2]).toContain('source .gemini/sandbox.bashrc');
85
+ });
86
+ it('should include socat commands for ports', () => {
87
+ process.env['SANDBOX_PORTS'] = '8080';
88
+ const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
89
+ expect(args[2]).toContain('socat TCP4-LISTEN:8080');
90
+ });
91
+ it('should use development command if NODE_ENV is development', () => {
92
+ process.env['NODE_ENV'] = 'development';
93
+ const args = entrypoint('/work', ['node', 'gemini', 'arg1']);
94
+ expect(args[2]).toContain('npm rebuild && npm run start --');
95
+ });
96
+ });
97
+ describe('shouldUseCurrentUserInSandbox', () => {
98
+ it('should return true if SANDBOX_SET_UID_GID is 1', async () => {
99
+ process.env['SANDBOX_SET_UID_GID'] = '1';
100
+ expect(await shouldUseCurrentUserInSandbox()).toBe(true);
101
+ });
102
+ it('should return false if SANDBOX_SET_UID_GID is 0', async () => {
103
+ process.env['SANDBOX_SET_UID_GID'] = '0';
104
+ expect(await shouldUseCurrentUserInSandbox()).toBe(false);
105
+ });
106
+ it('should return true on Debian Linux', async () => {
107
+ delete process.env['SANDBOX_SET_UID_GID'];
108
+ vi.mocked(os.platform).mockReturnValue('linux');
109
+ vi.mocked(readFile).mockResolvedValue('ID=debian\n');
110
+ expect(await shouldUseCurrentUserInSandbox()).toBe(true);
111
+ });
112
+ it('should return false on non-Linux', async () => {
113
+ delete process.env['SANDBOX_SET_UID_GID'];
114
+ vi.mocked(os.platform).mockReturnValue('darwin');
115
+ expect(await shouldUseCurrentUserInSandbox()).toBe(false);
116
+ });
117
+ });
118
+ });
119
+ //# sourceMappingURL=sandboxUtils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandboxUtils.test.js","sourceRoot":"","sources":["../../../src/utils/sandboxUtils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, vi } from 'vitest';
7
+ import { updateEventEmitter } from './updateEventEmitter.js';
8
+ describe('updateEventEmitter', () => {
9
+ it('should allow registering and emitting events', () => {
10
+ const callback = vi.fn();
11
+ const eventName = 'test-event';
12
+ updateEventEmitter.on(eventName, callback);
13
+ updateEventEmitter.emit(eventName, 'test-data');
14
+ expect(callback).toHaveBeenCalledWith('test-data');
15
+ updateEventEmitter.off(eventName, callback);
16
+ });
17
+ });
18
+ //# sourceMappingURL=updateEventEmitter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateEventEmitter.test.js","sourceRoot":"","sources":["../../../src/utils/updateEventEmitter.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,YAAY,CAAC;QAE/B,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC3C,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAEhD,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;QAEnD,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export {};