feat(core): implement progressive elevation and AI error awareness for Windows sandbox

This commit is contained in:
mkorwel
2026-03-09 22:46:13 -07:00
parent 5c0b0f98ec
commit 1633cd88ac
6 changed files with 77 additions and 33 deletions
+20 -20
View File
@@ -974,13 +974,32 @@ export class Config implements McpContext, AgentLoopContext {
this.useAlternateBuffer = params.useAlternateBuffer ?? false;
this.enableInteractiveShell = params.enableInteractiveShell ?? false;
this.skipNextSpeakerCheck = params.skipNextSpeakerCheck ?? true;
if (
os.platform() === 'win32' &&
(this.sandbox?.enabled || this.sandbox?.command === 'windows-native')
) {
this._sandboxManager = new WindowsSandboxManager();
} else {
this._sandboxManager = new NoopSandboxManager();
}
if (this.sandbox?.enabled && this._sandboxManager) {
this.fileSystemService = new SandboxedFileSystemService(
this._sandboxManager,
this.cwd,
);
} else {
this.fileSystemService = new StandardFileSystemService();
}
this.shellExecutionConfig = {
terminalWidth: params.shellExecutionConfig?.terminalWidth ?? 80,
terminalHeight: params.shellExecutionConfig?.terminalHeight ?? 24,
showColor: params.shellExecutionConfig?.showColor ?? false,
pager: params.shellExecutionConfig?.pager ?? 'cat',
sanitizationConfig: this.sanitizationConfig,
sandboxManager: this.sandboxManager,
sandboxManager: this._sandboxManager,
sandboxConfig: this.sandbox,
};
this.truncateToolOutputThreshold =
@@ -1097,25 +1116,6 @@ export class Config implements McpContext, AgentLoopContext {
}
}
this._geminiClient = new GeminiClient(this);
if (
os.platform() === 'win32' &&
(this.sandbox?.enabled || this.sandbox?.command === 'windows-native')
) {
this._sandboxManager = new WindowsSandboxManager();
} else {
this._sandboxManager = new NoopSandboxManager();
}
if (this.sandbox?.enabled && this._sandboxManager) {
this.fileSystemService = new SandboxedFileSystemService(
this._sandboxManager,
this.cwd,
);
} else {
this.fileSystemService = new StandardFileSystemService();
}
this.shellExecutionConfig.sandboxManager = this._sandboxManager;
this.modelRouterService = new ModelRouterService(this);
// HACK: The settings loading logic doesn't currently merge the default
@@ -4,9 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { describe, it, expect } from 'vitest';
import { WindowsSandboxManager } from './windowsSandboxManager.js';
import { SandboxRequest } from './sandboxManager.js';
import type { SandboxRequest } from './sandboxManager.js';
import * as os from 'node:os';
describe('WindowsSandboxManager', () => {
@@ -7,7 +7,6 @@
import fs from 'node:fs';
import { spawnSync } from 'node:child_process';
import path from 'node:path';
import os from 'node:os';
import { fileURLToPath } from 'node:url';
import {
type SandboxManager,
@@ -84,6 +83,20 @@ export class WindowsSandboxManager implements SandboxManager {
// Grant "Low Mandatory Level" write access to the CWD.
this.grantLowIntegrityAccess(req.cwd);
// Whitelist essential system paths for DLL loading and basic tool execution.
// This is required when using the Restricted Code SID (S-1-5-12).
const systemPaths = [
process.env['SystemRoot'] || 'C:\\Windows',
process.env['ProgramFiles'] || 'C:\\Program Files',
process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)',
];
for (const sysPath of systemPaths) {
if (fs.existsSync(sysPath)) {
this.grantLowIntegrityAccess(sysPath);
}
}
// Grant "Low Mandatory Level" read access to allowedPaths.
if (req.config?.allowedPaths) {
for (const allowedPath of req.config.allowedPaths) {