mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
## Why Enterprise sign-in needs to keep browser completion separate from credential storage so callers can recheck the active account and configuration before saving a grant. Logout must also prevent an earlier sign-in from restoring credentials, including from another process sharing `CODEX_HOME`. ## What changed - Add enterprise login APIs in `rmcp-client` that return an authorization URL and stage validated credentials for an explicit `commit_if` call. Store grants only in the keyring after rechecking caller authority under the credential lock. - Require a registered client ID, published metadata matching the configured issuer, HTTP loopback callbacks, a refresh token, and a valid OIDC identity assertion. Request `openid` and `offline_access` with `prompt=consent`, and omit MCP resource indicators from authorization and code exchange. - Persist a login generation under the credential lock so logout invalidates pending and staged sign-ins across processes, even when no grant is stored. - Keep credentials and account identifiers out of enterprise error chains and logs, and avoid logging callback payloads when the receiver has closed. ## Testing Add coverage for discovery validation, loopback callbacks, PKCE, staged keyring storage, cancellation, stale attempts, cross-process logout, and error/log privacy. Preserve ordinary MCP OAuth login without a refresh token, and adjust the terminal polling test deadline to include the minimum empty-poll wait. GitOrigin-RevId: 2a27b9a26505a2f6fdecce8877f6e2c21e148f72
70 lines
2.1 KiB
Rust
70 lines
2.1 KiB
Rust
use std::path::Path;
|
|
use std::sync::Mutex;
|
|
use std::sync::MutexGuard;
|
|
use std::sync::OnceLock;
|
|
use std::sync::PoisonError;
|
|
|
|
use tempfile::tempdir;
|
|
|
|
/// Build the actual client's Stop-policy route pool before measuring protocol deadlines.
|
|
/// Client construction loads platform/custom CA state and can be slow on developer hosts.
|
|
/// Use a separate local endpoint so warmup cannot affect the test server's request assertions;
|
|
/// the same production HTTP capability still applies all proxy and certificate policy.
|
|
pub(crate) async fn warm_http_client(
|
|
client: &dyn codex_exec_server::HttpClient,
|
|
) -> anyhow::Result<()> {
|
|
let server = wiremock::MockServer::start().await;
|
|
client
|
|
.http_request(codex_exec_server::HttpRequestParams {
|
|
method: "GET".to_string(),
|
|
url: server.uri(),
|
|
headers: Vec::new(),
|
|
body: None,
|
|
timeout_ms: None,
|
|
redirect_policy: codex_exec_server::HttpRedirectPolicy::Stop,
|
|
request_id: "test-client-warmup".to_string(),
|
|
stream_response: false,
|
|
})
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Serializes tests that mutate process-wide CODEX_HOME.
|
|
///
|
|
/// Keep OAuth tests on this one guard instead of defining per-module helpers; otherwise
|
|
/// concurrently running test modules can point File/Secrets storage at different homes.
|
|
pub(crate) struct TempCodexHome {
|
|
_guard: MutexGuard<'static, ()>,
|
|
_dir: tempfile::TempDir,
|
|
}
|
|
|
|
impl TempCodexHome {
|
|
pub(crate) fn new() -> Self {
|
|
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
|
|
let guard = LOCK
|
|
.get_or_init(Mutex::default)
|
|
.lock()
|
|
.unwrap_or_else(PoisonError::into_inner);
|
|
let dir = tempdir().expect("create CODEX_HOME temp dir");
|
|
unsafe {
|
|
std::env::set_var("CODEX_HOME", dir.path());
|
|
}
|
|
Self {
|
|
_guard: guard,
|
|
_dir: dir,
|
|
}
|
|
}
|
|
|
|
pub(super) fn path(&self) -> &Path {
|
|
self._dir.path()
|
|
}
|
|
}
|
|
|
|
impl Drop for TempCodexHome {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
std::env::remove_var("CODEX_HOME");
|
|
}
|
|
}
|
|
}
|