@@ -12,6 +12,7 @@ import { isPowerShell } from './runInTerminalHelpers.js';
12
12
13
13
interface IAutoApproveRule {
14
14
regex : RegExp ;
15
+ regexCaseInsensitive : RegExp ;
15
16
sourceText : string ;
16
17
}
17
18
@@ -65,14 +66,14 @@ export class CommandLineAutoApprover extends Disposable {
65
66
isCommandAutoApproved ( command : string , shell : string , os : OperatingSystem ) : { result : ICommandApprovalResult ; reason : string } {
66
67
// Check the deny list to see if this command requires explicit approval
67
68
for ( const rule of this . _denyListRules ) {
68
- if ( this . _commandMatchesRegex ( rule . regex , command , shell , os ) ) {
69
+ if ( this . _commandMatchesRule ( rule , command , shell , os ) ) {
69
70
return { result : 'denied' , reason : `Command '${ command } ' is denied by deny list rule: ${ rule . sourceText } ` } ;
70
71
}
71
72
}
72
73
73
74
// Check the allow list to see if the command is allowed to run without explicit approval
74
75
for ( const rule of this . _allowListRules ) {
75
- if ( this . _commandMatchesRegex ( rule . regex , command , shell , os ) ) {
76
+ if ( this . _commandMatchesRule ( rule , command , shell , os ) ) {
76
77
return { result : 'approved' , reason : `Command '${ command } ' is approved by allow list rule: ${ rule . sourceText } ` } ;
77
78
}
78
79
}
@@ -123,15 +124,16 @@ export class CommandLineAutoApprover extends Disposable {
123
124
return trimmedCommand ;
124
125
}
125
126
126
- private _commandMatchesRegex ( regex : RegExp , command : string , shell : string , os : OperatingSystem ) : boolean {
127
+ private _commandMatchesRule ( rule : IAutoApproveRule , command : string , shell : string , os : OperatingSystem ) : boolean {
127
128
const actualCommand = this . _removeEnvAssignments ( command , shell , os ) ;
129
+ const isPwsh = isPowerShell ( shell , os ) ;
128
130
129
- if ( regex . test ( actualCommand ) ) {
131
+ if ( ( isPwsh ? rule . regexCaseInsensitive : rule . regex ) . test ( actualCommand ) ) {
130
132
return true ;
131
- } else if ( isPowerShell ( shell , os ) && actualCommand . startsWith ( '(' ) ) {
133
+ } else if ( isPwsh && actualCommand . startsWith ( '(' ) ) {
132
134
// Allow ignoring of the leading ( for PowerShell commands as it's a command pattern to
133
135
// operate on the output of a command. For example `(Get-Content README.md) ...`
134
- if ( regex . test ( actualCommand . slice ( 1 ) ) ) {
136
+ if ( rule . regexCaseInsensitive . test ( actualCommand . slice ( 1 ) ) ) {
135
137
return true ;
136
138
}
137
139
}
@@ -160,29 +162,29 @@ export class CommandLineAutoApprover extends Disposable {
160
162
161
163
Object . entries ( config ) . forEach ( ( [ key , value ] ) => {
162
164
if ( typeof value === 'boolean' ) {
163
- const regex = this . _convertAutoApproveEntryToRegex ( key ) ;
165
+ const { regex, regexCaseInsensitive } = this . _convertAutoApproveEntryToRegex ( key ) ;
164
166
// IMPORTANT: Only true and false are used, null entries need to be ignored
165
167
if ( value === true ) {
166
- allowListRules . push ( { regex, sourceText : key } ) ;
168
+ allowListRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
167
169
} else if ( value === false ) {
168
- denyListRules . push ( { regex, sourceText : key } ) ;
170
+ denyListRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
169
171
}
170
172
} else if ( typeof value === 'object' && value !== null ) {
171
173
// Handle object format like { approve: true/false, matchCommandLine: true/false }
172
174
const objectValue = value as { approve ?: boolean ; matchCommandLine ?: boolean } ;
173
175
if ( typeof objectValue . approve === 'boolean' ) {
174
- const regex = this . _convertAutoApproveEntryToRegex ( key ) ;
176
+ const { regex, regexCaseInsensitive } = this . _convertAutoApproveEntryToRegex ( key ) ;
175
177
if ( objectValue . approve === true ) {
176
178
if ( objectValue . matchCommandLine === true ) {
177
- allowListCommandLineRules . push ( { regex, sourceText : key } ) ;
179
+ allowListCommandLineRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
178
180
} else {
179
- allowListRules . push ( { regex, sourceText : key } ) ;
181
+ allowListRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
180
182
}
181
183
} else if ( objectValue . approve === false ) {
182
184
if ( objectValue . matchCommandLine === true ) {
183
- denyListCommandLineRules . push ( { regex, sourceText : key } ) ;
185
+ denyListCommandLineRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
184
186
} else {
185
- denyListRules . push ( { regex, sourceText : key } ) ;
187
+ denyListRules . push ( { regex, regexCaseInsensitive , sourceText : key } ) ;
186
188
}
187
189
}
188
190
}
@@ -197,7 +199,15 @@ export class CommandLineAutoApprover extends Disposable {
197
199
} ;
198
200
}
199
201
200
- private _convertAutoApproveEntryToRegex ( value : string ) : RegExp {
202
+ private _convertAutoApproveEntryToRegex ( value : string ) : { regex : RegExp ; regexCaseInsensitive : RegExp } {
203
+ const regex = this . _doConvertAutoApproveEntryToRegex ( value ) ;
204
+ if ( regex . flags . includes ( 'i' ) ) {
205
+ return { regex, regexCaseInsensitive : regex } ;
206
+ }
207
+ return { regex, regexCaseInsensitive : new RegExp ( regex . source , regex . flags + 'i' ) } ;
208
+ }
209
+
210
+ private _doConvertAutoApproveEntryToRegex ( value : string ) : RegExp {
201
211
// If it's wrapped in `/`, it's in regex format and should be converted directly
202
212
// Support all standard JavaScript regex flags: d, g, i, m, s, u, v, y
203
213
const regexMatch = value . match ( / ^ \/ (?< pattern > .+ ) \/ (?< flags > [ d g i m s u v y ] * ) $ / ) ;
@@ -213,6 +223,7 @@ export class CommandLineAutoApprover extends Disposable {
213
223
// Allow .* as users expect this would match everything
214
224
if ( regexPattern === '.*' ) {
215
225
return new RegExp ( regexPattern ) ;
226
+
216
227
}
217
228
218
229
try {
0 commit comments