Skip to content

Commit cc1d86c

Browse files
authored
Merge pull request microsoft#256725 from microsoft/tyriar/autoapprove_merge
Merge allow and deny lists into autoApprove
2 parents 8551a1d + a932161 commit cc1d86c

File tree

4 files changed

+136
-141
lines changed

4 files changed

+136
-141
lines changed

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/commandLineAutoApprover.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ export class CommandLineAutoApprover extends Disposable {
1919
super();
2020
this.updateConfiguration();
2121
this._register(this._configurationService.onDidChangeConfiguration(e => {
22-
if (e.affectsConfiguration(TerminalChatAgentToolsSettingId.AllowList) || e.affectsConfiguration(TerminalChatAgentToolsSettingId.DenyList)) {
22+
if (e.affectsConfiguration(TerminalChatAgentToolsSettingId.AutoApprove)) {
2323
this.updateConfiguration();
2424
}
2525
}));
2626
}
2727

2828
updateConfiguration() {
29-
this._denyListRegexes = this._mapAutoApproveConfigToRegexList(this._configurationService.getValue(TerminalChatAgentToolsSettingId.DenyList));
30-
this._allowListRegexes = this._mapAutoApproveConfigToRegexList(this._configurationService.getValue(TerminalChatAgentToolsSettingId.AllowList));
29+
const { denyList, allowList } = this._mapAutoApproveConfigToRegexList(this._configurationService.getValue(TerminalChatAgentToolsSettingId.AutoApprove));
30+
this._allowListRegexes = allowList;
31+
this._denyListRegexes = denyList;
3132
}
3233

3334
isAutoApproved(command: string, shell: string, os: OperatingSystem): boolean {
@@ -64,13 +65,27 @@ export class CommandLineAutoApprover extends Disposable {
6465
return false;
6566
}
6667

67-
private _mapAutoApproveConfigToRegexList(config: unknown): RegExp[] {
68+
private _mapAutoApproveConfigToRegexList(config: unknown): { denyList: RegExp[]; allowList: RegExp[] } {
6869
if (!config || typeof config !== 'object') {
69-
return [];
70+
return { denyList: [], allowList: [] };
7071
}
71-
return Object.entries(config)
72-
.map(([key, value]) => value ? this._convertAutoApproveEntryToRegex(key) : undefined)
73-
.filter(e => !!e);
72+
73+
const denyList: RegExp[] = [];
74+
const allowList: RegExp[] = [];
75+
76+
Object.entries(config).forEach(([key, value]) => {
77+
if (typeof value === 'boolean') {
78+
const regex = this._convertAutoApproveEntryToRegex(key);
79+
// IMPORTANT: Only true and false are used, null entries need to be ignored
80+
if (value === true) {
81+
allowList.push(regex);
82+
} else if (value === false) {
83+
denyList.push(regex);
84+
}
85+
}
86+
});
87+
88+
return { denyList, allowList };
7489
}
7590

7691
private _convertAutoApproveEntryToRegex(value: string): RegExp {

src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalChatAgentToolsConfiguration.ts

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ import type { IConfigurationPropertySchema } from '../../../../../platform/confi
99

1010
export const enum TerminalChatAgentToolsSettingId {
1111
CoreToolsEnabled = 'chat.agent.terminal.coreToolsEnabled',
12-
AllowList = 'chat.agent.terminal.allowList',
13-
DenyList = 'chat.agent.terminal.denyList',
12+
AutoApprove = 'chat.agent.terminal.autoApprove',
1413
}
1514

1615
export interface ITerminalChatAgentToolsConfiguration {
1716
coreToolsEnabled: boolean;
18-
allowList: { [key: string]: string };
19-
denyList: { [key: string]: string };
17+
autoApprove: { [key: string]: boolean };
2018
}
2119

2220
export const terminalChatAgentToolsConfiguration: IStringDictionary<IConfigurationPropertySchema> = {
@@ -28,55 +26,43 @@ export const terminalChatAgentToolsConfiguration: IStringDictionary<IConfigurati
2826
],
2927
default: true,
3028
},
31-
[TerminalChatAgentToolsSettingId.AllowList]: {
32-
markdownDescription: localize('allowList', "A list of commands or regular expressions that allow the run in terminal tool commands to run without explicit approval. These will be matched against the start of a command. A regular expression can be provided by wrapping the string in `/` characters.\n\nExamples:\n- `\"mkdir\"` Will allow all command lines starting with `mkdir`\n- `\"npm run build\"` Will allow all command lines starting with `npm run build`\n- `\"/^git (status|show\\b.*)$/\"` will allow `git status` and all command lines starting with `git show`\n- `\"/.*/\"` will allow all command lines\n\nThis will be overridden by anything that matches an entry in `#chat.agent.terminal.denyList#`."),
29+
[TerminalChatAgentToolsSettingId.AutoApprove]: {
30+
markdownDescription: localize('autoApprove', "A list of commands or regular expressions that control whether the run in terminal tool commands require explicit approval. These will be matched against the start of a command. A regular expression can be provided by wrapping the string in `/` characters.\n\nSet to `true` to automatically approve commands, `false` to always require explicit approval or `null` to unset the value.\n\nExamples:\n- `\"mkdir\": true` Will allow all command lines starting with `mkdir`\n- `\"npm run build\": true` Will allow all command lines starting with `npm run build`\n- `\"rm\": false` Will require explicit approval for all command lines starting with `rm`\n- `\"/^git (status|show\\b.*)$/\": true` will allow `git status` and all command lines starting with `git show`\n- `\"/.*/\": true` will allow all command lines\n- `\"rm\": null` will unset the default `false` value for `rm`\n\nNote that these commands and regular expressions are evaluated for every _sub-command_ within a single command line, so `foo && bar` for example will need both `foo` and `bar` to match a `true` entry and must not match a `false` entry in order to auto approve. Inline commands are also detected so `echo $(rm file)` will need both `echo $(rm file)` and `rm file` to pass."),
3331
type: 'object',
3432
additionalProperties: {
35-
type: 'boolean',
36-
enum: [
37-
true,
38-
false,
39-
],
40-
enumDescriptions: [
41-
localize('allowList.true', "Allow the pattern."),
42-
localize('allowList.false', "Do not allow the pattern."),
43-
],
44-
description: localize('allowList.key', "The start of a command to match against. A regular expression can be provided by wrapping the string in `/` characters."),
45-
},
46-
tags: [
47-
'experimental'
48-
],
49-
default: {},
50-
},
51-
[TerminalChatAgentToolsSettingId.DenyList]: {
52-
markdownDescription: localize('denyList', "A list of commands or regular expressions that override matches in `#chat.agent.terminal.allowList#` and force a command line to require explicit approval. This will be matched against the start of a command. A regular expression can be provided by wrapping the string in `/` characters.\n\nExamples:\n- `\"rm\"` will require explicit approval for any command starting with `rm`\n- `\"/^git (push|pull)/\"` will require explicit approval for any command starting with `git push` or `git pull` \n\nThis provides basic protection by preventing certain commands from running automatically, especially those a user would likely want to approve first. It is not intended as a comprehensive security measure or a defense against prompt injection."),
53-
type: 'object',
54-
additionalProperties: {
55-
type: 'boolean',
56-
enum: [
57-
true,
58-
false
59-
],
60-
enumDescriptions: [
61-
localize('denyList.value.true', "Deny the pattern."),
62-
localize('denyList.value.false', "Do not deny the pattern."),
63-
],
64-
description: localize('denyList.key', "The start of a command to match against. A regular expression can be provided by wrapping the string in `/` characters.")
33+
anyOf: [
34+
{
35+
type: 'boolean',
36+
enum: [
37+
true,
38+
false,
39+
],
40+
enumDescriptions: [
41+
localize('autoApprove.true', "Automatically approve the pattern."),
42+
localize('autoApprove.false', "Require explicit approval for the pattern."),
43+
],
44+
description: localize('autoApprove.key', "The start of a command to match against. A regular expression can be provided by wrapping the string in `/` characters."),
45+
},
46+
{
47+
type: 'null',
48+
description: localize('autoApprove.null', "Ignore the pattern, this is useful for unsetting the same pattern set at a higher scope."),
49+
},
50+
]
6551
},
6652
tags: [
6753
'experimental'
6854
],
6955
default: {
70-
rm: true,
71-
rmdir: true,
72-
del: true,
73-
kill: true,
74-
curl: true,
75-
wget: true,
76-
eval: true,
77-
chmod: true,
78-
chown: true,
79-
'Remove-Item': true,
56+
rm: false,
57+
rmdir: false,
58+
del: false,
59+
kill: false,
60+
curl: false,
61+
wget: false,
62+
eval: false,
63+
chmod: false,
64+
chown: false,
65+
'Remove-Item': false,
8066
},
8167
}
8268
};

0 commit comments

Comments
 (0)