mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Wire app-server user verification RPCs to the native provider (#43568)
## Why The existing `userVerification/*` handlers always returned unavailability, leaving local clients unable to use the native verification provider. ## What changed - Dispatch status, enrollment, deletion, and challenge signing through an account-scoped provider. Enrollment creates or reuses a local key; it does not register credentials with a server. - Restrict enrollment, deletion, and signing to stdio and in-process connections, rejecting WebSocket and remote-control callers before parameter validation. - Bound native work to one operation per service with a 120-second timeout, and propagate in-process caller cancellation. Recheck connection, cancellation, and authentication state before delivering results, including after waiting for response queue capacity. - Add device-gated verification capability wiring for the experimental in-process `codex-tui` client, with automatic activation still disabled by default. ## Testing Add tests for local key reuse and deletion, decoded challenge signing, cancellation, authentication changes during verification and response queuing, concurrent worker rejection, and stdio/WebSocket RPC behavior. GitOrigin-RevId: 7eac15a5ffb049d27bf8fedcfbae19a49a3f6a3d
This commit is contained in:
@@ -135,6 +135,7 @@ fn reject_removed_permission_profile(request: &JSONRPCRequest) -> Result<(), JSO
|
||||
}
|
||||
|
||||
pub(crate) struct MessageProcessor {
|
||||
user_verification: Arc<crate::user_verification::Service>,
|
||||
outgoing: Arc<OutgoingMessageSender>,
|
||||
models_refresh_worker: ModelsRefreshWorker,
|
||||
turn_cost_worker: Option<TurnCostWorker>,
|
||||
@@ -168,6 +169,7 @@ pub(crate) struct MessageProcessor {
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ConnectionSessionState {
|
||||
pub(crate) rpc_gate: Arc<ConnectionRpcGate>,
|
||||
pub(crate) origin: crate::transport::ConnectionOrigin,
|
||||
pub(crate) mcp_event_streams: McpEventStreams,
|
||||
initialized: OnceLock<InitializedConnectionSessionState>,
|
||||
}
|
||||
@@ -182,15 +184,10 @@ pub(crate) struct InitializedConnectionSessionState {
|
||||
pub(crate) client_mcp_extensions: ClientMcpExtensions,
|
||||
}
|
||||
|
||||
impl Default for ConnectionSessionState {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectionSessionState {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub(crate) fn new(origin: crate::transport::ConnectionOrigin) -> Self {
|
||||
Self {
|
||||
origin,
|
||||
rpc_gate: Arc::new(ConnectionRpcGate::new()),
|
||||
mcp_event_streams: McpEventStreams::default(),
|
||||
initialized: OnceLock::new(),
|
||||
@@ -256,6 +253,7 @@ pub(crate) struct MessageProcessorArgs {
|
||||
pub(crate) config_warnings: Vec<ConfigWarningNotification>,
|
||||
pub(crate) session_source: SessionSource,
|
||||
pub(crate) auth_manager: Arc<AuthManager>,
|
||||
pub(crate) user_verification: Arc<crate::user_verification::Service>,
|
||||
pub(crate) installation_id: String,
|
||||
pub(crate) code_mode_session_provider: Option<Arc<dyn CodeModeSessionProvider>>,
|
||||
pub(crate) rpc_transport: AppServerRpcTransport,
|
||||
@@ -281,6 +279,7 @@ impl MessageProcessor {
|
||||
config_warnings,
|
||||
session_source,
|
||||
auth_manager,
|
||||
user_verification,
|
||||
installation_id,
|
||||
code_mode_session_provider,
|
||||
rpc_transport,
|
||||
@@ -448,6 +447,7 @@ impl MessageProcessor {
|
||||
Arc::clone(&config),
|
||||
config_warnings.clone(),
|
||||
rpc_transport,
|
||||
Arc::clone(&user_verification),
|
||||
);
|
||||
let marketplace_processor = MarketplaceRequestProcessor::new(
|
||||
Arc::clone(&config),
|
||||
@@ -569,6 +569,7 @@ impl MessageProcessor {
|
||||
);
|
||||
|
||||
Self {
|
||||
user_verification,
|
||||
outgoing,
|
||||
models_refresh_worker,
|
||||
turn_cost_worker,
|
||||
@@ -671,6 +672,7 @@ impl MessageProcessor {
|
||||
request: ClientRequest,
|
||||
session: Arc<ConnectionSessionState>,
|
||||
outbound_initialized: &AtomicBool,
|
||||
cancellation: tokio_util::sync::CancellationToken,
|
||||
) {
|
||||
let request_id = ConnectionRequestId {
|
||||
connection_id,
|
||||
@@ -678,8 +680,9 @@ impl MessageProcessor {
|
||||
};
|
||||
let request_span =
|
||||
crate::app_server_tracing::typed_request_span(&request, connection_id, &session);
|
||||
let request_context =
|
||||
let mut request_context =
|
||||
RequestContext::new(request_id.clone(), request_span, /*parent_trace*/ None);
|
||||
request_context.cancellation = cancellation;
|
||||
tracing::trace!(
|
||||
?connection_id,
|
||||
request_id = ?request_id.request_id,
|
||||
@@ -992,11 +995,43 @@ impl MessageProcessor {
|
||||
ClientRequest::Initialize { .. } => {
|
||||
panic!("Initialize should be handled before initialized request dispatch");
|
||||
}
|
||||
ClientRequest::UserVerificationStatus { .. }
|
||||
request @ (ClientRequest::UserVerificationStatus { .. }
|
||||
| ClientRequest::UserVerificationEnroll { .. }
|
||||
| ClientRequest::UserVerificationDelete { .. }
|
||||
| ClientRequest::UserVerificationVerify { .. } => {
|
||||
Err(crate::user_verification::unavailable())
|
||||
| ClientRequest::UserVerificationVerify { .. }) => {
|
||||
return Box::pin(async {
|
||||
// Keep verification temporaries out of unrelated RPCs' stack frames.
|
||||
let operation = match request {
|
||||
ClientRequest::UserVerificationStatus { .. } => {
|
||||
crate::user_verification::Operation::Status
|
||||
}
|
||||
ClientRequest::UserVerificationEnroll { .. } => {
|
||||
crate::user_verification::Operation::Enroll
|
||||
}
|
||||
ClientRequest::UserVerificationDelete { .. } => {
|
||||
crate::user_verification::Operation::Delete
|
||||
}
|
||||
ClientRequest::UserVerificationVerify { params, .. } => {
|
||||
crate::user_verification::Operation::Verify(params)
|
||||
}
|
||||
_ => unreachable!("matched a user-verification request"),
|
||||
};
|
||||
let response = self
|
||||
.user_verification
|
||||
.handle(
|
||||
operation,
|
||||
Arc::clone(&session.rpc_gate),
|
||||
request_context.cancellation.clone(),
|
||||
session.origin,
|
||||
)
|
||||
.await?;
|
||||
let (payload, check) = response.into_parts();
|
||||
self.outgoing
|
||||
.send_response_as_checked(request_id.clone(), payload, check)
|
||||
.await;
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
}
|
||||
ClientRequest::ServerDiagnostics { .. } => Ok(Some(read_server_diagnostics().into())),
|
||||
ClientRequest::ConfigRead { params, .. } => self
|
||||
|
||||
Reference in New Issue
Block a user