use owlen_core::McpToolCall; use owlen_core::mcp::remote_client::RemoteMcpClient; use tempfile::tempdir; #[tokio::test] async fn remote_write_and_delete() { // Build the server binary first let status = std::process::Command::new("cargo") .args(["build", "-p", "owlen-mcp-server"]) .status() .expect("failed to build MCP server"); assert!(status.success()); // Use a temp dir as project root let dir = tempdir().expect("tempdir"); std::env::set_current_dir(dir.path()).expect("set cwd"); let client = RemoteMcpClient::new().expect("client init"); // Write a file via MCP let write_call = McpToolCall { name: "resources/write".to_string(), arguments: serde_json::json!({ "path": "test.txt", "content": "hello" }), }; client.call_tool(write_call).await.expect("write tool"); // Verify content via local read (fallback check) let content = std::fs::read_to_string(dir.path().join("test.txt")).expect("read back"); assert_eq!(content, "hello"); // Delete the file via MCP let del_call = McpToolCall { name: "resources/delete".to_string(), arguments: serde_json::json!({ "path": "test.txt" }), }; client.call_tool(del_call).await.expect("delete tool"); assert!(!dir.path().join("test.txt").exists()); } #[tokio::test] async fn write_outside_root_is_rejected() { // Build server (already built in previous test, but ensure it exists) let status = std::process::Command::new("cargo") .args(["build", "-p", "owlen-mcp-server"]) .status() .expect("failed to build MCP server"); assert!(status.success()); // Set cwd to a fresh temp dir let dir = tempdir().expect("tempdir"); std::env::set_current_dir(dir.path()).expect("set cwd"); let client = RemoteMcpClient::new().expect("client init"); // Attempt to write outside the root using "../evil.txt" let call = McpToolCall { name: "resources/write".to_string(), arguments: serde_json::json!({ "path": "../evil.txt", "content": "bad" }), }; let err = client.call_tool(call).await.unwrap_err(); // The server returns a Network error with path traversal message let err_str = format!("{err}"); assert!( err_str.contains("path traversal") || err_str.contains("Path traversal"), "Expected path traversal error, got: {}", err_str ); }