mirror of
https://github.com/openai/codex.git
synced 2026-04-24 06:35:50 +00:00
Use OPENAI_API_KEY for api provisioning
Skip /api-provision when the current Codex process already inherited OPENAI_API_KEY, and otherwise persist the provisioned key to .env under OPENAI_API_KEY instead of CODEX_API_KEY. Validation: - cargo test -p codex-login - cargo test -p codex-tui - just fix -p codex-login - just fix -p codex-tui - just fmt Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -3,7 +3,7 @@ use std::io;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
|
||||
use codex_core::auth::CODEX_API_KEY_ENV_VAR;
|
||||
use codex_core::auth::OPENAI_API_KEY_ENV_VAR;
|
||||
|
||||
pub fn validate_dotenv_target(path: &Path) -> io::Result<()> {
|
||||
ensure_parent_dir(path)?;
|
||||
@@ -21,7 +21,7 @@ pub fn upsert_dotenv_api_key(path: &Path, api_key: &str) -> io::Result<()> {
|
||||
if api_key.contains(['\n', '\r']) {
|
||||
return Err(io::Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"CODEX_API_KEY must not contain newlines",
|
||||
"OPENAI_API_KEY must not contain newlines",
|
||||
));
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ pub fn upsert_dotenv_api_key(path: &Path, api_key: &str) -> io::Result<()> {
|
||||
let mut wrote_api_key = false;
|
||||
|
||||
for segment in split_lines_preserving_terminators(&existing) {
|
||||
if is_active_assignment_for(segment, CODEX_API_KEY_ENV_VAR) {
|
||||
if is_active_assignment_for(segment, OPENAI_API_KEY_ENV_VAR) {
|
||||
if !wrote_api_key {
|
||||
next.push_str(&format!("{CODEX_API_KEY_ENV_VAR}={api_key}\n"));
|
||||
next.push_str(&format!("{OPENAI_API_KEY_ENV_VAR}={api_key}\n"));
|
||||
wrote_api_key = true;
|
||||
}
|
||||
continue;
|
||||
@@ -52,7 +52,7 @@ pub fn upsert_dotenv_api_key(path: &Path, api_key: &str) -> io::Result<()> {
|
||||
if !next.is_empty() && !next.ends_with('\n') {
|
||||
next.push('\n');
|
||||
}
|
||||
next.push_str(&format!("{CODEX_API_KEY_ENV_VAR}={api_key}\n"));
|
||||
next.push_str(&format!("{OPENAI_API_KEY_ENV_VAR}={api_key}\n"));
|
||||
}
|
||||
|
||||
std::fs::write(path, next)
|
||||
@@ -104,7 +104,7 @@ mod tests {
|
||||
upsert_dotenv_api_key(&dotenv_path, "sk-test-key").expect("write dotenv");
|
||||
|
||||
let written = std::fs::read_to_string(&dotenv_path).expect("read dotenv");
|
||||
assert_eq!(written, "CODEX_API_KEY=sk-test-key\n");
|
||||
assert_eq!(written, "OPENAI_API_KEY=sk-test-key\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -113,7 +113,7 @@ mod tests {
|
||||
let dotenv_path = temp_dir.path().join(".env");
|
||||
std::fs::write(
|
||||
&dotenv_path,
|
||||
"# comment\nCODEX_API_KEY=sk-old-1\nOTHER=value\nexport CODEX_API_KEY = sk-old-2\n",
|
||||
"# comment\nOPENAI_API_KEY=sk-old-1\nOTHER=value\nexport OPENAI_API_KEY = sk-old-2\n",
|
||||
)
|
||||
.expect("seed dotenv");
|
||||
|
||||
@@ -122,7 +122,7 @@ mod tests {
|
||||
let written = std::fs::read_to_string(&dotenv_path).expect("read dotenv");
|
||||
assert_eq!(
|
||||
written,
|
||||
"# comment\nCODEX_API_KEY=sk-new-key\nOTHER=value\n"
|
||||
"# comment\nOPENAI_API_KEY=sk-new-key\nOTHER=value\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ use std::sync::Arc;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::auth::AuthCredentialsStoreMode;
|
||||
use codex_core::auth::login_with_api_key;
|
||||
use codex_core::auth::read_openai_api_key_from_env;
|
||||
use codex_login::ApiProvisionOptions;
|
||||
use codex_login::CODEX_API_KEY_ENV_VAR;
|
||||
use codex_login::OPENAI_API_KEY_ENV_VAR;
|
||||
use codex_login::PendingApiProvisioning;
|
||||
use codex_login::ProvisionedApiKey;
|
||||
use codex_login::start_api_provisioning;
|
||||
@@ -31,14 +32,18 @@ pub(crate) fn start_command(
|
||||
cwd: PathBuf,
|
||||
forced_login_method: Option<ForcedLoginMethod>,
|
||||
) -> Result<ApiProvisionStartMessage, String> {
|
||||
if read_openai_api_key_from_env().is_some() {
|
||||
return Ok(existing_shell_api_key_message());
|
||||
}
|
||||
|
||||
let dotenv_path = cwd.join(".env");
|
||||
let start_hint = format!(
|
||||
"Codex will save {CODEX_API_KEY_ENV_VAR} to {path} and hot-apply it here when allowed.",
|
||||
"Codex will save {OPENAI_API_KEY_ENV_VAR} to {path} and hot-apply it here when allowed.",
|
||||
path = dotenv_path.display()
|
||||
);
|
||||
validate_dotenv_target(&dotenv_path).map_err(|err| {
|
||||
format!(
|
||||
"Unable to prepare {} for {CODEX_API_KEY_ENV_VAR}: {err}",
|
||||
"Unable to prepare {} for {OPENAI_API_KEY_ENV_VAR}: {err}",
|
||||
dotenv_path.display(),
|
||||
)
|
||||
})?;
|
||||
@@ -72,6 +77,17 @@ pub(crate) fn start_command(
|
||||
})
|
||||
}
|
||||
|
||||
fn existing_shell_api_key_message() -> ApiProvisionStartMessage {
|
||||
ApiProvisionStartMessage {
|
||||
message: format!(
|
||||
"{OPENAI_API_KEY_ENV_VAR} is already set in this Codex session; skipping API provisioning."
|
||||
),
|
||||
hint: Some(format!(
|
||||
"This Codex session already inherited {OPENAI_API_KEY_ENV_VAR} from its shell environment. Unset it and run /api-provision again if you want Codex to provision and save a different key."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn complete_command(
|
||||
session: PendingApiProvisioning,
|
||||
dotenv_path: PathBuf,
|
||||
@@ -112,10 +128,9 @@ fn live_apply_api_key(
|
||||
auth_manager: Arc<AuthManager>,
|
||||
) -> LiveApplyOutcome {
|
||||
if matches!(forced_login_method, Some(ForcedLoginMethod::Chatgpt)) {
|
||||
return LiveApplyOutcome::Skipped(
|
||||
"Saved the key to .env, but left this session unchanged because ChatGPT login is required here."
|
||||
.to_string(),
|
||||
);
|
||||
return LiveApplyOutcome::Skipped(format!(
|
||||
"Saved {OPENAI_API_KEY_ENV_VAR} to .env, but left this session unchanged because ChatGPT login is required here."
|
||||
));
|
||||
}
|
||||
|
||||
match login_with_api_key(codex_home, api_key, AuthCredentialsStoreMode::Ephemeral) {
|
||||
@@ -147,14 +162,14 @@ fn success_cell(
|
||||
),
|
||||
LiveApplyOutcome::Skipped(reason) => Some(reason),
|
||||
LiveApplyOutcome::Failed(err) => Some(format!(
|
||||
"Saved the key to {}, but could not hot-apply it in this session: {err}",
|
||||
dotenv_path.display()
|
||||
"Saved {OPENAI_API_KEY_ENV_VAR} to {}, but could not hot-apply it in this session: {err}",
|
||||
dotenv_path.display(),
|
||||
)),
|
||||
};
|
||||
|
||||
history_cell::new_info_event(
|
||||
format!(
|
||||
"Provisioned an API key for {organization} / {project} and saved {CODEX_API_KEY_ENV_VAR} to {}.",
|
||||
"Provisioned an API key for {organization} / {project} and saved {OPENAI_API_KEY_ENV_VAR} to {}.",
|
||||
dotenv_path.display()
|
||||
),
|
||||
hint,
|
||||
@@ -206,7 +221,7 @@ mod tests {
|
||||
},
|
||||
Path::new("/tmp/workspace/.env"),
|
||||
LiveApplyOutcome::Skipped(
|
||||
"Saved the key to .env, but left this session unchanged because ChatGPT login is required here."
|
||||
"Saved OPENAI_API_KEY to .env, but left this session unchanged because ChatGPT login is required here."
|
||||
.to_string(),
|
||||
),
|
||||
);
|
||||
@@ -214,6 +229,22 @@ mod tests {
|
||||
assert_snapshot!(render_cell(&cell));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn existing_shell_api_key_message_mentions_openai_api_key() {
|
||||
let message = existing_shell_api_key_message();
|
||||
|
||||
assert_eq!(
|
||||
message.message,
|
||||
"OPENAI_API_KEY is already set in this Codex session; skipping API provisioning."
|
||||
);
|
||||
assert_eq!(
|
||||
message.hint,
|
||||
Some(
|
||||
"This Codex session already inherited OPENAI_API_KEY from its shell environment. Unset it and run /api-provision again if you want Codex to provision and save a different key.".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn render_cell(cell: &PlainHistoryCell) -> String {
|
||||
cell.display_lines(120)
|
||||
.into_iter()
|
||||
|
||||
@@ -3,4 +3,4 @@ source: tui/src/api_provision.rs
|
||||
assertion_line: 192
|
||||
expression: render_cell(&cell)
|
||||
---
|
||||
• Provisioned an API key for Default Org / Default Project and saved CODEX_API_KEY to /tmp/workspace/.env. Updated this session to use the newly provisioned API key without touching auth.json.
|
||||
• Provisioned an API key for Default Org / Default Project and saved OPENAI_API_KEY to /tmp/workspace/.env. Updated this session to use the newly provisioned API key without touching auth.json.
|
||||
|
||||
@@ -3,4 +3,4 @@ source: tui/src/api_provision.rs
|
||||
assertion_line: 214
|
||||
expression: render_cell(&cell)
|
||||
---
|
||||
• Provisioned an API key for org-default / proj-default and saved CODEX_API_KEY to /tmp/workspace/.env. Saved the key to .env, but left this session unchanged because ChatGPT login is required here.
|
||||
• Provisioned an API key for org-default / proj-default and saved OPENAI_API_KEY to /tmp/workspace/.env. Saved OPENAI_API_KEY to .env, but left this session unchanged because ChatGPT login is required here.
|
||||
|
||||
Reference in New Issue
Block a user