1
>
/*---------------------------------------------------------------------------------------------
terminalSandboxEngine.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { VSBuffer } from '../../../base/common/buffer.js';
7
>
import { Event } from '../../../base/common/event.js';
8
>
import { match as globMatch } from '../../../base/common/glob.js';
9
>
import { Disposable } from '../../../base/common/lifecycle.js';
10
>
import { posix, win32 } from '../../../base/common/path.js';
11
>
import { OperatingSystem, OS } from '../../../base/common/platform.js';
12
>
import { arch } from '../../../base/common/process.js';
13
>
import { ExtUri } from '../../../base/common/resources.js';
14
>
import { URI } from '../../../base/common/uri.js';
15
>
import { generateUuid } from '../../../base/common/uuid.js';
16
>
import { IFileService } from '../../files/common/files.js';
17
>
import { ILogService } from '../../log/common/log.js';
18
>
import { matchesDomainPattern, normalizeDomain } from '../../networkFilter/common/domainMatcher.js';
19
>
import { AgentNetworkDomainSettingId } from '../../networkFilter/common/settings.js';
20
>
import { ISandboxDependencyStatus, type IWindowsMxcConfig, IWindowsMxcFilesystemPolicy, type IWindowsMxcPolicyContainment, type IWindowsMxcSandboxPolicy } from './sandboxHelperService.js';
21
>
import { AgentSandboxEnabledValue, AgentSandboxSettingId, isAgentSandboxEnabledValue, normalizeAgentSandboxEnabledValue, type AgentSandboxEnabledSettingValue } from './settings.js';
22
>
import { IWindowsMxcTerminalSandboxRuntime } from './terminalSandboxMxcRuntime.js';
23
>
import { getTerminalSandboxReadAllowListForCommands } from './terminalSandboxReadAllowList.js';
24
>
import { getTerminalSandboxRuntimeConfigurationForCommands } from './terminalSandboxRuntimeConfigurationPerOperation.js';
25
>
import { ITerminalSandboxCommand, ITerminalSandboxFileAccessCheckResult, ITerminalSandboxPrecheckInputs, ITerminalSandboxPrerequisiteCheckResult, ITerminalSandboxResolvedNetworkDomains, ITerminalSandboxWrapResult, TerminalSandboxFileAccessPermission, TerminalSandboxPrerequisiteCheck, TerminalSandboxPreCheckRemediation } from './terminalSandboxService.js';
26
>
27
>
interface ITerminalSandboxFileSystemSetting {
28
>
denyRead?: string[];
29
>
allowRead?: string[];
30
>
allowWrite?: string[];
31
>
denyWrite?: string[];
32
>
}
33
>
34
>
interface ITerminalSandboxFileSystemAccessPaths {
35
>
allowReadPaths: string[];
36
>
allowWritePaths: string[];
37
>
denyReadPaths: string[];
38
>
denyWritePaths: string[] | undefined;
39
>
}
40
>
41
>
/** Runtime information needed to launch the sandbox-runtime CLI. */
42
>
export interface ITerminalSandboxRuntimeInfo {
43
>
/** Directory that contains `node_modules/@vscode/sandbox-runtime` and `node_modules/@vscode/ripgrep`. */
44
>
appRoot: string;
45
>
/**
46
>
* Name of the directory (relative to {@link appRoot}) that holds the native
47
>
* binaries `ripgrep-universal` and `@microsoft/mxc-sdk`. In a packaged desktop
48
>
* build these are unpacked from the archive into `node_modules.asar.unpacked`;
49
>
* in dev and on remote they live in plain `node_modules`. Defaults to
50
>
* `node_modules`. Note the sandbox-runtime CLI itself is always resolved from
51
>
* plain `node_modules` (it is duplicated out of the archive) because it is
52
>
* spawned as a standalone Node subprocess without the ASAR resolution hook.
53
>
*/
54
>
nativeModulesDir?: string;
55
>
/** Path of the node/electron executable used to run sandbox-runtime. */
56
>
execPath?: string;
57
>
/**
58
>
* When true the engine prefixes the wrapped command with `ELECTRON_RUN_AS_NODE=1`
59
>
* so the Electron binary acts as a Node.js executable. Set by hosts that resolve
60
>
* an Electron-based exec path (the local workbench); leave undefined / false when
61
>
* `execPath` already points at a real `node` binary (remote, agent host).
62
>
*/
63
>
runAsNode?: boolean;
64
>
/** CPU architecture of the environment that runs the sandbox runtime. */
65
>
arch?: string;
66
>
}
67
>
68
>
/**
69
>
* Host adapter that supplies the engine with environment/workspace data the
70
>
* platform layer cannot resolve on its own. Hosts (workbench, agent host)
71
>
* implement this to bridge their per-environment services (`IRemoteAgentService`,
72
>
* `IWorkspaceContextService`, `IEnvironmentService`, `IProductService`,
73
>
* `ISandboxHelperService`, …) into the engine.
74
>
*/
75
>
export interface ITerminalSandboxEngineHost {
76
>
/** Effective OS used by sandbox decisions. May be the remote OS in workbench. */
77
>
getOS(): Promise<OperatingSystem>;
78
>
/** Resolves app root + node/electron exec path (after the remote env is known, if applicable). */
79
>
getRuntimeInfo(): Promise<ITerminalSandboxRuntimeInfo>;
80
>
/** Resolves the user home used for `~`-expansion and the default deny-read entry. */
81
>
getUserHome(): Promise<URI | undefined>;
82
>
/**
83
>
* Resolves the directory the engine creates and uses as its sandbox temp dir
84
>
* (sandbox-settings JSON file lives here). May return undefined when no
85
>
* suitable location exists, in which case sandboxing is disabled.
86
>
*/
87
>
getSandboxTempDir(): Promise<URI | undefined>;
88
>
/** Path added to `allowRead` and `allowWrite` for the engine's workspace/session storage area. */
89
>
getWorkspaceStorageReadRoot(): Promise<URI | undefined>;
90
>
/** Roots that must be writable inside the sandbox (workspace folders / session cwds). */
91
>
getWriteRoots(): readonly URI[];
92
>
/** Fires when {@link getWriteRoots} or {@link getWorkspaceStorageReadRoot} change. */
93
>
readonly onDidChangeRoots: Event<void>;
94
>
/** Resolves the installed sandbox-dependency status (bubblewrap, socat). */
95
>
checkSandboxDependencies(): Promise<ISandboxDependencyStatus | undefined>;
96
>
/** Resolves host filesystem policy fragments needed by the Windows MXC process container. */
97
>
getWindowsMxcFilesystemPolicy(): Promise<IWindowsMxcFilesystemPolicy | undefined>;
98
>
/** Resolves host environment variables needed by the Windows MXC process container. */
99
>
getWindowsMxcEnvironment(): Promise<string[] | undefined>;
100
>
/** Builds a Windows MXC payload from a target-environment MXC sandbox policy. */
101
>
buildWindowsMxcSandboxPayload(commandLine: string, policy: IWindowsMxcSandboxPolicy, workingDirectory?: string, containerName?: string, containment?: IWindowsMxcPolicyContainment): Promise<IWindowsMxcConfig | undefined>;
102
>
/**
103
>
* Returns the effective value of a sandbox-related configuration setting,
104
>
* or `undefined` when the setting is not configured. Implementations are
105
>
* responsible for mapping deprecated keys to modern ones (the engine
106
>
* only ever asks for the modern setting IDs).
107
>
*/
108
>
getSandboxSetting<T>(settingId: string): T | undefined;
109
>
/**
110
>
* Fires when any value returned by {@link getSandboxSetting} may have
111
>
* changed. The engine invalidates its sandbox-config file on each event.
112
>
* Implementations should pre-filter to sandbox-relevant keys.
113
>
*/
114
>
readonly onDidChangeSandboxSettings: Event<void>;
115
>
}
116
>
117
>
/**
118
>
* Core sandbox engine. Encapsulates the platform-agnostic logic for wrapping
119
>
* commands in a sandbox runtime: enabledness checks, command-line wrapping,
120
>
* sandbox-config generation, network-domain extraction and prerequisite checks.
121
>
*
122
>
* Hosts (workbench / agent host) construct an engine with a host adapter that
123
>
* supplies workspace/remote-specific data, then forward their public service
124
>
* methods to the engine and add their own host-specific concerns
125
>
* (chat elicitation, lifecycle hooks, …) on top.
126
>
*/
127
>
export class TerminalSandboxEngine extends Disposable {
128
>
private static readonly _urlRegex = /(?:https?|wss?):\/\/[^\s'"`|&;<>]+/gi;
129
>
private static readonly _sshRemoteRegex = /(?:^|[\s'"`])(?:[^\s@:'"`]+@)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(?::[^\s'"`|&;<>]+)(?=$|[\s'"`|&;<>])/gi;
130
>
private static readonly _hostRegex = /(?:^|[\s'"`(=])([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(?::\d+)?(?=(?:\/[^\s'"`|&;<>]*)?(?:$|[\s'"`)\]|,;|&<>]))/gi;
131
>
132
>
private readonly _sandboxSettingsId: string = generateUuid();
133
>
private _runtimeResolved = false;
134
>
private _appRoot: string | undefined;
135
>
private _execPath: string | undefined;
136
>
private _runAsNode = false;
137
>
private _userHome: URI | undefined;
138
>
private _srtPath: string | undefined;
139
>
private _rgPath: string | undefined;
140
>
private _mxcPath: string | undefined;
141
>
private _windowsMxcFilesystemPolicy: IWindowsMxcFilesystemPolicy | undefined;
142
>
private _windowsMxcEnvironment: string[] | undefined;
143
>
private _sandboxConfigPath: string | undefined;
144
>
private _sandboxDependencyStatus: ISandboxDependencyStatus | undefined;
145
>
private _needsForceUpdateConfigFile = true;
146
>
private _tempDir: URI | undefined;
147
>
private _commandAllowListKeywords: readonly string[] = [];
148
>
private _commandAllowListCommandDetails: readonly ITerminalSandboxCommand[] = [];
149
>
private _commandCwd: URI | undefined;
150
>
private _commandLine: string | undefined;
151
>
private _commandShell: string | undefined;
152
>
private _commandAllowNetwork = false;
153
>
private _os: OperatingSystem = OS;
154
>
private readonly _defaultWritePaths: string[] = [];
155
>
private readonly _fileSystemPathExtUri = new ExtUri(() => this._os === OperatingSystem.Windows);
156
>
157
>
constructor(
158
private readonly _host: ITerminalSandboxEngineHost,
159
@IFileService private readonly _fileService: IFileService,