mirror of
https://github.com/openai/codex.git
synced 2026-05-15 08:42:34 +00:00
tui/exec: show effective workspace roots in summaries
This commit is contained in:
@@ -423,6 +423,7 @@ fn config_summary_entries(
|
||||
config: &Config,
|
||||
session_configured_event: &SessionConfiguredEvent,
|
||||
) -> Vec<(&'static str, String)> {
|
||||
let permission_profile = config.permissions.effective_permission_profile();
|
||||
let mut entries = vec![
|
||||
("workdir", config.cwd.display().to_string()),
|
||||
("model", session_configured_event.model.clone()),
|
||||
@@ -436,10 +437,7 @@ fn config_summary_entries(
|
||||
),
|
||||
(
|
||||
"sandbox",
|
||||
summarize_permission_profile(
|
||||
&config.permissions.effective_permission_profile(),
|
||||
config.cwd.as_path(),
|
||||
),
|
||||
summarize_permission_profile(&permission_profile, config.cwd.as_path()),
|
||||
),
|
||||
];
|
||||
if config.model_provider.wire_api == WireApi::Responses {
|
||||
|
||||
@@ -2,18 +2,24 @@ use codex_app_server_protocol::ServerNotification;
|
||||
use codex_app_server_protocol::ThreadItem;
|
||||
use codex_app_server_protocol::Turn;
|
||||
use codex_app_server_protocol::TurnStatus;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_protocol::SessionId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::SessionConfiguredEvent;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use codex_utils_absolute_path::test_support::test_path_buf;
|
||||
use owo_colors::Style;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::EventProcessorWithHumanOutput;
|
||||
use super::config_summary_entries;
|
||||
use super::final_message_from_turn_items;
|
||||
use super::paths_match_after_canonicalization;
|
||||
use super::reasoning_text;
|
||||
@@ -162,6 +168,70 @@ fn summarizes_managed_read_only_permission_profile() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn config_summary_entries_include_runtime_workspace_roots() {
|
||||
let codex_home = tempfile::tempdir().expect("create codex home");
|
||||
let cwd = tempfile::tempdir().expect("create cwd");
|
||||
let extra_root = tempfile::tempdir().expect("create extra root");
|
||||
let mut config = ConfigBuilder::default()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.fallback_cwd(Some(cwd.path().to_path_buf()))
|
||||
.build()
|
||||
.await
|
||||
.expect("build default config");
|
||||
let cwd = cwd.path().to_path_buf().abs();
|
||||
let extra_root = extra_root.path().to_path_buf().abs();
|
||||
let expected_extra_root =
|
||||
std::fs::canonicalize(extra_root.as_path()).expect("canonicalize extra root");
|
||||
config.cwd = cwd.clone();
|
||||
config.workspace_roots = vec![cwd.clone(), extra_root];
|
||||
config
|
||||
.permissions
|
||||
.set_workspace_roots(config.workspace_roots.clone());
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile(PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ true,
|
||||
/*exclude_slash_tmp*/ true,
|
||||
))
|
||||
.expect("set permission profile");
|
||||
|
||||
let session_configured_event = SessionConfiguredEvent {
|
||||
session_id: SessionId::new(),
|
||||
thread_id: ThreadId::new(),
|
||||
forked_from_id: None,
|
||||
thread_source: None,
|
||||
thread_name: None,
|
||||
model: "gpt-5.4".to_string(),
|
||||
model_provider_id: config.model_provider_id.clone(),
|
||||
service_tier: None,
|
||||
approval_policy: AskForApproval::Never,
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile: config.permissions.effective_permission_profile(),
|
||||
active_permission_profile: None,
|
||||
cwd,
|
||||
reasoning_effort: None,
|
||||
initial_messages: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
};
|
||||
|
||||
let summary_entries = config_summary_entries(&config, &session_configured_event);
|
||||
assert!(
|
||||
summary_entries.iter().any(|(key, value)| {
|
||||
*key == "sandbox"
|
||||
&& *value
|
||||
== format!(
|
||||
"workspace-write [workdir, {}]",
|
||||
expected_extra_root.display()
|
||||
)
|
||||
}),
|
||||
"expected runtime workspace root in sandbox summary: {summary_entries:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn distinct_missing_paths_do_not_match_after_canonicalization() {
|
||||
assert!(!paths_match_after_canonicalization(
|
||||
|
||||
@@ -902,11 +902,9 @@ fn permissions_display(config: &Config) -> String {
|
||||
}
|
||||
|
||||
let permission_profile = config.permissions.effective_permission_profile();
|
||||
let summary = summarize_permission_profile(
|
||||
&permission_profile,
|
||||
&config.cwd,
|
||||
config.permissions.workspace_roots(),
|
||||
);
|
||||
let workspace_roots = config.effective_workspace_roots();
|
||||
let summary =
|
||||
summarize_permission_profile(&permission_profile, &config.cwd, workspace_roots.as_slice());
|
||||
if let Some(details) = summary.strip_prefix("read-only")
|
||||
&& !details.contains("(network access enabled)")
|
||||
{
|
||||
|
||||
@@ -256,7 +256,7 @@ impl StatusHistoryCell {
|
||||
) -> (Self, StatusHistoryHandle) {
|
||||
let approval_policy = AskForApproval::from(config.permissions.approval_policy.value());
|
||||
let permission_profile = config.permissions.effective_permission_profile();
|
||||
let workspace_roots = config.permissions.workspace_roots();
|
||||
let workspace_roots = config.effective_workspace_roots();
|
||||
let mut config_entries = vec![
|
||||
("workdir", config.cwd.display().to_string()),
|
||||
("model", model_name.to_string()),
|
||||
@@ -267,7 +267,11 @@ impl StatusHistoryCell {
|
||||
),
|
||||
(
|
||||
"sandbox",
|
||||
summarize_permission_profile(&permission_profile, &config.cwd, workspace_roots),
|
||||
summarize_permission_profile(
|
||||
&permission_profile,
|
||||
&config.cwd,
|
||||
workspace_roots.as_slice(),
|
||||
),
|
||||
),
|
||||
];
|
||||
if config.model_provider.wire_api == WireApi::Responses {
|
||||
@@ -291,8 +295,9 @@ impl StatusHistoryCell {
|
||||
.map(|(_, v)| v.clone())
|
||||
.unwrap_or_else(|| "<unknown>".to_string());
|
||||
let active_permission_profile = config.permissions.active_permission_profile();
|
||||
let sandbox = status_permission_summary(&permission_profile, &config.cwd, workspace_roots);
|
||||
let workspace_root_suffix = workspace_root_suffix(workspace_roots, &config.cwd);
|
||||
let sandbox =
|
||||
status_permission_summary(&permission_profile, &config.cwd, workspace_roots.as_slice());
|
||||
let workspace_root_suffix = workspace_root_suffix(workspace_roots.as_slice(), &config.cwd);
|
||||
let approval = status_approval_label(approval_policy, config.approvals_reviewer, &approval);
|
||||
let permissions = status_permissions_label(
|
||||
active_permission_profile.as_ref(),
|
||||
|
||||
@@ -463,6 +463,42 @@ async fn status_permissions_workspace_roots_show_additional_directories() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn status_permissions_workspace_roots_include_profile_defined_directories() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
let mut config = test_config(&temp_home).await;
|
||||
set_workspace_cwd(&mut config, test_path_buf("/workspace/tests").abs());
|
||||
config
|
||||
.permissions
|
||||
.approval_policy
|
||||
.set(AskForApproval::OnRequest.to_core())
|
||||
.expect("set approval policy");
|
||||
let profile_root = test_path_buf("/workspace/shared").abs();
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile_with_active_profile(
|
||||
PermissionProfile::workspace_write_with(
|
||||
std::slice::from_ref(&profile_root),
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
/*exclude_tmpdir_env_var*/ false,
|
||||
/*exclude_slash_tmp*/ false,
|
||||
),
|
||||
Some(ActivePermissionProfile::new(":workspace")),
|
||||
)
|
||||
.expect("set permission profile");
|
||||
config
|
||||
.permissions
|
||||
.set_profile_workspace_roots(vec![profile_root.clone()]);
|
||||
|
||||
assert_eq!(
|
||||
permissions_text_for(&config),
|
||||
Some(format!(
|
||||
"Workspace [{}] (on-request)",
|
||||
profile_root.display()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn status_permissions_broadened_workspace_profile_shows_builtin_label() {
|
||||
let temp_home = TempDir::new().expect("temp home");
|
||||
|
||||
Reference in New Issue
Block a user