@google/gemini-cli-core 0.39.0 → 0.39.1

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 (50) hide show
  1. package/dist/docs/cli/cli-reference.md +1 -0
  2. package/dist/docs/cli/trusted-folders.md +28 -0
  3. package/dist/docs/reference/configuration.md +14 -0
  4. package/dist/google-gemini-cli-core-0.39.0.tgz +0 -0
  5. package/dist/src/config/storage.d.ts +2 -0
  6. package/dist/src/config/storage.js +7 -0
  7. package/dist/src/config/storage.js.map +1 -1
  8. package/dist/src/generated/git-commit.d.ts +2 -2
  9. package/dist/src/generated/git-commit.js +2 -2
  10. package/dist/src/index.d.ts +1 -0
  11. package/dist/src/index.js +2 -0
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/policy/config.d.ts +2 -0
  14. package/dist/src/policy/config.js +64 -10
  15. package/dist/src/policy/config.js.map +1 -1
  16. package/dist/src/policy/core-tools-mapping.test.d.ts +6 -0
  17. package/dist/src/policy/core-tools-mapping.test.js +44 -0
  18. package/dist/src/policy/core-tools-mapping.test.js.map +1 -0
  19. package/dist/src/policy/policy-engine.d.ts +1 -1
  20. package/dist/src/policy/policy-engine.js +57 -66
  21. package/dist/src/policy/policy-engine.js.map +1 -1
  22. package/dist/src/policy/policy-engine.test.js +32 -2
  23. package/dist/src/policy/policy-engine.test.js.map +1 -1
  24. package/dist/src/policy/shell-safety-regression.test.d.ts +6 -0
  25. package/dist/src/policy/shell-safety-regression.test.js +86 -0
  26. package/dist/src/policy/shell-safety-regression.test.js.map +1 -0
  27. package/dist/src/policy/shell-safety.test.js +24 -0
  28. package/dist/src/policy/shell-safety.test.js.map +1 -1
  29. package/dist/src/policy/shell-substitution.test.d.ts +6 -0
  30. package/dist/src/policy/shell-substitution.test.js +75 -0
  31. package/dist/src/policy/shell-substitution.test.js.map +1 -0
  32. package/dist/src/policy/types.d.ts +2 -0
  33. package/dist/src/policy/types.js.map +1 -1
  34. package/dist/src/utils/errors.d.ts +3 -0
  35. package/dist/src/utils/errors.js +6 -0
  36. package/dist/src/utils/errors.js.map +1 -1
  37. package/dist/src/utils/paths.d.ts +1 -0
  38. package/dist/src/utils/paths.js +1 -0
  39. package/dist/src/utils/paths.js.map +1 -1
  40. package/dist/src/utils/shell-utils.d.ts +1 -0
  41. package/dist/src/utils/shell-utils.js +13 -1
  42. package/dist/src/utils/shell-utils.js.map +1 -1
  43. package/dist/src/utils/trust.d.ts +64 -0
  44. package/dist/src/utils/trust.js +276 -0
  45. package/dist/src/utils/trust.js.map +1 -0
  46. package/dist/src/utils/trust.test.d.ts +6 -0
  47. package/dist/src/utils/trust.test.js +159 -0
  48. package/dist/src/utils/trust.test.js.map +1 -0
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +1 -1
@@ -0,0 +1,276 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import * as crypto from 'node:crypto';
9
+ import { lock } from 'proper-lockfile';
10
+ import stripJsonComments from 'strip-json-comments';
11
+ import { Storage } from '../config/storage.js';
12
+ import { normalizePath, isSubpath } from './paths.js';
13
+ import { FatalConfigError, getErrorMessage } from './errors.js';
14
+ import { coreEvents } from './events.js';
15
+ import { ideContextStore } from '../ide/ideContext.js';
16
+ export var TrustLevel;
17
+ (function (TrustLevel) {
18
+ TrustLevel["TRUST_FOLDER"] = "TRUST_FOLDER";
19
+ TrustLevel["TRUST_PARENT"] = "TRUST_PARENT";
20
+ TrustLevel["DO_NOT_TRUST"] = "DO_NOT_TRUST";
21
+ })(TrustLevel || (TrustLevel = {}));
22
+ export function isTrustLevel(value) {
23
+ return (typeof value === 'string' &&
24
+ Object.values(TrustLevel).some((v) => v === value));
25
+ }
26
+ /**
27
+ * Checks if a path is trusted based on headless mode, folder trust settings,
28
+ * IDE context, and local configuration file.
29
+ */
30
+ export function checkPathTrust(options) {
31
+ if (process.env['GEMINI_CLI_TRUST_WORKSPACE'] === 'true') {
32
+ return { isTrusted: true, source: 'env' };
33
+ }
34
+ if (!options.isFolderTrustEnabled) {
35
+ return { isTrusted: true, source: undefined };
36
+ }
37
+ const ideTrust = ideContextStore.get()?.workspaceState?.isTrusted;
38
+ if (ideTrust !== undefined) {
39
+ return { isTrusted: ideTrust, source: 'ide' };
40
+ }
41
+ const folders = loadTrustedFolders();
42
+ if (folders.errors.length > 0) {
43
+ const errorMessages = folders.errors.map((error) => `Error in ${error.path}: ${error.message}`);
44
+ throw new FatalConfigError(`${errorMessages.join('\n')}\nPlease fix the configuration file and try again.`);
45
+ }
46
+ const isTrusted = folders.isPathTrusted(options.path);
47
+ return {
48
+ isTrusted,
49
+ source: isTrusted !== undefined ? 'file' : undefined,
50
+ };
51
+ }
52
+ const realPathCache = new Map();
53
+ /**
54
+ * Parses the trusted folders JSON content, stripping comments.
55
+ */
56
+ function parseTrustedFoldersJson(content) {
57
+ return JSON.parse(stripJsonComments(content));
58
+ }
59
+ function isRecord(value) {
60
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
61
+ }
62
+ /**
63
+ * FOR TESTING PURPOSES ONLY.
64
+ * Clears the real path cache.
65
+ */
66
+ export function clearRealPathCacheForTesting() {
67
+ realPathCache.clear();
68
+ }
69
+ function getRealPath(location) {
70
+ let realPath = realPathCache.get(location);
71
+ if (realPath !== undefined) {
72
+ return realPath;
73
+ }
74
+ try {
75
+ realPath = fs.existsSync(location) ? fs.realpathSync(location) : location;
76
+ }
77
+ catch {
78
+ realPath = location;
79
+ }
80
+ realPathCache.set(location, realPath);
81
+ return realPath;
82
+ }
83
+ export class LoadedTrustedFolders {
84
+ user;
85
+ errors;
86
+ constructor(user, errors) {
87
+ this.user = user;
88
+ this.errors = errors;
89
+ }
90
+ get rules() {
91
+ return Object.entries(this.user.config).map(([path, trustLevel]) => ({
92
+ path,
93
+ trustLevel,
94
+ }));
95
+ }
96
+ /**
97
+ * Returns true or false if the path should be "trusted" based on the configuration.
98
+ *
99
+ * @param location path
100
+ * @param config optional config override
101
+ * @returns boolean if trusted/distrusted, undefined if no rule matches
102
+ */
103
+ isPathTrusted(location, config) {
104
+ const configToUse = config ?? this.user.config;
105
+ // Resolve location to its realpath for canonical comparison
106
+ const realLocation = getRealPath(location);
107
+ const normalizedLocation = normalizePath(realLocation);
108
+ let longestMatchLen = -1;
109
+ let longestMatchTrust = undefined;
110
+ for (const [rulePath, trustLevel] of Object.entries(configToUse)) {
111
+ const effectivePath = trustLevel === TrustLevel.TRUST_PARENT
112
+ ? path.dirname(rulePath)
113
+ : rulePath;
114
+ // Resolve effectivePath to its realpath for canonical comparison
115
+ const realEffectivePath = getRealPath(effectivePath);
116
+ const normalizedEffectivePath = normalizePath(realEffectivePath);
117
+ if (isSubpath(normalizedEffectivePath, normalizedLocation)) {
118
+ if (rulePath.length > longestMatchLen) {
119
+ longestMatchLen = rulePath.length;
120
+ longestMatchTrust = trustLevel;
121
+ }
122
+ }
123
+ }
124
+ if (longestMatchTrust === TrustLevel.DO_NOT_TRUST)
125
+ return false;
126
+ if (longestMatchTrust === TrustLevel.TRUST_FOLDER ||
127
+ longestMatchTrust === TrustLevel.TRUST_PARENT) {
128
+ return true;
129
+ }
130
+ return undefined;
131
+ }
132
+ async setValue(folderPath, trustLevel) {
133
+ if (this.errors.length > 0) {
134
+ const errorMessages = this.errors.map((error) => `Error in ${error.path}: ${error.message}`);
135
+ throw new FatalConfigError(`Cannot update trusted folders because the configuration file is invalid:\n${errorMessages.join('\n')}\nPlease fix the file manually before trying to update it.`);
136
+ }
137
+ const dirPath = path.dirname(this.user.path);
138
+ if (!fs.existsSync(dirPath)) {
139
+ await fs.promises.mkdir(dirPath, { recursive: true });
140
+ }
141
+ // lockfile requires the file to exist
142
+ if (!fs.existsSync(this.user.path)) {
143
+ await fs.promises.writeFile(this.user.path, JSON.stringify({}, null, 2), {
144
+ // Restrict file access to read/write for the owner only
145
+ mode: 0o600,
146
+ });
147
+ }
148
+ const release = await lock(this.user.path, {
149
+ retries: {
150
+ retries: 10,
151
+ minTimeout: 100,
152
+ },
153
+ });
154
+ const normalizedPath = normalizePath(folderPath);
155
+ const originalTrustLevel = this.user.config[normalizedPath];
156
+ try {
157
+ // Re-read the file to handle concurrent updates
158
+ const content = await fs.promises.readFile(this.user.path, 'utf-8');
159
+ const config = {};
160
+ try {
161
+ const parsed = parseTrustedFoldersJson(content);
162
+ if (isRecord(parsed)) {
163
+ for (const [rawPath, value] of Object.entries(parsed)) {
164
+ if (isTrustLevel(value)) {
165
+ config[rawPath] = value;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ catch (error) {
171
+ coreEvents.emitFeedback('error', `Failed to parse trusted folders file at ${this.user.path}. The file may be corrupted.`, error);
172
+ }
173
+ // Use normalized path as key
174
+ config[normalizedPath] = trustLevel;
175
+ this.user.config[normalizedPath] = trustLevel;
176
+ try {
177
+ saveTrustedFolders({ ...this.user, config });
178
+ }
179
+ catch (e) {
180
+ // Revert the in-memory change if the save failed.
181
+ if (originalTrustLevel === undefined) {
182
+ delete this.user.config[normalizedPath];
183
+ }
184
+ else {
185
+ this.user.config[normalizedPath] = originalTrustLevel;
186
+ }
187
+ throw e;
188
+ }
189
+ }
190
+ finally {
191
+ await release();
192
+ }
193
+ }
194
+ }
195
+ let loadedTrustedFolders;
196
+ /**
197
+ * FOR TESTING PURPOSES ONLY.
198
+ * Resets the in-memory cache of the trusted folders configuration.
199
+ */
200
+ export function resetTrustedFoldersForTesting() {
201
+ loadedTrustedFolders = undefined;
202
+ clearRealPathCacheForTesting();
203
+ }
204
+ export function loadTrustedFolders() {
205
+ if (loadedTrustedFolders) {
206
+ return loadedTrustedFolders;
207
+ }
208
+ const errors = [];
209
+ const userConfig = {};
210
+ const userPath = Storage.getTrustedFoldersPath();
211
+ try {
212
+ if (fs.existsSync(userPath)) {
213
+ const content = fs.readFileSync(userPath, 'utf-8');
214
+ const parsed = parseTrustedFoldersJson(content);
215
+ if (!isRecord(parsed)) {
216
+ errors.push({
217
+ message: 'Trusted folders file is not a valid JSON object.',
218
+ path: userPath,
219
+ });
220
+ }
221
+ else {
222
+ for (const [rawPath, trustLevel] of Object.entries(parsed)) {
223
+ const normalizedPath = normalizePath(rawPath);
224
+ if (isTrustLevel(trustLevel)) {
225
+ userConfig[normalizedPath] = trustLevel;
226
+ }
227
+ else {
228
+ const possibleValues = Object.values(TrustLevel).join(', ');
229
+ errors.push({
230
+ message: `Invalid trust level "${trustLevel}" for path "${rawPath}". Possible values are: ${possibleValues}.`,
231
+ path: userPath,
232
+ });
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+ catch (error) {
239
+ errors.push({
240
+ message: getErrorMessage(error),
241
+ path: userPath,
242
+ });
243
+ }
244
+ loadedTrustedFolders = new LoadedTrustedFolders({ path: userPath, config: userConfig }, errors);
245
+ return loadedTrustedFolders;
246
+ }
247
+ export function saveTrustedFolders(trustedFoldersFile) {
248
+ // Ensure the directory exists
249
+ const dirPath = path.dirname(trustedFoldersFile.path);
250
+ if (!fs.existsSync(dirPath)) {
251
+ fs.mkdirSync(dirPath, { recursive: true });
252
+ }
253
+ const content = JSON.stringify(trustedFoldersFile.config, null, 2);
254
+ const tempPath = `${trustedFoldersFile.path}.tmp.${crypto.randomUUID()}`;
255
+ try {
256
+ fs.writeFileSync(tempPath, content, {
257
+ encoding: 'utf-8',
258
+ // Restrict file access to read/write for the owner only
259
+ mode: 0o600,
260
+ });
261
+ fs.renameSync(tempPath, trustedFoldersFile.path);
262
+ }
263
+ catch (error) {
264
+ // Clean up temp file if it was created but rename failed
265
+ if (fs.existsSync(tempPath)) {
266
+ try {
267
+ fs.unlinkSync(tempPath);
268
+ }
269
+ catch {
270
+ // Ignore cleanup errors
271
+ }
272
+ }
273
+ throw error;
274
+ }
275
+ }
276
+ //# sourceMappingURL=trust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.js","sourceRoot":"","sources":["../../../src/utils/trust.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,159 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import * as fs from 'node:fs';
8
+ import * as path from 'node:path';
9
+ import * as os from 'node:os';
10
+ import { TrustLevel, loadTrustedFolders, resetTrustedFoldersForTesting, checkPathTrust, } from './trust.js';
11
+ import { Storage } from '../config/storage.js';
12
+ import { lock } from 'proper-lockfile';
13
+ import { ideContextStore } from '../ide/ideContext.js';
14
+ import * as headless from './headless.js';
15
+ import { coreEvents } from './events.js';
16
+ vi.mock('proper-lockfile');
17
+ vi.mock('./headless.js', async (importOriginal) => {
18
+ const original = await importOriginal();
19
+ return {
20
+ ...original,
21
+ isHeadlessMode: vi.fn(),
22
+ };
23
+ });
24
+ describe('Trust Utility (Core)', () => {
25
+ const tempDir = path.join(os.tmpdir(), 'gemini-trust-test-' + Math.random().toString(36).slice(2));
26
+ const trustedFoldersPath = path.join(tempDir, 'trustedFolders.json');
27
+ beforeEach(() => {
28
+ fs.mkdirSync(tempDir, { recursive: true });
29
+ vi.spyOn(Storage, 'getTrustedFoldersPath').mockReturnValue(trustedFoldersPath);
30
+ vi.mocked(lock).mockResolvedValue(vi.fn().mockResolvedValue(undefined));
31
+ vi.mocked(headless.isHeadlessMode).mockReturnValue(false);
32
+ ideContextStore.clear();
33
+ resetTrustedFoldersForTesting();
34
+ delete process.env['GEMINI_CLI_TRUST_WORKSPACE'];
35
+ });
36
+ afterEach(() => {
37
+ fs.rmSync(tempDir, { recursive: true, force: true });
38
+ vi.restoreAllMocks();
39
+ });
40
+ it('should load empty config if file does not exist', () => {
41
+ const folders = loadTrustedFolders();
42
+ expect(folders.user.config).toEqual({});
43
+ expect(folders.errors).toEqual([]);
44
+ });
45
+ it('should load config from file', () => {
46
+ const config = {
47
+ [path.resolve('/trusted/path')]: TrustLevel.TRUST_FOLDER,
48
+ };
49
+ fs.writeFileSync(trustedFoldersPath, JSON.stringify(config));
50
+ const folders = loadTrustedFolders();
51
+ // Use path.resolve for platform consistency in tests
52
+ const normalizedKey = path.resolve('/trusted/path').replace(/\\/g, '/');
53
+ const isWindows = process.platform === 'win32';
54
+ const finalKey = isWindows ? normalizedKey.toLowerCase() : normalizedKey;
55
+ expect(folders.user.config[finalKey]).toBe(TrustLevel.TRUST_FOLDER);
56
+ });
57
+ it('should handle isPathTrusted with longest match', () => {
58
+ const config = {
59
+ [path.resolve('/a')]: TrustLevel.TRUST_FOLDER,
60
+ [path.resolve('/a/b')]: TrustLevel.DO_NOT_TRUST,
61
+ [path.resolve('/a/b/c')]: TrustLevel.TRUST_FOLDER,
62
+ };
63
+ fs.writeFileSync(trustedFoldersPath, JSON.stringify(config));
64
+ const folders = loadTrustedFolders();
65
+ expect(folders.isPathTrusted(path.resolve('/a/file.txt'))).toBe(true);
66
+ expect(folders.isPathTrusted(path.resolve('/a/b/file.txt'))).toBe(false);
67
+ expect(folders.isPathTrusted(path.resolve('/a/b/c/file.txt'))).toBe(true);
68
+ expect(folders.isPathTrusted(path.resolve('/other'))).toBeUndefined();
69
+ });
70
+ it('should handle TRUST_PARENT', () => {
71
+ const config = {
72
+ [path.resolve('/project/.gemini')]: TrustLevel.TRUST_PARENT,
73
+ };
74
+ fs.writeFileSync(trustedFoldersPath, JSON.stringify(config));
75
+ const folders = loadTrustedFolders();
76
+ expect(folders.isPathTrusted(path.resolve('/project/file.txt'))).toBe(true);
77
+ expect(folders.isPathTrusted(path.resolve('/project/.gemini/config.yaml'))).toBe(true);
78
+ });
79
+ it('should save config correctly', async () => {
80
+ const folders = loadTrustedFolders();
81
+ const testPath = path.resolve('/new/trusted/path');
82
+ await folders.setValue(testPath, TrustLevel.TRUST_FOLDER);
83
+ const savedContent = JSON.parse(fs.readFileSync(trustedFoldersPath, 'utf-8'));
84
+ const normalizedKey = testPath.replace(/\\/g, '/');
85
+ const isWindows = process.platform === 'win32';
86
+ const finalKey = isWindows ? normalizedKey.toLowerCase() : normalizedKey;
87
+ expect(savedContent[finalKey]).toBe(TrustLevel.TRUST_FOLDER);
88
+ });
89
+ it('should handle comments in JSON', () => {
90
+ const content = `
91
+ {
92
+ // This is a comment
93
+ "path": "TRUST_FOLDER"
94
+ }
95
+ `;
96
+ fs.writeFileSync(trustedFoldersPath, content);
97
+ const folders = loadTrustedFolders();
98
+ expect(folders.errors).toHaveLength(0);
99
+ });
100
+ describe('checkPathTrust', () => {
101
+ it('should NOT return trusted if headless mode is on by default', () => {
102
+ const result = checkPathTrust({
103
+ path: '/any',
104
+ isFolderTrustEnabled: true,
105
+ isHeadless: true,
106
+ });
107
+ expect(result).toEqual({ isTrusted: undefined, source: undefined });
108
+ });
109
+ it('should return trusted if folder trust is disabled', () => {
110
+ const result = checkPathTrust({
111
+ path: '/any',
112
+ isFolderTrustEnabled: false,
113
+ });
114
+ expect(result).toEqual({ isTrusted: true, source: undefined });
115
+ });
116
+ it('should return IDE trust if available', () => {
117
+ ideContextStore.set({
118
+ workspaceState: { isTrusted: true },
119
+ });
120
+ const result = checkPathTrust({
121
+ path: '/any',
122
+ isFolderTrustEnabled: true,
123
+ });
124
+ expect(result).toEqual({ isTrusted: true, source: 'ide' });
125
+ });
126
+ it('should fall back to file trust', () => {
127
+ const config = {
128
+ [path.resolve('/trusted')]: TrustLevel.TRUST_FOLDER,
129
+ };
130
+ fs.writeFileSync(trustedFoldersPath, JSON.stringify(config));
131
+ const result = checkPathTrust({
132
+ path: path.resolve('/trusted/file.txt'),
133
+ isFolderTrustEnabled: true,
134
+ });
135
+ expect(result).toEqual({ isTrusted: true, source: 'file' });
136
+ });
137
+ it('should return undefined trust if no rule matches', () => {
138
+ const result = checkPathTrust({
139
+ path: '/any',
140
+ isFolderTrustEnabled: true,
141
+ });
142
+ expect(result).toEqual({ isTrusted: undefined, source: undefined });
143
+ });
144
+ });
145
+ describe('coreEvents.emitFeedback', () => {
146
+ it('should report corrupted config via coreEvents.emitFeedback in setValue', async () => {
147
+ const folders = loadTrustedFolders();
148
+ const testPath = path.resolve('/new/path');
149
+ // Initialize with valid JSON
150
+ fs.writeFileSync(trustedFoldersPath, '{}', 'utf-8');
151
+ // Corrupt the file after initial load
152
+ fs.writeFileSync(trustedFoldersPath, 'invalid json', 'utf-8');
153
+ const spy = vi.spyOn(coreEvents, 'emitFeedback');
154
+ await folders.setValue(testPath, TrustLevel.TRUST_FOLDER);
155
+ expect(spy).toHaveBeenCalledWith('error', expect.stringContaining('may be corrupted'), expect.any(Error));
156
+ });
157
+ });
158
+ });
159
+ //# sourceMappingURL=trust.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.test.js","sourceRoot":"","sources":["../../../src/utils/trust.test.ts"],"names":[],"mappings":"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"}