mirror of
https://github.com/openai/codex.git
synced 2026-08-28 13:58:49 +00:00
## What changed - Add `environmentConfigRead` to exec-server environment capabilities and advertise it for local executors. - Default the capability to `false` when deserializing responses from older executors. ## Testing - Verify legacy capability responses remain compatible and the environment config integration reports support. GitOrigin-RevId: c2110fea9e0e6e756eaeaaad096c50a943668c99
134 lines
4.7 KiB
Rust
134 lines
4.7 KiB
Rust
mod common;
|
|
|
|
use codex_config::CONFIG_TOML_FILE;
|
|
use codex_config::ConfigLayerSource;
|
|
use codex_config::format_config_layer_source;
|
|
use codex_config::loader::project_trust_key;
|
|
use codex_exec_server::Environment;
|
|
use codex_exec_server::EnvironmentConfigLayer;
|
|
use codex_exec_server::EnvironmentConfigLayerStack;
|
|
use codex_exec_server::EnvironmentConfigReadParams;
|
|
use codex_exec_server::EnvironmentConfigReadResponse;
|
|
use codex_exec_server::ExecServerError;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use codex_utils_path_uri::PathUri;
|
|
use common::exec_server::exec_server;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn remote_environment_reads_projected_executor_config() -> anyhow::Result<()> {
|
|
let mut server = exec_server().await?;
|
|
let codex_home =
|
|
AbsolutePathBuf::from_absolute_path(std::fs::canonicalize(server.codex_home())?)?;
|
|
let config_file = codex_home.join(CONFIG_TOML_FILE);
|
|
let project = codex_home.join("project");
|
|
let dot_codex = project.join(".codex");
|
|
tokio::fs::create_dir_all(dot_codex.as_path()).await?;
|
|
tokio::fs::write(project.join(".project-root").as_path(), "").await?;
|
|
let project_key = toml::Value::String(project_trust_key(project.as_path())).to_string();
|
|
tokio::fs::write(
|
|
&config_file,
|
|
format!(
|
|
"project_root_markers = [\".project-root\"]\n[projects.{project_key}]\ntrust_level = \"trusted\""
|
|
),
|
|
)
|
|
.await?;
|
|
tokio::fs::write(
|
|
dot_codex.join(CONFIG_TOML_FILE).as_path(),
|
|
r#"
|
|
[future_environment]
|
|
relative_path = "./executor-relative"
|
|
unselected = "do not return"
|
|
"#,
|
|
)
|
|
.await?;
|
|
|
|
let environment = Environment::create_for_tests(Some(server.websocket_url().to_string()))?;
|
|
let environment_info = environment.info().await?;
|
|
assert!(environment_info.capabilities.environment_config_read);
|
|
|
|
let response = environment
|
|
.read_environment_config(EnvironmentConfigReadParams {
|
|
cwd: PathUri::from_abs_path(&project),
|
|
config_paths: vec![vec![
|
|
"future_environment".to_string(),
|
|
"relative_path".to_string(),
|
|
]],
|
|
requirements_paths: Vec::new(),
|
|
})
|
|
.await?;
|
|
|
|
let projected_toml = toml::toml! {
|
|
[future_environment]
|
|
relative_path = "./executor-relative"
|
|
};
|
|
assert_eq!(
|
|
response,
|
|
EnvironmentConfigReadResponse {
|
|
user_home_dir: dirs::home_dir()
|
|
.and_then(|home_dir| PathUri::from_host_native_path(home_dir).ok()),
|
|
codex_home_dir: PathUri::from_abs_path(&codex_home),
|
|
hostname: codex_config::host_name(),
|
|
config: EnvironmentConfigLayerStack {
|
|
layers: vec![EnvironmentConfigLayer {
|
|
source: format_config_layer_source(
|
|
&ConfigLayerSource::Project {
|
|
dot_codex_folder: dot_codex.clone(),
|
|
},
|
|
CONFIG_TOML_FILE,
|
|
),
|
|
base_dir: PathUri::from_abs_path(&dot_codex),
|
|
toml: toml::to_string(&projected_toml)?,
|
|
}],
|
|
cloud_insertion_index: 0,
|
|
},
|
|
requirements: EnvironmentConfigLayerStack {
|
|
layers: Vec::new(),
|
|
cloud_insertion_index: 0,
|
|
},
|
|
}
|
|
);
|
|
|
|
server.shutdown().await?;
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn environment_config_read_rejects_empty_selectors() -> anyhow::Result<()> {
|
|
let mut server = exec_server().await?;
|
|
let codex_home =
|
|
AbsolutePathBuf::from_absolute_path(std::fs::canonicalize(server.codex_home())?)?;
|
|
let environment = Environment::create_for_tests(Some(server.websocket_url().to_string()))?;
|
|
|
|
for (config_paths, expected_message) in [
|
|
(
|
|
Vec::new(),
|
|
"at least one config or requirements path is required",
|
|
),
|
|
(
|
|
vec![Vec::new()],
|
|
"TOML paths must contain at least one key segment",
|
|
),
|
|
] {
|
|
let error = environment
|
|
.read_environment_config(EnvironmentConfigReadParams {
|
|
cwd: PathUri::from_abs_path(&codex_home),
|
|
config_paths,
|
|
requirements_paths: Vec::new(),
|
|
})
|
|
.await
|
|
.expect_err("invalid selectors should fail");
|
|
assert!(
|
|
matches!(
|
|
error,
|
|
ExecServerError::Server { code: -32602, ref message }
|
|
if message == expected_message
|
|
),
|
|
"unexpected error: {error:?}"
|
|
);
|
|
}
|
|
|
|
server.shutdown().await?;
|
|
Ok(())
|
|
}
|