mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-07-21 03:41:03 +02:00
test(mcp): harden symptomatic MCP fixes to construction-enforced
Four guards/refactors that convert previously convention-enforced MCP
invariants into ones a future edit can't silently break:
- H1 (loopback Host set): standalone.rs surface-guard asserts our loopback
allow-list is a superset of rmcp's own default set, so an rmcp bump that
adds a loopback form turns red instead of 403'ing that client. Pins the
::1 regression by construction rather than by a hand-kept literal list.
- H2 (one stored-query gate): extract a single invoke_query_request() in
handlers.rs used by GET /queries, POST /queries/{name}, and (imported) the
MCP tools/list + tools/call stored paths. REST and MCP can no longer drift
on which Cedar action governs the catalog. Deletes mcp.rs's local copy.
- H3 (expose chokepoint): tests/mcp.rs source-walk guard bans .lookup( and
registry.iter( in mcp.rs, so the agent surface can only reach stored
queries through exposed()/exposed_by_name() — an @mcp(expose:false) query
cannot leak back into tools/list via the expose-ignoring registry methods.
- H4 (list-gate relaxation lower-bound): a permit-all actor must see every
built-in tool, pinning the other end of the list-gate fix (no callable
tool may be hidden from tools/list).
cargo test -p omnigraph-mcp -p omnigraph-server green (the lone schema_routes
flake was disk-pressure during the clean build; passes in isolation).
This commit is contained in:
parent
fbf455a250
commit
8dab7e2e61
4 changed files with 92 additions and 24 deletions
|
|
@ -693,6 +693,58 @@ async fn stored_query_run_cannot_reach_unexposed_query() {
|
|||
assert_eq!(v["result"]["isError"], json!(true), "unexposed query must not run via stored_query_run: {v}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_backend_resolves_only_through_the_exposed_chokepoint() {
|
||||
// Construction guard for the stored-query expose class: the MCP backend must
|
||||
// reach stored queries ONLY through exposed()/exposed_by_name(), never the
|
||||
// expose-ignoring QueryRegistry::lookup/iter (those would leak an
|
||||
// `@mcp(expose: false)` query to the agent surface). HTTP/service callers may
|
||||
// use lookup/iter; the agent surface may not. A source-walk so a future edit
|
||||
// that reintroduces the bug fails loudly here.
|
||||
const SRC: &str = include_str!("../src/mcp.rs");
|
||||
assert!(
|
||||
!SRC.contains(".lookup("),
|
||||
"mcp.rs must not call registry.lookup — use exposed_by_name()"
|
||||
);
|
||||
assert!(
|
||||
!SRC.contains("registry.iter("),
|
||||
"mcp.rs must not call registry.iter — use exposed()"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn permit_all_actor_sees_every_builtin_tool() {
|
||||
// Relaxation lower-bound for `list_gate`: when the policy permits every
|
||||
// action, NO built-in may be hidden from tools/list (a hidden-but-callable
|
||||
// tool is the class the list-gate fix closed). Pairs with
|
||||
// `list_gate_matches_call_for_fixed_branchless_reads`, which pins the
|
||||
// fixed-branchless reads' faithful gate at the other end.
|
||||
let (_t, app) = app_for_loaded_graph_with_auth_tokens(&[("act", "tok")]).await;
|
||||
let (_s, list) =
|
||||
json_response(&app, mcp_request(Some("tok"), rpc(1, "tools/list", json!({})))).await;
|
||||
let names = tool_names(&list);
|
||||
for builtin in [
|
||||
"graph_health",
|
||||
"graph_query",
|
||||
"graph_snapshot",
|
||||
"schema_get",
|
||||
"branch_list",
|
||||
"commit_list",
|
||||
"commit_get",
|
||||
"graph_mutate",
|
||||
"graph_load",
|
||||
"branch_create",
|
||||
"branch_delete",
|
||||
"branch_merge",
|
||||
"schema_apply",
|
||||
] {
|
||||
assert!(
|
||||
names.contains(&builtin.to_string()),
|
||||
"a permit-all actor must see built-in '{builtin}' (list_gate must not hide a callable tool): {names:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stored_query_shadowing_a_builtin_is_a_load_error() {
|
||||
// A stored query whose tool name collides with a built-in must fail loudly
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue