sqry-mcp 6.0.21

MCP server for sqry semantic code search
Documentation
mod common;

use anyhow::Result;
use common::McpTestClient;
use serde_json::json;

#[cfg(unix)]
#[test]
fn symlink_escape_rejected() -> Result<()> {
    use std::fs;
    use std::os::unix::fs as unix_fs;

    let root = tempfile::tempdir()?;
    let root_path = root.path().to_path_buf();
    let inside = root_path.join("inside");
    fs::create_dir_all(&inside)?;

    let outside = tempfile::tempdir()?;
    let outside_path = outside.path().to_path_buf();

    let escape_link = inside.join("escape");
    unix_fs::symlink(&outside_path, &escape_link)?;

    let envs = vec![(
        "SQRY_MCP_WORKSPACE_ROOT".to_string(),
        root_path.to_string_lossy().to_string(),
    )];
    let mut client = McpTestClient::new_with_env_initialized(&envs)?;

    let response = client.call(
        "tools/call",
        json!({
            "name": "semantic_search",
            "arguments": {
                "query": "kind:function",
                "path": "inside/escape",
                "max_results": 5
            }
        }),
        42,
    )?;

    assert_eq!(response["jsonrpc"], "2.0");
    let error = response["error"].as_object().expect("error object");
    assert_eq!(error["code"], -32603);
    let message = error["message"].as_str().unwrap_or("");
    assert!(
        message.contains("outside of the workspace root")
            || message.contains("Failed to canonicalize path"),
        "unexpected error message: {message}"
    );

    Ok(())
}

#[test]
fn parent_directory_traversal_rejected() -> Result<()> {
    let mut client = McpTestClient::new_initialized()?;

    let response = client.call(
        "tools/call",
        json!({
            "name": "semantic_search",
            "arguments": {
                "query": "kind:function",
                "path": "../../../etc",
                "max_results": 5
            }
        }),
        7,
    )?;

    assert_eq!(response["jsonrpc"], "2.0");
    let error = response["error"].as_object().expect("error");
    assert_eq!(error["code"], -32603);
    let message = error["message"].as_str().unwrap_or("");
    assert!(
        message.contains("outside of the workspace root")
            || message.contains("Failed to canonicalize path"),
        "unexpected error message: {message}"
    );

    Ok(())
}