Spaces:
Running
Running
File size: 7,588 Bytes
4801adf 4f21d95 |
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
#!/usr/bin/env python3
"""
MCP server for Circle Test - a tool for checking code against security policies
"""
import gradio as gr
import aiohttp
import asyncio
import ssl
import os
from typing import Dict, List
from dotenv import load_dotenv
# Загружаем переменные окружения
load_dotenv()
# Получаем URL из переменных окружения
CIRCLE_API_URL = os.getenv('CIRCLE_API_URL', 'https://api.example.com/protect/check_violation')
async def check_violation(prompt: str, policies: Dict[str, str]) -> Dict:
"""
Проверяет код на соответствие политикам безопасности.
Args:
prompt (str): Код для проверки
policies (Dict[str, str]): Словарь политик безопасности
Returns:
Dict: Результаты проверки
"""
try:
payload = {
"dialog": [
{
"role": "assistant",
"content": prompt
}
],
"policies": policies
}
# Создаем SSL-контекст
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
async with aiohttp.ClientSession() as session:
async with session.post(
CIRCLE_API_URL,
json=payload,
timeout=30,
ssl=ssl_context
) as response:
result = await response.json()
# Преобразуем результат в более читаемый формат
if 'policies' in result:
formatted_result = {}
for policy_num, value in result['policies'].items():
policy_text = policies.get(policy_num, "Unknown policy")
formatted_result[policy_num] = {
"policy": policy_text,
"violation": "yes" if value == 1 else "no"
}
return {
"success": True,
"results": formatted_result
}
return {
"success": False,
"error": "Invalid response format"
}
except Exception as e:
return {
"success": False,
"error": f"Error checking violations: {str(e)}"
}
# Создаем Gradio интерфейс
with gr.Blocks(title="Circle Test MCP") as demo:
gr.Markdown("# 🔍 Circle Test Scanner")
gr.Markdown("Security policy compliance checker with MCP support")
with gr.Tab("Policy Check"):
with gr.Row():
with gr.Column():
code_input = gr.Textbox(
lines=10,
placeholder="Enter code to check...",
label="Code"
)
check_btn = gr.Button("🔍 Check Policies", variant="primary")
with gr.Column():
check_output = gr.JSON(label="Check Results")
check_btn.click(
fn=check_violation,
inputs=[
code_input,
gr.State({
"1": "Presence of SPDX-License-Identifier with an ID not in the approved list, or missing SPDX tag in top-level LICENSE file.",
"2": "Presence of plaintext credentials (passwords, tokens, keys) in configuration files (YAML, JSON, .env, etc.).",
"3": "Presence of TODO or FIXME tags in comments inside non-test production code files.",
"4": "Presence of any string literal starting with http:// not wrapped in a validated secure-client.",
"5": "Presence of logging statements that output sensitive data (user PII, private keys, passwords, tokens) without masking or hashing.",
"6": "Presence of calls to deprecated or outdated APIs (functions or methods marked as deprecated).",
"7": "Presence of subprocess or os.system calls where user input is concatenated directly without proper sanitization or escaping.",
"8": "Presence of file read/write operations using paths derived directly from user input without normalization or path-traversal checks.",
"9": "Presence of SQL queries built using string concatenation with user input instead of parameterized queries or ORM methods.",
"10": "Presence of string literals matching absolute filesystem paths (e.g., \"/home/...\" or \"C:\\\\...\") rather than relative paths or environment variables.",
"11": "Presence of hostnames or URLs containing \"prod\", \"production\", or \"release\" that reference production databases or services in non-test code.",
"12": "Presence of dependencies in lock files (Pipfile.lock or requirements.txt) without exact version pins (using version ranges like \">=\" or \"~=\" without a fixed version).",
"13": "Presence of hashlib.md5(...) or any MD5-based hashing, since MD5 is cryptographically broken (use SHA-256 or better).",
"14": "Presence of pdb.set_trace() or other pdb imports, as debug statements should not remain in production code.",
"15": "Presence of logging.debug($SENSITIVE) or similar logging calls that output sensitive information without redaction.",
"16": "Presence of re.compile($USER_INPUT) where $USER_INPUT is unsanitized, since this can lead to ReDoS attacks.",
"17": "Presence of xml.etree.ElementTree.parse($USER_INPUT) without secure parsing, leading to XXE vulnerabilities.",
"18": "Presence of zipfile.ZipFile($USER_INPUT) or similar extraction calls on untrusted zips, which can cause path traversal.",
"19": "Presence of tarfile.open($USER_INPUT) on untrusted tar files, leading to path traversal vulnerabilities.",
"20": "Presence of os.chmod($PATH, 0o777) or equivalent setting overly permissive permissions, which is insecure.",
"21": "Presence of os.environ[$KEY] = $VALUE modifying environment variables at runtime, which can introduce security risks."
})
],
outputs=check_output
)
with gr.Tab("Examples"):
gr.Markdown("""
## 🚨 Examples of code to check:
### 1. Insecure File Operations
```python
def read_file(filename):
with open(filename, "r") as f:
return f.read()
```
### 2. Hardcoded Credentials
```python
DB_PASSWORD = "secret123"
API_KEY = "sk_live_51H1h2K3L4M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8"
```
### 3. Insecure Subprocess
```python
import subprocess
subprocess.call(f"ls {user_input}", shell=True)
```
""")
if __name__ == "__main__":
# Получаем настройки сервера из переменных окружения
server_name = os.getenv("GRADIO_SERVER_NAME", "0.0.0.0")
server_port = int(os.getenv("GRADIO_SERVER_PORT", "7864"))
demo.launch(
mcp_server=True,
server_name=server_name,
server_port=server_port,
share=False
) |