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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user