feat(sandbox): dynamic macOS sandbox expansion and worktree support (#23301)

This commit is contained in:
Gal Zahavi
2026-03-23 21:48:13 -07:00
committed by GitHub
parent 7fdf708e1a
commit fe7baee18b
40 changed files with 2201 additions and 183 deletions
+57 -6
View File
@@ -6,6 +6,7 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import { SandboxPolicyManager } from '../policy/sandboxPolicyManager.js';
import { inspect } from 'node:util';
import process from 'node:process';
import { z } from 'zod';
@@ -730,7 +731,8 @@ export class Config implements McpContext, AgentLoopContext {
private readonly telemetrySettings: TelemetrySettings;
private readonly usageStatisticsEnabled: boolean;
private _geminiClient!: GeminiClient;
private readonly _sandboxManager: SandboxManager;
private _sandboxManager: SandboxManager;
private readonly _sandboxPolicyManager: SandboxPolicyManager;
private baseLlmClient!: BaseLlmClient;
private localLiteRtLmClient?: LocalLiteRtLmClient;
private modelRouterService: ModelRouterService;
@@ -905,14 +907,14 @@ export class Config implements McpContext, AgentLoopContext {
params.embeddingModel ?? DEFAULT_GEMINI_EMBEDDING_MODEL;
this.sandbox = params.sandbox
? {
enabled: params.sandbox.enabled ?? false,
enabled: params.sandbox.enabled || params.toolSandboxing || false,
allowedPaths: params.sandbox.allowedPaths ?? [],
networkAccess: params.sandbox.networkAccess ?? false,
command: params.sandbox.command,
image: params.sandbox.image,
}
: {
enabled: false,
enabled: params.toolSandboxing || false,
allowedPaths: [],
networkAccess: false,
};
@@ -931,6 +933,30 @@ export class Config implements McpContext, AgentLoopContext {
this.fileSystemService = new StandardFileSystemService();
}
this._sandboxPolicyManager = new SandboxPolicyManager();
const initialApprovalMode =
params.approvalMode ??
params.policyEngineConfig?.approvalMode ??
'default';
this._sandboxManager = createSandboxManager(
this.sandbox,
params.targetDir,
this._sandboxPolicyManager,
initialApprovalMode,
);
if (
!(this._sandboxManager instanceof NoopSandboxManager) &&
this.sandbox?.enabled
) {
this.fileSystemService = new SandboxedFileSystemService(
this._sandboxManager,
params.targetDir,
);
} else {
this.fileSystemService = new StandardFileSystemService();
}
this.targetDir = path.resolve(params.targetDir);
this.folderTrust = params.folderTrust ?? false;
this.workspaceContext = new WorkspaceContext(this.targetDir, []);
@@ -1160,12 +1186,19 @@ export class Config implements McpContext, AgentLoopContext {
params.policyUpdateConfirmationRequest;
this.disableAlwaysAllow = params.disableAlwaysAllow ?? false;
const engineApprovalMode =
params.approvalMode ??
params.policyEngineConfig?.approvalMode ??
ApprovalMode.DEFAULT;
this.policyEngine = new PolicyEngine(
{
...params.policyEngineConfig,
approvalMode:
params.approvalMode ?? params.policyEngineConfig?.approvalMode,
approvalMode: engineApprovalMode,
disableAlwaysAllow: this.disableAlwaysAllow,
toolSandboxEnabled: this.getSandboxEnabled(),
sandboxApprovedTools:
this.sandboxPolicyManager?.getModeConfig(engineApprovalMode)
?.approvedTools ?? [],
},
checkerRunner,
);
@@ -1560,6 +1593,20 @@ export class Config implements McpContext, AgentLoopContext {
return this._geminiClient;
}
private refreshSandboxManager(): void {
this._sandboxManager = createSandboxManager(
this.sandbox,
this.targetDir,
this._sandboxPolicyManager,
this.getApprovalMode(),
);
this.shellExecutionConfig.sandboxManager = this._sandboxManager;
}
get sandboxPolicyManager() {
return this._sandboxPolicyManager;
}
get sandboxManager(): SandboxManager {
return this._sandboxManager;
}
@@ -2339,7 +2386,11 @@ export class Config implements McpContext, AgentLoopContext {
);
}
this.policyEngine.setApprovalMode(mode);
this.policyEngine.setApprovalMode(
mode,
this.sandboxPolicyManager?.getModeConfig(mode)?.approvedTools ?? [],
);
this.refreshSandboxManager();
const isPlanModeTransition =
currentMode !== mode &&
@@ -22,6 +22,7 @@ vi.mock('../confirmation-bus/message-bus.js', () => ({
vi.mock('../policy/policy-engine.js', () => ({
PolicyEngine: vi.fn().mockImplementation(() => ({
getExcludedTools: vi.fn().mockReturnValue(new Set()),
getApprovalMode: vi.fn().mockReturnValue('yolo'),
})),
}));
vi.mock('../skills/skillManager.js', () => ({