@@ -6,6 +6,7 @@ use crossterm::style::{
6
6
Color ,
7
7
} ;
8
8
use eyre:: Result ;
9
+ use regex:: Regex ;
9
10
use serde:: Deserialize ;
10
11
use tracing:: error;
11
12
@@ -48,6 +49,17 @@ impl ExecuteCommand {
48
49
pub fn requires_acceptance ( & self , allowed_commands : Option < & Vec < String > > , allow_read_only : bool ) -> bool {
49
50
let default_arr = vec ! [ ] ;
50
51
let allowed_commands = allowed_commands. unwrap_or ( & default_arr) ;
52
+
53
+ let has_regex_match = allowed_commands
54
+ . iter ( )
55
+ . map ( |cmd| Regex :: new ( & format ! ( r"\A{}\z" , cmd) ) )
56
+ . filter ( Result :: is_ok)
57
+ . flatten ( )
58
+ . any ( |regex| regex. is_match ( & self . command ) ) ;
59
+ if has_regex_match {
60
+ return false ;
61
+ }
62
+
51
63
let Some ( args) = shlex:: split ( & self . command ) else {
52
64
return true ;
53
65
} ;
@@ -98,9 +110,6 @@ impl ExecuteCommand {
98
110
return true ;
99
111
} ,
100
112
Some ( cmd) => {
101
- if allowed_commands. contains ( cmd) {
102
- continue ;
103
- }
104
113
// Special casing for `grep`. -P flag for perl regexp has RCE issues, apparently
105
114
// should not be supported within grep but is flagged as a possibility since this is perl
106
115
// regexp.
@@ -339,4 +348,40 @@ mod tests {
339
348
) ;
340
349
}
341
350
}
351
+
352
+ #[ test]
353
+ fn test_requires_acceptance_allowed_commands ( ) {
354
+ let allowed_cmds: & [ String ] = & [
355
+ String :: from ( "git status" ) ,
356
+ String :: from ( "root" ) ,
357
+ String :: from ( "command subcommand a=[0-9]{10} b=[0-9]{10}" ) ,
358
+ String :: from ( "command subcommand && command subcommand" ) ,
359
+ ] ;
360
+ let cmds = & [
361
+ // Command first argument 'root' allowed (allows all subcommands)
362
+ ( "root" , false ) ,
363
+ ( "root subcommand" , true ) ,
364
+ // Valid allowed_command_regex matching
365
+ ( "git" , true ) ,
366
+ ( "git status" , false ) ,
367
+ ( "command subcommand a=0123456789 b=0123456789" , false ) ,
368
+ ( "command subcommand a=0123456789 b=012345678" , true ) ,
369
+ ( "command subcommand alternate a=0123456789 b=0123456789" , true ) ,
370
+ // Control characters ignored due to direct allowed_command_regex match
371
+ ( "command subcommand && command subcommand" , false ) ,
372
+ ] ;
373
+ for ( cmd, expected) in cmds {
374
+ let tool = serde_json:: from_value :: < ExecuteCommand > ( serde_json:: json!( {
375
+ "command" : cmd,
376
+ } ) )
377
+ . unwrap ( ) ;
378
+ assert_eq ! (
379
+ tool. requires_acceptance( Option :: from( & allowed_cmds. to_vec( ) ) , true ) ,
380
+ * expected,
381
+ "expected command: `{}` to have requires_acceptance: `{}`" ,
382
+ cmd,
383
+ expected
384
+ ) ;
385
+ }
386
+ }
342
387
}
0 commit comments