mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## Why Concurrent Codex processes can otherwise refresh the same rotating token, and a cancelled or partially persisted refresh can leave durable and in-memory MCP credentials out of sync. ## What changed - Serialize each credential's read-refresh-write transaction across processes, reread the authoritative store after locking, and adopt credentials refreshed by another process. - Keep refresh persistence running after caller cancellation, bound lock and provider waits independently, and preserve omitted refresh tokens and scopes. - Fail MCP startup and operations when refresh or persistence fails instead of continuing with stale credentials, while requiring reauthorization for missing, unusable, or rejected refresh tokens. - Exclude OAuth refresh time from the MCP initialization timeout. ## Testing Add coverage for lock contention, concurrent refreshes, rejected and missing credentials, storage failures, caller cancellation, and provider timeouts. GitOrigin-RevId: 4d29b879bec646d2ceb922b526dc793b1a1f5423
41 lines
1.0 KiB
Rust
41 lines
1.0 KiB
Rust
use super::RefreshCredentialLock;
|
|
use anyhow::Result;
|
|
use std::time::Duration;
|
|
use tempfile::tempdir;
|
|
|
|
#[tokio::test]
|
|
async fn acquisition_times_out_without_stealing() -> Result<()> {
|
|
let codex_home = tempdir()?;
|
|
let store_key = "test-store-key";
|
|
let held_lock = RefreshCredentialLock::acquire_in(
|
|
codex_home.path(),
|
|
store_key,
|
|
Duration::from_millis(/*millis*/ 100),
|
|
)
|
|
.await?;
|
|
|
|
let error = RefreshCredentialLock::acquire_in(
|
|
codex_home.path(),
|
|
store_key,
|
|
Duration::from_millis(/*millis*/ 50),
|
|
)
|
|
.await
|
|
.err()
|
|
.expect("contending lock acquisition should time out");
|
|
assert!(
|
|
error
|
|
.to_string()
|
|
.contains("timed out after 50ms waiting for OAuth refresh lock"),
|
|
"unexpected error: {error:#}"
|
|
);
|
|
|
|
drop(held_lock);
|
|
let _reacquired = RefreshCredentialLock::acquire_in(
|
|
codex_home.path(),
|
|
store_key,
|
|
Duration::from_millis(/*millis*/ 100),
|
|
)
|
|
.await?;
|
|
Ok(())
|
|
}
|