""" A2H2A Client - Bibliotek for å poste A2H2A tickets fra agenter Med støtte for alle MCP tools """ import httpx import os from datetime import datetime from typing import Dict, List, Optional OPAX_BASE_URL = os.getenv('OPAX_BASE_URL', 'https://opax.vauco.no') MCP_SECRET = os.getenv('MCP_SECRET') # MCP Tool Registry - alle tools som krever A2H2A A2H2A_TOOLS = { "opax.secrets.rotate": { "severity": "CRITICAL", "timeout_minutes": 15, "description": "Roter hemmelighet i Secret Manager" }, "opax.traffic.shift": { "severity": "CRITICAL", "timeout_minutes": 15, "description": "Skift trafikk mellom Cloud Run revisjoner" }, "tyr.kms.attest": { "severity": "HIGH", "timeout_minutes": 60, "description": "Signer container digest med KMS for Binary Authorization" }, "tyr.perimeter.update": { "severity": "CRITICAL", "timeout_minutes": 30, "description": "Juster VPC-SC perimeter policyer" }, "osvauco.git.filter": { "severity": "CRITICAL", "timeout_minutes": 30, "description": "Fjern sensitiv historikk fra Git" }, "osvauco.firewall.block": { "severity": "HIGH", "timeout_minutes": 15, "description": "Blokker IP via Cloud Armor / VPC brannmur" } } class A2H2AClient: def __init__(self): self.base_url = OPAX_BASE_URL self.headers = { 'X-MCP-Secret': MCP_SECRET, 'Content-Type': 'application/json' } def get_tool_config(self, tool_name: str) -> Optional[Dict]: """Hent konfigurasjon for et tool""" return A2H2A_TOOLS.get(tool_name) async def create_ticket_for_tool( self, tool_name: str, tool_parameters: Dict, reporter: str, trigger: str, affected_service: str, summary: str, evidence_logs: List[str], rollback_plan: str, project_id: str = "propane-will-491900-m5", region: str = "us-central1", category: str = "AUTOMATED_REMEDIATION", authorized_approver: str = "chris.christiansen@vauco.no" ) -> Dict: """ Opprett A2H2A ticket basert på tool-konfigurasjon. Automatisk henter severity og timeout fra A2H2A_TOOLS registry. """ tool_config = self.get_tool_config(tool_name) if not tool_config: raise ValueError(f"Tool '{tool_name}' er ikke registrert i A2H2A_TOOLS") ticket = { "ticket_id": f"A2H2A-{datetime.utcnow().strftime('%Y%m%d-%H%M%S')}", "timestamp": datetime.utcnow(), "severity": tool_config["severity"], "category": category, "source": { "reporter": reporter, "trigger": trigger, "affected_service": affected_service, "project_id": project_id, "region": region }, "context": { "summary": summary, "evidence_logs": evidence_logs }, "proposed_action": { "action_type": "AUTOMATED_REMEDIATION", "runbook_reference": f"docs/RUNBOOK.md#scenario-{category.lower()}", "execution_tool": tool_name, "parameters": tool_parameters, "rollback_plan": rollback_plan }, "governance": { "approval_status": "PENDING", "authorized_approver": authorized_approver, "requires_mfa": True, "timeout_minutes": tool_config["timeout_minutes"] } } async with httpx.AsyncClient() as client: response = await client.post( f"{self.base_url}/api/v1/a2h2a/tickets", json=ticket, headers=self.headers ) return response.json() async def register_new_tool( self, tool_name: str, severity: str, timeout_minutes: int, description: str ): """ Registrer et nytt tool i A2H2A_TOOLS (for fremtidige tools). Dette kan kalles dynamisk når nye tools legges til i server.py """ A2H2A_TOOLS[tool_name] = { "severity": severity, "timeout_minutes": timeout_minutes, "description": description } # Convenience function async def post_a2h2a_ticket_for_tool(tool_name: str, **kwargs): client = A2H2AClient() return await client.create_ticket_for_tool(tool_name, **kwargs)