Add support for an additional exclusion file besides .gitignore and .geminiignore (#16487)

Co-authored-by: Adam Weidman <adamfweidman@google.com>
This commit is contained in:
Alisa
2026-01-27 17:19:13 -08:00
committed by GitHub
parent 18efe82ddc
commit adc8e11bb1
40 changed files with 1394 additions and 612 deletions
+53 -1
View File
@@ -19,6 +19,7 @@ import { StandardFileSystemService } from '../services/fileSystemService.js';
import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js';
import { WorkspaceContext } from '../utils/workspaceContext.js';
import { createMockMessageBus } from '../test-utils/mock-message-bus.js';
import { GEMINI_IGNORE_FILE_NAME } from '../config/constants.js';
vi.mock('../telemetry/loggers.js', () => ({
logFileOperation: vi.fn(),
@@ -438,7 +439,7 @@ describe('ReadFileTool', () => {
describe('with .geminiignore', () => {
beforeEach(async () => {
await fsp.writeFile(
path.join(tempRootDir, '.geminiignore'),
path.join(tempRootDir, GEMINI_IGNORE_FILE_NAME),
['foo.*', 'ignored/'].join('\n'),
);
const mockConfigInstance = {
@@ -509,6 +510,57 @@ describe('ReadFileTool', () => {
const invocation = tool.build(params);
expect(typeof invocation).not.toBe('string');
});
it('should allow reading ignored files if respectGeminiIgnore is false', async () => {
const ignoredFilePath = path.join(tempRootDir, 'foo.bar');
await fsp.writeFile(ignoredFilePath, 'content', 'utf-8');
const configNoIgnore = {
getFileService: () => new FileDiscoveryService(tempRootDir),
getFileSystemService: () => new StandardFileSystemService(),
getTargetDir: () => tempRootDir,
getWorkspaceContext: () => new WorkspaceContext(tempRootDir),
getFileFilteringOptions: () => ({
respectGitIgnore: true,
respectGeminiIgnore: false,
}),
storage: {
getProjectTempDir: () => path.join(tempRootDir, '.temp'),
},
isInteractive: () => false,
isPathAllowed(this: Config, absolutePath: string): boolean {
const workspaceContext = this.getWorkspaceContext();
if (workspaceContext.isPathWithinWorkspace(absolutePath)) {
return true;
}
const projectTempDir = this.storage.getProjectTempDir();
return isSubpath(path.resolve(projectTempDir), absolutePath);
},
validatePathAccess(
this: Config,
absolutePath: string,
): string | null {
if (this.isPathAllowed(absolutePath)) {
return null;
}
const workspaceDirs = this.getWorkspaceContext().getDirectories();
const projectTempDir = this.storage.getProjectTempDir();
return `Path not in workspace: Attempted path "${absolutePath}" resolves outside the allowed workspace directories: ${workspaceDirs.join(', ')} or the project temp directory: ${projectTempDir}`;
},
} as unknown as Config;
const toolNoIgnore = new ReadFileTool(
configNoIgnore,
createMockMessageBus(),
);
const params: ReadFileToolParams = {
file_path: ignoredFilePath,
};
const invocation = toolNoIgnore.build(params);
expect(typeof invocation).not.toBe('string');
});
});
});
});