fix(gateway): block services/schema spec disclosure via the op path (review-002 PRJ-16)

Internal/ACL-restricted op specs were readable through
POST /call {"operation":"services/schema","input":{"name":...}}
(the MCP call/batch tools identically): the outer-name pre-checks pass
(services/schema is External) and alkcall's services_schema_handler
projects any registered spec with no visibility/ACL check of its own
(alkcall CF-004 is the complete fix there).

- GatewayDispatch.invoke/invoke_streaming now apply the GET /schema
  route's is-internal + access-control checks to the meta-op's inner
  name input before dispatch (404 Internal / FORBIDDEN ACL), one
  interception point covering /call, /batch, /subscribe and the MCP
  call/batch tools; /publish cannot reach the Query-typed meta-op
- the visibility+ACL check is one shared fn (schema_disclosure_denial)
  used by the HTTP /schema route, the dispatch guard, and the MCP
  schema tool, so transports cannot drift
- when CF-004 lands, this guard remains as defense-in-depth (ADR-071)

Tests: dispatch-spine guard unit tests; /call 404 + 401/403 matrix,
/batch NOT_FOUND entry, /subscribe error event; MCP call/batch tools
via services/schema with an Internal inner name (mcp feature).

Verify: cargo test (405), --all-features (523), clippy default and
--all-features --all-targets -D warnings, fmt --check — all pass.
This commit is contained in:
2026-08-31 01:32:59 +00:00
parent a7f10ed04c
commit 207bca4f23
6 changed files with 744 additions and 13 deletions
+2
View File
@@ -3,6 +3,8 @@ pub mod error;
pub mod routes;
pub(crate) mod schema_cache;
#[cfg(feature = "mcp")]
pub(crate) use dispatch::schema_disclosure_denial;
pub use dispatch::GatewayDispatch;
pub use routes::CallRequest;