feat: support dotenv (including ~/.codex/.env) (#1653)
This PR adds a `load_dotenv()` helper function to the `codex-common` crate that is available when the `cli` feature is enabled. The function uses [`dotenvy`](https://crates.io/crates/dotenvy) to update the environment from: - `$CODEX_HOME/.env` - `$(pwd)/.env` To test: - ran `printenv OPENAI_API_KEY` to verify the env var exists in my environment - ran `just codex exec hello` to verify the CLI uses my `OPENAI_API_KEY` - ran `unset OPENAI_API_KEY` - ran `just codex exec hello` again and got **ERROR: Missing environment variable: `OPENAI_API_KEY`**, as expected - created `~/.codex/.env` and added `OPENAI_API_KEY=sk-proj-...` (also ran `chmod 400 ~/.codex/.env` for good measure) - ran `just codex exec hello` again and it worked, verifying it picked up `OPENAI_API_KEY` from `~/.codex/.env` Note this functionality was available in the TypeScript CLI: https://github.com/openai/codex/pull/122 and was recently requested over on https://github.com/openai/codex/issues/1262#issuecomment-3093203551.
This commit is contained in:
8
codex-rs/Cargo.lock
generated
8
codex-rs/Cargo.lock
generated
@@ -756,7 +756,9 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"codex-common",
|
||||||
"codex-core",
|
"codex-core",
|
||||||
|
"dotenvy",
|
||||||
"landlock",
|
"landlock",
|
||||||
"libc",
|
"libc",
|
||||||
"seccompiler",
|
"seccompiler",
|
||||||
@@ -1272,6 +1274,12 @@ version = "0.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenvy"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dupe"
|
name = "dupe"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ fn default_model() -> String {
|
|||||||
/// function will Err if the path does not exist.
|
/// function will Err if the path does not exist.
|
||||||
/// - If `CODEX_HOME` is not set, this function does not verify that the
|
/// - If `CODEX_HOME` is not set, this function does not verify that the
|
||||||
/// directory exists.
|
/// directory exists.
|
||||||
fn find_codex_home() -> std::io::Result<PathBuf> {
|
pub fn find_codex_home() -> std::io::Result<PathBuf> {
|
||||||
// Honor the `CODEX_HOME` environment variable when it is set to allow users
|
// Honor the `CODEX_HOME` environment variable when it is set to allow users
|
||||||
// (and tests) to override the default location.
|
// (and tests) to override the default location.
|
||||||
if let Ok(val) = std::env::var("CODEX_HOME") {
|
if let Ok(val) = std::env::var("CODEX_HOME") {
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
codex-common = { path = "../common", features = ["cli"] }
|
||||||
codex-core = { path = "../core" }
|
codex-core = { path = "../core" }
|
||||||
|
dotenvy = "0.15.7"
|
||||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ where
|
|||||||
crate::run_main();
|
crate::run_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This modifies the environment, which is not thread-safe, so do this
|
||||||
|
// before creating any threads/the Tokio runtime.
|
||||||
|
load_dotenv();
|
||||||
|
|
||||||
// Regular invocation – create a Tokio runtime and execute the provided
|
// Regular invocation – create a Tokio runtime and execute the provided
|
||||||
// async entry-point.
|
// async entry-point.
|
||||||
let runtime = tokio::runtime::Runtime::new()?;
|
let runtime = tokio::runtime::Runtime::new()?;
|
||||||
@@ -61,3 +65,11 @@ where
|
|||||||
pub fn run_main() -> ! {
|
pub fn run_main() -> ! {
|
||||||
panic!("codex-linux-sandbox is only supported on Linux");
|
panic!("codex-linux-sandbox is only supported on Linux");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load env vars from ~/.codex/.env and `$(pwd)/.env`.
|
||||||
|
fn load_dotenv() {
|
||||||
|
if let Ok(codex_home) = codex_core::config::find_codex_home() {
|
||||||
|
dotenvy::from_path(codex_home.join(".env")).ok();
|
||||||
|
}
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user