permissions: move workspace roots onto thread state

This commit is contained in:
Michael Bolin
2026-05-13 16:50:23 -07:00
parent d666238b40
commit 7f45c2f625
165 changed files with 3171 additions and 3675 deletions
@@ -223,6 +223,7 @@ macro_rules! client_request_definitions {
/// Typed response from the server to the client.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[allow(clippy::large_enum_variant)]
#[serde(tag = "method", rename_all = "camelCase")]
pub enum ClientResponse {
$(
@@ -2299,7 +2300,7 @@ mod tests {
approvals_reviewer: v2::ApprovalsReviewer::User,
sandbox: v2::SandboxPolicy::DangerFullAccess,
permission_profile: None,
active_permission_profile: None,
workspace_roots: Vec::new(),
reasoning_effort: None,
},
};
@@ -2345,7 +2346,7 @@ mod tests {
"type": "dangerFullAccess"
},
"permissionProfile": null,
"activePermissionProfile": null,
"workspaceRoots": [],
"reasoningEffort": null
}
}),
@@ -5,7 +5,6 @@ use codex_protocol::approvals::NetworkApprovalProtocol as CoreNetworkApprovalPro
use codex_protocol::approvals::NetworkPolicyAmendment as CoreNetworkPolicyAmendment;
use codex_protocol::approvals::NetworkPolicyRuleAction as CoreNetworkPolicyRuleAction;
use codex_protocol::models::ActivePermissionProfile as CoreActivePermissionProfile;
use codex_protocol::models::ActivePermissionProfileModification as CoreActivePermissionProfileModification;
use codex_protocol::models::AdditionalPermissionProfile as CoreAdditionalPermissionProfile;
use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions;
use codex_protocol::models::ManagedFileSystemPermissions as CoreManagedFileSystemPermissions;
@@ -437,41 +436,6 @@ pub struct ActivePermissionProfile {
/// inheritance. This is currently always `null`.
#[serde(default)]
pub extends: Option<String>,
/// Bounded user-requested modifications applied on top of the named
/// profile, if any.
#[serde(default)]
pub modifications: Vec<ActivePermissionProfileModification>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type")]
#[ts(export_to = "v2/")]
pub enum ActivePermissionProfileModification {
/// Additional concrete directory that should be writable.
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
AdditionalWritableRoot { path: AbsolutePathBuf },
}
impl From<CoreActivePermissionProfileModification> for ActivePermissionProfileModification {
fn from(value: CoreActivePermissionProfileModification) -> Self {
match value {
CoreActivePermissionProfileModification::AdditionalWritableRoot { path } => {
Self::AdditionalWritableRoot { path }
}
}
}
}
impl From<ActivePermissionProfileModification> for CoreActivePermissionProfileModification {
fn from(value: ActivePermissionProfileModification) -> Self {
match value {
ActivePermissionProfileModification::AdditionalWritableRoot { path } => {
Self::AdditionalWritableRoot { path }
}
}
}
}
impl From<CoreActivePermissionProfile> for ActivePermissionProfile {
@@ -479,11 +443,6 @@ impl From<CoreActivePermissionProfile> for ActivePermissionProfile {
Self {
id: value.id,
extends: value.extends,
modifications: value
.modifications
.into_iter()
.map(ActivePermissionProfileModification::from)
.collect(),
}
}
}
@@ -493,42 +452,10 @@ impl From<ActivePermissionProfile> for CoreActivePermissionProfile {
Self {
id: value.id,
extends: value.extends,
modifications: value
.modifications
.into_iter()
.map(CoreActivePermissionProfileModification::from)
.collect(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type")]
#[ts(export_to = "v2/")]
pub enum PermissionProfileSelectionParams {
/// Select a named built-in or user-defined profile and optionally apply
/// bounded modifications that Codex knows how to validate.
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
Profile {
id: String,
#[ts(optional = nullable)]
modifications: Option<Vec<PermissionProfileModificationParams>>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type")]
#[ts(export_to = "v2/")]
pub enum PermissionProfileModificationParams {
/// Additional concrete directory that should be writable.
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
AdditionalWritableRoot { path: AbsolutePathBuf },
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -3442,9 +3442,9 @@ fn thread_lifecycle_responses_default_missing_optional_fields() {
assert_eq!(start.permission_profile, None);
assert_eq!(resume.permission_profile, None);
assert_eq!(fork.permission_profile, None);
assert_eq!(start.active_permission_profile, None);
assert_eq!(resume.active_permission_profile, None);
assert_eq!(fork.active_permission_profile, None);
assert_eq!(start.workspace_roots, Vec::<AbsolutePathBuf>::new());
assert_eq!(resume.workspace_roots, Vec::<AbsolutePathBuf>::new());
assert_eq!(fork.workspace_roots, Vec::<AbsolutePathBuf>::new());
}
#[test]
@@ -3469,6 +3469,7 @@ fn turn_start_params_preserve_explicit_null_service_tier() {
responsesapi_client_metadata: None,
environments: None,
cwd: None,
workspace_roots: None,
approval_policy: None,
approvals_reviewer: None,
sandbox_policy: None,
@@ -1,8 +1,6 @@
use super::ActivePermissionProfile;
use super::ApprovalsReviewer;
use super::AskForApproval;
use super::PermissionProfile;
use super::PermissionProfileSelectionParams;
use super::SandboxMode;
use super::SandboxPolicy;
use super::Thread;
@@ -117,11 +115,14 @@ pub struct ThreadStartParams {
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
/// Named profile selection for this thread. Cannot be combined with
/// `sandbox`. Use bounded `modifications` for supported turn/thread
/// adjustments instead of replacing the full permissions profile.
/// `sandbox`.
#[experimental("thread/start.permissions")]
#[ts(optional = nullable)]
pub permissions: Option<PermissionProfileSelectionParams>,
pub permissions: Option<String>,
/// Override the runtime workspace roots for this thread.
#[experimental("thread/start.workspaceRoots")]
#[ts(optional = nullable)]
pub workspace_roots: Option<Vec<PathBuf>>,
#[ts(optional = nullable)]
pub config: Option<HashMap<String, JsonValue>>,
#[ts(optional = nullable)]
@@ -206,16 +207,15 @@ pub struct ThreadStartResponse {
/// should prefer `permissionProfile` when they need exact runtime
/// permissions.
pub sandbox: SandboxPolicy,
/// Full active permissions for this thread. `activePermissionProfile`
/// carries display/provenance metadata for this runtime profile.
/// Named or implicit built-in profile that produced the active runtime
/// permissions, when known.
#[experimental("thread/start.permissionProfile")]
#[serde(default)]
pub permission_profile: Option<PermissionProfile>,
/// Named or implicit built-in profile that produced the active
/// permissions, when known.
#[experimental("thread/start.activePermissionProfile")]
pub permission_profile: Option<ActivePermissionProfile>,
/// Runtime workspace roots currently associated with the thread.
#[experimental("thread/start.workspaceRoots")]
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub workspace_roots: Vec<AbsolutePathBuf>,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -274,11 +274,14 @@ pub struct ThreadResumeParams {
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
/// Named profile selection for the resumed thread. Cannot be combined
/// with `sandbox`. Use bounded `modifications` for supported thread
/// adjustments instead of replacing the full permissions profile.
/// with `sandbox`.
#[experimental("thread/resume.permissions")]
#[ts(optional = nullable)]
pub permissions: Option<PermissionProfileSelectionParams>,
pub permissions: Option<String>,
/// Override the runtime workspace roots for the resumed thread.
#[experimental("thread/resume.workspaceRoots")]
#[ts(optional = nullable)]
pub workspace_roots: Option<Vec<PathBuf>>,
#[ts(optional = nullable)]
pub config: Option<HashMap<String, serde_json::Value>>,
#[ts(optional = nullable)]
@@ -321,16 +324,15 @@ pub struct ThreadResumeResponse {
/// should prefer `permissionProfile` when they need exact runtime
/// permissions.
pub sandbox: SandboxPolicy,
/// Full active permissions for this thread. `activePermissionProfile`
/// carries display/provenance metadata for this runtime profile.
/// Named or implicit built-in profile that produced the active runtime
/// permissions, when known.
#[experimental("thread/resume.permissionProfile")]
#[serde(default)]
pub permission_profile: Option<PermissionProfile>,
/// Named or implicit built-in profile that produced the active
/// permissions, when known.
#[experimental("thread/resume.activePermissionProfile")]
pub permission_profile: Option<ActivePermissionProfile>,
/// Runtime workspace roots currently associated with the thread.
#[experimental("thread/resume.workspaceRoots")]
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub workspace_roots: Vec<AbsolutePathBuf>,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -380,11 +382,14 @@ pub struct ThreadForkParams {
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
/// Named profile selection for the forked thread. Cannot be combined with
/// `sandbox`. Use bounded `modifications` for supported thread
/// adjustments instead of replacing the full permissions profile.
/// `sandbox`.
#[experimental("thread/fork.permissions")]
#[ts(optional = nullable)]
pub permissions: Option<PermissionProfileSelectionParams>,
pub permissions: Option<String>,
/// Override the runtime workspace roots for the forked thread.
#[experimental("thread/fork.workspaceRoots")]
#[ts(optional = nullable)]
pub workspace_roots: Option<Vec<PathBuf>>,
#[ts(optional = nullable)]
pub config: Option<HashMap<String, serde_json::Value>>,
#[ts(optional = nullable)]
@@ -430,16 +435,15 @@ pub struct ThreadForkResponse {
/// should prefer `permissionProfile` when they need exact runtime
/// permissions.
pub sandbox: SandboxPolicy,
/// Full active permissions for this thread. `activePermissionProfile`
/// carries display/provenance metadata for this runtime profile.
/// Named or implicit built-in profile that produced the active runtime
/// permissions, when known.
#[experimental("thread/fork.permissionProfile")]
#[serde(default)]
pub permission_profile: Option<PermissionProfile>,
/// Named or implicit built-in profile that produced the active
/// permissions, when known.
#[experimental("thread/fork.activePermissionProfile")]
pub permission_profile: Option<ActivePermissionProfile>,
/// Runtime workspace roots currently associated with the thread.
#[experimental("thread/fork.workspaceRoots")]
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub workspace_roots: Vec<AbsolutePathBuf>,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -1,6 +1,5 @@
use super::ApprovalsReviewer;
use super::AskForApproval;
use super::PermissionProfileSelectionParams;
use super::SandboxPolicy;
use super::Turn;
use codex_experimental_api_macros::ExperimentalApi;
@@ -64,6 +63,10 @@ pub struct TurnStartParams {
/// Override the working directory for this turn and subsequent turns.
#[ts(optional = nullable)]
pub cwd: Option<PathBuf>,
/// Override the runtime workspace roots for this turn and subsequent turns.
#[experimental("turn/start.workspaceRoots")]
#[ts(optional = nullable)]
pub workspace_roots: Option<Vec<PathBuf>>,
/// Override the approval policy for this turn and subsequent turns.
#[experimental(nested)]
#[ts(optional = nullable)]
@@ -76,12 +79,10 @@ pub struct TurnStartParams {
#[ts(optional = nullable)]
pub sandbox_policy: Option<SandboxPolicy>,
/// Select a named permissions profile for this turn and subsequent turns.
/// Cannot be combined with `sandboxPolicy`. Use bounded `modifications`
/// for supported turn adjustments instead of replacing the full
/// permissions profile.
/// Cannot be combined with `sandboxPolicy`.
#[experimental("turn/start.permissions")]
#[ts(optional = nullable)]
pub permissions: Option<PermissionProfileSelectionParams>,
pub permissions: Option<String>,
/// Override the model for this turn and subsequent turns.
#[ts(optional = nullable)]
pub model: Option<String>,