15 Commits
Author SHA1 Message Date
Nick Steele a6baf8867c Signal abandonment of unanswered MCP elicitations (#51611)
## Why

Published MCP elicitation requests could lose their response waiter without notifying the event consumer that the request was no longer answerable.

## What changed

- Add `ElicitationAbandoned` with the original server name and response token for requests published through unbounded event channels.
- Emit abandonment exactly once when a waiter is dropped, response delivery fails, or the MCP runtime shuts down.
- Close the elicitation router during shutdown, reject new requests on unbounded sources, and wait for terminal deliveries before shutdown completes. Preserve bounded sources' request-only behavior and backpressure.

## Testing

Add router tests for ordered, exactly-once abandonment, closed receivers, failed response delivery, shutdown coordination, and bounded-channel backpressure. Add a core integration scenario verifying that a pending form's abandonment precedes `ShutdownComplete`.

GitOrigin-RevId: 53fe9f4a8b32f7324be180288aa492f31f4d2057
2026-10-07 07:57:14 +00:00
Nick Steele ecc78e4cf5 Add renewable EMA HTTP authentication and credential versioning (#49987)
## What changed

- Add `EmaAuthenticatedHttpClient` to cache and renew resource bearers, serialize concurrent renewals, and include authentication time in the request deadline. Confine bearers to the configured MCP endpoint and reject redirects.
- Return authentication-required errors for `401` responses without replaying MCP operations. Preserve a newer cached bearer when a delayed response rejects an older one.
- Add revocable request authority that cancels pending requests and ends response streams.
- Pin enterprise credentials to a persistent version advanced on save or deletion. Use short credential locks and invalidate rejected grants only when their record and version are still current, preserving newer logins.
- Hide keyring account identifiers from enterprise credential errors and traces while preserving authentication failure classification.

## Testing

Add tests for token expiry and renewal, endpoint confinement, redirects, request deadlines, revocation during renewal and streaming, delayed `401` responses, credential replacement and logout races, and credential error privacy.

GitOrigin-RevId: ee3e5cf7ecbba3d09e1ab29ed4fbb2a35eacc60d
2026-10-01 13:57:48 +00:00
Nick Steele 15fd656ddb Discover and validate MCP authorization servers before ID-JAG exchange (#49478)
## What changed

Add `exchange_ema_auth_token` to discover and validate the MCP resource's authorization server before resolving enterprise identity credentials and performing the ID-JAG token exchange. Keep the lower-level exchange primitive private.

- Probe `server/discover` with the enterprise-managed authorization extension, support recognized legacy discovery rejections, and follow protected-resource metadata challenges or well-known fallbacks.
- Match configured resource and issuer constraints, require advertised public-client JWT bearer support, and validate token endpoint metadata without requiring an authorization endpoint.
- Bound discovery with a shared timeout, redirect and authorization-server limits, reject cross-origin metadata redirects, and restrict private authorization-server destinations while allowing local loopback discovery.

## Testing

Add tests covering resource and issuer mismatches before identity access, metadata capability validation, query preservation, modern challenges, JSON and SSE legacy fallback behavior, cross-origin redirect rejection, and private or malformed issuer destinations.

GitOrigin-RevId: 9a55233a20ff42c293f9bd8175e01141ac2d8576
2026-09-30 04:30:01 +00:00
Nick Steele c9b3924a62 Use the rmcp SDK for enterprise-managed token exchanges (#49473)
## What changed

Upgrade `rmcp` to a pinned Git revision of version `3.3.0` and enable `auth-enterprise-managed`. Delegate the two-stage ID-JAG exchange and token validation to the SDK, replacing the local implementation while retaining Codex HTTP routing and credential lifecycle policy.

Map SDK errors by exchange stage so `invalid_grant` distinguishes enterprise identity failures from resource authorization failures, and preserve handling of `insufficient_user_authentication`.

## Testing

Update exchange tests to verify rejection of unsupported `authorization_details` and malformed signed scopes. Exercise errors from both token endpoints to check credential policy, prevent credential reflection in diagnostics, and ensure rejected grants are not retried.

GitOrigin-RevId: a56034aa3fd70002754ea552fd2da70bdcd85b31
2026-09-30 03:33:43 +00:00
Nick Steele 4773a132c3 Add /mcp login <name> to the TUI (#49290)
## What changed

Allow users with an active session to start MCP OAuth sign-in through `/mcp login <name>`. Request login through the app server, open the authorization URL in the browser, and display success or failure in the originating thread.

Guard overlapping start requests and track login attempts per server so stale retry completions do not overwrite current results. Skip opening the browser when the attempt has already completed, and retain results across thread switches and session refreshes.

## Testing

Add command dispatch coverage and regression tests for overlapping starts, stale retry completions, rejected starts, independent server logins, and result retention across thread switches and session refreshes.

GitOrigin-RevId: aeec2dbee566660f9aa26ef23039196ef3ca49d6
2026-09-29 16:00:05 +00:00
Nick Steele 4994306e9f Enable enterprise MCP sign-in and account-scoped grant cleanup (#49276)
## Why

The app server previously rejected OAuth login for enterprise-managed MCP servers. These servers need an explicit sign-in flow that ties saved authorization to the active Codex user and workspace and prevents canceled or superseded attempts from saving credentials.

## What changed

- Enable enterprise sign-in through `mcpServer/oauth/login` for configured servers with a connected thread, trusted IdP registration, and `features.use_xaa` enabled. Scope shared enterprise credentials by user, workspace, issuer, and client ID.
- Add `loginId` to MCP OAuth login responses and completion notifications, preserving compatibility with older servers that omit it.
- Support enterprise login replacement and `account/login/cancel`, wait for callback listener shutdown before replacement, and recheck account and configuration before saving grants. Fence stale attempts across processes and account changes.
- Remove shared enterprise authorization during account logout and `codex mcp logout`, including when the feature is disabled. Continue account logout if enterprise cleanup fails, and invalidate MCP runtimes on account changes.

Start a fresh session after successful enterprise sign-in to use the saved grant.

## Testing

Add regression coverage for login replacement and cancellation, callback port reuse, account changes during setup, cross-process logout invalidation, persisted workspace policy selection, cleanup failures, and responses from older servers without `loginId`.

GitOrigin-RevId: 7ed4caaab4659ed1e67064262cf5cee48e3a26ac
2026-09-29 14:46:33 +00:00
Nick Steele 0b1b78a4f1 Preserve thread overrides and cloud policy validity during config reloads (#49269)
## Why

Reloads can reject a valid thread configuration when the host configuration references a missing model provider that thread overrides replace. Concurrent cloud refreshes can also leave older policy snapshots or staged cache writes eligible for publication.

## What changed

- Compose preserved session layers before materializing refreshed configuration, retaining source-aware validation errors.
- Carry cloud policy revision bindings through config loading and role overrides. Reject stale MCP refreshes and disable enterprise MCP authorization when the policy is suspended. Retire the old policy when replacing or clearing its loader.
- Stage cloud cache writes in temporary files and publish them atomically only while their policy revision remains current.
- Route file reloads through the shared runtime refresh path, resolve paths relative to each config file, and preserve session settings. Restore host defaults for `secret_auth_storage` and `mcp_oauth_refresh_coordination` when explicit overrides are removed.

## Testing

Add regressions for thread-provided model providers, managed plugin and feature requirement refreshes, stale and suspended policy snapshots, superseded and retired cache writes, and file reloads preserving runtime settings and restoring feature defaults.

GitOrigin-RevId: 3280a2445eeb7074a142f720690bb0e4f01d174b
2026-09-29 13:58:09 +00:00
Nick Steele af0d68a236 Restrict enterprise MCP auth and fail closed on config refresh (#49260)
## Why

Configuration reloads must honor current managed restrictions without granting new enterprise MCP authority to existing sessions or overwriting newer configuration with stale snapshots.

## What changed

- Allow enterprise managed authentication only for configured MCP servers. Remove plugin `ema_auth` overlays from the schema and disable servers that still use them.
- Refresh ordinary MCP settings while preserving session settings and initially admitted enterprise registrations. Disable enterprise MCP when its registration changes, policy revokes access, or configuration loading or resolution fails; require a new session to restore enterprise authority.
- Publish refreshes only when their captured configuration is still current, with bounded retries in app-server reloads. Preserve updated managed restrictions even when a refresh is rejected.
- Finish processing other thread refreshes before `config/mcpServer/reload` reports a rejection, and document that an error can accompany partially applied changes.

## Testing

Add regression coverage for stale refreshes, bounded retries, managed-policy revocation, persistent enterprise disablement, ordinary MCP transport changes, and rejection of plugin enterprise authentication. Verify that denied enterprise servers receive no requests.

GitOrigin-RevId: 34429cd339c1ec152a2ee8697cb29f0cff5d9e5f
2026-09-29 13:08:37 +00:00
Nick Steele 7cec3e110c Mask daemon socket paths exposed through ancestor bind mounts (#47079)
## Why

The Linux sandbox rejected bind mounts of ancestors of the app-server socket directory, even when the exposed socket paths could be masked. This prevented sandbox startup with otherwise usable temporary-directory mount layouts.

## What changed

- Collect the socket directory and its exposed ancestor-mount aliases, then mask each path after filesystem binds, including read-only subpaths and the synthetic-mount registry.
- Continue rejecting direct directory or socket aliases and nested mounts that cannot preserve socket isolation.
- Reject non-UTF-8 mask destinations to avoid masking a different path through lossy conversion.

## Testing

Extend mount-analysis tests for ancestor aliases, private temporary directories, and WSLg masks. Extend socket-isolation coverage to verify that ancestor and registry aliases hide daemon sockets while unrelated sockets remain reachable. Add a regression test for non-UTF-8 mask paths.

GitOrigin-RevId: 49a9a764fbe1fddacd99c3a78099fbffff53b944
2026-09-21 18:04:14 +00:00
Nick Steele 374c4b2d82 Resolve enterprise-managed MCP registrations in the catalog (#45459)
## What changed

- Retain the trusted enterprise identity provider in runtime configuration and bind winning MCP registrations during catalog finalization. Require `features.use_xaa` and a configured identity provider for activation, while preserving existing server restrictions.
- Apply plugin `ema_auth` client, issuer, resource, and scope settings to installed and selected plugins. Disable registrations with mismatched endpoints or empty resources without rewriting plugin endpoints.
- Preserve enterprise auth policy across catalog rebuilds and rebind registrations when materialized server settings change. Keep registration rejection separate from persistent server-name vetoes so it does not disable replacement hosted apps.

## Testing

Add coverage for activation gates, configuration ownership, plugin endpoint validation, catalog rebuilds, and skipping interactive OAuth during installation of enterprise-managed plugins. Stabilize the sandbox network proxy test by reading request headers before closing the loopback connection.

GitOrigin-RevId: 3374f507d120835b285767cedbbb511fc7b0fba2
2026-09-14 16:30:00 +00:00
Nick Steele 654b0a77d0 Add trusted enterprise MCP auth configuration (#44832)
## Why

Enterprise MCP authorization must remain controlled by host, user, or managed configuration. Project settings and plugin declarations must not redirect enterprise credentials or downgrade the selected authentication mode.

## What changed

- Add `auth = "ema_auth"`, shared `mcp_enterprise_managed_auth` IdP configuration, and per-plugin enterprise registration settings.
- Require enterprise registrations to come from one non-project configuration layer, preserve managed IdP precedence, and reject project overrides that change authorization or re-enable disabled enterprise servers.
- Add the disabled-by-default `use_xaa` feature flag and require non-project opt-in or a managed requirement.
- Reject plugin declarations that select `ema_auth`. Keep EMA connections unsupported and block ordinary MCP OAuth login and credential fallback for this mode.
- Extend the configuration schema and serialization for the new settings.

## Testing

Add coverage for IdP precedence, incomplete registrations, alternate credential validation, project-only opt-in, plugin self-declaration rejection, configuration round-tripping, and trusted-project attempts to downgrade enterprise auth to OAuth or ChatGPT auth.

GitOrigin-RevId: f193bdfda74208c98e496a23bf2916955b131a1c
2026-09-11 14:25:56 +00:00
Nick Steele 86661eb626 Simplify enterprise OAuth login helpers and expand callback tests (#44616)
## What changed

- Consolidate callback address and port parsing in `enterprise_callback_settings`.
- Reuse `StoredOAuthTokens::has_refresh_token` for credential validation.
- Keep `EnterpriseOAuthHttpClient` private and inline removal of the `resource` parameter from authorization code token requests.
- Share the `complete_login` test helper across login and logout tests.

## Testing

Expand callback settings coverage to check default and configured ports, ports from callback URLs, and rejection of conflicting ports alongside loopback address validation.

GitOrigin-RevId: 42c9be5663ce13b7349cefac2c6a20c4fa974aef
2026-09-10 18:43:15 +00:00
Nick Steele b090e901f8 Add staged enterprise OIDC login and coordinated logout (#43844)
## 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
2026-09-08 16:07:38 +00:00
Nick Steele 9b4a0f8a0a Add enterprise IdP identity resolution for MCP OAuth (#40739)
## What changed

- Resolve stored enterprise IdP sessions against discovered authorization
  metadata, requiring the configured issuer, public-client authentication, and
  supported ID-JAG token exchange capabilities.
- Bind OIDC identity claims and MCP resource indicators to their configured
  issuer, client, and server, and require reauthentication when pinned keyring
  credentials are removed or replaced.
- Hold the credential lock while rereading refresh tokens, and isolate
  enterprise credentials by reserved namespace and Codex home.

## Testing

- Cover metadata and claim validation, resource binding, credential replacement
  and keyring failures, refresh locking, expired ID tokens, and credential
  namespace isolation.

GitOrigin-RevId: edce3c6159f7d6831edf72e9608b3fc3f5823c83
2026-08-25 23:51:57 +00:00
Nick Steele f6805328c4 Add enterprise ID-JAG exchange for MCP OAuth (#40722)
## What changed

- Add a non-interactive two-step exchange that obtains an ID-JAG from an
  enterprise identity provider and trades it for a resource-bound MCP bearer
  token.
- Validate trusted endpoint URLs, request inputs, ID-JAG claims, resource and
  scope bindings, and token responses before credentials are forwarded or a
  bearer token is returned.
- Expose structured authentication failures while redacting credentials and
  provider-controlled error details from diagnostics.

## Testing

- Cover successful exchanges, signed scope narrowing, invalid claims and token
  responses, request validation, and error redaction.

GitOrigin-RevId: d716e0e1c2dc6b230cecbc0e9cc09afeee81d599
2026-08-25 22:12:41 +00:00