@@ -49,8 +49,8 @@ use codex_protocol::config_types::WebSearchToolConfig;
4949use codex_protocol:: config_types:: WindowsSandboxLevel ;
5050use codex_protocol:: models:: PermissionProfile ;
5151use codex_protocol:: openai_models:: ReasoningEffort ;
52+ use codex_protocol:: permissions:: NetworkSandboxPolicy ;
5253use codex_protocol:: protocol:: AskForApproval ;
53- use codex_protocol:: protocol:: SandboxPolicy ;
5454use codex_utils_absolute_path:: AbsolutePathBuf ;
5555use codex_utils_path:: normalize_for_path_comparison;
5656use schemars:: JsonSchema ;
@@ -641,15 +641,19 @@ pub struct GhostSnapshotToml {
641641}
642642
643643impl ConfigToml {
644- /// Derive the effective sandbox policy from the configuration.
645- pub async fn derive_sandbox_policy (
644+ /// Derive the effective permission profile from legacy sandbox config.
645+ ///
646+ /// Call this only after ruling out `default_permissions`: named
647+ /// `[permissions]` profiles must be compiled through the permissions
648+ /// profile pipeline, not reconstructed from `sandbox_mode`.
649+ pub async fn derive_permission_profile (
646650 & self ,
647651 sandbox_mode_override : Option < SandboxMode > ,
648652 profile_sandbox_mode : Option < SandboxMode > ,
649653 windows_sandbox_level : WindowsSandboxLevel ,
650654 active_project : Option < & ProjectConfig > ,
651655 permission_profile_constraint : Option < & crate :: Constrained < PermissionProfile > > ,
652- ) -> SandboxPolicy {
656+ ) -> PermissionProfile {
653657 let sandbox_mode_was_explicit = sandbox_mode_override. is_some ( )
654658 || profile_sandbox_mode. is_some ( )
655659 || self . sandbox_mode . is_some ( ) ;
@@ -677,50 +681,53 @@ impl ConfigToml {
677681 } )
678682 } )
679683 . unwrap_or_default ( ) ;
680- let mut sandbox_policy = match resolved_sandbox_mode {
681- SandboxMode :: ReadOnly => SandboxPolicy :: new_read_only_policy ( ) ,
684+ let effective_sandbox_mode = if cfg ! ( target_os = "windows" )
685+ // If the experimental Windows sandbox is enabled, do not force a downgrade.
686+ && windows_sandbox_level == WindowsSandboxLevel :: Disabled
687+ && matches ! ( resolved_sandbox_mode, SandboxMode :: WorkspaceWrite )
688+ {
689+ SandboxMode :: ReadOnly
690+ } else {
691+ resolved_sandbox_mode
692+ } ;
693+
694+ let permission_profile = match effective_sandbox_mode {
695+ SandboxMode :: ReadOnly => PermissionProfile :: read_only ( ) ,
682696 SandboxMode :: WorkspaceWrite => match self . sandbox_workspace_write . as_ref ( ) {
683697 Some ( SandboxWorkspaceWrite {
684698 writable_roots,
685699 network_access,
686700 exclude_tmpdir_env_var,
687701 exclude_slash_tmp,
688- } ) => SandboxPolicy :: WorkspaceWrite {
689- writable_roots : writable_roots. clone ( ) ,
690- network_access : * network_access,
691- exclude_tmpdir_env_var : * exclude_tmpdir_env_var,
692- exclude_slash_tmp : * exclude_slash_tmp,
693- } ,
694- None => SandboxPolicy :: new_workspace_write_policy ( ) ,
702+ } ) => {
703+ let network_policy = if * network_access {
704+ NetworkSandboxPolicy :: Enabled
705+ } else {
706+ NetworkSandboxPolicy :: Restricted
707+ } ;
708+ PermissionProfile :: workspace_write_with (
709+ writable_roots,
710+ network_policy,
711+ * exclude_tmpdir_env_var,
712+ * exclude_slash_tmp,
713+ )
714+ }
715+ None => PermissionProfile :: workspace_write ( ) ,
695716 } ,
696- SandboxMode :: DangerFullAccess => SandboxPolicy :: DangerFullAccess ,
697- } ;
698- let downgrade_workspace_write_if_unsupported = |policy : & mut SandboxPolicy | {
699- if cfg ! ( target_os = "windows" )
700- // If the experimental Windows sandbox is enabled, do not force a downgrade.
701- && windows_sandbox_level == WindowsSandboxLevel :: Disabled
702- && matches ! ( & * policy, SandboxPolicy :: WorkspaceWrite { .. } )
703- {
704- * policy = SandboxPolicy :: new_read_only_policy ( ) ;
705- }
717+ SandboxMode :: DangerFullAccess => PermissionProfile :: Disabled ,
706718 } ;
707- if matches ! ( resolved_sandbox_mode, SandboxMode :: WorkspaceWrite ) {
708- downgrade_workspace_write_if_unsupported ( & mut sandbox_policy) ;
709- }
710719 if !sandbox_mode_was_explicit
711720 && let Some ( constraint) = permission_profile_constraint
712- && let Err ( err) = constraint. can_set ( & PermissionProfile :: from_legacy_sandbox_policy (
713- & sandbox_policy,
714- ) )
721+ && let Err ( err) = constraint. can_set ( & permission_profile)
715722 {
716723 tracing:: warn!(
717724 error = %err,
718725 "default sandbox policy is disallowed by requirements; falling back to required default"
719726 ) ;
720- sandbox_policy = SandboxPolicy :: new_read_only_policy ( ) ;
721- downgrade_workspace_write_if_unsupported ( & mut sandbox_policy) ;
727+ PermissionProfile :: read_only ( )
728+ } else {
729+ permission_profile
722730 }
723- sandbox_policy
724731 }
725732
726733 /// Resolves the cwd to an existing project, or returns None if ConfigToml
0 commit comments