mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
permissions: resolve profile identity with constraints
This commit is contained in:
@@ -589,7 +589,7 @@ pub async fn run_main_with_transport_options(
|
||||
});
|
||||
}
|
||||
if let Some(warning) =
|
||||
codex_core::config::system_bwrap_warning(config.permissions.permission_profile().get())
|
||||
codex_core::config::system_bwrap_warning(config.permissions.permission_profile())
|
||||
{
|
||||
config_warnings.push(ConfigWarningNotification {
|
||||
summary: warning,
|
||||
|
||||
@@ -164,7 +164,7 @@ impl CommandExecRequestProcessor {
|
||||
let started_network_proxy = match self.config.permissions.network.as_ref() {
|
||||
Some(spec) => match spec
|
||||
.start_proxy(
|
||||
self.config.permissions.permission_profile().get(),
|
||||
self.config.permissions.permission_profile(),
|
||||
/*policy_decider*/ None,
|
||||
/*blocked_request_observer*/ None,
|
||||
managed_network_requirements_enabled,
|
||||
|
||||
@@ -230,7 +230,7 @@ async fn run_command_under_sandbox(
|
||||
let network_proxy = match config.permissions.network.as_ref() {
|
||||
Some(spec) => Some(
|
||||
spec.start_proxy(
|
||||
config.permissions.permission_profile().get(),
|
||||
config.permissions.permission_profile(),
|
||||
/*policy_decider*/ None,
|
||||
/*blocked_request_observer*/ None,
|
||||
managed_network_requirements_enabled,
|
||||
|
||||
@@ -80,6 +80,13 @@ impl McpConnectionManager {
|
||||
pub fn new_uninitialized(
|
||||
approval_policy: &Constrained<AskForApproval>,
|
||||
permission_profile: &Constrained<PermissionProfile>,
|
||||
) -> Self {
|
||||
Self::new_uninitialized_with_permission_profile(approval_policy, permission_profile.get())
|
||||
}
|
||||
|
||||
pub fn new_uninitialized_with_permission_profile(
|
||||
approval_policy: &Constrained<AskForApproval>,
|
||||
permission_profile: &PermissionProfile,
|
||||
) -> Self {
|
||||
Self {
|
||||
clients: HashMap::new(),
|
||||
@@ -87,7 +94,7 @@ impl McpConnectionManager {
|
||||
host_owned_codex_apps_enabled: false,
|
||||
elicitation_requests: ElicitationRequestManager::new(
|
||||
approval_policy.value(),
|
||||
permission_profile.get().clone(),
|
||||
permission_profile.clone(),
|
||||
/*reviewer*/ None,
|
||||
),
|
||||
startup_cancellation_token: CancellationToken::new(),
|
||||
|
||||
@@ -104,6 +104,18 @@ use std::path::Path;
|
||||
use std::time::Duration;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn active_permission_profile_state(
|
||||
permission_profile: PermissionProfile,
|
||||
profile_id: impl Into<String>,
|
||||
) -> PermissionProfileState {
|
||||
PermissionProfileState::from_constrained_active_profile(
|
||||
Constrained::allow_any(permission_profile),
|
||||
Some(ActivePermissionProfile::new(profile_id)),
|
||||
Vec::new(),
|
||||
)
|
||||
.expect("active permission profile state should be valid")
|
||||
}
|
||||
|
||||
fn stdio_mcp(command: &str) -> McpServerConfig {
|
||||
McpServerConfig {
|
||||
transport: McpServerTransportConfig::Stdio {
|
||||
@@ -7467,12 +7479,10 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
model_provider: fixture.openai_provider.clone(),
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::Never),
|
||||
constrained_permissions_profile: Constrained::allow_any(
|
||||
PermissionProfile::read_only()
|
||||
),
|
||||
active_permission_profile: Some(ActivePermissionProfile::new(
|
||||
permission_profile_state: active_permission_profile_state(
|
||||
PermissionProfile::read_only(),
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
)),
|
||||
),
|
||||
workspace_roots: vec![fixture.cwd()],
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
@@ -7921,10 +7931,10 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
model_provider: fixture.openai_custom_provider.clone(),
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::UnlessTrusted),
|
||||
constrained_permissions_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
active_permission_profile: Some(ActivePermissionProfile::new(
|
||||
permission_profile_state: active_permission_profile_state(
|
||||
PermissionProfile::read_only(),
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
)),
|
||||
),
|
||||
workspace_roots: vec![fixture.cwd()],
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
@@ -8087,10 +8097,10 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
model_provider: fixture.openai_provider.clone(),
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::OnFailure),
|
||||
constrained_permissions_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
active_permission_profile: Some(ActivePermissionProfile::new(
|
||||
permission_profile_state: active_permission_profile_state(
|
||||
PermissionProfile::read_only(),
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
)),
|
||||
),
|
||||
workspace_roots: vec![fixture.cwd()],
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
@@ -8238,10 +8248,10 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
model_provider: fixture.openai_provider.clone(),
|
||||
permissions: Permissions {
|
||||
approval_policy: Constrained::allow_any(AskForApproval::OnFailure),
|
||||
constrained_permissions_profile: Constrained::allow_any(PermissionProfile::read_only()),
|
||||
active_permission_profile: Some(ActivePermissionProfile::new(
|
||||
permission_profile_state: active_permission_profile_state(
|
||||
PermissionProfile::read_only(),
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
)),
|
||||
),
|
||||
workspace_roots: vec![fixture.cwd()],
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
|
||||
+104
-51
@@ -134,6 +134,7 @@ mod managed_features;
|
||||
mod network_proxy_spec;
|
||||
mod otel;
|
||||
mod permissions;
|
||||
mod resolved_permission_profile;
|
||||
#[cfg(test)]
|
||||
mod schema;
|
||||
pub use codex_config::ConfigLoadOptions;
|
||||
@@ -148,6 +149,7 @@ pub use managed_features::ManagedFeatures;
|
||||
pub use network_proxy_spec::NetworkProxySpec;
|
||||
pub use network_proxy_spec::StartedNetworkProxy;
|
||||
pub(crate) use permissions::resolve_permission_profile;
|
||||
pub(crate) use resolved_permission_profile::PermissionProfileState;
|
||||
|
||||
const DEFAULT_IGNORE_LARGE_UNTRACKED_DIRS: i64 = 200;
|
||||
const DEFAULT_IGNORE_LARGE_UNTRACKED_FILES: i64 = 10 * 1024 * 1024;
|
||||
@@ -247,15 +249,11 @@ pub(crate) async fn test_config() -> Config {
|
||||
pub struct Permissions {
|
||||
/// Approval policy for executing commands.
|
||||
pub approval_policy: Constrained<AskForApproval>,
|
||||
/// Canonical constrained permissions profile before runtime workspace-root
|
||||
/// materialization has been applied.
|
||||
constrained_permissions_profile: Constrained<PermissionProfile>,
|
||||
/// Named or implicit built-in profile selected by config, rather than an
|
||||
/// ad-hoc override.
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
/// Constrained permission profile plus its selected profile identity, if
|
||||
/// the profile came from a built-in or named config profile.
|
||||
permission_profile_state: PermissionProfileState,
|
||||
/// Thread-scoped runtime workspace roots. Symbolic `:workspace_roots`
|
||||
/// entries in `constrained_permissions_profile` are materialized against
|
||||
/// these roots.
|
||||
/// entries in the permission profile are materialized against these roots.
|
||||
workspace_roots: Vec<AbsolutePathBuf>,
|
||||
/// Effective network configuration applied to all spawned processes.
|
||||
pub network: Option<NetworkProxySpec>,
|
||||
@@ -286,8 +284,10 @@ impl Permissions {
|
||||
) -> Self {
|
||||
Self {
|
||||
approval_policy,
|
||||
constrained_permissions_profile: permission_profile,
|
||||
active_permission_profile: None,
|
||||
permission_profile_state: PermissionProfileState::from_constrained_legacy(
|
||||
permission_profile,
|
||||
)
|
||||
.expect("initial constrained permission profile should be valid"),
|
||||
workspace_roots: Vec::new(),
|
||||
network: None,
|
||||
allow_login_shell: true,
|
||||
@@ -297,21 +297,88 @@ impl Permissions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the constrained canonical profile. This preserves the raw
|
||||
/// symbolic `:workspace_roots` form for session/thread state.
|
||||
pub fn permission_profile(&self) -> &Constrained<PermissionProfile> {
|
||||
&self.constrained_permissions_profile
|
||||
pub(crate) fn permission_profile_state(&self) -> &PermissionProfileState {
|
||||
&self.permission_profile_state
|
||||
}
|
||||
|
||||
/// Set the full constrained profile value and preserve the active profile
|
||||
/// sidecar when the caller has already validated both together.
|
||||
pub fn set_constrained_permission_profile_with_active_profile(
|
||||
pub(crate) fn set_permission_profile_state(
|
||||
&mut self,
|
||||
permission_profile_state: PermissionProfileState,
|
||||
) {
|
||||
self.permission_profile_state = permission_profile_state;
|
||||
}
|
||||
|
||||
/// Apply a permission profile snapshot emitted by core session state.
|
||||
///
|
||||
/// This is a trusted-state bridge for consumers of `SessionConfigured`.
|
||||
/// Config loading and app-server selection should resolve named profiles
|
||||
/// through config instead of constructing this pair directly.
|
||||
pub fn set_permission_profile_from_session_snapshot(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
) -> ConstraintResult<()> {
|
||||
self.set_permission_profile_from_session_snapshot_with_profile_workspace_roots(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_permission_profile_from_session_snapshot_with_profile_workspace_roots(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
) -> ConstraintResult<()> {
|
||||
self.permission_profile_state.set_active_permission_profile(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
profile_workspace_roots,
|
||||
)
|
||||
}
|
||||
|
||||
/// Replace the current permission constraints with a trusted session
|
||||
/// snapshot. This is only for clients that must mirror core session state
|
||||
/// after their local config constraints reject the snapshot.
|
||||
pub fn replace_permission_profile_from_session_snapshot(
|
||||
&mut self,
|
||||
permission_profile: Constrained<PermissionProfile>,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
) {
|
||||
self.constrained_permissions_profile = permission_profile;
|
||||
self.active_permission_profile = active_permission_profile;
|
||||
) -> ConstraintResult<()> {
|
||||
self.replace_permission_profile_from_session_snapshot_with_profile_workspace_roots(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn replace_permission_profile_from_session_snapshot_with_profile_workspace_roots(
|
||||
&mut self,
|
||||
permission_profile: Constrained<PermissionProfile>,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
) -> ConstraintResult<()> {
|
||||
self.permission_profile_state = PermissionProfileState::from_constrained_active_profile(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
profile_workspace_roots,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Borrow the canonical profile before runtime workspace-root
|
||||
/// materialization has been applied.
|
||||
pub fn permission_profile(&self) -> &PermissionProfile {
|
||||
self.permission_profile_state.permission_profile()
|
||||
}
|
||||
|
||||
pub fn can_set_permission_profile(
|
||||
&self,
|
||||
permission_profile: &PermissionProfile,
|
||||
) -> ConstraintResult<()> {
|
||||
self.permission_profile_state
|
||||
.can_set_legacy_permission_profile(permission_profile)
|
||||
}
|
||||
|
||||
pub fn set_workspace_roots(&mut self, workspace_roots: Vec<AbsolutePathBuf>) {
|
||||
@@ -323,8 +390,7 @@ impl Permissions {
|
||||
}
|
||||
|
||||
fn materialized_permission_profile(&self) -> PermissionProfile {
|
||||
self.constrained_permissions_profile
|
||||
.get()
|
||||
self.permission_profile()
|
||||
.clone()
|
||||
.materialize_project_roots_with_workspace_roots(&self.workspace_roots)
|
||||
}
|
||||
@@ -337,7 +403,7 @@ impl Permissions {
|
||||
|
||||
/// Named profile selected by config, if the current profile has one.
|
||||
pub fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
|
||||
self.active_permission_profile.clone()
|
||||
self.permission_profile_state.active_permission_profile()
|
||||
}
|
||||
|
||||
/// Effective filesystem sandbox policy derived from the canonical profile.
|
||||
@@ -348,9 +414,7 @@ impl Permissions {
|
||||
|
||||
/// Effective network sandbox policy derived from the canonical profile.
|
||||
pub fn network_sandbox_policy(&self) -> NetworkSandboxPolicy {
|
||||
self.constrained_permissions_profile
|
||||
.get()
|
||||
.network_sandbox_policy()
|
||||
self.permission_profile().network_sandbox_policy()
|
||||
}
|
||||
|
||||
/// Legacy compatibility projection derived from the canonical profile.
|
||||
@@ -380,8 +444,8 @@ impl Permissions {
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
);
|
||||
self.constrained_permissions_profile
|
||||
.can_set(&permission_profile)
|
||||
self.permission_profile_state
|
||||
.can_set_legacy_permission_profile(&permission_profile)
|
||||
}
|
||||
|
||||
/// Set permissions from a legacy sandbox policy and keep every permission
|
||||
@@ -421,9 +485,8 @@ impl Permissions {
|
||||
],
|
||||
};
|
||||
|
||||
self.constrained_permissions_profile
|
||||
.set(permission_profile)?;
|
||||
self.active_permission_profile = None;
|
||||
self.permission_profile_state
|
||||
.set_legacy_permission_profile(permission_profile)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -432,23 +495,8 @@ impl Permissions {
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
) -> ConstraintResult<()> {
|
||||
self.set_permission_profile_with_active_profile(
|
||||
permission_profile,
|
||||
/*active_permission_profile*/ None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Set permissions from the canonical profile and record the named source
|
||||
/// profile, if one is known.
|
||||
pub fn set_permission_profile_with_active_profile(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
) -> ConstraintResult<()> {
|
||||
self.constrained_permissions_profile
|
||||
.set(permission_profile)?;
|
||||
self.active_permission_profile = active_permission_profile;
|
||||
Ok(())
|
||||
self.permission_profile_state
|
||||
.set_legacy_permission_profile(permission_profile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3226,6 +3274,12 @@ impl Config {
|
||||
.value
|
||||
.set(effective_permission_profile)
|
||||
.map_err(std::io::Error::from)?;
|
||||
let permission_profile_state = PermissionProfileState::from_constrained_active_profile(
|
||||
constrained_permission_profile.value,
|
||||
active_permission_profile,
|
||||
Vec::new(),
|
||||
)
|
||||
.map_err(std::io::Error::from)?;
|
||||
let otel = otel::resolve_config(cfg.otel.unwrap_or_default(), &mut startup_warnings);
|
||||
let config = Self {
|
||||
model,
|
||||
@@ -3241,8 +3295,7 @@ impl Config {
|
||||
startup_warnings,
|
||||
permissions: Permissions {
|
||||
approval_policy: constrained_approval_policy.value,
|
||||
constrained_permissions_profile: constrained_permission_profile.value,
|
||||
active_permission_profile,
|
||||
permission_profile_state,
|
||||
workspace_roots,
|
||||
network,
|
||||
allow_login_shell,
|
||||
@@ -3529,7 +3582,7 @@ impl Config {
|
||||
|
||||
pub fn managed_network_requirements_enabled(&self) -> bool {
|
||||
!matches!(
|
||||
self.permissions.permission_profile().get(),
|
||||
self.permissions.permission_profile(),
|
||||
PermissionProfile::Disabled
|
||||
) && self
|
||||
.config_layer_stack
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
use codex_config::Constrained;
|
||||
use codex_config::ConstraintResult;
|
||||
use codex_protocol::models::ActivePermissionProfile;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY;
|
||||
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum BuiltInPermissionProfileId {
|
||||
ReadOnly,
|
||||
Workspace,
|
||||
DangerFullAccess,
|
||||
}
|
||||
|
||||
impl BuiltInPermissionProfileId {
|
||||
fn from_str(id: &str) -> Option<Self> {
|
||||
match id {
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY => Some(Self::ReadOnly),
|
||||
BUILT_IN_PERMISSION_PROFILE_WORKSPACE => Some(Self::Workspace),
|
||||
BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS => Some(Self::DangerFullAccess),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::ReadOnly => BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
Self::Workspace => BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
|
||||
Self::DangerFullAccess => BUILT_IN_PERMISSION_PROFILE_DANGER_FULL_ACCESS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum ResolvedPermissionProfile {
|
||||
Legacy(LegacyPermissionProfile),
|
||||
BuiltIn(BuiltInPermissionProfile),
|
||||
Named(NamedPermissionProfile),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct LegacyPermissionProfile {
|
||||
permission_profile: PermissionProfile,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct BuiltInPermissionProfile {
|
||||
id: BuiltInPermissionProfileId,
|
||||
extends: Option<String>,
|
||||
permission_profile: PermissionProfile,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct NamedPermissionProfile {
|
||||
id: String,
|
||||
extends: Option<String>,
|
||||
permission_profile: PermissionProfile,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
}
|
||||
|
||||
impl ResolvedPermissionProfile {
|
||||
pub(crate) fn from_active_profile(
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
) -> Self {
|
||||
let Some(active_permission_profile) = active_permission_profile else {
|
||||
return Self::legacy(permission_profile);
|
||||
};
|
||||
|
||||
let ActivePermissionProfile { id, extends } = active_permission_profile;
|
||||
if let Some(built_in_id) = BuiltInPermissionProfileId::from_str(&id) {
|
||||
Self::BuiltIn(BuiltInPermissionProfile {
|
||||
id: built_in_id,
|
||||
extends,
|
||||
permission_profile,
|
||||
profile_workspace_roots,
|
||||
})
|
||||
} else {
|
||||
Self::Named(NamedPermissionProfile {
|
||||
id,
|
||||
extends,
|
||||
permission_profile,
|
||||
profile_workspace_roots,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn legacy(permission_profile: PermissionProfile) -> Self {
|
||||
Self::Legacy(LegacyPermissionProfile { permission_profile })
|
||||
}
|
||||
|
||||
pub(crate) fn permission_profile(&self) -> &PermissionProfile {
|
||||
match self {
|
||||
Self::Legacy(profile) => &profile.permission_profile,
|
||||
Self::BuiltIn(profile) => &profile.permission_profile,
|
||||
Self::Named(profile) => &profile.permission_profile,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
|
||||
match self {
|
||||
Self::Legacy(_) => None,
|
||||
Self::BuiltIn(profile) => Some(ActivePermissionProfile {
|
||||
id: profile.id.as_str().to_string(),
|
||||
extends: profile.extends.clone(),
|
||||
}),
|
||||
Self::Named(profile) => Some(ActivePermissionProfile {
|
||||
id: profile.id.clone(),
|
||||
extends: profile.extends.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct PermissionProfileState {
|
||||
resolved_permission_profile: Constrained<ResolvedPermissionProfile>,
|
||||
}
|
||||
|
||||
impl PermissionProfileState {
|
||||
pub(crate) fn from_constrained_legacy(
|
||||
constrained_permission_profile: Constrained<PermissionProfile>,
|
||||
) -> ConstraintResult<Self> {
|
||||
let resolved =
|
||||
ResolvedPermissionProfile::legacy(constrained_permission_profile.get().clone());
|
||||
Self::from_constrained_resolved(constrained_permission_profile, resolved)
|
||||
}
|
||||
|
||||
pub(crate) fn from_constrained_active_profile(
|
||||
constrained_permission_profile: Constrained<PermissionProfile>,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
) -> ConstraintResult<Self> {
|
||||
let resolved = ResolvedPermissionProfile::from_active_profile(
|
||||
constrained_permission_profile.get().clone(),
|
||||
active_permission_profile,
|
||||
profile_workspace_roots,
|
||||
);
|
||||
Self::from_constrained_resolved(constrained_permission_profile, resolved)
|
||||
}
|
||||
|
||||
pub(crate) fn from_constrained_resolved(
|
||||
constrained_permission_profile: Constrained<PermissionProfile>,
|
||||
resolved_permission_profile: ResolvedPermissionProfile,
|
||||
) -> ConstraintResult<Self> {
|
||||
let permission_profile_constraint = constrained_permission_profile.clone();
|
||||
let resolved_permission_profile = Constrained::new(
|
||||
resolved_permission_profile,
|
||||
move |candidate: &ResolvedPermissionProfile| {
|
||||
permission_profile_constraint.can_set(candidate.permission_profile())
|
||||
},
|
||||
)?;
|
||||
Ok(Self {
|
||||
resolved_permission_profile,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn permission_profile(&self) -> &PermissionProfile {
|
||||
self.resolved_permission_profile.get().permission_profile()
|
||||
}
|
||||
|
||||
pub(crate) fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
|
||||
self.resolved_permission_profile
|
||||
.get()
|
||||
.active_permission_profile()
|
||||
}
|
||||
|
||||
pub(crate) fn can_set_legacy_permission_profile(
|
||||
&self,
|
||||
permission_profile: &PermissionProfile,
|
||||
) -> ConstraintResult<()> {
|
||||
let candidate = ResolvedPermissionProfile::legacy(permission_profile.clone());
|
||||
self.resolved_permission_profile.can_set(&candidate)
|
||||
}
|
||||
|
||||
pub(crate) fn set_legacy_permission_profile(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
) -> ConstraintResult<()> {
|
||||
self.resolved_permission_profile
|
||||
.set(ResolvedPermissionProfile::legacy(permission_profile))
|
||||
}
|
||||
|
||||
pub(crate) fn set_active_permission_profile(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
) -> ConstraintResult<()> {
|
||||
let candidate = ResolvedPermissionProfile::from_active_profile(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
profile_workspace_roots,
|
||||
);
|
||||
self.resolved_permission_profile.set(candidate)
|
||||
}
|
||||
}
|
||||
@@ -920,7 +920,7 @@ pub(crate) fn build_guardian_review_session_config(
|
||||
guardian_config.permissions.network = Some(NetworkProxySpec::from_config_and_constraints(
|
||||
live_network_config,
|
||||
network_constraints,
|
||||
guardian_config.permissions.permission_profile().get(),
|
||||
guardian_config.permissions.permission_profile(),
|
||||
)?);
|
||||
}
|
||||
for feature in [
|
||||
|
||||
@@ -2163,7 +2163,7 @@ async fn guardian_review_session_config_preserves_parent_network_proxy() {
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
parent_config.permissions.permission_profile().get(),
|
||||
parent_config.permissions.permission_profile(),
|
||||
)
|
||||
.expect("network proxy spec");
|
||||
parent_config.permissions.network = Some(network.clone());
|
||||
@@ -2191,9 +2191,7 @@ async fn guardian_review_session_config_preserves_parent_network_proxy() {
|
||||
);
|
||||
assert_eq!(
|
||||
guardian_config.permissions.permission_profile(),
|
||||
&Constrained::allow_only(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
))
|
||||
&PermissionProfile::from_legacy_sandbox_policy(&SandboxPolicy::new_read_only_policy())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2230,7 +2228,7 @@ async fn guardian_review_session_config_uses_live_network_proxy_state() {
|
||||
NetworkProxySpec::from_config_and_constraints(
|
||||
parent_network,
|
||||
/*requirements*/ None,
|
||||
parent_config.permissions.permission_profile().get(),
|
||||
parent_config.permissions.permission_profile(),
|
||||
)
|
||||
.expect("parent network proxy spec"),
|
||||
);
|
||||
|
||||
@@ -173,6 +173,7 @@ use crate::compact::collect_user_messages;
|
||||
use crate::config::Config;
|
||||
use crate::config::Constrained;
|
||||
use crate::config::ConstraintResult;
|
||||
use crate::config::PermissionProfileState;
|
||||
use crate::config::StartedNetworkProxy;
|
||||
use crate::config::resolve_web_search_mode_for_turn;
|
||||
use crate::context_manager::ContextManager;
|
||||
@@ -617,8 +618,7 @@ impl Codex {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
|
||||
@@ -63,11 +63,10 @@ pub(crate) struct SessionConfiguration {
|
||||
/// When to escalate for approval for execution
|
||||
pub(super) approval_policy: Constrained<AskForApproval>,
|
||||
pub(super) approvals_reviewer: ApprovalsReviewer,
|
||||
/// Canonical permission profile for the session.
|
||||
pub(super) permission_profile: Constrained<PermissionProfile>,
|
||||
/// Named or implicit built-in permissions profile selected from config, if
|
||||
/// any.
|
||||
pub(super) active_permission_profile: Option<ActivePermissionProfile>,
|
||||
/// Permission profile state for the session. Keep the constrained profile
|
||||
/// and selected profile id in sync by using the methods below instead of
|
||||
/// mutating the fields independently.
|
||||
pub(super) permission_profile_state: PermissionProfileState,
|
||||
pub(super) windows_sandbox_level: WindowsSandboxLevel,
|
||||
|
||||
/// Absolute working directory that should be treated as the *root* of the
|
||||
@@ -103,12 +102,32 @@ impl SessionConfiguration {
|
||||
&self.codex_home
|
||||
}
|
||||
|
||||
pub(super) fn permission_profile_state(&self) -> &PermissionProfileState {
|
||||
&self.permission_profile_state
|
||||
}
|
||||
|
||||
pub(super) fn permission_profile(&self) -> PermissionProfile {
|
||||
self.permission_profile.get().clone()
|
||||
self.permission_profile_state.permission_profile().clone()
|
||||
}
|
||||
|
||||
pub(super) fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
|
||||
self.active_permission_profile.clone()
|
||||
self.permission_profile_state.active_permission_profile()
|
||||
}
|
||||
|
||||
pub(super) fn apply_permission_profile_to_permissions(
|
||||
&self,
|
||||
permissions: &mut crate::config::Permissions,
|
||||
) {
|
||||
permissions.set_permission_profile_state(self.permission_profile_state.clone());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(super) fn set_permission_profile_for_tests(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
) -> ConstraintResult<()> {
|
||||
self.permission_profile_state
|
||||
.set_legacy_permission_profile(permission_profile)
|
||||
}
|
||||
|
||||
pub(super) fn sandbox_policy(&self) -> SandboxPolicy {
|
||||
@@ -117,7 +136,7 @@ impl SessionConfiguration {
|
||||
.unwrap_or_else(|_| {
|
||||
let file_system_sandbox_policy = self.file_system_sandbox_policy();
|
||||
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
|
||||
self.permission_profile.get(),
|
||||
self.permission_profile_state.permission_profile(),
|
||||
&file_system_sandbox_policy,
|
||||
self.network_sandbox_policy(),
|
||||
&self.cwd,
|
||||
@@ -126,11 +145,13 @@ impl SessionConfiguration {
|
||||
}
|
||||
|
||||
pub(super) fn file_system_sandbox_policy(&self) -> FileSystemSandboxPolicy {
|
||||
self.permission_profile.get().file_system_sandbox_policy()
|
||||
self.permission_profile().file_system_sandbox_policy()
|
||||
}
|
||||
|
||||
pub(super) fn network_sandbox_policy(&self) -> NetworkSandboxPolicy {
|
||||
self.permission_profile.get().network_sandbox_policy()
|
||||
self.permission_profile_state
|
||||
.permission_profile()
|
||||
.network_sandbox_policy()
|
||||
}
|
||||
|
||||
pub(super) fn thread_config_snapshot(&self) -> ThreadConfigSnapshot {
|
||||
@@ -227,16 +248,16 @@ impl SessionConfiguration {
|
||||
let active_permission_profile =
|
||||
updates.active_permission_profile.clone().or_else(|| {
|
||||
if permission_profile == self.permission_profile() {
|
||||
self.active_permission_profile.clone()
|
||||
self.active_permission_profile()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
next_configuration.set_permission_profile_projection(
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
Some(¤t_file_system_sandbox_policy),
|
||||
)?;
|
||||
next_configuration.active_permission_profile = active_permission_profile;
|
||||
} else if let Some(sandbox_policy) = updates.sandbox_policy.clone() {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
@@ -245,14 +266,15 @@ impl SessionConfiguration {
|
||||
¤t_file_system_sandbox_policy,
|
||||
);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
next_configuration.permission_profile.set(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
),
|
||||
)?;
|
||||
next_configuration.active_permission_profile = None;
|
||||
next_configuration
|
||||
.permission_profile_state
|
||||
.set_legacy_permission_profile(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
),
|
||||
)?;
|
||||
} else if cwd_changed
|
||||
&& file_system_policy_matches_legacy
|
||||
&& file_system_policy_has_rebindable_project_root_write
|
||||
@@ -266,13 +288,15 @@ impl SessionConfiguration {
|
||||
&next_configuration.cwd,
|
||||
¤t_file_system_sandbox_policy,
|
||||
);
|
||||
next_configuration.permission_profile.set(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(¤t_sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
current_network_sandbox_policy,
|
||||
),
|
||||
)?;
|
||||
next_configuration
|
||||
.permission_profile_state
|
||||
.set_legacy_permission_profile(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(¤t_sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
current_network_sandbox_policy,
|
||||
),
|
||||
)?;
|
||||
}
|
||||
if let Some(app_server_client_name) = updates.app_server_client_name.clone() {
|
||||
next_configuration.app_server_client_name = Some(app_server_client_name);
|
||||
@@ -286,6 +310,7 @@ impl SessionConfiguration {
|
||||
fn set_permission_profile_projection(
|
||||
&mut self,
|
||||
permission_profile: PermissionProfile,
|
||||
active_permission_profile: Option<ActivePermissionProfile>,
|
||||
preserve_deny_reads_from: Option<&FileSystemSandboxPolicy>,
|
||||
) -> ConstraintResult<()> {
|
||||
let enforcement = permission_profile.enforcement();
|
||||
@@ -301,8 +326,11 @@ impl SessionConfiguration {
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
);
|
||||
self.permission_profile.set(effective_permission_profile)?;
|
||||
Ok(())
|
||||
self.permission_profile_state.set_active_permission_profile(
|
||||
effective_permission_profile,
|
||||
active_permission_profile,
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,7 +797,7 @@ impl Session {
|
||||
let (network_proxy, session_network_proxy) = Self::start_managed_network_proxy(
|
||||
spec,
|
||||
current_exec_policy.as_ref(),
|
||||
config.permissions.permission_profile().get(),
|
||||
config.permissions.permission_profile(),
|
||||
network_policy_decider.as_ref().map(Arc::clone),
|
||||
blocked_request_observer.as_ref().map(Arc::clone),
|
||||
managed_network_requirements_configured,
|
||||
@@ -831,10 +859,12 @@ impl Session {
|
||||
// before any MCP-related events. It is reasonable to consider
|
||||
// changing this to use Option or OnceCell, though the current
|
||||
// setup is straightforward enough and performs well.
|
||||
mcp_connection_manager: Arc::new(RwLock::new(McpConnectionManager::new_uninitialized(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
))),
|
||||
mcp_connection_manager: Arc::new(RwLock::new(
|
||||
McpConnectionManager::new_uninitialized_with_permission_profile(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
),
|
||||
)),
|
||||
mcp_startup_cancellation_token: Mutex::new(CancellationToken::new()),
|
||||
unified_exec_manager: UnifiedExecProcessManager::new(
|
||||
config.background_terminal_max_timeout,
|
||||
@@ -939,7 +969,9 @@ impl Session {
|
||||
initial_messages,
|
||||
network_proxy: session_network_proxy.filter(|_| {
|
||||
Self::managed_network_proxy_active_for_permission_profile(
|
||||
session_configuration.permission_profile.get(),
|
||||
session_configuration
|
||||
.permission_profile_state()
|
||||
.permission_profile(),
|
||||
)
|
||||
}),
|
||||
rollout_path,
|
||||
|
||||
@@ -868,8 +868,7 @@ async fn new_turn_refreshes_managed_network_proxy_for_sandbox_change() -> anyhow
|
||||
state.session_configuration.original_config_do_not_use = Arc::new(config);
|
||||
state
|
||||
.session_configuration
|
||||
.permission_profile
|
||||
.set(PermissionProfile::from_legacy_sandbox_policy(
|
||||
.set_permission_profile_for_tests(PermissionProfile::from_legacy_sandbox_policy(
|
||||
&initial_policy,
|
||||
))
|
||||
.expect("test setup should allow permission profile");
|
||||
@@ -2887,8 +2886,7 @@ async fn set_rate_limits_retains_previous_credits() {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -2991,8 +2989,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -3464,8 +3461,7 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -3528,13 +3524,15 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd
|
||||
},
|
||||
]);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
session_configuration.permission_profile = codex_config::Constrained::allow_any(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
),
|
||||
);
|
||||
session_configuration
|
||||
.set_permission_profile_for_tests(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
),
|
||||
)
|
||||
.expect("set permission profile");
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
@@ -3569,13 +3567,15 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
|
||||
);
|
||||
existing_file_system_policy.glob_scan_max_depth = Some(2);
|
||||
existing_file_system_policy.entries.push(deny_entry.clone());
|
||||
session_configuration.permission_profile = codex_config::Constrained::allow_any(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&workspace_policy),
|
||||
&existing_file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
),
|
||||
);
|
||||
session_configuration
|
||||
.set_permission_profile_for_tests(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&workspace_policy),
|
||||
&existing_file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
),
|
||||
)
|
||||
.expect("set permission profile");
|
||||
|
||||
let requested_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&workspace_policy,
|
||||
@@ -3750,13 +3750,15 @@ async fn session_configuration_apply_rederives_legacy_file_system_policy_on_cwd_
|
||||
&sandbox_policy,
|
||||
&session_configuration.cwd,
|
||||
);
|
||||
session_configuration.permission_profile = codex_config::Constrained::allow_any(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
),
|
||||
);
|
||||
session_configuration
|
||||
.set_permission_profile_for_tests(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(&sandbox_policy),
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::from(&sandbox_policy),
|
||||
),
|
||||
)
|
||||
.expect("set permission profile");
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
@@ -3802,13 +3804,15 @@ async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_up
|
||||
access: FileSystemAccessMode::Write,
|
||||
},
|
||||
]);
|
||||
session_configuration.permission_profile = codex_config::Constrained::allow_any(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::Managed,
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
),
|
||||
);
|
||||
session_configuration
|
||||
.set_permission_profile_for_tests(
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::Managed,
|
||||
&file_system_sandbox_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
),
|
||||
)
|
||||
.expect("set permission profile");
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
@@ -3997,8 +4001,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -4106,8 +4109,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -4151,10 +4153,12 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
);
|
||||
|
||||
let services = SessionServices {
|
||||
mcp_connection_manager: Arc::new(RwLock::new(McpConnectionManager::new_uninitialized(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
))),
|
||||
mcp_connection_manager: Arc::new(RwLock::new(
|
||||
McpConnectionManager::new_uninitialized_with_permission_profile(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
),
|
||||
)),
|
||||
mcp_startup_cancellation_token: Mutex::new(CancellationToken::new()),
|
||||
unified_exec_manager: UnifiedExecProcessManager::new(
|
||||
config.background_terminal_max_timeout,
|
||||
@@ -4338,8 +4342,7 @@ async fn make_session_with_config_and_rx(
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -4441,8 +4444,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -5958,8 +5960,7 @@ where
|
||||
compact_prompt: config.compact_prompt.clone(),
|
||||
approval_policy: config.permissions.approval_policy.clone(),
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.permission_profile().clone(),
|
||||
active_permission_profile: config.permissions.active_permission_profile(),
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
@@ -6003,10 +6004,12 @@ where
|
||||
);
|
||||
|
||||
let services = SessionServices {
|
||||
mcp_connection_manager: Arc::new(RwLock::new(McpConnectionManager::new_uninitialized(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
))),
|
||||
mcp_connection_manager: Arc::new(RwLock::new(
|
||||
McpConnectionManager::new_uninitialized_with_permission_profile(
|
||||
&config.permissions.approval_policy,
|
||||
config.permissions.permission_profile(),
|
||||
),
|
||||
)),
|
||||
mcp_startup_cancellation_token: Mutex::new(CancellationToken::new()),
|
||||
unified_exec_manager: UnifiedExecProcessManager::new(
|
||||
config.background_terminal_max_timeout,
|
||||
|
||||
@@ -438,12 +438,8 @@ impl Session {
|
||||
per_turn_config.service_tier = session_configuration.service_tier.clone();
|
||||
per_turn_config.personality = session_configuration.personality;
|
||||
per_turn_config.approvals_reviewer = session_configuration.approvals_reviewer;
|
||||
per_turn_config
|
||||
.permissions
|
||||
.set_constrained_permission_profile_with_active_profile(
|
||||
session_configuration.permission_profile.clone(),
|
||||
session_configuration.active_permission_profile.clone(),
|
||||
);
|
||||
session_configuration
|
||||
.apply_permission_profile_to_permissions(&mut per_turn_config.permissions);
|
||||
let permission_profile = session_configuration.permission_profile();
|
||||
let resolved_web_search_mode =
|
||||
resolve_web_search_mode_for_turn(&per_turn_config.web_search_mode, &permission_profile);
|
||||
|
||||
@@ -3900,7 +3900,7 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr
|
||||
#[tokio::test]
|
||||
async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
fn pick_allowed_sandbox_policy(
|
||||
constraint: &crate::config::Constrained<PermissionProfile>,
|
||||
permissions: &crate::config::Permissions,
|
||||
base: SandboxPolicy,
|
||||
cwd: &std::path::Path,
|
||||
) -> SandboxPolicy {
|
||||
@@ -3915,16 +3915,9 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
if *candidate == base {
|
||||
return false;
|
||||
}
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(candidate, cwd);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(candidate);
|
||||
let permission_profile =
|
||||
PermissionProfile::from_runtime_permissions_with_enforcement(
|
||||
SandboxEnforcement::from_legacy_sandbox_policy(candidate),
|
||||
&file_system_sandbox_policy,
|
||||
network_sandbox_policy,
|
||||
);
|
||||
constraint.can_set(&permission_profile).is_ok()
|
||||
permissions
|
||||
.can_set_legacy_sandbox_policy(candidate, cwd)
|
||||
.is_ok()
|
||||
})
|
||||
.unwrap_or(base)
|
||||
}
|
||||
@@ -3948,7 +3941,7 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
#[allow(deprecated)]
|
||||
let turn_cwd = turn.cwd.clone();
|
||||
let sandbox_policy = pick_allowed_sandbox_policy(
|
||||
turn.config.permissions.permission_profile(),
|
||||
&turn.config.permissions,
|
||||
turn.config.legacy_sandbox_policy(),
|
||||
turn_cwd.as_path(),
|
||||
);
|
||||
|
||||
@@ -759,7 +759,7 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> {
|
||||
event_processor.print_config_summary(&config, &prompt_summary, &session_configured);
|
||||
if !json_mode
|
||||
&& let Some(message) =
|
||||
codex_core::config::system_bwrap_warning(config.permissions.permission_profile().get())
|
||||
codex_core::config::system_bwrap_warning(config.permissions.permission_profile())
|
||||
{
|
||||
event_processor.process_warning(message);
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ pub(super) fn emit_project_config_warnings(app_event_tx: &AppEventSender, config
|
||||
}
|
||||
|
||||
pub(super) fn emit_system_bwrap_warning(app_event_tx: &AppEventSender, config: &Config) {
|
||||
let Some(message) = crate::legacy_core::config::system_bwrap_warning(
|
||||
config.permissions.permission_profile().get(),
|
||||
) else {
|
||||
let Some(message) =
|
||||
crate::legacy_core::config::system_bwrap_warning(config.permissions.permission_profile())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ impl ChatWidget {
|
||||
let permission_sync = self
|
||||
.config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
session.permission_profile.clone(),
|
||||
session.active_permission_profile.clone(),
|
||||
);
|
||||
@@ -55,10 +55,11 @@ impl ChatWidget {
|
||||
tracing::warn!(%err, "failed to sync permissions from SessionConfigured");
|
||||
self.config
|
||||
.permissions
|
||||
.set_constrained_permission_profile_with_active_profile(
|
||||
.replace_permission_profile_from_session_snapshot(
|
||||
Constrained::allow_only(session.permission_profile.clone()),
|
||||
session.active_permission_profile.clone(),
|
||||
);
|
||||
)
|
||||
.expect("allow-only snapshot should satisfy its own constraint");
|
||||
}
|
||||
self.config.approvals_reviewer = session.approvals_reviewer;
|
||||
self.status_line_project_root_name_cache = None;
|
||||
|
||||
@@ -306,7 +306,7 @@ async fn status_permissions_named_read_only_profile_shows_builtin_label() {
|
||||
.expect("set approval policy");
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::read_only(),
|
||||
Some(ActivePermissionProfile::new(
|
||||
BUILT_IN_PERMISSION_PROFILE_READ_ONLY,
|
||||
@@ -335,7 +335,7 @@ async fn status_permissions_read_only_profile_shows_additional_writable_roots()
|
||||
.with_additional_writable_roots(config.cwd.as_path(), std::slice::from_ref(&extra_root));
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::from_runtime_permissions(
|
||||
&file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
@@ -363,7 +363,7 @@ async fn status_permissions_named_workspace_profile_shows_builtin_label() {
|
||||
.expect("set approval policy");
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write(),
|
||||
Some(ActivePermissionProfile::new(
|
||||
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
|
||||
@@ -389,7 +389,7 @@ async fn status_permissions_workspace_auto_review_shows_reviewer_label() {
|
||||
.expect("set approval policy");
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write(),
|
||||
Some(ActivePermissionProfile::new(
|
||||
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
|
||||
@@ -415,7 +415,7 @@ async fn status_permissions_named_profile_shows_additional_writable_roots() {
|
||||
let extra_root = test_path_buf("/workspace/extra").abs();
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write_with(
|
||||
std::slice::from_ref(&extra_root),
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
@@ -451,7 +451,7 @@ async fn status_permissions_workspace_roots_show_additional_directories() {
|
||||
.set_workspace_roots(config.workspace_roots.clone());
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write(),
|
||||
Some(ActivePermissionProfile::new(":workspace")),
|
||||
)
|
||||
@@ -474,7 +474,7 @@ async fn status_permissions_broadened_workspace_profile_shows_builtin_label() {
|
||||
.expect("set approval policy");
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
@@ -499,7 +499,7 @@ async fn status_permissions_user_defined_profile_shows_name() {
|
||||
let mut config = test_config(&temp_home).await;
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::read_only(),
|
||||
Some(ActivePermissionProfile::new("locked")),
|
||||
)
|
||||
@@ -519,7 +519,7 @@ async fn status_snapshot_shows_active_user_defined_profile() {
|
||||
set_workspace_cwd(&mut config, test_path_buf("/workspace/tests").abs());
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::read_only(),
|
||||
Some(ActivePermissionProfile::new("locked")),
|
||||
)
|
||||
@@ -617,7 +617,7 @@ async fn status_snapshot_shows_auto_review_permissions() {
|
||||
config.approvals_reviewer = ApprovalsReviewer::AutoReview;
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
.set_permission_profile_from_session_snapshot(
|
||||
PermissionProfile::workspace_write(),
|
||||
Some(ActivePermissionProfile::new(
|
||||
BUILT_IN_PERMISSION_PROFILE_WORKSPACE,
|
||||
|
||||
Reference in New Issue
Block a user