@@ -40,6 +40,7 @@ use crate::features::FeatureOverrides;
4040use crate :: features:: Features ;
4141use crate :: features:: FeaturesToml ;
4242use crate :: git_info:: resolve_root_git_project_for_trust;
43+ use crate :: memories:: memory_root;
4344use crate :: model_provider_info:: LEGACY_OLLAMA_CHAT_PROVIDER_ID ;
4445use crate :: model_provider_info:: LMSTUDIO_OSS_PROVIDER_ID ;
4546use crate :: model_provider_info:: ModelProviderInfo ;
@@ -1805,6 +1806,15 @@ impl Config {
18051806 Some ( & constrained_sandbox_policy) ,
18061807 ) ;
18071808 if let SandboxPolicy :: WorkspaceWrite { writable_roots, .. } = & mut sandbox_policy {
1809+ let memories_root = memory_root ( & codex_home) ;
1810+ std:: fs:: create_dir_all ( & memories_root) ?;
1811+ let memories_root = AbsolutePathBuf :: from_absolute_path ( & memories_root) ?;
1812+ if !writable_roots
1813+ . iter ( )
1814+ . any ( |existing| existing == & memories_root)
1815+ {
1816+ writable_roots. push ( memories_root) ;
1817+ }
18081818 for path in additional_writable_roots {
18091819 if !writable_roots. iter ( ) . any ( |existing| existing == & path) {
18101820 writable_roots. push ( path) ;
@@ -3156,6 +3166,56 @@ trust_level = "trusted"
31563166 Ok ( ( ) )
31573167 }
31583168
3169+ #[ test]
3170+ fn workspace_write_always_includes_memories_root_once ( ) -> std:: io:: Result < ( ) > {
3171+ let codex_home = TempDir :: new ( ) ?;
3172+ let memories_root = codex_home. path ( ) . join ( "memories" ) ;
3173+ let config = Config :: load_from_base_config_with_overrides (
3174+ ConfigToml {
3175+ sandbox_workspace_write : Some ( SandboxWorkspaceWrite {
3176+ writable_roots : vec ! [ AbsolutePathBuf :: from_absolute_path( & memories_root) ?] ,
3177+ ..Default :: default ( )
3178+ } ) ,
3179+ ..Default :: default ( )
3180+ } ,
3181+ ConfigOverrides {
3182+ sandbox_mode : Some ( SandboxMode :: WorkspaceWrite ) ,
3183+ ..Default :: default ( )
3184+ } ,
3185+ codex_home. path ( ) . to_path_buf ( ) ,
3186+ ) ?;
3187+
3188+ if cfg ! ( target_os = "windows" ) {
3189+ match config. permissions . sandbox_policy . get ( ) {
3190+ SandboxPolicy :: ReadOnly { .. } => { }
3191+ other => panic ! ( "expected read-only policy on Windows, got {other:?}" ) ,
3192+ }
3193+ } else {
3194+ assert ! (
3195+ memories_root. is_dir( ) ,
3196+ "expected memories root directory to exist at {}" ,
3197+ memories_root. display( )
3198+ ) ;
3199+ let expected_memories_root = AbsolutePathBuf :: from_absolute_path ( & memories_root) ?;
3200+ match config. permissions . sandbox_policy . get ( ) {
3201+ SandboxPolicy :: WorkspaceWrite { writable_roots, .. } => {
3202+ assert_eq ! (
3203+ writable_roots
3204+ . iter( )
3205+ . filter( |root| * * root == expected_memories_root)
3206+ . count( ) ,
3207+ 1 ,
3208+ "expected single writable root entry for {}" ,
3209+ expected_memories_root. display( )
3210+ ) ;
3211+ }
3212+ other => panic ! ( "expected workspace-write policy, got {other:?}" ) ,
3213+ }
3214+ }
3215+
3216+ Ok ( ( ) )
3217+ }
3218+
31593219 #[ test]
31603220 fn config_defaults_to_file_cli_auth_store_mode ( ) -> std:: io:: Result < ( ) > {
31613221 let codex_home = TempDir :: new ( ) ?;
0 commit comments