-
Notifications
You must be signed in to change notification settings - Fork 14.1k
fix(browser-agent): enable "Allow all server tools" session policy #22343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
0315833
trying the fix
cynthialong0-0 24c5d9f
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 32ada00
refactor(core): centralize MCP policy management and standardize wild…
cynthialong0-0 44cffcc
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 2c68d20
fix build
cynthialong0-0 07abf8e
fix config
cynthialong0-0 4e24293
refactor the fix
cynthialong0-0 0978c76
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 b79a3ff
fix merge conflict
cynthialong0-0 6076f7d
add config change
cynthialong0-0 9993383
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 9b58e3c
update comment
cynthialong0-0 19b8e34
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 24a8b8b
add unit test and e2e test to prevent regression
cynthialong0-0 8224e66
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 630b390
remove unncessary wait
cynthialong0-0 ff8e507
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 44ced17
test(core): fix lint issues in policy-updater.test
cynthialong0-0 8caa23d
fix format
cynthialong0-0 6fb836b
fix server name in test
cynthialong0-0 2d8d178
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 e2c39d5
try to fix the sandbox:none test case
cynthialong0-0 0c63661
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 127e1ca
rever test change
cynthialong0-0 770861a
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 526a19d
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 00f1367
include privacy notice update in the test
cynthialong0-0 eeaa118
Merge branch 'main' into refactor/mcp-policy-centralization
cynthialong0-0 cba984d
try to make sandbox none & macos to work
cynthialong0-0 accef78
update test
cynthialong0-0 773489b
try defaultApprovalMode in setting
cynthialong0-0 fb38c4d
fix test failure in macos env
cynthialong0-0 b43bb92
try removing new_page from final output
cynthialong0-0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you with that."},{"functionCall":{"name":"browser_agent","args":{"task":"Open https://example.com and check if there is a heading"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} | ||
| {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"new_page","args":{"url":"https://example.com"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} | ||
| {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"take_snapshot","args":{}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} | ||
| {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"complete_task","args":{"success":true,"summary":"SUCCESS_POLICY_TEST_COMPLETED"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} | ||
| {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"Task completed successfully. The page has the heading \"Example Domain\"."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":50,"totalTokenCount":250}}]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2026 Google LLC | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| import { describe, it, expect, beforeEach, afterEach } from 'vitest'; | ||
| import { TestRig, poll } from './test-helper.js'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { execSync } from 'node:child_process'; | ||
| import { existsSync, writeFileSync, readFileSync, mkdirSync } from 'node:fs'; | ||
| import stripAnsi from 'strip-ansi'; | ||
|
|
||
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = dirname(__filename); | ||
|
|
||
| const chromeAvailable = (() => { | ||
| try { | ||
| if (process.platform === 'darwin') { | ||
| execSync( | ||
| 'test -d "/Applications/Google Chrome.app" || test -d "/Applications/Chromium.app"', | ||
| { | ||
| stdio: 'ignore', | ||
| }, | ||
| ); | ||
| } else if (process.platform === 'linux') { | ||
| execSync( | ||
| 'which google-chrome || which chromium-browser || which chromium', | ||
| { stdio: 'ignore' }, | ||
| ); | ||
| } else if (process.platform === 'win32') { | ||
| const chromePaths = [ | ||
| 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', | ||
| 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', | ||
| `${process.env['LOCALAPPDATA'] ?? ''}\\Google\\Chrome\\Application\\chrome.exe`, | ||
| ]; | ||
| const found = chromePaths.some((p) => existsSync(p)); | ||
| if (!found) { | ||
| execSync('where chrome || where chromium', { stdio: 'ignore' }); | ||
| } | ||
| } else { | ||
| return false; | ||
| } | ||
| return true; | ||
| } catch { | ||
| return false; | ||
| } | ||
| })(); | ||
|
|
||
| describe.skipIf(!chromeAvailable)('browser-policy', () => { | ||
| let rig: TestRig; | ||
|
|
||
| beforeEach(() => { | ||
| rig = new TestRig(); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| await rig.cleanup(); | ||
| }); | ||
|
|
||
| it('should skip confirmation when "Allow all server tools for this session" is chosen', async () => { | ||
| rig.setup('browser-policy-skip-confirmation', { | ||
| fakeResponsesPath: join(__dirname, 'browser-policy.responses'), | ||
| settings: { | ||
| agents: { | ||
| overrides: { | ||
| browser_agent: { | ||
| enabled: true, | ||
| }, | ||
| }, | ||
| browser: { | ||
| headless: true, | ||
| sessionMode: 'isolated', | ||
| allowedDomains: ['example.com'], | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| // Manually trust the folder to avoid the dialog and enable option 3 | ||
| const geminiDir = join(rig.homeDir!, '.gemini'); | ||
| mkdirSync(geminiDir, { recursive: true }); | ||
|
|
||
| // Write to trustedFolders.json | ||
| const trustedFoldersPath = join(geminiDir, 'trustedFolders.json'); | ||
| const trustedFolders = { | ||
| [rig.testDir!]: 'TRUST_FOLDER', | ||
| }; | ||
| writeFileSync(trustedFoldersPath, JSON.stringify(trustedFolders, null, 2)); | ||
|
|
||
| // Force confirmation for browser agent. | ||
| // NOTE: We don't force confirm browser tools here because "Allow all server tools" | ||
| // adds a rule with ALWAYS_ALLOW_PRIORITY (3.9x) which would be overshadowed by | ||
| // a rule in the user tier (4.x) like the one from this TOML. | ||
| // By removing the explicit mcp rule, the first MCP tool will still prompt | ||
| // due to default approvalMode = 'default', and then "Allow all" will correctly | ||
| // bypass subsequent tools. | ||
| const policyFile = join(rig.testDir!, 'force-confirm.toml'); | ||
| writeFileSync( | ||
| policyFile, | ||
| ` | ||
| [[rule]] | ||
| name = "Force confirm browser_agent" | ||
| toolName = "browser_agent" | ||
| decision = "ask_user" | ||
| priority = 200 | ||
| `, | ||
| ); | ||
|
|
||
| // Update settings.json in both project and home directories to point to the policy file | ||
| for (const baseDir of [rig.testDir!, rig.homeDir!]) { | ||
| const settingsPath = join(baseDir, '.gemini', 'settings.json'); | ||
| if (existsSync(settingsPath)) { | ||
| const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); | ||
| settings.policyPaths = [policyFile]; | ||
| // Ensure folder trust is enabled | ||
| settings.security = settings.security || {}; | ||
| settings.security.folderTrust = settings.security.folderTrust || {}; | ||
| settings.security.folderTrust.enabled = true; | ||
| writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); | ||
| } | ||
| } | ||
|
|
||
| const run = await rig.runInteractive({ | ||
| approvalMode: 'default', | ||
| env: { | ||
| GEMINI_CLI_INTEGRATION_TEST: 'true', | ||
| }, | ||
| }); | ||
|
|
||
| await run.sendKeys( | ||
| 'Open https://example.com and check if there is a heading\r', | ||
| ); | ||
| await run.sendKeys('\r'); | ||
|
|
||
| // Handle confirmations. | ||
| // 1. Initial browser_agent delegation (likely only 3 options, so use option 1: Allow once) | ||
| await poll( | ||
| () => stripAnsi(run.output).toLowerCase().includes('action required'), | ||
| 60000, | ||
| 1000, | ||
| ); | ||
| await run.sendKeys('1\r'); | ||
| await new Promise((r) => setTimeout(r, 2000)); | ||
|
|
||
| // Handle privacy notice | ||
| await poll( | ||
| () => stripAnsi(run.output).toLowerCase().includes('privacy notice'), | ||
| 5000, | ||
| 100, | ||
| ); | ||
| await run.sendKeys('1\r'); | ||
| await new Promise((r) => setTimeout(r, 5000)); | ||
|
|
||
| // new_page (MCP tool, should have 4 options, use option 3: Allow all server tools) | ||
| await poll( | ||
| () => { | ||
| const stripped = stripAnsi(run.output).toLowerCase(); | ||
| return ( | ||
| stripped.includes('new_page') && | ||
| stripped.includes('allow all server tools for this session') | ||
| ); | ||
| }, | ||
| 60000, | ||
| 1000, | ||
| ); | ||
|
|
||
| // Select "Allow all server tools for this session" (option 3) | ||
| await run.sendKeys('3\r'); | ||
| await new Promise((r) => setTimeout(r, 30000)); | ||
|
|
||
| const output = stripAnsi(run.output).toLowerCase(); | ||
|
|
||
| expect(output).toContain('browser_agent'); | ||
| expect(output).toContain('completed successfully'); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.