Use native permission profiles for diagnostics and sandbox checks (#61369)

## What changed

- Derive sampling diagnostic and rollout trace labels directly from permission profiles instead of constructing legacy sandbox policies. Rename the trace metadata field from `sandbox_policy` to `permissions_profile`.
- Extract `with_workspace_write_cwd` to share default workspace metadata protections between legacy policy conversion and the TUI's sandbox-mode compatibility check. Build the check's workspace-write profile from filesystem and network permissions directly.

## Testing

Add a regression test confirming that the sandbox-mode compatibility check accepts standard workspace metadata protections and rejects a profile with an additional writable `.git` root.

GitOrigin-RevId: f20d23afd80dff6347865df3d6a94d6f5e90e1e0
This commit is contained in:
ioanbudea-OAI
2026-11-13 20:22:45 +00:00
committed by copyberry
parent 6d99161bce
commit 400a1e1e82
9 changed files with 70 additions and 53 deletions
+4 -15
View File
@@ -265,17 +265,6 @@ impl SessionConfiguration {
.set_legacy_permission_profile(permission_profile)
}
pub(super) fn sandbox_policy(
&self,
environments: &[TurnEnvironmentSelection],
) -> SandboxPolicy {
let permission_profile = self.materialized_permission_profile(environments);
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
&permission_profile,
self.cwd(),
)
}
pub(super) fn file_system_sandbox_policy(
&self,
environments: &[TurnEnvironmentSelection],
@@ -1334,10 +1323,10 @@ impl Session {
.approval_policy
.value()
.to_string(),
sandbox_policy: format!(
"{:?}",
session_configuration.sandbox_policy(environment_selections)
),
permissions_profile: session_configuration
.materialized_permission_profile(environment_selections)
.legacy_sandbox_policy_label(session_configuration.cwd())
.to_string(),
};
let mut post_session_configured_events = Vec::<Event>::new();
+2 -11
View File
@@ -5636,7 +5636,7 @@ async fn session_configuration_apply_permission_profile_accepts_direct_write_roo
let file_system_sandbox_policy =
FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {
path: FileSystemPath::Path {
path: external_write_path.clone().into(),
path: external_write_path.into(),
},
access: FileSystemAccessMode::Write,
missing_path_behavior: None,
@@ -5661,15 +5661,6 @@ async fn session_configuration_apply_permission_profile_accepts_direct_write_roo
updated.file_system_sandbox_policy(&[]),
file_system_sandbox_policy
);
assert_eq!(
updated.sandbox_policy(&[]),
SandboxPolicy::WorkspaceWrite {
writable_roots: vec![external_write_path],
network_access: false,
exclude_tmpdir_env_var: true,
exclude_slash_tmp: true,
}
);
}
#[test_case::test_case(false; "ordinary_proxy")]
@@ -8877,7 +8868,7 @@ async fn submission_loop_channel_close_runs_full_thread_teardown() -> anyhow::Re
model: turn_context.model_info().slug.clone(),
provider_name: config.model_provider_id.clone(),
approval_policy: "never".to_string(),
sandbox_policy: "danger-full-access".to_string(),
permissions_profile: "danger-full-access".to_string(),
},
)?;
let live_thread = LiveThread::create(
+7 -1
View File
@@ -2909,10 +2909,16 @@ async fn try_run_sampling_request(
draining_for_mailbox: &mut bool,
) -> CodexResult<SamplingRequestResult> {
let turn_context = Arc::clone(&step_context.turn);
#[expect(deprecated, reason = "Classify feedback using the initial turn cwd.")]
let diagnostic_cwd = &turn_context.cwd;
feedback_tags!(
model = step_context.settings.model_info.slug.clone(),
approval_policy = turn_context.approval_policy(),
sandbox_policy = &turn_context.sandbox_policy(),
sandbox_policy = tracing::field::display(
turn_context
.permission_profile()
.legacy_sandbox_policy_label(diagnostic_cwd)
),
effort = step_context.settings.reasoning_effort(),
auth_mode = sess.services.auth_manager.auth_mode(),
tags_json = tracing::field::display(serde_json::json!(crate::feedback_config::usage_tags(
@@ -796,14 +796,6 @@ impl TurnContext {
self.permission_profile().network_sandbox_policy()
}
pub(crate) fn sandbox_policy(&self) -> SandboxPolicy {
#[allow(deprecated)]
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
&self.permission_profile(),
&self.cwd,
)
}
/// Legacy: returns the frozen initial-turn reasoning effort, including the initial model default.
/// Step-scoped consumers should use their captured `StepContext::settings`.
pub(crate) fn effective_reasoning_effort(&self) -> Option<ReasoningEffortConfig> {
@@ -421,7 +421,7 @@ fn attach_test_trace(session: &mut Session, turn: &TurnContext, root: &Path) ->
model: "gpt-test".to_string(),
provider_name: "test-provider".to_string(),
approval_policy: "never".to_string(),
sandbox_policy: "danger-full-access".to_string(),
permissions_profile: "danger-full-access".to_string(),
},
)?;
rollout_thread_trace.record_codex_turn_started(turn.sub_id.as_str());