Migrate all remaining collapsible_if patterns to Rust 2024 let-chain syntax across the entire codebase. This modernizes conditional logic by replacing nested if statements with single-level expressions using the && operator with let patterns. Changes: - storage.rs: 2 let-chain conversions (database dir creation, legacy archiving) - session.rs: 3 let-chain conversions (empty content check, ledger dir creation, consent flow) - ollama.rs: 8 let-chain conversions (socket parsing, cloud validation, model caching, capabilities) - main.rs: 2 let-chain conversions (API key validation, provider enablement) - owlen-tui: ~50 let-chain conversions across app/mod.rs, chat_app.rs, ui.rs, highlight.rs, and state modules Test fixes: - prompt_server.rs: Add missing .await on async RemoteMcpClient::new_with_config - presets.rs, prompt_server.rs: Add missing rpc_timeout_secs field to McpServerConfig - file_write.rs: Update error assertion to accept new "escapes workspace boundary" message Verification: - cargo build --all: ✅ succeeds - cargo clippy --all -- -D clippy::collapsible_if: ✅ zero warnings - cargo test --all: ✅ 109+ tests pass Net result: -46 lines of code, improved readability and maintainability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
70 lines
2.5 KiB
Rust
70 lines
2.5 KiB
Rust
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().await.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().await.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")
|
|
|| err_str.contains("escapes workspace boundary"),
|
|
"Expected path traversal error, got: {}",
|
|
err_str
|
|
);
|
|
}
|