1
>
/*---------------------------------------------------------------------------------------------
sessionPermissions.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 { realpath as fsRealpath } from 'fs';
7
>
import { homedir } from 'os';
8
>
import { promisify } from 'util';
9
>
import { match as globMatch } from '../../../base/common/glob.js';
10
>
import { untildify } from '../../../base/common/labels.js';
11
>
import { Disposable } from '../../../base/common/lifecycle.js';
12
>
import { Schemas } from '../../../base/common/network.js';
13
>
import * as path from '../../../base/common/path.js';
14
>
import { isMacintosh, isWindows } from '../../../base/common/platform.js';
15
>
import { extUriBiasedIgnorePathCase, normalizePath } from '../../../base/common/resources.js';
16
>
import { isDefined } from '../../../base/common/types.js';
17
>
import { URI } from '../../../base/common/uri.js';
18
>
import { localize } from '../../../nls.js';
19
>
import { ILogService } from '../../log/common/log.js';
20
>
import { AgentHostGlobalAutoApproveEnabledConfigKey, AgentHostTerminalAutoApproveEnabledConfigKey, AgentHostTerminalAutoApproveRulesConfigKey, platformRootSchema, platformSessionSchema } from '../common/agentHostSchema.js';
21
>
import type { IAgentToolPendingConfirmationSignal } from '../common/agentService.js';
22
>
import { SessionConfigKey } from '../common/sessionConfigKeys.js';
23
>
import { ConfirmationOptionKind, type ConfirmationOption } from '../common/state/protocol/state.js';
24
>
import { ActionType, type IToolCallReadyAction } from '../common/state/sessionActions.js';
25
>
import {
26
>
isAhpChatChannel,
27
>
parseRequiredSessionUriFromChatUri,
28
>
ResponsePartKind,
29
>
ToolCallConfirmationReason,
30
>
type URI as ProtocolURI,
31
>
} from '../common/state/sessionState.js';
32
>
import { IAgentConfigurationService } from './agentConfigurationService.js';
33
>
import { AgentHostStateManager } from './agentHostStateManager.js';
34
>
import { CommandAutoApprover } from './commandAutoApprover.js';
35
>
36
>
/**
37
>
* Event fields needed for auto-approval decisions.
38
>
* Matches the subset of {@link IAgentToolPendingConfirmationSignal} used by the
39
>
* approval pipeline.
40
>
*/
41
>
export interface IToolApprovalEvent {
42
>
readonly toolCallId: string;
43
>
readonly session: URI;
44
>
readonly permissionKind?: IAgentToolPendingConfirmationSignal['permissionKind'];
45
>
readonly permissionPath?: string;
46
>
readonly toolInput?: string;
47
>
readonly requestSandboxBypass?: boolean;
48
>
}
49
>
50
>
/** Standard per-tool confirmation options presented to the user. */
51
>
const ALLOW_SESSION_OPTION_ID = 'allow-session';
52
>
const CONFIRMATION_OPTIONS: readonly ConfirmationOption[] = [
53
>
{ id: ALLOW_SESSION_OPTION_ID, label: localize('sessionPermissions.allowSession', "Allow in this Session"), kind: ConfirmationOptionKind.Approve, group: 1 },
54
>
{ id: 'allow-once', label: localize('sessionPermissions.allowOnce', "Allow Once"), kind: ConfirmationOptionKind.Approve },
55
>
{ id: 'skip', label: localize('sessionPermissions.skip', "Skip"), kind: ConfirmationOptionKind.Deny, group: 2 },
56
>
];
57
>
58
>
/** Default write-path glob rules applied to auto-approved edits. */
59
>
const DEFAULT_EDIT_AUTO_APPROVE_PATTERNS: Readonly<Record<string, boolean>> = {
60
>
'**/*': true,
61
>
'**/.vscode/*.json': false,
62
>
'**/.git/**': false,
63
>
'**/{package.json,server.xml,build.rs,web.config,.gitattributes,.env}': false,
64
>
'**/*.{code-workspace,csproj,fsproj,vbproj,vcxproj,proj,targets,props}': false,
65
>
'**/*.lock': false,
66
>
'**/*-lock.{yaml,json}': false,
67
>
// Files that can register lifecycle hooks running arbitrary shell commands.
68
>
// Writing them must never be auto-approved. Keep in sync with the hook and
69
>
// agent source locations in `promptFileLocations.ts`.
70
>
'**/.github/agents/**': false,
71
>
'**/.github/hooks/**': false,
72
>
'**/.claude/agents/**': false,
73
>
'**/.claude/settings.json': false,
74
>
'**/.claude/settings.local.json': false,
75
>
};
76
>
77
>
const HOME_DIR = URI.file(homedir());
78
>
79
>
/**
80
>
* Absolute directory prefixes whose contents are platform configuration data
81
>
* (e.g. `~/Library`, `%APPDATA%`). Writes under these require confirmation
82
>
* unless the working directory itself lives inside the restricted directory.
83
>
*/
84
>
const PLATFORM_RESTRICTED_DIRS: readonly string[] = (
85
>
isWindows
86
? [process.env.APPDATA, process.env.LOCALAPPDATA]
88
? [homedir() + '/Library']
90
>
).filter(isDefined);
91
>
92
>
const realpath = promisify(fsRealpath);
93
>
94
>
/**
95
>
* Validates that a path doesn't contain suspicious characters that could be
96
>
* used to bypass security checks on Windows (e.g. NTFS Alternate Data Streams,
97
>
* invalid characters, reserved device names). Throws if the path is suspicious.
98
>
*/
99
function assertPathIsSafe(fsPath: string, _isWindows = isWindows): void {
100
if (fsPath.includes('\0')) {