mirror of
https://github.com/hansjone/netx.git
synced 2026-10-18 17:20:44 +08:00
MCP: add bizMonitor server, align ops/topology tools, harden CLI exec
- New packages/netx-bizmonitor-mcp: 8 read-only cutover/biz-state tools mirroring the netxops bizMonitor group. - Align netx-mcp (15) and netx-topology-mcp (16) with backend HTTP contracts; surface partial batch failures as tool errors. - CLI hard gate: single-line show/display only; exec job IDs, path containment, owner and ne:exec checks. - Cisco IOSv collection: stable prompt/echo handling over CR. - Remove legacy netx_api/mcp and mcp_server.py; add mcp.all.json; sync skills and docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d8da7acb7d
commit
9085cac742
63 changed files with 3251 additions and 1092 deletions
26
packages/netx-mcp/src/netx_mcp/cli_guard.py
Normal file
26
packages/netx-mcp/src/netx_mcp/cli_guard.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""MCP 独立只读边界:后端开放 shell 策略也不能扩大模型的执行权限。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
_PREFIX = re.compile(r"(?i)^(show|display)[ \t]+\S")
|
||||
_CONTROL = re.compile(r"[\x00-\x08\x0a-\x1f\x7f-\x9f\u2028\u2029]")
|
||||
_SHELL = re.compile(r"[;&`$<>]")
|
||||
_DESTRUCTIVE = re.compile(
|
||||
r"(?i)\b(reboot|reload|shutdown|erase|format|delete|commit|rollback|redirect|append|tee)\b"
|
||||
r"|\b(?:configure\s+terminal|conf\s+t|write\s+memory|system-view|undo\s+)"
|
||||
)
|
||||
_FILTER = re.compile(r"(?i)^(include|exclude|begin|section|count|match|grep|one-line|no-more)(?:[ \t]|$)")
|
||||
|
||||
|
||||
def validate_readonly_cli(command: str) -> None:
|
||||
if not isinstance(command, str) or not command.strip():
|
||||
raise ValueError("MCP CLI requires a nonempty show/display command")
|
||||
if len(command) > 500 or _CONTROL.search(command) or _SHELL.search(command):
|
||||
raise ValueError("MCP CLI rejects control characters, shell operators and commands longer than 500 characters")
|
||||
cmd = command.strip()
|
||||
if not _PREFIX.match(cmd) or _DESTRUCTIVE.search(cmd):
|
||||
raise ValueError("MCP CLI allows read-only show/display only; open device policies do not override this boundary")
|
||||
parts = cmd.split("|")
|
||||
if any(not _FILTER.match(part.strip()) for part in parts[1:]):
|
||||
raise ValueError("MCP CLI pipes allow output filters only")
|
||||
Loading…
Add table
Add a link
Reference in a new issue