Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codex-rs/app-server/src/codex_message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2597,7 +2597,7 @@ impl CodexMessageProcessor {
requested_permissions_trust_project(&typesafe_overrides, config.cwd.as_path());

if requested_cwd.is_some()
&& !config.active_project.is_trusted()
&& config.active_project.trust_level.is_none()
&& (requested_permissions_trust_project
|| matches!(
config.permissions.sandbox_policy.get(),
Expand Down
38 changes: 38 additions & 0 deletions codex-rs/app-server/tests/suite/v2/thread_start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,44 @@ async fn thread_start_with_read_only_sandbox_does_not_persist_project_trust() ->
Ok(())
}

#[tokio::test]
async fn thread_start_preserves_untrusted_project_trust() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;

let codex_home = TempDir::new()?;
create_config_toml_without_approval_policy(codex_home.path(), &server.uri())?;

let workspace = TempDir::new()?;
let config_path = codex_home.path().join("config.toml");
let workspace_key = workspace.path().display().to_string();
let mut config_toml =
std::fs::read_to_string(&config_path)?.parse::<toml_edit::DocumentMut>()?;
config_toml["projects"][workspace_key.as_str()]["trust_level"] = toml_edit::value("untrusted");
std::fs::write(&config_path, config_toml.to_string())?;
let config_before = std::fs::read_to_string(&config_path)?;

let mut mcp = McpProcess::new(codex_home.path()).await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;

let request_id = mcp
.send_thread_start_request(ThreadStartParams {
cwd: Some(workspace.path().display().to_string()),
sandbox: Some(SandboxMode::WorkspaceWrite),
..Default::default()
})
.await?;
timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
)
.await??;

let config_after = std::fs::read_to_string(&config_path)?;
assert_eq!(config_after, config_before);

Ok(())
}

#[tokio::test]
async fn thread_start_skips_trust_write_when_project_is_already_trusted() -> Result<()> {
let server = create_mock_responses_server_repeating_assistant("Done").await;
Expand Down
Loading