Compare commits

...

2 Commits

Author SHA1 Message Date
starr-openai
a93264e294 Simplify tmp project isolation test
Keep the core-skills config helper on the normal project-layer path while letting the non-git parent-walk test override only the system project-root markers. Anchor that fixture inside its temp tree so helper-built project layers cannot see ambient /tmp metadata.

Collapse the TUI isolated project path into test_project_path and hash the deliberately missing secrets cwd directly.

Co-authored-by: Codex <noreply@openai.com>
2026-05-04 15:03:36 -07:00
starr-openai
10b09d160b Fix tmp project test isolation
Use isolated test paths where Linux CI parent /tmp state can otherwise leak into project-root discovery.

Co-authored-by: Codex <noreply@openai.com>
2026-05-04 14:37:33 -07:00
4 changed files with 50 additions and 19 deletions

View File

@@ -80,6 +80,15 @@ fn project_layers_for_cwd(cwd: &Path) -> Vec<ConfigLayerEntry> {
}
async fn make_config_for_cwd(codex_home: &TempDir, cwd: PathBuf) -> TestConfig {
make_config_for_cwd_with_system_config(codex_home, cwd, TomlValue::Table(toml::map::Map::new()))
.await
}
async fn make_config_for_cwd_with_system_config(
codex_home: &TempDir,
cwd: PathBuf,
system_config: TomlValue,
) -> TestConfig {
let user_config_path = codex_home.path().join(CONFIG_TOML_FILE);
let system_config_path = codex_home.path().join("etc/codex/config.toml");
fs::create_dir_all(
@@ -94,7 +103,7 @@ async fn make_config_for_cwd(codex_home: &TempDir, cwd: PathBuf) -> TestConfig {
ConfigLayerSource::System {
file: config_file(system_config_path),
},
TomlValue::Table(toml::map::Map::new()),
system_config,
),
ConfigLayerEntry::new(
ConfigLayerSource::User {
@@ -1691,18 +1700,28 @@ async fn non_git_repo_skills_search_does_not_walk_parents() {
let outer_dir = tempfile::tempdir().expect("tempdir");
let nested_dir = outer_dir.path().join("nested/inner");
fs::create_dir_all(&nested_dir).unwrap();
mark_as_git_repo(&nested_dir);
write_skill_at(
&outer_dir
.path()
.join(REPO_ROOT_CONFIG_DIR_NAME)
.join(SKILLS_DIR_NAME),
&outer_dir.path().join(AGENTS_DIR_NAME).join(SKILLS_DIR_NAME),
"outer",
"outer-skill",
"from outer",
);
let cfg = make_config_for_cwd(&codex_home, nested_dir).await;
let mut system_config = toml::map::Map::new();
system_config.insert(
"project_root_markers".to_string(),
TomlValue::Array(vec![TomlValue::String(
"__codex_test_project_root_marker_that_does_not_exist__".to_string(),
)]),
);
let cfg = make_config_for_cwd_with_system_config(
&codex_home,
nested_dir,
TomlValue::Table(system_config),
)
.await;
let outcome = load_skills_for_test(&cfg).await;
assert!(
@@ -1746,6 +1765,7 @@ async fn loads_skills_from_system_cache_when_present() {
#[tokio::test]
async fn skill_roots_include_admin_with_lowest_priority() {
let codex_home = tempfile::tempdir().expect("tempdir");
mark_as_git_repo(codex_home.path());
let cfg = make_config(&codex_home).await;
let scopes: Vec<SkillScope> = super::skill_roots(

View File

@@ -188,16 +188,11 @@ mod tests {
#[test]
fn environment_id_fallback_has_cwd_prefix() {
let dir = tempfile::tempdir().expect("tempdir");
let env_id = environment_id_from_cwd(dir.path());
let canonical = dir
.path()
.canonicalize()
.expect("tempdir canonical path should exist")
.to_string_lossy()
.into_owned();
let cwd = PathBuf::from(std::path::MAIN_SEPARATOR.to_string())
.join("codex-secrets-test-missing-cwd");
let env_id = environment_id_from_cwd(&cwd);
let mut hasher = Sha256::new();
hasher.update(canonical.as_bytes());
hasher.update(cwd.to_string_lossy().as_bytes());
let digest = hasher.finalize();
let hex = format!("{digest:x}");
let short = hex.get(..12).expect("digest has at least 12 chars");

View File

@@ -1,6 +1,7 @@
use super::*;
use codex_app_server_protocol::PluginAvailability;
use pretty_assertions::assert_eq;
use std::sync::OnceLock;
pub(super) async fn test_config() -> Config {
// Start from the built-in defaults so tests do not inherit host/system config.
@@ -16,7 +17,7 @@ pub(super) async fn test_config() -> Config {
config.codex_home = codex_home.abs();
config.sqlite_home = codex_home.clone();
config.log_dir = codex_home.join("log");
config.cwd = PathBuf::from(test_path_display("/tmp/project")).abs();
config.cwd = test_project_path().abs();
config.config_layer_stack = ConfigLayerStack::default();
config.startup_warnings.clear();
config.user_instructions = None;
@@ -24,7 +25,19 @@ pub(super) async fn test_config() -> Config {
}
pub(super) fn test_project_path() -> PathBuf {
PathBuf::from(test_path_display("/tmp/project"))
static TEST_PROJECT_PATH: OnceLock<PathBuf> = OnceLock::new();
TEST_PROJECT_PATH
.get_or_init(|| {
let root = tempfile::Builder::new()
.prefix("chatwidget-project-")
.tempdir()
.expect("tempdir")
.keep();
let project = root.join("project");
std::fs::create_dir_all(project.join(".git")).expect("create test project git marker");
project
})
.clone()
}
pub(super) fn truncated_path_variants(path: &str) -> Vec<String> {
@@ -37,6 +50,9 @@ pub(super) fn truncated_path_variants(path: &str) -> Vec<String> {
pub(super) fn normalize_snapshot_paths(text: impl Into<String>) -> String {
let mut text = text.into();
let isolated_project = test_project_path().to_string_lossy().into_owned();
text = text.replace(&isolated_project, "/tmp/project");
for unix_path in ["/tmp/project", "/tmp/hooks.json"] {
let platform_path = test_path_display(unix_path);
if platform_path != unix_path {

View File

@@ -1512,7 +1512,7 @@ async fn status_line_model_with_reasoning_includes_fast_for_fast_capable_models(
let test_cwd = test_path_display("/tmp/project");
assert_eq!(
status_line_text(&chat),
status_line_text(&chat).map(normalize_snapshot_paths),
Some(format!("gpt-5.4 xhigh fast · Context 0% used · {test_cwd}"))
);
@@ -1520,7 +1520,7 @@ async fn status_line_model_with_reasoning_includes_fast_for_fast_capable_models(
chat.refresh_status_line();
assert_eq!(
status_line_text(&chat),
status_line_text(&chat).map(normalize_snapshot_paths),
Some(format!(
"gpt-5.3-codex xhigh · Context 0% used · {test_cwd}"
))