//! End-to-end: drive the real `sandbox-mcp` server over stdio with the client //! bridge — exactly the path an editor (agent-zed) takes to route execution //! through the attested sandbox and receive the signed receipt. use sandbox_mcp::SandboxMcp; use serde_json::json; const TRIVIAL: &str = r#"(module (func (export "run") (result i32) (i32.const 0)))"#; #[test] fn editor_drives_an_attested_build_over_mcp() { let mut mcp = SandboxMcp::spawn(env!("CARGO_BIN_EXE_sandbox-mcp")).expect("spawn server"); // The tools an editor can call are advertised. let tools = mcp.list_tools().unwrap().to_string(); assert!(tools.contains("\"build\"")); assert!(tools.contains("\"run_wasm\"")); // A build with op provenance + a speculative fallback comes back attested. let receipt = mcp .build( "scaffold a note app and test it", json!([ { "id": "generate", "wat": TRIVIAL, "kv": true, "op": { "path": "src/store.rs", "author": "agent-zed" }, "candidates": [ { "label": "fallback", "wat": TRIVIAL } ] }, { "id": "test", "wat": TRIVIAL } ]), ) .expect("build tool"); assert_eq!(receipt["verified"], true); assert_eq!(receipt["tier_floor"], "S2"); assert!(receipt["build_id"].as_str().unwrap().starts_with("b3:")); assert_eq!(receipt["steps"].as_array().unwrap().len(), 2); // The op provenance the editor supplied round-tripped into the signed receipt. assert_eq!(receipt["steps"][0]["op"]["author"], "agent-zed"); assert_eq!(receipt["steps"][0]["op"]["path"], "src/store.rs"); // A single unit run is also attested. let run = mcp.run_wasm(json!({ "wat": TRIVIAL })).expect("run_wasm"); assert_eq!(run["eat"]["profile"], "https://transaction.science/sandbox/eat/v1"); } #[test] fn a_tool_error_surfaces_as_err() { let mut mcp = SandboxMcp::spawn(env!("CARGO_BIN_EXE_sandbox-mcp")).unwrap(); // `build` with no steps is a tool error — the client returns Err, not a panic. assert!(mcp.build("nothing", json!([])).is_err()); }