From 08584b229d6ae5fb3510f088f7d84538d3840d89 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Sun, 30 Aug 2026 22:50:15 +0000 Subject: [PATCH] refactor(gateway): delete dead accessors and FromRef impls (review 002 COV-13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverage-confirmed dead code (every binary, zero hits): - server/state.rs: drop FromRef impls for Arc and Arc — no route extracts these types; the auth middleware receives the provider directly via from_fn_with_state - gateway/dispatch.rs: drop identity_provider() and resolve_bearer() accessors; resolve_bearer's doc promised an auth hook the middleware never calls (spec/code drift). Wire-or-delete resolved to delete: bearer resolution lives in the middleware (SRV-11 single-resolve ordering), the dispatch spine only needs the per-call Option. GatewayDispatch::new consequently takes the registry alone (GatewayState loses its unused identity_provider passthrough; dispatch.rs/to_mcp.rs tests simplified) - websocket/upgrade.rs: drop FromRef for Arc — no router carries SessionState as its state type; the inverse FromRef> for SessionState (custom upgrade routes, integration tests) remains Verification: ./scripts/verify.sh (352 passed), ./scripts/verify.sh --all-features (466 passed), clippy -D warnings, fmt --check. --- src/adapters/to_mcp.rs | 91 +++++++++------------------------------- src/gateway/dispatch.rs | 78 ++++++++-------------------------- src/gateway/routes.rs | 16 ++----- src/server/adapter.rs | 5 +-- src/server/state.rs | 12 ------ src/websocket/upgrade.rs | 6 --- 6 files changed, 41 insertions(+), 167 deletions(-) diff --git a/src/adapters/to_mcp.rs b/src/adapters/to_mcp.rs index 89d3e7c..3e16ea6 100644 --- a/src/adapters/to_mcp.rs +++ b/src/adapters/to_mcp.rs @@ -502,7 +502,6 @@ pub fn to_mcp_service(dispatch: Arc) -> ToMcpService { #[cfg(test)] mod tests { use super::*; - use alkcall::core::auth::{AuthToken, IdentityProvider}; use alkcall::core::types::Capabilities; use alkcall::registry::context::{OperationContext, ScopedPeerEnv}; use alkcall::registry::discovery::{ @@ -516,41 +515,6 @@ mod tests { use futures::StreamExt; use rmcp::model::Extensions; use std::collections::HashMap; - use std::sync::Mutex as StdMutex; - - struct StaticIdentityProvider { - tokens: StdMutex>, - } - - impl StaticIdentityProvider { - fn new() -> Self { - Self { - tokens: StdMutex::new(HashMap::new()), - } - } - - fn with_token(self, token: &str, identity: Identity) -> Self { - self.tokens - .lock() - .unwrap_or_else(|e| e.into_inner()) - .insert(token.to_string(), identity); - self - } - } - - impl IdentityProvider for StaticIdentityProvider { - fn resolve_from_fingerprint(&self, _fp: &str) -> Option { - None - } - fn resolve_from_token(&self, token: &AuthToken) -> Option { - let token_str = String::from_utf8_lossy(&token.raw); - self.tokens - .lock() - .unwrap_or_else(|e| e.into_inner()) - .get(token_str.as_ref()) - .cloned() - } - } fn identity_with_scopes(id: &str, scopes: &[&str]) -> Identity { Identity { @@ -675,15 +639,8 @@ mod tests { Arc::new(dispatch_registry) } - fn dispatch( - registry: Arc, - provider: Arc, - ) -> Arc { - Arc::new(GatewayDispatch::new(registry, provider)) - } - - fn provider() -> Arc { - Arc::new(StaticIdentityProvider::new()) + fn dispatch(registry: Arc) -> Arc { + Arc::new(GatewayDispatch::new(registry)) } fn extensions_with_identity(identity: Option) -> Extensions { @@ -728,7 +685,7 @@ mod tests { #[tokio::test] async fn list_tools_returns_exactly_four_gateway_tools() { - let _gateway = ToMcpGateway::new(dispatch(full_registry_with_ops(vec![]), provider())); + let _gateway = ToMcpGateway::new(dispatch(full_registry_with_ops(vec![]))); let tools = gateway_tools(); let names: Vec = tools.iter().map(|t| t.name.to_string()).collect(); assert_eq!(names.len(), 4); @@ -745,7 +702,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let _gateway = ToMcpGateway::new(dispatch(registry, provider())); + let _gateway = ToMcpGateway::new(dispatch(registry)); let tools = gateway_tools(); for tool in &tools { assert_ne!(tool.name, "fs/readFile"); @@ -777,9 +734,7 @@ mod tests { AccessControl::default(), ), ]); - let idp: Arc = - Arc::new(StaticIdentityProvider::new()); - let gateway = ToMcpGateway::new(dispatch(registry, idp)); + let gateway = ToMcpGateway::new(dispatch(registry)); let result = invoke_tool( &gateway, @@ -833,7 +788,7 @@ mod tests { AccessControl::default(), ), ]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let result = invoke_tool(&gateway, "search", None, None).await; assert_eq!(result.is_error, Some(false)); @@ -871,7 +826,7 @@ mod tests { AccessControl::default(), ), ]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert("query".to_string(), Value::String("fs".to_string())); @@ -900,7 +855,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert("name".to_string(), Value::String("fs/readFile".to_string())); @@ -926,7 +881,7 @@ mod tests { ..Default::default() }, )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert("name".to_string(), Value::String("fs/readFile".to_string())); @@ -956,7 +911,7 @@ mod tests { ..Default::default() }, )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1027,7 +982,7 @@ mod tests { Capabilities::new(), )) .unwrap(); - let gateway = ToMcpGateway::new(dispatch(Arc::new(dispatch_registry), provider())); + let gateway = ToMcpGateway::new(dispatch(Arc::new(dispatch_registry))); let mut args = Map::new(); args.insert("name".to_string(), Value::String("secret/op".to_string())); @@ -1066,7 +1021,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1095,7 +1050,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1116,7 +1071,7 @@ mod tests { #[tokio::test] async fn call_argument_errors_carry_retryable_and_truthy_messages() { let registry = full_registry_with_ops(vec![]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let missing = invoke_tool(&gateway, "call", None, None).await; assert_eq!(missing.is_error, Some(true)); @@ -1154,7 +1109,7 @@ mod tests { #[tokio::test] async fn call_returns_structured_error_for_call_error() { let registry = full_registry_with_ops(vec![]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1178,7 +1133,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1235,9 +1190,7 @@ mod tests { ..Default::default() }, )]); - let idp: Arc = - Arc::new(StaticIdentityProvider::new()); - let gateway = ToMcpGateway::new(dispatch(registry, idp)); + let gateway = ToMcpGateway::new(dispatch(registry)); let mut args = Map::new(); args.insert( @@ -1256,7 +1209,7 @@ mod tests { #[tokio::test] async fn unknown_tool_name_returns_not_found_structured_error() { - let gateway = ToMcpGateway::new(dispatch(Arc::new(OperationRegistry::new()), provider())); + let gateway = ToMcpGateway::new(dispatch(Arc::new(OperationRegistry::new()))); let result = invoke_tool(&gateway, "bogus", None, None).await; assert_eq!(result.is_error, Some(true)); let structured = result.structured_content.expect("structured error present"); @@ -1276,11 +1229,7 @@ mod tests { ..Default::default() }, )]); - let idp: Arc = Arc::new( - StaticIdentityProvider::new() - .with_token("alk_admin", identity_with_scopes("admin-peer", &["admin"])), - ); - let gateway = ToMcpGateway::new(dispatch(registry, idp)); + let gateway = ToMcpGateway::new(dispatch(registry)); let admin_identity = identity_with_scopes("admin-peer", &["admin"]); let extensions = extensions_with_identity(Some(admin_identity.clone())); @@ -1354,7 +1303,7 @@ mod tests { OperationType::Query, AccessControl::default(), )]); - let gateway = ToMcpGateway::new(dispatch(registry, provider())); + let gateway = ToMcpGateway::new(dispatch(registry)); let search_result = invoke_tool(&gateway, "search", None, None).await; let ops = search_result diff --git a/src/gateway/dispatch.rs b/src/gateway/dispatch.rs index e4ec582..daa5d45 100644 --- a/src/gateway/dispatch.rs +++ b/src/gateway/dispatch.rs @@ -3,8 +3,9 @@ //! //! Thin concrete struct (not a trait — the alknet research ruled out a //! trait with an associated output type). Holds `Arc` -//! and `Arc` and exposes a `resolve_bearer()` and -//! `invoke()` method pair returning the neutral `ResponseEnvelope`. Each +//! and exposes an `invoke()` family returning the neutral +//! `ResponseEnvelope` — identity is supplied per-call, resolved upstream +//! in the auth middleware. Each //! gateway maps the envelope to its own wire shape (`to_openapi` → HTTP //! `Response`, `to_mcp` → `CallToolResult`). //! @@ -33,7 +34,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; -use alkcall::core::auth::{AuthToken, Identity, IdentityProvider}; +use alkcall::core::auth::Identity; use alkcall::core::types::Capabilities; use alkcall::protocol::wire::{CallError, ResponseEnvelope}; use alkcall::registry::context::{AbortPolicy, OperationContext, ScopedPeerEnv}; @@ -44,25 +45,19 @@ use serde_json::Value; const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); -/// The shared dispatch spine: registry + identity provider, wired for +/// The shared dispatch spine over the registry, invoking operations for /// the neutral `ResponseEnvelope` result shape both gateway projections -/// map to their wire formats. +/// map to their wire formats. Identity arrives per-call as +/// `Option` — bearer resolution happens upstream in the auth +/// middleware, not here. pub struct GatewayDispatch { registry: Arc, - identity_provider: Arc, } impl GatewayDispatch { - /// Assemble a dispatch spine over a registry and an identity - /// provider. - pub fn new( - registry: Arc, - identity_provider: Arc, - ) -> Self { - Self { - registry, - identity_provider, - } + /// Assemble a dispatch spine over a registry. + pub fn new(registry: Arc) -> Self { + Self { registry } } /// The registry operations resolve against. @@ -70,16 +65,6 @@ impl GatewayDispatch { &self.registry } - /// The identity provider bearer tokens resolve against. - pub fn identity_provider(&self) -> &Arc { - &self.identity_provider - } - - /// Resolve a bearer token to an identity (the auth-middleware hook). - pub fn resolve_bearer(&self, token: &AuthToken) -> Option { - self.identity_provider.resolve_from_token(token) - } - /// Invoke a Query/Mutation op under the 30 s gateway deadline; a /// hung handler surfaces as a `TIMEOUT` error envelope (504). pub async fn invoke( @@ -221,33 +206,10 @@ mod tests { }; use alkcall::registry::spec::{AccessControl, OperationSpec, OperationType, Visibility}; use futures::StreamExt; - use std::sync::Mutex as StdMutex; // The tests below run against the module's real 30 s deadline; only // the elapsed-time bound (< 60 s, anti-flake) is asserted by hand. - struct StaticIdentityProvider { - tokens: StdMutex>, - } - - impl StaticIdentityProvider { - fn new() -> Self { - Self { - tokens: StdMutex::new(HashMap::new()), - } - } - } - - impl IdentityProvider for StaticIdentityProvider { - fn resolve_from_fingerprint(&self, _fp: &str) -> Option { - None - } - fn resolve_from_token(&self, token: &AuthToken) -> Option { - let token_str = String::from_utf8_lossy(&token.raw); - self.tokens.lock().unwrap().get(token_str.as_ref()).cloned() - } - } - fn spec(name: &str, visibility: Visibility, op_type: OperationType) -> OperationSpec { OperationSpec::new( name, @@ -280,8 +242,7 @@ mod tests { #[tokio::test] async fn invoke_external_op_round_trips() { - let dispatch = - GatewayDispatch::new(echo_registry(), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(echo_registry()); let envelope = dispatch .invoke(None, "/echo/run", serde_json::json!({ "x": 1 })) .await; @@ -290,8 +251,7 @@ mod tests { #[tokio::test] async fn invoke_unknown_op_returns_not_found() { - let dispatch = - GatewayDispatch::new(echo_registry(), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(echo_registry()); let envelope = dispatch .invoke(None, "/missing/op", serde_json::json!({})) .await; @@ -316,8 +276,7 @@ mod tests { Capabilities::new(), )) .unwrap(); - let dispatch = - GatewayDispatch::new(Arc::new(registry), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(Arc::new(registry)); let envelope = dispatch .invoke(None, "/internal/op", serde_json::json!({})) .await; @@ -345,8 +304,7 @@ mod tests { Capabilities::new(), )) .unwrap(); - let dispatch = - GatewayDispatch::new(Arc::new(registry), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(Arc::new(registry)); let started = std::time::Instant::now(); let envelope = dispatch .invoke(None, "/hung/op", serde_json::json!({})) @@ -367,8 +325,7 @@ mod tests { #[tokio::test] async fn invoke_completes_within_the_deadline_for_a_fast_handler() { - let dispatch = - GatewayDispatch::new(echo_registry(), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(echo_registry()); let envelope = dispatch .invoke(None, "/echo/run", serde_json::json!({})) .await; @@ -394,8 +351,7 @@ mod tests { Capabilities::new(), )) .unwrap(); - let dispatch = - GatewayDispatch::new(Arc::new(registry), Arc::new(StaticIdentityProvider::new())); + let dispatch = GatewayDispatch::new(Arc::new(registry)); let mut stream = dispatch.invoke_streaming(None, "/tick/stream", serde_json::json!({ "count": 3 })); let mut ticks = Vec::new(); diff --git a/src/gateway/routes.rs b/src/gateway/routes.rs index 2ad32fd..2deec97 100644 --- a/src/gateway/routes.rs +++ b/src/gateway/routes.rs @@ -24,7 +24,7 @@ use std::convert::Infallible; use std::sync::Arc; use std::time::Duration; -use alkcall::core::auth::{Identity, IdentityProvider}; +use alkcall::core::auth::Identity; use alkcall::protocol::wire::{CallError, ResponseEnvelope}; use alkcall::registry::registration::OperationRegistry; use alkcall::registry::spec::{AccessResult, Visibility}; @@ -83,38 +83,28 @@ type ByteStream = futures::stream::BoxStream<'static, Result #[derive(Clone)] pub(crate) struct GatewayState { registry: Arc, - identity_provider: Arc, publish_schemas: crate::gateway::schema_cache::PublishSchemaCache, } impl GatewayState { pub(crate) fn new( registry: Arc, - identity_provider: Arc, publish_schemas: crate::gateway::schema_cache::PublishSchemaCache, ) -> Self { Self { registry, - identity_provider, publish_schemas, } } fn dispatch(&self) -> GatewayDispatch { - GatewayDispatch::new( - Arc::clone(&self.registry), - Arc::clone(&self.identity_provider), - ) + GatewayDispatch::new(Arc::clone(&self.registry)) } } impl FromRef for GatewayState { fn from_ref(state: &RouterState) -> Self { - GatewayState::new( - Arc::clone(&state.registry), - Arc::clone(&state.identity_provider), - state.publish_schemas.clone(), - ) + GatewayState::new(Arc::clone(&state.registry), state.publish_schemas.clone()) } } diff --git a/src/server/adapter.rs b/src/server/adapter.rs index c092d4d..bd63b30 100644 --- a/src/server/adapter.rs +++ b/src/server/adapter.rs @@ -285,10 +285,7 @@ fn build_router(state: RouterState, extra_routes: Option) -> Router { #[cfg(feature = "mcp")] let mcp_router: Router = { - let dispatch = crate::gateway::GatewayDispatch::new( - Arc::clone(&state.registry), - Arc::clone(&state.identity_provider), - ); + let dispatch = crate::gateway::GatewayDispatch::new(Arc::clone(&state.registry)); Router::new() .nest_service( "/mcp", diff --git a/src/server/state.rs b/src/server/state.rs index 6e1c232..3151c68 100644 --- a/src/server/state.rs +++ b/src/server/state.rs @@ -71,18 +71,6 @@ impl axum::extract::FromRef for DecoyConfig { } } -impl axum::extract::FromRef for Arc { - fn from_ref(state: &RouterState) -> Self { - Arc::clone(&state.registry) - } -} - -impl axum::extract::FromRef for Arc { - fn from_ref(state: &RouterState) -> Self { - Arc::clone(&state.identity_provider) - } -} - impl axum::extract::FromRef for crate::server::adapter::CachedOpenAPIDoc { fn from_ref(state: &RouterState) -> Self { state.openapi_doc.clone() diff --git a/src/websocket/upgrade.rs b/src/websocket/upgrade.rs index cf93954..af102b1 100644 --- a/src/websocket/upgrade.rs +++ b/src/websocket/upgrade.rs @@ -141,12 +141,6 @@ impl SessionState { } } -impl axum::extract::FromRef for Arc { - fn from_ref(state: &SessionState) -> Self { - Arc::clone(&state.registry) - } -} - /// `FromRef` chain: a bare `Arc` router state lifts /// into the handler's [`SessionState`]; a full `RouterState` carries /// the shared [`WsSessions`] instance and lifts through its own impl.