permissions: derive snapshot sandbox projections

This commit is contained in:
Michael Bolin
2026-04-26 23:09:14 -07:00
parent ec9a1d7689
commit 59e21e6030
5 changed files with 26 additions and 15 deletions

View File

@@ -2859,6 +2859,7 @@ impl CodexMessageProcessor {
/*has_in_progress_turn*/ false,
);
let sandbox_policy = config_snapshot.sandbox_policy();
let permission_profile =
thread_response_permission_profile(config_snapshot.permission_profile);
@@ -2871,7 +2872,7 @@ impl CodexMessageProcessor {
instruction_sources,
approval_policy: config_snapshot.approval_policy.into(),
approvals_reviewer: config_snapshot.approvals_reviewer.into(),
sandbox: config_snapshot.sandbox_policy.into(),
sandbox: sandbox_policy.into(),
permission_profile,
reasoning_effort: config_snapshot.reasoning_effort,
};
@@ -3597,7 +3598,7 @@ impl CodexMessageProcessor {
builder.model_provider = Some(model_provider.clone());
builder.cwd = config_snapshot.cwd.to_path_buf();
builder.cli_version = Some(env!("CARGO_PKG_VERSION").to_string());
builder.sandbox_policy = config_snapshot.sandbox_policy.clone();
builder.sandbox_policy = config_snapshot.sandbox_policy();
builder.approval_mode = config_snapshot.approval_policy;
let metadata = builder.build(model_provider.as_str());
if let Err(err) = state_db_ctx.insert_thread_if_absent(&metadata).await {
@@ -4687,7 +4688,7 @@ impl CodexMessageProcessor {
instruction_sources,
approval_policy: session_configured.approval_policy.into(),
approvals_reviewer: session_configured.approvals_reviewer.into(),
sandbox: config_snapshot.sandbox_policy.into(),
sandbox: config_snapshot.sandbox_policy().into(),
permission_profile,
reasoning_effort: session_configured.reasoning_effort,
};
@@ -5418,7 +5419,7 @@ impl CodexMessageProcessor {
instruction_sources,
approval_policy: session_configured.approval_policy.into(),
approvals_reviewer: session_configured.approvals_reviewer.into(),
sandbox: config_snapshot.sandbox_policy.into(),
sandbox: config_snapshot.sandbox_policy().into(),
permission_profile,
reasoning_effort: session_configured.reasoning_effort,
};
@@ -8997,13 +8998,13 @@ async fn handle_pending_thread_resume_request(
tracing::warn!("failed to apply goal resume runtime effects: {err}");
}
let sandbox_policy = pending.config_snapshot.sandbox_policy();
let ThreadConfigSnapshot {
model,
model_provider_id,
service_tier,
approval_policy,
approvals_reviewer,
sandbox_policy,
permission_profile,
cwd,
reasoning_effort,
@@ -9226,8 +9227,9 @@ fn collect_resume_override_mismatches(
}
}
if let Some(requested_sandbox) = request.sandbox.as_ref() {
let active_sandbox = config_snapshot.sandbox_policy();
let sandbox_matches = matches!(
(requested_sandbox, &config_snapshot.sandbox_policy),
(requested_sandbox, &active_sandbox),
(
SandboxMode::ReadOnly,
codex_protocol::protocol::SandboxPolicy::ReadOnly { .. }
@@ -9245,7 +9247,7 @@ fn collect_resume_override_mismatches(
if !sandbox_matches {
mismatch_details.push(format!(
"sandbox requested={requested_sandbox:?} active={:?}",
config_snapshot.sandbox_policy
active_sandbox
));
}
}
@@ -10931,7 +10933,6 @@ mod tests {
service_tier: Some(codex_protocol::config_types::ServiceTier::Flex),
approval_policy: codex_protocol::protocol::AskForApproval::OnRequest,
approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer::User,
sandbox_policy: codex_protocol::protocol::SandboxPolicy::DangerFullAccess,
permission_profile: codex_protocol::models::PermissionProfile::Disabled,
cwd,
ephemeral: false,

View File

@@ -47,7 +47,6 @@ pub struct ThreadConfigSnapshot {
pub service_tier: Option<ServiceTier>,
pub approval_policy: AskForApproval,
pub approvals_reviewer: ApprovalsReviewer,
pub sandbox_policy: SandboxPolicy,
pub permission_profile: PermissionProfile,
pub cwd: AbsolutePathBuf,
pub ephemeral: bool,
@@ -56,6 +55,18 @@ pub struct ThreadConfigSnapshot {
pub session_source: SessionSource,
}
impl ThreadConfigSnapshot {
pub fn sandbox_policy(&self) -> SandboxPolicy {
let file_system_sandbox_policy = self.permission_profile.file_system_sandbox_policy();
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
&self.permission_profile,
&file_system_sandbox_policy,
self.permission_profile.network_sandbox_policy(),
self.cwd.as_path(),
)
}
}
/// Turn context overrides that app-server validates before starting a turn.
#[derive(Clone, Default)]
pub struct CodexThreadTurnContextOverrides {

View File

@@ -718,11 +718,11 @@ mod phase2 {
config_snapshot.cwd.as_path(),
memory_root(&harness.config.codex_home).as_path()
);
match &config_snapshot.sandbox_policy {
let sandbox_policy = config_snapshot.sandbox_policy();
match &sandbox_policy {
SandboxPolicy::WorkspaceWrite { network_access, .. } => {
assert!(!*network_access);
let effective_writable_roots: Vec<_> = config_snapshot
.sandbox_policy
let effective_writable_roots: Vec<_> = sandbox_policy
.get_writable_roots_with_cwd(config_snapshot.cwd.as_path())
.into_iter()
.map(|root| root.root)
@@ -752,7 +752,7 @@ mod phase2 {
let file_system_sandbox_policy = turn_context.file_system_sandbox_policy();
let legacy_file_system_sandbox_policy =
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
&config_snapshot.sandbox_policy,
&sandbox_policy,
config_snapshot.cwd.as_path(),
);
assert!(

View File

@@ -126,7 +126,6 @@ impl SessionConfiguration {
service_tier: self.service_tier,
approval_policy: self.approval_policy.value(),
approvals_reviewer: self.approvals_reviewer,
sandbox_policy: self.sandbox_policy(),
permission_profile: self.permission_profile(),
cwd: self.cwd.clone(),
ephemeral: self.original_config_do_not_use.ephemeral,

View File

@@ -2143,7 +2143,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
.expect("spawned agent thread should exist")
.config_snapshot()
.await;
assert_eq!(snapshot.sandbox_policy, expected_sandbox);
assert_eq!(snapshot.sandbox_policy(), expected_sandbox);
assert_eq!(snapshot.approval_policy, AskForApproval::OnRequest);
assert_eq!(snapshot.permission_profile, expected_permission_profile);
let child_thread = manager