fix(codex): probe CODEX_SQLITE_HOME when locating state DB for history migration

The session-history migration only scanned ~/.codex/state_5.sqlite and the
config.toml `sqlite_home` location. When Codex's SQLite state is relocated via
the CODEX_SQLITE_HOME env var, the state DB was never scanned and its threads
kept their old provider bucket. Add a CODEX_SQLITE_HOME fallback (config
`sqlite_home` still takes precedence) in the shared codex_state_db_paths helper
used by both the third-party and unified-session history migrations, plus serial
env tests.
This commit is contained in:
Jason
2026-06-16 16:32:16 +08:00
parent 0bb3b7515a
commit 69341db284
+86 -5
View File
@@ -1116,16 +1116,23 @@ fn migrate_codex_state_dbs(
}
fn codex_state_db_paths(codex_dir: &Path, config_text: &str) -> Vec<PathBuf> {
let mut paths = vec![codex_dir.join(CODEX_STATE_DB_FILENAME)];
let mut paths = Vec::new();
push_unique_path(&mut paths, codex_dir.join(CODEX_STATE_DB_FILENAME));
// Codex lets SQLite state move away from CODEX_HOME; config takes precedence.
if let Some(sqlite_home) = sqlite_home_from_codex_config(config_text) {
let db_path = sqlite_home.join(CODEX_STATE_DB_FILENAME);
if !paths.contains(&db_path) {
paths.push(db_path);
}
push_unique_path(&mut paths, sqlite_home.join(CODEX_STATE_DB_FILENAME));
} else if let Some(sqlite_home) = sqlite_home_from_env() {
push_unique_path(&mut paths, sqlite_home.join(CODEX_STATE_DB_FILENAME));
}
paths
}
fn push_unique_path(paths: &mut Vec<PathBuf>, path: PathBuf) {
if !paths.contains(&path) {
paths.push(path);
}
}
fn sqlite_home_from_codex_config(config_text: &str) -> Option<PathBuf> {
let doc = config_text.parse::<DocumentMut>().ok()?;
let raw = doc.get("sqlite_home")?.as_str()?.trim();
@@ -1135,6 +1142,15 @@ fn sqlite_home_from_codex_config(config_text: &str) -> Option<PathBuf> {
Some(resolve_user_path(raw))
}
fn sqlite_home_from_env() -> Option<PathBuf> {
let raw = std::env::var("CODEX_SQLITE_HOME").ok()?;
let raw = raw.trim();
if raw.is_empty() {
return None;
}
Some(resolve_user_path(raw))
}
fn resolve_user_path(raw: &str) -> PathBuf {
if raw == "~" {
return crate::config::get_home_dir();
@@ -1313,8 +1329,33 @@ fn relative_backup_path(path: &Path, root: &Path) -> PathBuf {
mod tests {
use super::*;
use crate::provider::Provider;
use serial_test::serial;
use std::ffi::OsString;
use tempfile::tempdir;
struct EnvVarGuard {
key: &'static str,
previous: Option<OsString>,
}
impl EnvVarGuard {
fn set(key: &'static str, value: &Path) -> Self {
let previous = std::env::var_os(key);
std::env::set_var(key, value);
Self { key, previous }
}
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
if let Some(previous) = &self.previous {
std::env::set_var(self.key, previous);
} else {
std::env::remove_var(self.key);
}
}
}
fn source_ids(values: &[&str]) -> BTreeSet<String> {
values.iter().map(|value| value.to_string()).collect()
}
@@ -2116,6 +2157,46 @@ base_url = "https://proxy.example/v1"
assert_eq!(backed_up_source_count, 2);
}
#[test]
#[serial]
fn state_db_paths_include_codex_sqlite_home_env() {
let dir = tempdir().expect("tempdir");
let codex_dir = dir.path().join(".codex");
let sqlite_home = dir.path().join("sqlite-home");
let _guard = EnvVarGuard::set("CODEX_SQLITE_HOME", &sqlite_home);
let paths = codex_state_db_paths(&codex_dir, "");
assert_eq!(
paths,
vec![
codex_dir.join(CODEX_STATE_DB_FILENAME),
sqlite_home.join(CODEX_STATE_DB_FILENAME),
]
);
}
#[test]
#[serial]
fn config_sqlite_home_takes_precedence_over_codex_sqlite_home_env() {
let dir = tempdir().expect("tempdir");
let codex_dir = dir.path().join(".codex");
let env_sqlite_home = dir.path().join("env-sqlite-home");
let config_sqlite_home = dir.path().join("config-sqlite-home");
let _guard = EnvVarGuard::set("CODEX_SQLITE_HOME", &env_sqlite_home);
let config_text = format!("sqlite_home = \"{}\"\n", config_sqlite_home.display());
let paths = codex_state_db_paths(&codex_dir, &config_text);
assert_eq!(
paths,
vec![
codex_dir.join(CODEX_STATE_DB_FILENAME),
config_sqlite_home.join(CODEX_STATE_DB_FILENAME),
]
);
}
#[test]
fn collects_third_party_provider_ids_from_codex_providers() {
let db = Database::memory().expect("memory db");