mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-24 03:54:43 -07:00
feat(core): implement Stage 2 security and consistency improvements for web_fetch (#22217)
This commit is contained in:
@@ -497,7 +497,7 @@ describe('WebFetchTool', () => {
|
||||
|
||||
expect(result.llmContent).toBe('fallback processed response');
|
||||
expect(result.returnDisplay).toContain(
|
||||
'2 URL(s) processed using fallback fetch',
|
||||
'URL(s) processed using fallback fetch',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -530,7 +530,7 @@ describe('WebFetchTool', () => {
|
||||
// Verify private URL was NOT fetched (mockFetch would throw if it was called for private.com)
|
||||
});
|
||||
|
||||
it('should return WEB_FETCH_FALLBACK_FAILED on fallback fetch failure', async () => {
|
||||
it('should return WEB_FETCH_FALLBACK_FAILED on total failure', async () => {
|
||||
vi.spyOn(fetchUtils, 'isPrivateIp').mockReturnValue(false);
|
||||
mockGenerateContent.mockRejectedValue(new Error('primary fail'));
|
||||
mockFetch('https://public.ip/', new Error('fallback fetch failed'));
|
||||
@@ -541,16 +541,6 @@ describe('WebFetchTool', () => {
|
||||
expect(result.error?.type).toBe(ToolErrorType.WEB_FETCH_FALLBACK_FAILED);
|
||||
});
|
||||
|
||||
it('should return WEB_FETCH_FALLBACK_FAILED on general processing failure (when fallback also fails)', async () => {
|
||||
vi.spyOn(fetchUtils, 'isPrivateIp').mockReturnValue(false);
|
||||
mockGenerateContent.mockRejectedValue(new Error('API error'));
|
||||
const tool = new WebFetchTool(mockConfig, bus);
|
||||
const params = { prompt: 'fetch https://public.ip' };
|
||||
const invocation = tool.build(params);
|
||||
const result = await invocation.execute(new AbortController().signal);
|
||||
expect(result.error?.type).toBe(ToolErrorType.WEB_FETCH_FALLBACK_FAILED);
|
||||
});
|
||||
|
||||
it('should log telemetry when falling back due to primary fetch failure', async () => {
|
||||
vi.spyOn(fetchUtils, 'isPrivateIp').mockReturnValue(false);
|
||||
// Mock primary fetch to return empty response, triggering fallback
|
||||
@@ -639,6 +629,14 @@ describe('WebFetchTool', () => {
|
||||
const invocation = tool.build(params);
|
||||
const result = await invocation.execute(new AbortController().signal);
|
||||
|
||||
const sanitizeXml = (text: string) =>
|
||||
text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
|
||||
if (shouldConvert) {
|
||||
expect(convert).toHaveBeenCalledWith(content, {
|
||||
wordwrap: false,
|
||||
@@ -647,10 +645,12 @@ describe('WebFetchTool', () => {
|
||||
{ selector: 'img', format: 'skip' },
|
||||
],
|
||||
});
|
||||
expect(result.llmContent).toContain(`Converted: ${content}`);
|
||||
expect(result.llmContent).toContain(
|
||||
`Converted: ${sanitizeXml(content)}`,
|
||||
);
|
||||
} else {
|
||||
expect(convert).not.toHaveBeenCalled();
|
||||
expect(result.llmContent).toContain(content);
|
||||
expect(result.llmContent).toContain(sanitizeXml(content));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user