File size: 4,648 Bytes
3921e25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import gradio as gr
import httpx
import json
import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

MODAL_MCP_ENDPOINT = os.getenv("MODAL_MCP_ENDPOINT", "YOUR_MODAL_MCP_ENDPOINT_HERE")
BANDIT_TOOL_NAME = "bandit"

async def call_bandit_tool_on_modal(tool_parameters_json: str):
    if MODAL_MCP_ENDPOINT == "YOUR_MODAL_MCP_ENDPOINT_HERE" or not MODAL_MCP_ENDPOINT:
        return {"error": "MODAL_MCP_ENDPOINT is not set. Please create a .env file in the 'mcp_deploy' directory with MODAL_MCP_ENDPOINT='your_url' or set it as an environment variable."}

    try:
        tool_parameters = json.loads(tool_parameters_json)
    except json.JSONDecodeError as e:
        return {"error": "Invalid JSON format for tool parameters.", "details": str(e)}

    # Ensure 'code' parameter is present, as Bandit expects it.
    if "code" not in tool_parameters:
        return {"error": "Missing 'code' parameter in JSON. Bandit requires a 'code' field with the Python code string to analyze."}

    payload = {
        "tool_name": BANDIT_TOOL_NAME,
        "tool_params": tool_parameters,
        "agent_id": "gradio-bandit-ui",
        "session_id": "default_session"
    }

    async with httpx.AsyncClient(timeout=60.0) as client:
        try:
            print(f"Calling MCP tool: {BANDIT_TOOL_NAME} at {MODAL_MCP_ENDPOINT} with params: {tool_parameters}")
            response = await client.post(MODAL_MCP_ENDPOINT, json=payload)
            response.raise_for_status()
            print(response.json())
            
            # Handle Modal's [response_dict, status_code] tuple format
            raw_response_data = response.json()
            if isinstance(raw_response_data, list) and len(raw_response_data) > 0 and isinstance(raw_response_data[0], dict):
                actual_response = raw_response_data[0]
            elif isinstance(raw_response_data, dict):
                actual_response = raw_response_data
            else:
                return {"error": "Unexpected response format from MCP server", "details": raw_response_data}
            return actual_response
            
        except httpx.HTTPStatusError as e:
            error_message = f"HTTP error: {e.response.status_code}"
            try:
                error_details = e.response.json()
                error_message += f" - {json.dumps(error_details)}"
            except json.JSONDecodeError:
                error_message += f" - {e.response.text}"
            return {"error": error_message}
        except httpx.RequestError as e:
            return {"error": f"Request error for {e.request.url!r}: {str(e)}"}
        except Exception as e:
            return {"error": f"An unexpected error occurred: {str(e)}"}


# Define Gradio inputs and outputs
tool_params_input = gr.Textbox(
    label="Bandit Parameters (JSON string with 'code' field)",
    placeholder='e.g., {\"code\": \"import os\nprint(os.listdir(\".\"))\"}',
    lines=10,
    info="Enter parameters as a valid JSON string. Must include a 'code' field containing the Python code to analyze."
)
output_display = gr.JSON(label="Bandit Analysis Output")

# Example for Bandit tool
bandit_example_code = """import subprocess\n\n# Example of a potential security risk with subprocess\nsubprocess.call("ls -l", shell=True)"""
bandit_example_params = json.dumps({"code": bandit_example_code}, indent=2)

# Create the Gradio interface
iface = gr.Interface(
    fn=call_bandit_tool_on_modal,
    inputs=[tool_params_input],
    outputs=output_display,
    title="Bandit Security Scanner Interface (via Modal MCP)",
    description="""Interface with the Bandit security scanner tool hosted on Modal via the MCP server.
Provide Python code within a JSON structure under the 'code' key.
Ensure `MODAL_MCP_ENDPOINT` is correctly set in a .env file in the `mcp_deploy` directory or as an environment variable.
The endpoint should point to your Modal function that handles MCP tool execution (e.g., /execute_tool).""",
    examples=[
        [bandit_example_params]
    ],
    allow_flagging="never"
)

if __name__ == "__main__":
    print(f"Attempting to use Modal Endpoint for Bandit: {MODAL_MCP_ENDPOINT}")
    if MODAL_MCP_ENDPOINT == "YOUR_MODAL_MCP_ENDPOINT_HERE" or not MODAL_MCP_ENDPOINT:
        print("\nWARNING: MODAL_MCP_ENDPOINT is not configured. The app will show an error on submit.")
        print("Please create a .env file in the 'mcp_deploy' directory with:")
        print("MODAL_MCP_ENDPOINT=\"your_actual_modal_mcp_endpoint_url\"\n")
    iface.launch(server_name="0.0.0.0") # mcp_server=True removed as it's not needed for this direct app