mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
permissions: make legacy profile conversion cwd-free (#19414)
## Why The profile conversion path still required a `cwd` even when it was only translating a legacy `SandboxPolicy` into a `PermissionProfile`. That made profile producers invent an ambient `cwd`, which is exactly the anchoring we are trying to remove from permission-profile data. A legacy workspace-write policy can be represented symbolically instead: `:cwd = write` plus read-only `:project_roots` metadata subpaths. This PR creates that cwd-free base so the rest of the stack can stop threading cwd through profile construction. Callers that actually need a concrete runtime filesystem policy for a specific cwd still have an explicitly named cwd-bound conversion. ## What Changed - `PermissionProfile::from_legacy_sandbox_policy` now takes only `&SandboxPolicy`. - `FileSystemSandboxPolicy::from_legacy_sandbox_policy` is now the symbolic, cwd-free projection for profiles. - The old concrete projection is retained as `FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd` for runtime/boundary code that must materialize legacy cwd behavior. - Workspace-write profiles preserve `CurrentWorkingDirectory` and `ProjectRoots` special entries instead of materializing cwd into absolute paths. ## Verification - `cargo check -p codex-protocol -p codex-core -p codex-app-server-protocol -p codex-app-server -p codex-exec -p codex-exec-server -p codex-tui -p codex-sandboxing -p codex-linux-sandbox -p codex-analytics --tests` - `just fix -p codex-protocol -p codex-core -p codex-app-server-protocol -p codex-app-server -p codex-exec -p codex-exec-server -p codex-tui -p codex-sandboxing -p codex-linux-sandbox -p codex-analytics` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19414). * #19395 * #19394 * #19393 * #19392 * #19391 * __->__ #19414
This commit is contained in:
committed by
GitHub
Unverified
parent
7262c0c450
commit
13e0ec1614
@@ -161,11 +161,7 @@ fn sample_thread_start_response(thread_id: &str, ephemeral: bool, model: &str) -
|
||||
}
|
||||
|
||||
fn sample_permission_profile() -> AppServerPermissionProfile {
|
||||
CorePermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
&test_path_buf("/tmp"),
|
||||
)
|
||||
.into()
|
||||
CorePermissionProfile::from_legacy_sandbox_policy(&SandboxPolicy::DangerFullAccess).into()
|
||||
}
|
||||
|
||||
fn sample_app_server_client_metadata() -> CodexAppServerClientMetadata {
|
||||
|
||||
@@ -1471,7 +1471,7 @@ mod tests {
|
||||
model: "gpt-5".to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: None,
|
||||
cwd: cwd.clone(),
|
||||
cwd,
|
||||
instruction_sources: vec![absolute_path("/tmp/AGENTS.md")],
|
||||
approval_policy: v2::AskForApproval::OnFailure,
|
||||
approvals_reviewer: v2::ApprovalsReviewer::User,
|
||||
@@ -1479,7 +1479,6 @@ mod tests {
|
||||
permission_profile: Some(
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&codex_protocol::protocol::SandboxPolicy::DangerFullAccess,
|
||||
cwd.as_path(),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
|
||||
@@ -2291,7 +2291,7 @@ impl CodexMessageProcessor {
|
||||
match self.config.permissions.sandbox_policy.can_set(&policy) {
|
||||
Ok(()) => {
|
||||
let file_system_sandbox_policy =
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, &sandbox_cwd);
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&policy, &sandbox_cwd);
|
||||
let network_sandbox_policy =
|
||||
codex_protocol::permissions::NetworkSandboxPolicy::from(&policy);
|
||||
(policy, file_system_sandbox_policy, network_sandbox_policy)
|
||||
@@ -10545,18 +10545,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn thread_response_permission_profile_preserves_enforcement() {
|
||||
let cwd = test_path_buf("/tmp").abs();
|
||||
let full_access_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
cwd.as_path(),
|
||||
);
|
||||
let external_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::ExternalSandbox {
|
||||
network_access: codex_protocol::protocol::NetworkAccess::Restricted,
|
||||
},
|
||||
cwd.as_path(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
@@ -10575,17 +10572,14 @@ mod tests {
|
||||
let full_access_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
cwd.as_path(),
|
||||
);
|
||||
let workspace_write_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
cwd.as_path(),
|
||||
);
|
||||
let read_only_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.as_path(),
|
||||
);
|
||||
|
||||
assert!(requested_permissions_trust_project(
|
||||
@@ -10797,7 +10791,6 @@ mod tests {
|
||||
permission_profile:
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&codex_protocol::protocol::SandboxPolicy::DangerFullAccess,
|
||||
cwd.as_path(),
|
||||
),
|
||||
cwd,
|
||||
ephemeral: false,
|
||||
|
||||
@@ -1583,7 +1583,7 @@ exclude_slash_tmp = true
|
||||
let sandbox_policy = config.permissions.sandbox_policy.get();
|
||||
assert_eq!(
|
||||
config.permissions.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, cwd.path()),
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd.path()),
|
||||
"case `{name}` should preserve filesystem semantics from legacy config"
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -1866,7 +1866,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&sandbox_policy,
|
||||
resolved_cwd.as_path(),
|
||||
);
|
||||
|
||||
@@ -36,8 +36,10 @@ pub async fn spawn_command_under_linux_sandbox<P>(
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_policy_cwd);
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
sandbox_policy,
|
||||
sandbox_policy_cwd,
|
||||
);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(sandbox_policy);
|
||||
let args = create_linux_sandbox_command_args_for_policies(
|
||||
command,
|
||||
|
||||
@@ -329,7 +329,7 @@ mod agent {
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
let consolidation_file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&consolidation_sandbox_policy,
|
||||
agent_config.cwd.as_path(),
|
||||
);
|
||||
|
||||
@@ -742,7 +742,7 @@ mod phase2 {
|
||||
let turn_context = subagent.codex.session.new_default_turn().await;
|
||||
pretty_assertions::assert_eq!(
|
||||
turn_context.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&config_snapshot.sandbox_policy,
|
||||
config_snapshot.cwd.as_path(),
|
||||
),
|
||||
|
||||
@@ -178,7 +178,7 @@ fn read_only_policy_rejects_patch_with_read_only_reason() {
|
||||
let action = ApplyPatchAction::new_add_for_test(&inside_path, "".to_string());
|
||||
let sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, &cwd);
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &cwd);
|
||||
|
||||
assert!(!is_write_patch_constrained_to_writable_paths(
|
||||
&action,
|
||||
@@ -300,7 +300,7 @@ fn missing_project_dot_codex_config_requires_approval() {
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, &cwd);
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &cwd);
|
||||
|
||||
assert!(!is_write_patch_constrained_to_writable_paths(
|
||||
&action,
|
||||
|
||||
@@ -121,7 +121,7 @@ impl SessionConfiguration {
|
||||
pub(crate) fn apply(&self, updates: &SessionSettingsUpdate) -> ConstraintResult<Self> {
|
||||
let mut next_configuration = self.clone();
|
||||
let file_system_policy_matches_legacy = self.file_system_sandbox_policy
|
||||
== FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
== FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
self.sandbox_policy.get(),
|
||||
&self.cwd,
|
||||
);
|
||||
@@ -201,7 +201,7 @@ impl SessionConfiguration {
|
||||
// Preserve richer split policies across cwd-only updates; only
|
||||
// rederive when the session is already using the legacy bridge.
|
||||
next_configuration.file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
next_configuration.sandbox_policy.get(),
|
||||
&next_configuration.cwd,
|
||||
);
|
||||
|
||||
@@ -1496,7 +1496,6 @@ async fn session_configured_reports_permission_profile_for_external_sandbox() ->
|
||||
let expected_permission_profile =
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&expected_sandbox_policy,
|
||||
test.session_configured.cwd.as_path(),
|
||||
);
|
||||
assert_eq!(
|
||||
test.session_configured.permission_profile,
|
||||
@@ -2886,15 +2885,16 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
|
||||
},
|
||||
access: FileSystemAccessMode::None,
|
||||
};
|
||||
let mut existing_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&workspace_policy,
|
||||
session_configuration.cwd.as_path(),
|
||||
);
|
||||
let mut existing_file_system_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&workspace_policy,
|
||||
session_configuration.cwd.as_path(),
|
||||
);
|
||||
existing_file_system_policy.glob_scan_max_depth = Some(2);
|
||||
existing_file_system_policy.entries.push(deny_entry.clone());
|
||||
session_configuration.file_system_sandbox_policy = existing_file_system_policy;
|
||||
|
||||
let requested_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let requested_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&workspace_policy,
|
||||
session_configuration.cwd.as_path(),
|
||||
);
|
||||
@@ -3027,7 +3027,7 @@ async fn session_configuration_apply_rederives_legacy_file_system_policy_on_cwd_
|
||||
exclude_slash_tmp: true,
|
||||
});
|
||||
session_configuration.file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
session_configuration.sandbox_policy.get(),
|
||||
&session_configuration.cwd,
|
||||
);
|
||||
@@ -3041,7 +3041,7 @@ async fn session_configuration_apply_rederives_legacy_file_system_policy_on_cwd_
|
||||
|
||||
assert_eq!(
|
||||
updated.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
updated.sandbox_policy.get(),
|
||||
&project_root,
|
||||
)
|
||||
@@ -5460,7 +5460,7 @@ async fn build_initial_context_restates_realtime_start_when_reference_context_is
|
||||
}
|
||||
|
||||
fn file_system_policy_with_unreadable_glob(turn_context: &TurnContext) -> FileSystemSandboxPolicy {
|
||||
let mut policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let mut policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
turn_context.sandbox_policy.get(),
|
||||
&turn_context.cwd,
|
||||
);
|
||||
@@ -5476,10 +5476,11 @@ fn file_system_policy_with_unreadable_glob(turn_context: &TurnContext) -> FileSy
|
||||
#[tokio::test]
|
||||
async fn turn_context_item_omits_legacy_equivalent_file_system_sandbox_policy() {
|
||||
let (_session, mut turn_context) = make_session_and_context().await;
|
||||
turn_context.file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
turn_context.sandbox_policy.get(),
|
||||
&turn_context.cwd,
|
||||
);
|
||||
turn_context.file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
turn_context.sandbox_policy.get(),
|
||||
&turn_context.cwd,
|
||||
);
|
||||
|
||||
let item = turn_context.to_turn_context_item();
|
||||
|
||||
|
||||
@@ -280,10 +280,11 @@ impl TurnContext {
|
||||
// the legacy sandbox policy. This keeps turn-context payloads stable
|
||||
// while both fields exist; once callers consume only the split policy,
|
||||
// this comparison and the legacy projection should go away.
|
||||
let legacy_file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
self.sandbox_policy.get(),
|
||||
&self.cwd,
|
||||
);
|
||||
let legacy_file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
self.sandbox_policy.get(),
|
||||
&self.cwd,
|
||||
);
|
||||
(self.file_system_sandbox_policy != legacy_file_system_sandbox_policy)
|
||||
.then(|| self.file_system_sandbox_policy.clone())
|
||||
}
|
||||
|
||||
@@ -2101,7 +2101,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
turn.config.permissions.sandbox_policy.get().clone(),
|
||||
);
|
||||
let expected_file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&expected_sandbox, &turn.cwd);
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&expected_sandbox, &turn.cwd);
|
||||
let expected_network_sandbox_policy = NetworkSandboxPolicy::from(&expected_sandbox);
|
||||
turn.approval_policy
|
||||
.set(AskForApproval::OnRequest)
|
||||
@@ -3620,7 +3620,7 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
turn.config.permissions.sandbox_policy.get().clone(),
|
||||
);
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, &turn.cwd);
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &turn.cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
turn.sandbox_policy
|
||||
.set(sandbox_policy)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use async_trait::async_trait;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::SandboxEnforcement;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxKind;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use std::path::Path;
|
||||
@@ -57,8 +59,13 @@ pub struct FileSystemSandboxContext {
|
||||
|
||||
impl FileSystemSandboxContext {
|
||||
pub fn from_legacy_sandbox_policy(sandbox_policy: SandboxPolicy, cwd: AbsolutePathBuf) -> Self {
|
||||
let permissions =
|
||||
PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy, cwd.as_path());
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&sandbox_policy, &cwd);
|
||||
let permissions = PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
);
|
||||
Self::from_permission_profile_with_cwd(permissions, cwd)
|
||||
}
|
||||
|
||||
|
||||
@@ -430,7 +430,6 @@ fn session_configured_from_thread_response_uses_review_policy_from_response() {
|
||||
permission_profile: Some(
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&codex_protocol::protocol::SandboxPolicy::new_workspace_write_policy(),
|
||||
&test_path_buf("/tmp"),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
|
||||
@@ -44,7 +44,7 @@ async fn spawn_command_under_sandbox(
|
||||
arg0: None,
|
||||
},
|
||||
sandbox_policy,
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_cwd),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(sandbox_policy, sandbox_cwd),
|
||||
NetworkSandboxPolicy::from(sandbox_policy),
|
||||
sandbox_cwd,
|
||||
&codex_linux_sandbox_exe,
|
||||
|
||||
@@ -324,7 +324,7 @@ fn resolve_sandbox_policies(
|
||||
})
|
||||
}
|
||||
(Some(sandbox_policy), None) => Ok(EffectiveSandboxPolicies {
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
file_system_sandbox_policy: FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&sandbox_policy,
|
||||
sandbox_policy_cwd,
|
||||
),
|
||||
@@ -354,8 +354,14 @@ fn legacy_sandbox_policies_match_semantics(
|
||||
) -> bool {
|
||||
NetworkSandboxPolicy::from(provided) == NetworkSandboxPolicy::from(derived)
|
||||
&& file_system_sandbox_policies_match_semantics(
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(provided, sandbox_policy_cwd),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(derived, sandbox_policy_cwd),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
provided,
|
||||
sandbox_policy_cwd,
|
||||
),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
derived,
|
||||
sandbox_policy_cwd,
|
||||
),
|
||||
sandbox_policy_cwd,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -429,10 +429,10 @@ impl PermissionProfile {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_legacy_sandbox_policy(sandbox_policy: &SandboxPolicy, cwd: &Path) -> Self {
|
||||
pub fn from_legacy_sandbox_policy(sandbox_policy: &SandboxPolicy) -> Self {
|
||||
Self::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(sandbox_policy),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, cwd),
|
||||
&FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy),
|
||||
NetworkSandboxPolicy::from(sandbox_policy),
|
||||
)
|
||||
}
|
||||
@@ -1765,10 +1765,8 @@ mod tests {
|
||||
#[test]
|
||||
fn permission_profile_round_trip_preserves_disabled_sandbox() -> Result<()> {
|
||||
let cwd = tempdir()?;
|
||||
let permission_profile = PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::DangerFullAccess,
|
||||
cwd.path(),
|
||||
);
|
||||
let permission_profile =
|
||||
PermissionProfile::from_legacy_sandbox_policy(&SandboxPolicy::DangerFullAccess);
|
||||
|
||||
assert_eq!(permission_profile, PermissionProfile::Disabled);
|
||||
assert_eq!(
|
||||
@@ -1839,8 +1837,7 @@ mod tests {
|
||||
let sandbox_policy = SandboxPolicy::ExternalSandbox {
|
||||
network_access: crate::protocol::NetworkAccess::Restricted,
|
||||
};
|
||||
let permission_profile =
|
||||
PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy, cwd.path());
|
||||
let permission_profile = PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy);
|
||||
|
||||
assert_eq!(
|
||||
permission_profile,
|
||||
|
||||
@@ -321,7 +321,7 @@ impl FileSystemSandboxPolicy {
|
||||
cwd: &Path,
|
||||
existing: &Self,
|
||||
) -> Self {
|
||||
let mut rebuilt = Self::from_legacy_sandbox_policy(sandbox_policy, cwd);
|
||||
let mut rebuilt = Self::from_legacy_sandbox_policy_for_cwd(sandbox_policy, cwd);
|
||||
if !matches!(rebuilt.kind, FileSystemSandboxKind::Restricted) {
|
||||
return rebuilt;
|
||||
}
|
||||
@@ -413,30 +413,74 @@ impl FileSystemSandboxPolicy {
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts a legacy sandbox policy into a cwd-independent filesystem policy.
|
||||
///
|
||||
/// `WorkspaceWrite` uses symbolic entries for cwd-scoped access so callers
|
||||
/// can preserve the active cwd binding until the policy is actually
|
||||
/// resolved for a turn or command.
|
||||
pub fn from_legacy_sandbox_policy(sandbox_policy: &SandboxPolicy) -> Self {
|
||||
let mut file_system_policy = Self::from(sandbox_policy);
|
||||
let SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots,
|
||||
exclude_tmpdir_env_var,
|
||||
exclude_slash_tmp,
|
||||
..
|
||||
} = sandbox_policy
|
||||
else {
|
||||
return file_system_policy;
|
||||
};
|
||||
|
||||
prune_read_entries_under_writable_roots(
|
||||
&mut file_system_policy.entries,
|
||||
&legacy_non_cwd_writable_roots(
|
||||
writable_roots,
|
||||
*exclude_tmpdir_env_var,
|
||||
*exclude_slash_tmp,
|
||||
),
|
||||
);
|
||||
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
".git",
|
||||
);
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
".agents",
|
||||
);
|
||||
append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
".codex",
|
||||
);
|
||||
for writable_root in writable_roots {
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
writable_root,
|
||||
/*protect_missing_dot_codex*/ false,
|
||||
) {
|
||||
append_default_read_only_path_if_no_explicit_rule(
|
||||
&mut file_system_policy.entries,
|
||||
protected_path,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
file_system_policy
|
||||
}
|
||||
|
||||
/// Converts a legacy sandbox policy into an equivalent filesystem policy
|
||||
/// for the provided cwd.
|
||||
/// after resolving cwd-sensitive legacy defaults for the provided cwd.
|
||||
///
|
||||
/// Legacy `WorkspaceWrite` policies may list readable roots that live
|
||||
/// under an already-writable root. Those paths were redundant in the
|
||||
/// legacy model and should not become read-only carveouts when projected
|
||||
/// into split filesystem policy.
|
||||
pub fn from_legacy_sandbox_policy(sandbox_policy: &SandboxPolicy, cwd: &Path) -> Self {
|
||||
pub fn from_legacy_sandbox_policy_for_cwd(sandbox_policy: &SandboxPolicy, cwd: &Path) -> Self {
|
||||
let mut file_system_policy = Self::from(sandbox_policy);
|
||||
if let SandboxPolicy::WorkspaceWrite { writable_roots, .. } = sandbox_policy {
|
||||
let legacy_writable_roots = sandbox_policy.get_writable_roots_with_cwd(cwd);
|
||||
file_system_policy.entries.retain(|entry| {
|
||||
if entry.access != FileSystemAccessMode::Read {
|
||||
return true;
|
||||
}
|
||||
|
||||
match &entry.path {
|
||||
FileSystemPath::Path { path } => !legacy_writable_roots
|
||||
.iter()
|
||||
.any(|root| root.is_path_writable(path.as_path())),
|
||||
FileSystemPath::GlobPattern { .. } => true,
|
||||
FileSystemPath::Special { .. } => true,
|
||||
}
|
||||
});
|
||||
prune_read_entries_under_writable_roots(
|
||||
&mut file_system_policy.entries,
|
||||
&legacy_writable_roots,
|
||||
);
|
||||
|
||||
if let Ok(cwd_root) = AbsolutePathBuf::from_absolute_path(cwd) {
|
||||
for protected_path in default_read_only_subpaths_for_writable_root(
|
||||
@@ -584,7 +628,7 @@ impl FileSystemSandboxPolicy {
|
||||
};
|
||||
|
||||
self.semantic_signature(cwd)
|
||||
!= FileSystemSandboxPolicy::from_legacy_sandbox_policy(&legacy_policy, cwd)
|
||||
!= FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&legacy_policy, cwd)
|
||||
.semantic_signature(cwd)
|
||||
}
|
||||
|
||||
@@ -1378,41 +1422,92 @@ fn default_read_only_subpaths_for_writable_root(
|
||||
dedup_absolute_paths(subpaths, /*normalize_effective_paths*/ false)
|
||||
}
|
||||
|
||||
fn append_path_entry_if_missing(
|
||||
fn append_default_read_only_project_root_subpath_if_no_explicit_rule(
|
||||
entries: &mut Vec<FileSystemSandboxEntry>,
|
||||
path: AbsolutePathBuf,
|
||||
access: FileSystemAccessMode,
|
||||
subpath: impl Into<PathBuf>,
|
||||
) {
|
||||
if entries.iter().any(|entry| {
|
||||
entry.access == access
|
||||
&& matches!(
|
||||
&entry.path,
|
||||
FileSystemPath::Path { path: existing } if existing == &path
|
||||
)
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
||||
entries.push(FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path { path },
|
||||
access,
|
||||
});
|
||||
append_default_read_only_entry_if_no_explicit_rule(
|
||||
entries,
|
||||
FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(subpath.into())),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn append_default_read_only_path_if_no_explicit_rule(
|
||||
entries: &mut Vec<FileSystemSandboxEntry>,
|
||||
path: AbsolutePathBuf,
|
||||
) {
|
||||
if entries.iter().any(|entry| {
|
||||
matches!(
|
||||
&entry.path,
|
||||
FileSystemPath::Path { path: existing } if existing == &path
|
||||
)
|
||||
}) {
|
||||
append_default_read_only_entry_if_no_explicit_rule(entries, FileSystemPath::Path { path });
|
||||
}
|
||||
|
||||
fn append_default_read_only_entry_if_no_explicit_rule(
|
||||
entries: &mut Vec<FileSystemSandboxEntry>,
|
||||
path: FileSystemPath,
|
||||
) {
|
||||
if entries
|
||||
.iter()
|
||||
.any(|entry| file_system_paths_share_target(&entry.path, &path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
append_path_entry_if_missing(entries, path, FileSystemAccessMode::Read);
|
||||
entries.push(FileSystemSandboxEntry {
|
||||
path,
|
||||
access: FileSystemAccessMode::Read,
|
||||
});
|
||||
}
|
||||
|
||||
fn prune_read_entries_under_writable_roots(
|
||||
entries: &mut Vec<FileSystemSandboxEntry>,
|
||||
legacy_writable_roots: &[WritableRoot],
|
||||
) {
|
||||
entries.retain(|entry| {
|
||||
if entry.access != FileSystemAccessMode::Read {
|
||||
return true;
|
||||
}
|
||||
|
||||
match &entry.path {
|
||||
FileSystemPath::Path { path } => !legacy_writable_roots
|
||||
.iter()
|
||||
.any(|root| root.is_path_writable(path.as_path())),
|
||||
FileSystemPath::GlobPattern { .. } | FileSystemPath::Special { .. } => true,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn legacy_non_cwd_writable_roots(
|
||||
writable_roots: &[AbsolutePathBuf],
|
||||
exclude_tmpdir_env_var: bool,
|
||||
exclude_slash_tmp: bool,
|
||||
) -> Vec<WritableRoot> {
|
||||
let mut roots: Vec<AbsolutePathBuf> = writable_roots.to_vec();
|
||||
|
||||
if cfg!(unix)
|
||||
&& !exclude_slash_tmp
|
||||
&& let Ok(slash_tmp) = AbsolutePathBuf::from_absolute_path("/tmp")
|
||||
&& slash_tmp.as_path().is_dir()
|
||||
{
|
||||
roots.push(slash_tmp);
|
||||
}
|
||||
|
||||
if !exclude_tmpdir_env_var
|
||||
&& let Some(tmpdir) = std::env::var_os("TMPDIR")
|
||||
&& !tmpdir.is_empty()
|
||||
&& let Ok(tmpdir_path) = AbsolutePathBuf::from_absolute_path(PathBuf::from(tmpdir))
|
||||
{
|
||||
roots.push(tmpdir_path);
|
||||
}
|
||||
|
||||
dedup_absolute_paths(roots, /*normalize_effective_paths*/ true)
|
||||
.into_iter()
|
||||
.map(|root| WritableRoot {
|
||||
read_only_subpaths: default_read_only_subpaths_for_writable_root(
|
||||
&root, /*protect_missing_dot_codex*/ false,
|
||||
),
|
||||
root,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn has_explicit_resolved_path_entry(
|
||||
@@ -1552,6 +1647,50 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_workspace_write_projection_preserves_symbolic_cwd() {
|
||||
let policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
read_only_access: ReadOnlyAccess::Restricted {
|
||||
include_platform_defaults: false,
|
||||
readable_roots: Vec::new(),
|
||||
},
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
exclude_slash_tmp: true,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy),
|
||||
FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::CurrentWorkingDirectory,
|
||||
},
|
||||
access: FileSystemAccessMode::Write,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(".git".into())),
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(".agents".into())),
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(Some(".codex".into())),
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn writable_roots_skip_default_dot_codex_when_explicit_user_rule_exists() {
|
||||
@@ -1612,7 +1751,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let file_system_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, cwd.path());
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&policy, cwd.path());
|
||||
|
||||
assert!(!file_system_policy.can_write_path_with_cwd(&dot_codex_config, cwd.path()));
|
||||
}
|
||||
@@ -1639,7 +1778,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let file_system_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, relative_cwd);
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&policy, relative_cwd);
|
||||
|
||||
assert_eq!(
|
||||
file_system_policy,
|
||||
@@ -2098,7 +2237,7 @@ mod tests {
|
||||
policy.needs_direct_runtime_enforcement(NetworkSandboxPolicy::Restricted, cwd.path(),)
|
||||
);
|
||||
|
||||
let legacy_workspace_write = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let legacy_workspace_write = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
|
||||
@@ -3058,7 +3058,7 @@ impl TurnContextItem {
|
||||
self.permission_profile.clone().unwrap_or_else(|| {
|
||||
let file_system_sandbox_policy =
|
||||
self.file_system_sandbox_policy.clone().unwrap_or_else(|| {
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&self.sandbox_policy,
|
||||
&self.cwd,
|
||||
)
|
||||
@@ -4644,7 +4644,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
sorted_writable_roots(
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&policy, cwd.path())
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&policy, cwd.path())
|
||||
.get_writable_roots_with_cwd(cwd.path())
|
||||
),
|
||||
vec![(canonical_cwd, vec![expected_dot_codex.to_path_buf()])]
|
||||
@@ -4736,9 +4736,10 @@ mod tests {
|
||||
];
|
||||
|
||||
for expected in policies {
|
||||
let actual = FileSystemSandboxPolicy::from_legacy_sandbox_policy(&expected, cwd.path())
|
||||
.to_legacy_sandbox_policy(NetworkSandboxPolicy::from(&expected), cwd.path())
|
||||
.expect("legacy bridge should preserve legacy policy semantics");
|
||||
let actual =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(&expected, cwd.path())
|
||||
.to_legacy_sandbox_policy(NetworkSandboxPolicy::from(&expected), cwd.path())
|
||||
.expect("legacy bridge should preserve legacy policy semantics");
|
||||
|
||||
assert_same_sandbox_policy_semantics(&expected, &actual, cwd.path());
|
||||
}
|
||||
|
||||
@@ -532,8 +532,10 @@ fn create_seatbelt_command_args_for_legacy_policy(
|
||||
enforce_managed_network: bool,
|
||||
network: Option<&NetworkProxy>,
|
||||
) -> Vec<String> {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(sandbox_policy, sandbox_policy_cwd);
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
sandbox_policy,
|
||||
sandbox_policy_cwd,
|
||||
);
|
||||
create_seatbelt_command_args(CreateSeatbeltCommandArgsParams {
|
||||
command,
|
||||
file_system_sandbox_policy: &file_system_sandbox_policy,
|
||||
|
||||
@@ -561,7 +561,7 @@ fn create_seatbelt_args_allowlists_unix_socket_paths() {
|
||||
#[test]
|
||||
fn create_seatbelt_args_allowlists_explicit_unix_socket_paths_without_proxy() {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
@@ -601,7 +601,7 @@ fn create_seatbelt_args_allowlists_explicit_unix_socket_paths_without_proxy() {
|
||||
#[tokio::test]
|
||||
async fn create_seatbelt_args_merges_proxy_and_explicit_unix_socket_paths() -> anyhow::Result<()> {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
@@ -660,7 +660,7 @@ async fn create_seatbelt_args_merges_proxy_and_explicit_unix_socket_paths() -> a
|
||||
#[test]
|
||||
fn create_seatbelt_args_preserves_full_network_with_explicit_unix_socket_paths() {
|
||||
let cwd = TempDir::new().expect("temp cwd");
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
let file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.path(),
|
||||
);
|
||||
|
||||
@@ -546,7 +546,7 @@ impl App {
|
||||
fn sync_runtime_permissions_from_legacy_sandbox_policy(config: &mut Config) {
|
||||
let sandbox_policy = config.permissions.sandbox_policy.get();
|
||||
config.permissions.file_system_sandbox_policy =
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
sandbox_policy,
|
||||
&config.cwd,
|
||||
);
|
||||
|
||||
@@ -2218,7 +2218,6 @@ async fn inactive_thread_approval_bubbles_into_active_view() -> Result<()> {
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/agent"),
|
||||
)),
|
||||
rollout_path: Some(test_path_buf("/tmp/agent-rollout.jsonl")),
|
||||
..test_thread_session(agent_thread_id, test_path_buf("/tmp/agent"))
|
||||
@@ -2381,7 +2380,6 @@ async fn side_defers_subagent_approval_overlay_until_side_exits() -> Result<()>
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/agent"),
|
||||
)),
|
||||
rollout_path: Some(test_path_buf("/tmp/agent-rollout.jsonl")),
|
||||
..test_thread_session(agent_thread_id, test_path_buf("/tmp/agent"))
|
||||
@@ -2607,7 +2605,6 @@ async fn inactive_thread_approval_badge_clears_after_turn_completion_notificatio
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/agent"),
|
||||
)),
|
||||
rollout_path: Some(test_path_buf("/tmp/agent-rollout.jsonl")),
|
||||
..test_thread_session(agent_thread_id, test_path_buf("/tmp/agent"))
|
||||
@@ -2664,7 +2661,6 @@ async fn inactive_thread_started_notification_initializes_replay_session() -> Re
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/main"),
|
||||
)),
|
||||
..test_thread_session(main_thread_id, test_path_buf("/tmp/main"))
|
||||
};
|
||||
@@ -2780,7 +2776,6 @@ async fn inactive_thread_started_notification_preserves_primary_model_when_path_
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/main"),
|
||||
)),
|
||||
..test_thread_session(main_thread_id, test_path_buf("/tmp/main"))
|
||||
};
|
||||
@@ -2852,7 +2847,6 @@ async fn thread_read_session_state_does_not_reuse_primary_permission_profile() {
|
||||
sandbox_policy: SandboxPolicy::new_workspace_write_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_workspace_write_policy(),
|
||||
std::path::Path::new("/tmp/main"),
|
||||
)),
|
||||
..test_thread_session(main_thread_id, test_path_buf("/tmp/main"))
|
||||
};
|
||||
@@ -3754,7 +3748,6 @@ fn test_thread_session(thread_id: ThreadId, cwd: PathBuf) -> ThreadSessionState
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.as_path(),
|
||||
)),
|
||||
cwd: cwd.abs(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
|
||||
@@ -305,7 +305,6 @@ mod tests {
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
permission_profile: Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
cwd.as_path(),
|
||||
)),
|
||||
cwd: cwd.abs(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
|
||||
@@ -172,9 +172,14 @@ mod tests {
|
||||
codex_config::Constrained::allow_any(AskForApproval::OnRequest);
|
||||
app.config.approvals_reviewer = ApprovalsReviewer::AutoReview;
|
||||
let expected_sandbox_policy = SandboxPolicy::new_workspace_write_policy();
|
||||
let expected_permission_profile = PermissionProfile::from_legacy_sandbox_policy(
|
||||
&expected_sandbox_policy,
|
||||
&main_session.cwd,
|
||||
let expected_file_system_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&expected_sandbox_policy,
|
||||
&main_session.cwd,
|
||||
);
|
||||
let expected_permission_profile = PermissionProfile::from_runtime_permissions(
|
||||
&expected_file_system_policy,
|
||||
NetworkSandboxPolicy::from(&expected_sandbox_policy),
|
||||
);
|
||||
app.chat_widget.handle_thread_session(main_session.clone());
|
||||
app.chat_widget
|
||||
|
||||
@@ -1541,10 +1541,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn turn_start_permission_overrides_send_profiles_only_for_embedded_runtime_overrides() {
|
||||
let cwd = test_path_buf("/tmp/project");
|
||||
let workspace_write = SandboxPolicy::new_workspace_write_policy();
|
||||
let workspace_write_profile =
|
||||
PermissionProfile::from_legacy_sandbox_policy(&workspace_write, &cwd);
|
||||
PermissionProfile::from_legacy_sandbox_policy(&workspace_write);
|
||||
|
||||
let (sandbox, profile) = turn_start_permission_overrides(
|
||||
ThreadParamsMode::Embedded,
|
||||
@@ -1567,7 +1566,6 @@ mod tests {
|
||||
workspace_write.clone(),
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&workspace_write,
|
||||
&cwd,
|
||||
)),
|
||||
);
|
||||
assert_eq!(sandbox, Some(workspace_write.into()));
|
||||
@@ -1581,13 +1579,12 @@ mod tests {
|
||||
external_sandbox.clone(),
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&external_sandbox,
|
||||
&cwd,
|
||||
)),
|
||||
);
|
||||
assert_eq!(sandbox, None);
|
||||
assert_eq!(
|
||||
profile,
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(&external_sandbox, &cwd).into())
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(&external_sandbox).into())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1672,7 +1669,6 @@ mod tests {
|
||||
permission_profile: Some(
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&codex_protocol::protocol::SandboxPolicy::new_read_only_policy(),
|
||||
&test_path_buf("/tmp/project"),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
@@ -1721,7 +1717,6 @@ mod tests {
|
||||
SandboxPolicy::new_read_only_policy(),
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
std::path::Path::new("/tmp/project"),
|
||||
)),
|
||||
test_path_buf("/tmp/project").abs(),
|
||||
Vec::new(),
|
||||
@@ -1755,7 +1750,6 @@ mod tests {
|
||||
SandboxPolicy::new_read_only_policy(),
|
||||
Some(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
std::path::Path::new("/tmp/project"),
|
||||
)),
|
||||
test_path_buf("/tmp/project").abs(),
|
||||
Vec::new(),
|
||||
|
||||
@@ -2125,7 +2125,7 @@ impl ChatWidget {
|
||||
{
|
||||
Some(permission_profile) => permission_profile.to_runtime_permissions(),
|
||||
None => (
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&event.sandbox_policy,
|
||||
&event.cwd,
|
||||
),
|
||||
@@ -9791,7 +9791,7 @@ impl ChatWidget {
|
||||
self.config.permissions.sandbox_policy.set(policy)?;
|
||||
let sandbox_policy = self.config.permissions.sandbox_policy.get();
|
||||
self.config.permissions.file_system_sandbox_policy =
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
codex_protocol::permissions::FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
sandbox_policy,
|
||||
&self.config.cwd,
|
||||
);
|
||||
|
||||
@@ -321,13 +321,20 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
let updated_sandbox = SandboxPolicy::new_workspace_write_policy();
|
||||
chat.set_sandbox_policy(updated_sandbox.clone())
|
||||
.expect("set sandbox policy");
|
||||
let updated_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&updated_sandbox,
|
||||
&expected_cwd,
|
||||
);
|
||||
assert_eq!(
|
||||
chat.config_ref().permissions.permission_profile(),
|
||||
codex_protocol::models::PermissionProfile::from_legacy_sandbox_policy(
|
||||
&updated_sandbox,
|
||||
&expected_cwd
|
||||
codex_protocol::models::PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
codex_protocol::models::SandboxEnforcement::from_legacy_sandbox_policy(
|
||||
&updated_sandbox
|
||||
),
|
||||
&updated_file_system_policy,
|
||||
NetworkSandboxPolicy::from(&updated_sandbox),
|
||||
),
|
||||
"local sandbox changes should replace SessionConfigured profile-derived runtime permissions"
|
||||
"local sandbox changes should replace SessionConfigured profile-derived runtime permissions using the widget cwd"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user