"""Bunny Shield tools — Shield Zone API (/shield/shield-zone, /shield/shield-zones). NOTE: Shield는 Pull Zone 필드(ShieldDDosProtectionEnabled 등)가 아니라 별도 Shield Zone API로 관리됨. Pull Zone 업데이트로는 Shield를 켤 수 없음. """ import json from typing import Annotated from pydantic import Field from ..client import client from ..config import logger def register_shield_tools(mcp): @mcp.tool() async def bunny_shield_list() -> str: """List all Shield Zones with WAF/DDoS configuration.""" try: data = await client.get("/shield/shield-zones", params={"page": 1, "perPage": 50}) zones = data.get("data", []) if isinstance(data, dict) else data result = [] for z in zones: result.append({ "shieldZoneId": z.get("shieldZoneId"), "pullZoneId": z.get("pullZoneId"), "wafEnabled": z.get("wafEnabled"), "dDoSShieldSensitivity": z.get("dDoSShieldSensitivity"), "dDoSExecutionMode": z.get("dDoSExecutionMode"), "learningMode": z.get("learningMode"), "learningModeUntil": z.get("learningModeUntil"), "planType": z.get("planType"), }) return json.dumps(result, indent=2) except Exception as e: logger.error("bunny_shield_list failed: %s", e) return f"Error: {e}" @mcp.tool() async def bunny_shield_status( shield_zone_id: Annotated[int, Field(description="Shield Zone ID (not Pull Zone ID). Use bunny_shield_list to find it.")], ) -> str: """Get Shield Zone configuration by Shield Zone ID.""" try: data = await client.get(f"/shield/shield-zone/{shield_zone_id}") return json.dumps(data, indent=2) except Exception as e: logger.error("bunny_shield_status failed: %s", e) return f"Error: {e}" @mcp.tool() async def bunny_shield_create( pullzone_id: Annotated[int, Field(description="Pull Zone ID to enable Shield on")], waf_enabled: Annotated[bool, Field(default=True, description="Enable WAF")] = True, ddos_sensitivity: Annotated[int, Field(default=2, description="DDoS sensitivity: 0=off, 1=low, 2=medium, 3=high, 4=extreme")] = 2, ) -> str: """Create a Shield Zone for a Pull Zone (enables Shield protection). Returns 409 if already exists.""" try: body = { "pullZoneId": pullzone_id, "wafEnabled": waf_enabled, "dDoSShieldSensitivity": ddos_sensitivity, } data = await client.post("/shield/shield-zone", json=body) return json.dumps(data, indent=2) except Exception as e: logger.error("bunny_shield_create failed: %s", e) return f"Error: {e}" @mcp.tool() async def bunny_shield_update( shield_zone_id: Annotated[int, Field(description="Shield Zone ID (not Pull Zone ID)")], settings: Annotated[str, Field(description="JSON string of shield settings (e.g. '{\"wafEnabled\": true, \"dDoSShieldSensitivity\": 2}')")], ) -> str: """Update Shield Zone configuration by Shield Zone ID.""" try: parsed = json.loads(settings) except json.JSONDecodeError as e: return f"Error: Invalid JSON: {e}" try: data = await client.put(f"/shield/shield-zone/{shield_zone_id}", json=parsed) return json.dumps(data, indent=2) if isinstance(data, dict) else f"Shield zone {shield_zone_id} updated" except Exception as e: logger.error("bunny_shield_update failed: %s", e) return f"Error: {e}" @mcp.tool() async def bunny_waf_rules( shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], ) -> str: """List WAF rules for a Shield Zone.""" try: data = await client.get(f"/shield/waf/{shield_zone_id}") return json.dumps(data, indent=2) except Exception as e: logger.error("bunny_waf_rules failed: %s", e) return f"Error: {e}" @mcp.tool() async def bunny_waf_logs( shield_zone_id: Annotated[int, Field(description="Shield Zone ID")], page: Annotated[int, Field(default=1, description="Page number")] = 1, per_page: Annotated[int, Field(default=25, description="Results per page (max 100)")] = 25, ) -> str: """Get WAF event logs for a Shield Zone.""" try: params = {"page": page, "perPage": min(per_page, 100)} data = await client.get(f"/shield/event-logs/{shield_zone_id}", params=params) return json.dumps(data, indent=2) except Exception as e: logger.error("bunny_waf_logs failed: %s", e) return f"Error: {e}"