@@ -79,6 +79,10 @@ pub struct Config {
7979
8080 pub sandbox_policy : SandboxPolicy ,
8181
82+ /// True if the user passed in an override or set a value in config.toml
83+ /// for either of approval_policy or sandbox_mode.
84+ pub did_user_set_custom_approval_policy_or_sandbox_mode : bool ,
85+
8286 pub shell_environment_policy : ShellEnvironmentPolicy ,
8387
8488 /// When `true`, `AgentReasoning` events emitted by the backend will be
@@ -754,12 +758,18 @@ impl From<ToolsToml> for Tools {
754758
755759impl ConfigToml {
756760 /// Derive the effective sandbox policy from the configuration.
757- pub fn derive_sandbox_policy (
761+ fn derive_sandbox_policy (
758762 & self ,
759763 sandbox_mode_override : Option < SandboxMode > ,
764+ resolved_cwd : & Path ,
760765 ) -> SandboxPolicy {
761766 let resolved_sandbox_mode = sandbox_mode_override
762767 . or ( self . sandbox_mode )
768+ . or_else ( || {
769+ // if no sandbox_mode is set, but user has marked directory as trusted, use WorkspaceWrite
770+ self . is_cwd_trusted ( resolved_cwd)
771+ . then_some ( SandboxMode :: WorkspaceWrite )
772+ } )
763773 . unwrap_or_default ( ) ;
764774 match resolved_sandbox_mode {
765775 SandboxMode :: ReadOnly => SandboxPolicy :: new_read_only_policy ( ) ,
@@ -863,7 +873,7 @@ impl Config {
863873 model,
864874 review_model : override_review_model,
865875 cwd,
866- approval_policy,
876+ approval_policy : approval_policy_override ,
867877 sandbox_mode,
868878 model_provider,
869879 config_profile : config_profile_key,
@@ -894,7 +904,42 @@ impl Config {
894904 None => ConfigProfile :: default ( ) ,
895905 } ;
896906
897- let sandbox_policy = cfg. derive_sandbox_policy ( sandbox_mode) ;
907+ let resolved_cwd = {
908+ use std:: env;
909+
910+ match cwd {
911+ None => {
912+ tracing:: info!( "cwd not set, using current dir" ) ;
913+ env:: current_dir ( ) ?
914+ }
915+ Some ( p) if p. is_absolute ( ) => p,
916+ Some ( p) => {
917+ // Resolve relative path against the current working directory.
918+ tracing:: info!( "cwd is relative, resolving against current dir" ) ;
919+ let mut current = env:: current_dir ( ) ?;
920+ current. push ( p) ;
921+ current
922+ }
923+ }
924+ } ;
925+
926+ let sandbox_policy = cfg. derive_sandbox_policy ( sandbox_mode, & resolved_cwd) ;
927+ let approval_policy = approval_policy_override
928+ . or ( config_profile. approval_policy )
929+ . or ( cfg. approval_policy )
930+ . or_else ( || {
931+ // If no explicit approval policy is set, but we trust cwd, default to OnRequest
932+ cfg. is_cwd_trusted ( & resolved_cwd)
933+ . then_some ( AskForApproval :: OnRequest )
934+ } )
935+ . unwrap_or_else ( AskForApproval :: default) ;
936+ let did_user_set_custom_approval_policy_or_sandbox_mode = approval_policy_override
937+ . is_some ( )
938+ || config_profile. approval_policy . is_some ( )
939+ || cfg. approval_policy . is_some ( )
940+ // TODO: policy.sandbox_mode is not implemented
941+ || sandbox_mode. is_some ( )
942+ || cfg. sandbox_mode . is_some ( ) ;
898943
899944 let mut model_providers = built_in_model_providers ( ) ;
900945 // Merge user-defined providers into the built-in list.
@@ -918,25 +963,6 @@ impl Config {
918963
919964 let shell_environment_policy = cfg. shell_environment_policy . into ( ) ;
920965
921- let resolved_cwd = {
922- use std:: env;
923-
924- match cwd {
925- None => {
926- tracing:: info!( "cwd not set, using current dir" ) ;
927- env:: current_dir ( ) ?
928- }
929- Some ( p) if p. is_absolute ( ) => p,
930- Some ( p) => {
931- // Resolve relative path against the current working directory.
932- tracing:: info!( "cwd is relative, resolving against current dir" ) ;
933- let mut current = env:: current_dir ( ) ?;
934- current. push ( p) ;
935- current
936- }
937- }
938- } ;
939-
940966 let history = cfg. history . unwrap_or_default ( ) ;
941967
942968 let tools_web_search_request = override_tools_web_search_request
@@ -1003,11 +1029,9 @@ impl Config {
10031029 model_provider_id,
10041030 model_provider,
10051031 cwd : resolved_cwd,
1006- approval_policy : approval_policy
1007- . or ( config_profile. approval_policy )
1008- . or ( cfg. approval_policy )
1009- . unwrap_or_else ( AskForApproval :: default) ,
1032+ approval_policy,
10101033 sandbox_policy,
1034+ did_user_set_custom_approval_policy_or_sandbox_mode,
10111035 shell_environment_policy,
10121036 notify : cfg. notify ,
10131037 user_instructions,
@@ -1230,7 +1254,8 @@ network_access = false # This should be ignored.
12301254 let sandbox_mode_override = None ;
12311255 assert_eq ! (
12321256 SandboxPolicy :: DangerFullAccess ,
1233- sandbox_full_access_cfg. derive_sandbox_policy( sandbox_mode_override)
1257+ sandbox_full_access_cfg
1258+ . derive_sandbox_policy( sandbox_mode_override, & PathBuf :: from( "/tmp/test" ) )
12341259 ) ;
12351260
12361261 let sandbox_read_only = r#"
@@ -1245,7 +1270,8 @@ network_access = true # This should be ignored.
12451270 let sandbox_mode_override = None ;
12461271 assert_eq ! (
12471272 SandboxPolicy :: ReadOnly ,
1248- sandbox_read_only_cfg. derive_sandbox_policy( sandbox_mode_override)
1273+ sandbox_read_only_cfg
1274+ . derive_sandbox_policy( sandbox_mode_override, & PathBuf :: from( "/tmp/test" ) )
12491275 ) ;
12501276
12511277 let sandbox_workspace_write = r#"
@@ -1269,7 +1295,36 @@ exclude_slash_tmp = true
12691295 exclude_tmpdir_env_var: true ,
12701296 exclude_slash_tmp: true ,
12711297 } ,
1272- sandbox_workspace_write_cfg. derive_sandbox_policy( sandbox_mode_override)
1298+ sandbox_workspace_write_cfg
1299+ . derive_sandbox_policy( sandbox_mode_override, & PathBuf :: from( "/tmp/test" ) )
1300+ ) ;
1301+
1302+ let sandbox_workspace_write = r#"
1303+ sandbox_mode = "workspace-write"
1304+
1305+ [sandbox_workspace_write]
1306+ writable_roots = [
1307+ "/my/workspace",
1308+ ]
1309+ exclude_tmpdir_env_var = true
1310+ exclude_slash_tmp = true
1311+
1312+ [projects."/tmp/test"]
1313+ trust_level = "trusted"
1314+ "# ;
1315+
1316+ let sandbox_workspace_write_cfg = toml:: from_str :: < ConfigToml > ( sandbox_workspace_write)
1317+ . expect ( "TOML deserialization should succeed" ) ;
1318+ let sandbox_mode_override = None ;
1319+ assert_eq ! (
1320+ SandboxPolicy :: WorkspaceWrite {
1321+ writable_roots: vec![ PathBuf :: from( "/my/workspace" ) ] ,
1322+ network_access: false ,
1323+ exclude_tmpdir_env_var: true ,
1324+ exclude_slash_tmp: true ,
1325+ } ,
1326+ sandbox_workspace_write_cfg
1327+ . derive_sandbox_policy( sandbox_mode_override, & PathBuf :: from( "/tmp/test" ) )
12731328 ) ;
12741329 }
12751330
@@ -1631,6 +1686,7 @@ model_verbosity = "high"
16311686 model_provider: fixture. openai_provider. clone( ) ,
16321687 approval_policy: AskForApproval :: Never ,
16331688 sandbox_policy: SandboxPolicy :: new_read_only_policy( ) ,
1689+ did_user_set_custom_approval_policy_or_sandbox_mode: true ,
16341690 shell_environment_policy: ShellEnvironmentPolicy :: default ( ) ,
16351691 user_instructions: None ,
16361692 notify: None ,
@@ -1689,6 +1745,7 @@ model_verbosity = "high"
16891745 model_provider : fixture. openai_chat_completions_provider . clone ( ) ,
16901746 approval_policy : AskForApproval :: UnlessTrusted ,
16911747 sandbox_policy : SandboxPolicy :: new_read_only_policy ( ) ,
1748+ did_user_set_custom_approval_policy_or_sandbox_mode : true ,
16921749 shell_environment_policy : ShellEnvironmentPolicy :: default ( ) ,
16931750 user_instructions : None ,
16941751 notify : None ,
@@ -1762,6 +1819,7 @@ model_verbosity = "high"
17621819 model_provider : fixture. openai_provider . clone ( ) ,
17631820 approval_policy : AskForApproval :: OnFailure ,
17641821 sandbox_policy : SandboxPolicy :: new_read_only_policy ( ) ,
1822+ did_user_set_custom_approval_policy_or_sandbox_mode : true ,
17651823 shell_environment_policy : ShellEnvironmentPolicy :: default ( ) ,
17661824 user_instructions : None ,
17671825 notify : None ,
@@ -1821,6 +1879,7 @@ model_verbosity = "high"
18211879 model_provider : fixture. openai_provider . clone ( ) ,
18221880 approval_policy : AskForApproval :: OnFailure ,
18231881 sandbox_policy : SandboxPolicy :: new_read_only_policy ( ) ,
1882+ did_user_set_custom_approval_policy_or_sandbox_mode : true ,
18241883 shell_environment_policy : ShellEnvironmentPolicy :: default ( ) ,
18251884 user_instructions : None ,
18261885 notify : None ,
0 commit comments