@@ -411,6 +411,16 @@ struct InputArgs {
411411 /// swallowed as a query/file positional instead.
412412 #[ arg( long = "allow-env" , num_args = 0 .., require_equals = true , value_delimiter = ',' , value_name = "NAME" ) ]
413413 allow_env : Option < Vec < String > > ,
414+
415+ /// Grant every sandboxed permission at once (read/write/net/run/env). Disabled by
416+ /// default. Cannot be combined with the individual --allow-* flags above.
417+ #[ arg(
418+ short = 'a' ,
419+ long = "allow-all" ,
420+ default_value_t = false ,
421+ conflicts_with_all = [ "allow_net" , "allow_read" , "allow_write" , "allow_run" , "allow_env" ]
422+ ) ]
423+ allow_all : bool ,
414424}
415425
416426#[ derive( Clone , Debug , clap:: Args , Default ) ]
@@ -839,15 +849,19 @@ impl Cli {
839849 // full native access (unchanged from before this Io existed) — --allow-read/
840850 // write/net/run instead gate what a running query's read_file/write_file/http/
841851 // system builtins can do at runtime, via the ambient Io set below.
842- let mut engine = mq_lang:: DefaultEngine :: default ( ) ;
843- engine. set_io ( Shared :: new (
844- mq_lang:: SandboxedIo :: new ( mq_lang:: NativeIo :: default ( ) )
852+ let sandboxed_io = mq_lang:: SandboxedIo :: new ( mq_lang:: NativeIo :: default ( ) ) ;
853+ let sandboxed_io = if self . input . allow_all {
854+ sandboxed_io. allow_all ( )
855+ } else {
856+ sandboxed_io
845857 . allow_read ( self . input . allow_read . clone ( ) )
846858 . allow_write ( self . input . allow_write . clone ( ) )
847859 . allow_net ( self . input . allow_net )
848860 . allow_run ( self . input . allow_run )
849- . allow_env ( self . input . allow_env . clone ( ) ) ,
850- ) ) ;
861+ . allow_env ( self . input . allow_env . clone ( ) )
862+ } ;
863+ let mut engine = mq_lang:: DefaultEngine :: default ( ) ;
864+ engine. set_io ( Shared :: new ( sandboxed_io) ) ;
851865 engine. load_builtin_module ( ) ;
852866 engine. set_optimization_level ( self . optimize_level . clone ( ) . into ( ) ) ;
853867
@@ -1836,6 +1850,59 @@ mod tests {
18361850 ) ;
18371851 }
18381852
1853+ #[ test]
1854+ fn test_allow_all_flag_grants_every_capability ( ) {
1855+ // SAFETY: no other threads read/write this env var concurrently in this test.
1856+ unsafe { std:: env:: set_var ( "MQ_ALLOW_ALL_TEST_VAR" , "test_value" ) } ;
1857+ defer ! {
1858+ unsafe { std:: env:: remove_var( "MQ_ALLOW_ALL_TEST_VAR" ) } ;
1859+ }
1860+
1861+ let base_cli = |query : & str , allow_all : bool | Cli {
1862+ input : InputArgs {
1863+ input_format : Some ( InputFormat :: Null ) ,
1864+ allow_all,
1865+ ..Default :: default ( )
1866+ } ,
1867+ output : OutputArgs :: default ( ) ,
1868+ commands : None ,
1869+ query : Some ( query. to_string ( ) ) ,
1870+ files : None ,
1871+ ..Cli :: default ( )
1872+ } ;
1873+
1874+ assert ! (
1875+ base_cli( "$MQ_ALLOW_ALL_TEST_VAR" , false ) . run( ) . is_err( ) ,
1876+ "$VAR should be blocked without --allow-all"
1877+ ) ;
1878+ assert ! (
1879+ base_cli( "$MQ_ALLOW_ALL_TEST_VAR" , true ) . run( ) . is_ok( ) ,
1880+ "$VAR should succeed with --allow-all"
1881+ ) ;
1882+
1883+ let system_query = "system(\" echo\" , [\" hi\" ])" ;
1884+ assert ! (
1885+ base_cli( system_query, false ) . run( ) . is_err( ) ,
1886+ "system should be blocked without --allow-all"
1887+ ) ;
1888+ assert ! (
1889+ base_cli( system_query, true ) . run( ) . is_ok( ) ,
1890+ "system should succeed with --allow-all"
1891+ ) ;
1892+ }
1893+
1894+ #[ rstest]
1895+ #[ case( & [ "mq" , "--allow-all" , "--allow-read=/tmp" , "self" ] ) ]
1896+ #[ case( & [ "mq" , "--allow-all" , "--allow-write=/tmp" , "self" ] ) ]
1897+ #[ case( & [ "mq" , "--allow-all" , "--allow-run" , "self" ] ) ]
1898+ #[ case( & [ "mq" , "--allow-all" , "--allow-env" , "self" ] ) ]
1899+ fn test_allow_all_conflicts_with_individual_allow_flags ( #[ case] args : & [ & str ] ) {
1900+ assert ! (
1901+ Cli :: try_parse_from( args) . is_err( ) ,
1902+ "--allow-all should conflict with individual --allow-* flags"
1903+ ) ;
1904+ }
1905+
18391906 #[ rstest]
18401907 #[ case( 0.0 ) ]
18411908 #[ case( -1.0 ) ]
0 commit comments