mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
Default CLI auth credentials store to auto
This commit is contained in:
committed by
Mikhail Sosonkin
parent
19afbc35c1
commit
5802e4868f
@@ -339,6 +339,7 @@ unwrap_used = "deny"
|
||||
# silence the false positive here instead of deleting a real dependency.
|
||||
[workspace.metadata.cargo-shear]
|
||||
ignored = [
|
||||
"askama",
|
||||
"icu_provider",
|
||||
"openssl-sys",
|
||||
"codex-utils-readiness",
|
||||
|
||||
@@ -804,7 +804,13 @@ async fn external_auth_refresh_invalid_access_token_fails_turn() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn login_account_api_key_succeeds_and_notifies() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
create_config_toml(codex_home.path(), CreateConfigTomlParams::default())?;
|
||||
create_config_toml(
|
||||
codex_home.path(),
|
||||
CreateConfigTomlParams {
|
||||
requires_openai_auth: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
@@ -844,7 +850,28 @@ async fn login_account_api_key_succeeds_and_notifies() -> Result<()> {
|
||||
};
|
||||
pretty_assertions::assert_eq!(payload.auth_mode, Some(AuthMode::ApiKey));
|
||||
|
||||
assert!(codex_home.path().join("auth.json").exists());
|
||||
drop(mcp);
|
||||
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
|
||||
let get_id = mcp
|
||||
.send_get_account_request(GetAccountParams {
|
||||
refresh_token: false,
|
||||
})
|
||||
.await?;
|
||||
let get_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(get_id)),
|
||||
)
|
||||
.await??;
|
||||
let account: GetAccountResponse = to_response(get_resp)?;
|
||||
let expected = GetAccountResponse {
|
||||
account: Some(Account::ApiKey {}),
|
||||
requires_openai_auth: true,
|
||||
};
|
||||
assert_eq!(account, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -169,4 +169,4 @@ wiremock = { workspace = true }
|
||||
zstd = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["openssl-sys"]
|
||||
ignored = ["askama", "openssl-sys"]
|
||||
|
||||
@@ -125,6 +125,13 @@
|
||||
"AuthCredentialsStoreMode": {
|
||||
"description": "Determine where Codex should store CLI auth credentials.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Use keyring when available; otherwise, fall back to a file in CODEX_HOME.",
|
||||
"enum": [
|
||||
"auto"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Persist credentials in CODEX_HOME/auth.json.",
|
||||
"enum": [
|
||||
@@ -139,13 +146,6 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Use keyring when available; otherwise, fall back to a file in CODEX_HOME.",
|
||||
"enum": [
|
||||
"auto"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Store credentials in memory only for the current process.",
|
||||
"enum": [
|
||||
@@ -1286,7 +1286,7 @@
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"description": "Preferred backend for storing CLI auth credentials. file (default): Use a file in the Codex home directory. keyring: Use an OS-specific keyring service. auto: Use the keyring if available, otherwise use a file."
|
||||
"description": "Preferred backend for storing CLI auth credentials. auto (default): Use the keyring if available, otherwise use a file. file: Use a file in the Codex home directory. keyring: Use an OS-specific keyring service."
|
||||
},
|
||||
"compact_prompt": {
|
||||
"description": "Compact prompt used for history compaction.",
|
||||
|
||||
@@ -29,13 +29,13 @@ use once_cell::sync::Lazy;
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AuthCredentialsStoreMode {
|
||||
/// Use keyring when available; otherwise, fall back to a file in CODEX_HOME.
|
||||
#[default]
|
||||
Auto,
|
||||
/// Persist credentials in CODEX_HOME/auth.json.
|
||||
File,
|
||||
/// Persist credentials in the keyring. Fail if unavailable.
|
||||
Keyring,
|
||||
/// Use keyring when available; otherwise, fall back to a file in CODEX_HOME.
|
||||
Auto,
|
||||
/// Store credentials in memory only for the current process.
|
||||
Ephemeral,
|
||||
}
|
||||
@@ -260,8 +260,13 @@ impl AuthStorageBackend for AutoAuthStorage {
|
||||
}
|
||||
|
||||
fn delete(&self) -> std::io::Result<bool> {
|
||||
// Keyring storage will delete from disk as well
|
||||
self.keyring_storage.delete()
|
||||
match self.keyring_storage.delete() {
|
||||
Ok(removed) => Ok(removed),
|
||||
Err(err) => {
|
||||
warn!("failed to delete auth from keyring, falling back to file deletion: {err}");
|
||||
self.file_storage.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,4 +760,28 @@ mod tests {
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_auth_storage_delete_falls_back_when_keyring_errors() -> anyhow::Result<()> {
|
||||
let codex_home = tempdir()?;
|
||||
let mock_keyring = MockKeyringStore::default();
|
||||
let storage = AutoAuthStorage::new(
|
||||
codex_home.path().to_path_buf(),
|
||||
Arc::new(mock_keyring.clone()),
|
||||
);
|
||||
let key = compute_store_key(codex_home.path())?;
|
||||
mock_keyring.set_error(&key, KeyringError::Invalid("error".into(), "delete".into()));
|
||||
|
||||
let auth_file = get_auth_file(codex_home.path());
|
||||
std::fs::write(&auth_file, "stale")?;
|
||||
|
||||
let removed = storage.delete()?;
|
||||
|
||||
assert!(removed, "fallback deletion should report removal");
|
||||
assert!(
|
||||
!auth_file.exists(),
|
||||
"fallback auth.json should be removed when keyring delete fails"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,9 +261,9 @@ pub struct Config {
|
||||
pub cwd: PathBuf,
|
||||
|
||||
/// Preferred store for CLI auth credentials.
|
||||
/// file (default): Use a file in the Codex home directory.
|
||||
/// auto (default): Use the OS-specific keyring service if available, otherwise use a file.
|
||||
/// file: Use a file in the Codex home directory.
|
||||
/// keyring: Use an OS-specific keyring service.
|
||||
/// auto: Use the OS-specific keyring service if available, otherwise use a file.
|
||||
pub cli_auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
|
||||
/// Definition for MCP servers that Codex can reach out to for tool calls.
|
||||
@@ -923,9 +923,9 @@ pub struct ConfigToml {
|
||||
pub forced_login_method: Option<ForcedLoginMethod>,
|
||||
|
||||
/// Preferred backend for storing CLI auth credentials.
|
||||
/// file (default): Use a file in the Codex home directory.
|
||||
/// auto (default): Use the keyring if available, otherwise use a file.
|
||||
/// file: Use a file in the Codex home directory.
|
||||
/// keyring: Use an OS-specific keyring service.
|
||||
/// auto: Use the keyring if available, otherwise use a file.
|
||||
#[serde(default)]
|
||||
pub cli_auth_credentials_store: Option<AuthCredentialsStoreMode>,
|
||||
|
||||
@@ -2465,7 +2465,7 @@ trust_level = "trusted"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_defaults_to_file_cli_auth_store_mode() -> std::io::Result<()> {
|
||||
fn config_defaults_to_auto_cli_auth_store_mode() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml::default();
|
||||
|
||||
@@ -2477,7 +2477,7 @@ trust_level = "trusted"
|
||||
|
||||
assert_eq!(
|
||||
config.cli_auth_credentials_store_mode,
|
||||
AuthCredentialsStoreMode::File,
|
||||
AuthCredentialsStoreMode::Auto,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user